essential-eth 0.4.11 → 0.5.4-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/classes/Contract.d.ts +3 -2
- package/lib/cjs/classes/Contract.js +3 -2
- package/lib/cjs/classes/utils/clean-block.d.ts +3 -3
- package/lib/cjs/classes/utils/clean-block.js +3 -2
- package/lib/cjs/classes/utils/clean-transaction.d.ts +3 -3
- package/lib/cjs/classes/utils/clean-transaction.js +10 -6
- package/lib/cjs/classes/utils/encode-decode-transaction.d.ts +1 -0
- package/lib/cjs/classes/utils/encode-decode-transaction.js +4 -4
- package/lib/cjs/classes/utils/fetchers.d.ts +1 -1
- package/lib/cjs/index.d.ts +6 -3
- package/lib/cjs/index.js +19 -1
- package/lib/cjs/logger/logger.d.ts +11 -0
- package/lib/cjs/logger/logger.js +36 -0
- package/lib/cjs/logger/package-version.d.ts +1 -0
- package/lib/cjs/logger/package-version.js +5 -0
- package/lib/cjs/providers/BaseProvider.d.ts +261 -0
- package/lib/cjs/providers/BaseProvider.js +340 -0
- package/lib/cjs/providers/FallthroughProvider.d.ts +25 -0
- package/lib/cjs/providers/FallthroughProvider.js +65 -0
- package/lib/cjs/providers/JsonRpcProvider.d.ts +7 -33
- package/lib/cjs/providers/JsonRpcProvider.js +11 -93
- package/lib/cjs/providers/test/rpc-urls.d.ts +1 -0
- package/lib/cjs/providers/test/rpc-urls.js +1 -0
- package/lib/cjs/providers/utils/chains-info.d.ts +14 -0
- package/lib/cjs/providers/utils/chains-info.js +42 -0
- package/lib/cjs/shared/tiny-big/tiny-big.d.ts +9 -2
- package/lib/cjs/shared/tiny-big/tiny-big.js +26 -2
- package/lib/cjs/types/Block.types.d.ts +8 -19
- package/lib/cjs/types/Transaction.types.d.ts +23 -14
- package/lib/cjs/utils/bytes.d.ts +171 -0
- package/lib/cjs/utils/bytes.js +564 -0
- package/lib/cjs/utils/solidity-keccak256.d.ts +30 -0
- package/lib/cjs/utils/solidity-keccak256.js +125 -0
- package/lib/esm/classes/Contract.js +1 -1
- package/lib/esm/classes/utils/clean-block.d.ts +2 -2
- package/lib/esm/classes/utils/clean-block.js +2 -1
- package/lib/esm/classes/utils/clean-transaction.d.ts +2 -2
- package/lib/esm/classes/utils/clean-transaction.js +10 -6
- package/lib/esm/classes/utils/encode-decode-transaction.d.ts +1 -0
- package/lib/esm/classes/utils/encode-decode-transaction.js +2 -2
- package/lib/esm/classes/utils/fetchers.d.ts +1 -1
- package/lib/esm/index.d.ts +6 -3
- package/lib/esm/index.js +4 -1
- package/lib/esm/logger/logger.d.ts +11 -0
- package/lib/esm/logger/logger.js +33 -0
- package/lib/esm/logger/package-version.d.ts +1 -0
- package/lib/esm/logger/package-version.js +1 -0
- package/lib/esm/providers/BaseProvider.d.ts +17 -0
- package/lib/esm/providers/BaseProvider.js +88 -0
- package/lib/esm/providers/FallthroughProvider.d.ts +12 -0
- package/lib/esm/providers/FallthroughProvider.js +41 -0
- package/lib/esm/providers/JsonRpcProvider.d.ts +4 -9
- package/lib/esm/providers/JsonRpcProvider.js +8 -67
- package/lib/esm/providers/test/rpc-urls.d.ts +1 -0
- package/lib/esm/providers/test/rpc-urls.js +1 -0
- package/lib/esm/providers/utils/chains-info.d.ts +14 -0
- package/lib/esm/providers/utils/chains-info.js +42 -0
- package/lib/esm/shared/tiny-big/tiny-big.d.ts +2 -0
- package/lib/esm/shared/tiny-big/tiny-big.js +19 -0
- package/lib/esm/types/Block.types.d.ts +7 -19
- package/lib/esm/types/Transaction.types.d.ts +22 -14
- package/lib/esm/utils/bytes.d.ts +39 -0
- package/lib/esm/utils/bytes.js +245 -0
- package/lib/esm/utils/solidity-keccak256.d.ts +3 -0
- package/lib/esm/utils/solidity-keccak256.js +91 -0
- package/package.json +19 -19
- package/readme.md +251 -61
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.solidityKeccak256 = exports.hashKeccak256 = exports.pack = void 0;
|
|
4
|
+
const buffer_1 = require("buffer");
|
|
5
|
+
const sha3_1 = require("sha3");
|
|
6
|
+
const encode_decode_transaction_1 = require("../classes/utils/encode-decode-transaction");
|
|
7
|
+
const logger_1 = require("../logger/logger");
|
|
8
|
+
const tiny_big_1 = require("../shared/tiny-big/tiny-big");
|
|
9
|
+
const bytes_1 = require("./bytes");
|
|
10
|
+
const regexBytes = new RegExp('^bytes([0-9]+)$');
|
|
11
|
+
const regexNumber = new RegExp('^(u?int)([0-9]*)$');
|
|
12
|
+
const regexArray = new RegExp('^(.*)\\[([0-9]*)\\]$');
|
|
13
|
+
function _pack(type, value, isArray) {
|
|
14
|
+
switch (type) {
|
|
15
|
+
case 'address':
|
|
16
|
+
if (isArray) {
|
|
17
|
+
return (0, bytes_1.zeroPad)(value, 32);
|
|
18
|
+
}
|
|
19
|
+
return (0, bytes_1.arrayify)(value);
|
|
20
|
+
case 'string':
|
|
21
|
+
return buffer_1.Buffer.from(value);
|
|
22
|
+
case 'bytes':
|
|
23
|
+
return (0, bytes_1.arrayify)(value);
|
|
24
|
+
case 'bool':
|
|
25
|
+
value = value ? '0x01' : '0x00';
|
|
26
|
+
if (isArray) {
|
|
27
|
+
return (0, bytes_1.zeroPad)(value, 32);
|
|
28
|
+
}
|
|
29
|
+
return (0, bytes_1.arrayify)(value);
|
|
30
|
+
}
|
|
31
|
+
let match = type.match(regexNumber);
|
|
32
|
+
if (match) {
|
|
33
|
+
//let signed = (match[1] === "int")
|
|
34
|
+
let size = parseInt(match[2] || '256');
|
|
35
|
+
if ((match[2] && String(size) !== match[2]) ||
|
|
36
|
+
size % 8 !== 0 ||
|
|
37
|
+
size === 0 ||
|
|
38
|
+
size > 256) {
|
|
39
|
+
logger_1.logger.throwArgumentError('invalid number type', 'type', type);
|
|
40
|
+
}
|
|
41
|
+
if (isArray) {
|
|
42
|
+
size = 256;
|
|
43
|
+
}
|
|
44
|
+
value = (0, tiny_big_1.tinyBig)(value).toTwos(size).toNumber();
|
|
45
|
+
const hexValue = (0, bytes_1.hexlify)(value);
|
|
46
|
+
return (0, bytes_1.zeroPad)(hexValue, size / 8);
|
|
47
|
+
}
|
|
48
|
+
match = type.match(regexBytes);
|
|
49
|
+
if (match) {
|
|
50
|
+
const size = parseInt(match[1]);
|
|
51
|
+
if (String(size) !== match[1] || size === 0 || size > 32) {
|
|
52
|
+
logger_1.logger.throwArgumentError('invalid bytes type', 'type', type);
|
|
53
|
+
}
|
|
54
|
+
if ((0, bytes_1.arrayify)(value).byteLength !== size) {
|
|
55
|
+
logger_1.logger.throwArgumentError(`invalid value for ${type}`, 'value', value);
|
|
56
|
+
}
|
|
57
|
+
if (isArray) {
|
|
58
|
+
return (0, bytes_1.arrayify)((value + encode_decode_transaction_1.hexFalse).substring(0, 66));
|
|
59
|
+
}
|
|
60
|
+
return value;
|
|
61
|
+
}
|
|
62
|
+
match = type.match(regexArray);
|
|
63
|
+
if (match && Array.isArray(value)) {
|
|
64
|
+
const baseType = match[1];
|
|
65
|
+
const count = parseInt(match[2] || String(value.length));
|
|
66
|
+
if (count != value.length) {
|
|
67
|
+
logger_1.logger.throwArgumentError(`invalid array length for ${type}`, 'value', value);
|
|
68
|
+
}
|
|
69
|
+
const result = [];
|
|
70
|
+
value.forEach(function (value) {
|
|
71
|
+
result.push(_pack(baseType, value, true));
|
|
72
|
+
});
|
|
73
|
+
return (0, bytes_1.concat)(result);
|
|
74
|
+
}
|
|
75
|
+
return logger_1.logger.throwArgumentError('invalid type', 'type', type);
|
|
76
|
+
}
|
|
77
|
+
function pack(types, values) {
|
|
78
|
+
if (types.length != values.length) {
|
|
79
|
+
logger_1.logger.throwArgumentError('wrong number of values; expected ${ types.length }', 'values', values);
|
|
80
|
+
}
|
|
81
|
+
const tight = [];
|
|
82
|
+
types.forEach(function (type, index) {
|
|
83
|
+
tight.push(_pack(type, values[index]));
|
|
84
|
+
});
|
|
85
|
+
return (0, bytes_1.hexlify)((0, bytes_1.concat)(tight));
|
|
86
|
+
}
|
|
87
|
+
exports.pack = pack;
|
|
88
|
+
const hashKeccak256 = (data) => {
|
|
89
|
+
const keccak = new sha3_1.Keccak(256);
|
|
90
|
+
const bufferableData = buffer_1.Buffer.from(data.replace(/^0x/, ''), 'hex');
|
|
91
|
+
const addressHash = '0x' + keccak.update(bufferableData).digest('hex');
|
|
92
|
+
return addressHash;
|
|
93
|
+
};
|
|
94
|
+
exports.hashKeccak256 = hashKeccak256;
|
|
95
|
+
/**
|
|
96
|
+
* Hashes data from Solidity using the Keccak256 algorithm.
|
|
97
|
+
*
|
|
98
|
+
* Similar to ["solidityKeccak256" in ethers.js](https://docs.ethers.io/v5/api/utils/hashing/#utils-solidityKeccak256)
|
|
99
|
+
*
|
|
100
|
+
* @param types - Each [Solidity type](https://docs.soliditylang.org/en/v0.8.13/types.html) corresponding to the values passed in. Helps the function parse and pack data properly.
|
|
101
|
+
*
|
|
102
|
+
* @param values - Data to be concatenated (combined) and then hashed.
|
|
103
|
+
*
|
|
104
|
+
* @returns - A Keccak256 hash (hex string) based on the values provided
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* ```javascript
|
|
108
|
+
* const types = ['string', 'bool', 'uint32'];
|
|
109
|
+
* const values = ['essential-eth is great', true, 14];
|
|
110
|
+
* solidityKeccak256(types, values);
|
|
111
|
+
* // '0xe4d4c8e809faac09d58f468f0aeab9474fe8965d554c6c0f868c433c3fd6acab'
|
|
112
|
+
* ```
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* ```javascript
|
|
116
|
+
* const types = ['bytes4', 'uint32[5]'];
|
|
117
|
+
* const values = [[116, 101, 115, 116], [5, 3, 4, 9, 18]];
|
|
118
|
+
* solidityKeccak256(types, values);
|
|
119
|
+
* // '0x038707a887f09355dc545412b058e7ba8f3c74047050c7c5e5e52eec608053d9'
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
function solidityKeccak256(types, values) {
|
|
123
|
+
return (0, exports.hashKeccak256)(pack(types, values));
|
|
124
|
+
}
|
|
125
|
+
exports.solidityKeccak256 = solidityKeccak256;
|
|
@@ -40,7 +40,7 @@ export class BaseContract {
|
|
|
40
40
|
? estimateGas(data)
|
|
41
41
|
: null;
|
|
42
42
|
const req = () => __awaiter(this, void 0, void 0, function* () {
|
|
43
|
-
return yield post(this._provider.
|
|
43
|
+
return yield post(this._provider.selectRpcUrl(), buildRPCPostBody('eth_call', [
|
|
44
44
|
Object.assign({ to: this._address.toLowerCase(), data }, (decimalGas
|
|
45
45
|
? { gas: `0x${decimalGas.toString(16)}` }
|
|
46
46
|
: {})),
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { BlockResponse } from '../..';
|
|
2
2
|
import { RPCBlock } from '../../types/Block.types';
|
|
3
|
-
export declare function cleanBlock(block: RPCBlock, returnTransactionObjects: boolean):
|
|
3
|
+
export declare function cleanBlock(block: RPCBlock, returnTransactionObjects: boolean): BlockResponse;
|
|
@@ -27,7 +27,8 @@ export function cleanBlock(block, returnTransactionObjects) {
|
|
|
27
27
|
}
|
|
28
28
|
});
|
|
29
29
|
if (returnTransactionObjects) {
|
|
30
|
-
|
|
30
|
+
const txns = block.transactions;
|
|
31
|
+
txns.forEach((transaction, index) => {
|
|
31
32
|
cleanedBlock.transactions[index] = cleanTransaction(transaction);
|
|
32
33
|
});
|
|
33
34
|
}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { RPCTransaction,
|
|
2
|
-
export declare function cleanTransaction(transaction: RPCTransaction):
|
|
1
|
+
import { RPCTransaction, TransactionResponse } from '../../types/Transaction.types';
|
|
2
|
+
export declare function cleanTransaction(transaction: RPCTransaction): TransactionResponse;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { toChecksumAddress } from '../..';
|
|
1
|
+
import { tinyBig, toChecksumAddress } from '../..';
|
|
2
2
|
import { hexToDecimal } from './hex-to-decimal';
|
|
3
3
|
export function cleanTransaction(transaction) {
|
|
4
4
|
const cleanedTransaction = Object.assign({}, transaction);
|
|
@@ -7,22 +7,26 @@ export function cleanTransaction(transaction) {
|
|
|
7
7
|
return;
|
|
8
8
|
switch (key) {
|
|
9
9
|
case 'blockNumber':
|
|
10
|
-
case '
|
|
10
|
+
case 'chainId':
|
|
11
11
|
case 'nonce':
|
|
12
12
|
case 'transactionIndex':
|
|
13
13
|
case 'type':
|
|
14
|
+
case 'v':
|
|
14
15
|
cleanedTransaction[key] = Number(hexToDecimal(transaction[key]));
|
|
15
16
|
break;
|
|
16
|
-
case 'gasPrice':
|
|
17
|
-
case 'value':
|
|
18
|
-
cleanedTransaction[key] = hexToDecimal(transaction[key]);
|
|
19
|
-
break;
|
|
20
17
|
case 'from':
|
|
21
18
|
case 'to':
|
|
22
19
|
if (transaction[key]) {
|
|
23
20
|
cleanedTransaction[key] = toChecksumAddress(transaction[key]);
|
|
24
21
|
}
|
|
25
22
|
break;
|
|
23
|
+
case 'value':
|
|
24
|
+
case 'gas':
|
|
25
|
+
case 'gasPrice':
|
|
26
|
+
case 'maxFeePerGas':
|
|
27
|
+
case 'maxPriorityFeePerGas':
|
|
28
|
+
cleanedTransaction[key] = tinyBig(hexToDecimal(transaction[key]));
|
|
29
|
+
break;
|
|
26
30
|
}
|
|
27
31
|
});
|
|
28
32
|
return cleanedTransaction;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { JSONABIArgument } from '../../types/Contract.types';
|
|
2
|
+
export declare const hexFalse: string;
|
|
2
3
|
export declare function encodeData(jsonABIArgument: JSONABIArgument, args: any[]): string;
|
|
3
4
|
export declare function decodeRPCResponse(jsonABIArgument: JSONABIArgument, nodeResponse: string): string | number | boolean | import("../..").TinyBig | (string | number | boolean | import("../..").TinyBig)[];
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Keccak } from 'sha3';
|
|
2
2
|
import { tinyBig, toChecksumAddress } from '../..';
|
|
3
3
|
import { hexToDecimal } from './hex-to-decimal';
|
|
4
|
-
const
|
|
5
|
-
const
|
|
4
|
+
export const hexFalse = '0'.repeat(64);
|
|
5
|
+
const hexTrue = '0'.repeat(63) + '1';
|
|
6
6
|
function expandType(type) {
|
|
7
7
|
if (type === 'uint[]') {
|
|
8
8
|
return 'uint256[]';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare function post(url: string, body: Record<string, unknown>): Promise<any>;
|
|
2
|
-
declare type RPCMethodName = 'eth_getBlockByNumber' | 'eth_call' | 'eth_chainId' | 'eth_gasPrice' | 'eth_getBalance';
|
|
2
|
+
declare type RPCMethodName = 'eth_getBlockByNumber' | 'eth_getBlockByHash' | 'eth_call' | 'eth_chainId' | 'eth_gasPrice' | 'eth_getBalance' | 'eth_getTransactionByHash' | 'eth_getTransactionCount';
|
|
3
3
|
export declare function buildRPCPostBody(method: RPCMethodName, params: unknown[]): {
|
|
4
4
|
jsonrpc: string;
|
|
5
5
|
id: number;
|
package/lib/esm/index.d.ts
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
import { Contract } from './classes/Contract';
|
|
2
|
+
import { FallthroughProvider } from './providers/FallthroughProvider';
|
|
2
3
|
import { JsonRpcProvider, jsonRpcProvider } from './providers/JsonRpcProvider';
|
|
3
4
|
import { tinyBig, TinyBig } from './shared/tiny-big/tiny-big';
|
|
4
|
-
import {
|
|
5
|
+
import { BlockResponse } from './types/Block.types';
|
|
5
6
|
import { ContractTypes, JSONABI, JSONABIArgument } from './types/Contract.types';
|
|
6
7
|
import { Network } from './types/Network.types';
|
|
7
|
-
import {
|
|
8
|
+
import { TransactionResponse } from './types/Transaction.types';
|
|
8
9
|
import { etherToGwei } from './utils/ether-to-gwei';
|
|
9
10
|
import { etherToWei } from './utils/ether-to-wei';
|
|
10
11
|
import { gweiToEther } from './utils/gwei-to-ether';
|
|
11
12
|
import { isAddress } from './utils/is-address';
|
|
12
13
|
import { toChecksumAddress } from './utils/to-checksum-address';
|
|
13
14
|
import { weiToEther } from './utils/wei-to-ether';
|
|
14
|
-
export
|
|
15
|
+
export * from './utils/bytes';
|
|
16
|
+
export * from './utils/solidity-keccak256';
|
|
17
|
+
export { etherToWei, etherToGwei, isAddress, jsonRpcProvider, JsonRpcProvider, FallthroughProvider, tinyBig, toChecksumAddress, weiToEther, gweiToEther, Contract, TinyBig, BlockResponse, ContractTypes, JSONABI, JSONABIArgument, Network, TransactionResponse, };
|
package/lib/esm/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Contract } from './classes/Contract';
|
|
2
|
+
import { FallthroughProvider } from './providers/FallthroughProvider';
|
|
2
3
|
import { JsonRpcProvider, jsonRpcProvider } from './providers/JsonRpcProvider';
|
|
3
4
|
import { tinyBig, TinyBig } from './shared/tiny-big/tiny-big';
|
|
4
5
|
import { etherToGwei } from './utils/ether-to-gwei';
|
|
@@ -7,4 +8,6 @@ import { gweiToEther } from './utils/gwei-to-ether';
|
|
|
7
8
|
import { isAddress } from './utils/is-address';
|
|
8
9
|
import { toChecksumAddress } from './utils/to-checksum-address';
|
|
9
10
|
import { weiToEther } from './utils/wei-to-ether';
|
|
10
|
-
export
|
|
11
|
+
export * from './utils/bytes';
|
|
12
|
+
export * from './utils/solidity-keccak256';
|
|
13
|
+
export { etherToWei, etherToGwei, isAddress, jsonRpcProvider, JsonRpcProvider, FallthroughProvider, tinyBig, toChecksumAddress, weiToEther, gweiToEther, Contract, TinyBig, };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
declare class Logger {
|
|
2
|
+
private packageVersion;
|
|
3
|
+
constructor();
|
|
4
|
+
throwError(message: string, args: {
|
|
5
|
+
[key: string]: any;
|
|
6
|
+
}): never;
|
|
7
|
+
throwArgumentError(message: string, arg: string, value: any): never;
|
|
8
|
+
checkSafeUint53(value: number, message?: string): void;
|
|
9
|
+
}
|
|
10
|
+
export declare const logger: Logger;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { version } from './package-version';
|
|
2
|
+
class Logger {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.packageVersion = version;
|
|
5
|
+
}
|
|
6
|
+
throwError(message, args) {
|
|
7
|
+
const argsLength = Object.keys(args).length;
|
|
8
|
+
throw new Error(`${message} (${Object.entries(args).map(([key, value], index) => `${key}=${value}${index < argsLength - 1 && ', '}`)}, version=essential-eth@${this.packageVersion})`);
|
|
9
|
+
}
|
|
10
|
+
throwArgumentError(message, arg, value) {
|
|
11
|
+
throw new Error(`${message} (argument="${arg}" value=${value}, version=essential-eth@${this.packageVersion})`);
|
|
12
|
+
}
|
|
13
|
+
checkSafeUint53(value, message = 'value not safe') {
|
|
14
|
+
if (typeof value !== 'number') {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (value < 0 || value >= 0x1fffffffffffff) {
|
|
18
|
+
this.throwError(message, {
|
|
19
|
+
operation: 'checkSafeInteger',
|
|
20
|
+
fault: 'out-of-safe-range',
|
|
21
|
+
value: value,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
if (value % 1) {
|
|
25
|
+
this.throwError(message, {
|
|
26
|
+
operation: 'checkSafeInteger',
|
|
27
|
+
fault: 'non-integer',
|
|
28
|
+
value: value,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export const logger = new Logger();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const version = "0.5.4-alpha.0";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const version = '0.5.4-alpha.0';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { TinyBig } from '../shared/tiny-big/tiny-big';
|
|
2
|
+
import { BlockResponse, BlockTag } from '../types/Block.types';
|
|
3
|
+
import { Network } from '../types/Network.types';
|
|
4
|
+
import { TransactionResponse } from '../types/Transaction.types';
|
|
5
|
+
export declare abstract class BaseProvider {
|
|
6
|
+
abstract selectRpcUrl(): string;
|
|
7
|
+
abstract post(body: Record<string, unknown>): Promise<any>;
|
|
8
|
+
readonly _rpcUrls: string[];
|
|
9
|
+
protected _post: (body: Record<string, unknown>) => Promise<any>;
|
|
10
|
+
constructor(rpcUrls: string[]);
|
|
11
|
+
getNetwork(): Promise<Network>;
|
|
12
|
+
getTransaction(transactionHash: string): Promise<TransactionResponse>;
|
|
13
|
+
getTransactionCount(address: string, blockTag?: BlockTag): Promise<number>;
|
|
14
|
+
getBlock(timeFrame?: BlockTag, returnTransactionObjects?: boolean): Promise<BlockResponse>;
|
|
15
|
+
getGasPrice(): Promise<TinyBig>;
|
|
16
|
+
getBalance(address: string, blockTag?: BlockTag): Promise<TinyBig>;
|
|
17
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { cleanBlock } from '../classes/utils/clean-block';
|
|
11
|
+
import { cleanTransaction } from '../classes/utils/clean-transaction';
|
|
12
|
+
import { buildRPCPostBody, post } from '../classes/utils/fetchers';
|
|
13
|
+
import { hexToDecimal } from '../classes/utils/hex-to-decimal';
|
|
14
|
+
import { tinyBig } from '../shared/tiny-big/tiny-big';
|
|
15
|
+
import chainsInfo from './utils/chains-info';
|
|
16
|
+
export class BaseProvider {
|
|
17
|
+
constructor(rpcUrls) {
|
|
18
|
+
this._rpcUrls = [];
|
|
19
|
+
this._post = (body) => post(this.selectRpcUrl(), body);
|
|
20
|
+
this._rpcUrls = rpcUrls;
|
|
21
|
+
}
|
|
22
|
+
getNetwork() {
|
|
23
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
24
|
+
const hexChainId = (yield this.post(buildRPCPostBody('eth_chainId', [])));
|
|
25
|
+
const chainId = hexToDecimal(hexChainId);
|
|
26
|
+
const info = chainsInfo[chainId];
|
|
27
|
+
return {
|
|
28
|
+
chainId: Number(chainId),
|
|
29
|
+
name: info[0] || 'unknown',
|
|
30
|
+
ensAddress: info[1] || null,
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
getTransaction(transactionHash) {
|
|
35
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
36
|
+
const [rpcTransaction, blockNumber] = yield Promise.all([
|
|
37
|
+
this.post(buildRPCPostBody('eth_getTransactionByHash', [transactionHash])),
|
|
38
|
+
this.getBlock('latest'),
|
|
39
|
+
]);
|
|
40
|
+
const cleanedTransaction = cleanTransaction(rpcTransaction);
|
|
41
|
+
cleanedTransaction.confirmations =
|
|
42
|
+
blockNumber.number - cleanedTransaction.blockNumber + 1;
|
|
43
|
+
return cleanedTransaction;
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
getTransactionCount(address, blockTag = 'latest') {
|
|
47
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
48
|
+
if (typeof blockTag === 'number') {
|
|
49
|
+
blockTag = `0x${blockTag.toString(16)}`;
|
|
50
|
+
}
|
|
51
|
+
const transactionCount = (yield this.post(buildRPCPostBody('eth_getTransactionCount', [address, blockTag])));
|
|
52
|
+
return Number(hexToDecimal(transactionCount));
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
getBlock(timeFrame = 'latest', returnTransactionObjects = false) {
|
|
56
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
57
|
+
let rpcTimeFrame;
|
|
58
|
+
let type = 'Number';
|
|
59
|
+
if (typeof timeFrame === 'number') {
|
|
60
|
+
rpcTimeFrame = `0x${timeFrame.toString(16)}`;
|
|
61
|
+
}
|
|
62
|
+
else if (timeFrame.startsWith('0x')) {
|
|
63
|
+
rpcTimeFrame = timeFrame;
|
|
64
|
+
type = 'Hash';
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
rpcTimeFrame = timeFrame;
|
|
68
|
+
}
|
|
69
|
+
const rpcBlock = (yield this.post(buildRPCPostBody(`eth_getBlockBy${type}`, [
|
|
70
|
+
rpcTimeFrame,
|
|
71
|
+
returnTransactionObjects,
|
|
72
|
+
])));
|
|
73
|
+
return cleanBlock(rpcBlock, returnTransactionObjects);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
getGasPrice() {
|
|
77
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
78
|
+
const hexGasPrice = (yield this.post(buildRPCPostBody('eth_gasPrice', [])));
|
|
79
|
+
return tinyBig(hexToDecimal(hexGasPrice));
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
getBalance(address, blockTag = 'latest') {
|
|
83
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
84
|
+
const hexBalance = (yield this.post(buildRPCPostBody('eth_getBalance', [address, blockTag])));
|
|
85
|
+
return tinyBig(hexToDecimal(hexBalance));
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BaseProvider } from './BaseProvider';
|
|
2
|
+
interface ConstructorOptions {
|
|
3
|
+
timeoutDuration?: number;
|
|
4
|
+
}
|
|
5
|
+
export declare class FallthroughProvider extends BaseProvider {
|
|
6
|
+
private rpcUrlCounter;
|
|
7
|
+
private readonly timeoutDuration;
|
|
8
|
+
selectRpcUrl(): string;
|
|
9
|
+
constructor(rpcUrls: string[], options?: ConstructorOptions);
|
|
10
|
+
post: (body: Record<string, unknown>) => Promise<any>;
|
|
11
|
+
}
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { logger } from '../logger/logger';
|
|
2
|
+
import { BaseProvider } from './BaseProvider';
|
|
3
|
+
const promiseTimeout = (prom, time) => Promise.race([
|
|
4
|
+
prom,
|
|
5
|
+
new Promise((_r, reject) => setTimeout(() => reject('Promise timed out'), time)),
|
|
6
|
+
]);
|
|
7
|
+
const DEFAULT_TIMEOUT_DURATION = 8000;
|
|
8
|
+
export class FallthroughProvider extends BaseProvider {
|
|
9
|
+
constructor(rpcUrls, options = {}) {
|
|
10
|
+
if (!Array.isArray(rpcUrls)) {
|
|
11
|
+
logger.throwError('Array required', { rpcUrls });
|
|
12
|
+
}
|
|
13
|
+
if (rpcUrls.length <= 1) {
|
|
14
|
+
logger.throwError('More than one rpcUrl is required', { rpcUrls });
|
|
15
|
+
}
|
|
16
|
+
super(rpcUrls);
|
|
17
|
+
this.rpcUrlCounter = 0;
|
|
18
|
+
this.post = (body) => {
|
|
19
|
+
const genesisCount = this.rpcUrlCounter;
|
|
20
|
+
const recursivePostRetry = () => {
|
|
21
|
+
const genesisRpcUrl = this.selectRpcUrl();
|
|
22
|
+
const res = promiseTimeout(this._post(body), this.timeoutDuration).catch((e) => {
|
|
23
|
+
if (genesisRpcUrl === this.selectRpcUrl()) {
|
|
24
|
+
this.rpcUrlCounter =
|
|
25
|
+
(this.rpcUrlCounter + 1) % this._rpcUrls.length;
|
|
26
|
+
}
|
|
27
|
+
if (this.rpcUrlCounter === genesisCount) {
|
|
28
|
+
throw e;
|
|
29
|
+
}
|
|
30
|
+
return recursivePostRetry();
|
|
31
|
+
});
|
|
32
|
+
return res;
|
|
33
|
+
};
|
|
34
|
+
return recursivePostRetry();
|
|
35
|
+
};
|
|
36
|
+
this.timeoutDuration = options.timeoutDuration || DEFAULT_TIMEOUT_DURATION;
|
|
37
|
+
}
|
|
38
|
+
selectRpcUrl() {
|
|
39
|
+
return this._rpcUrls[this.rpcUrlCounter];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
readonly _rpcUrl: string;
|
|
1
|
+
import { BaseProvider } from './BaseProvider';
|
|
2
|
+
export declare class JsonRpcProvider extends BaseProvider {
|
|
3
|
+
selectRpcUrl(): string;
|
|
4
|
+
post(body: Record<string, unknown>): Promise<any>;
|
|
6
5
|
constructor(rpcUrl?: string);
|
|
7
|
-
getBlock(timeFrame: BlockTag, returnTransactionObjects?: boolean): Promise<Block>;
|
|
8
|
-
getNetwork(): Promise<Network>;
|
|
9
|
-
getGasPrice(): Promise<TinyBig>;
|
|
10
|
-
getBalance(address: string, blockTag?: BlockTag): Promise<TinyBig>;
|
|
11
6
|
}
|
|
12
7
|
export declare function jsonRpcProvider(rpcUrl?: string): JsonRpcProvider;
|
|
@@ -1,72 +1,13 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
-
});
|
|
9
|
-
};
|
|
10
|
-
import { cleanBlock } from '../classes/utils/clean-block';
|
|
11
|
-
import { buildRPCPostBody, post } from '../classes/utils/fetchers';
|
|
12
|
-
import { hexToDecimal } from '../classes/utils/hex-to-decimal';
|
|
13
|
-
import { tinyBig } from '../shared/tiny-big/tiny-big';
|
|
14
|
-
import chainsInfo from './utils/chains-info';
|
|
15
|
-
export class JsonRpcProvider {
|
|
16
|
-
constructor(rpcUrl) {
|
|
17
|
-
this._rpcUrl = rpcUrl || 'https://free-eth-node.com/api/eth';
|
|
1
|
+
import { BaseProvider } from './BaseProvider';
|
|
2
|
+
export class JsonRpcProvider extends BaseProvider {
|
|
3
|
+
selectRpcUrl() {
|
|
4
|
+
return this._rpcUrls[0];
|
|
18
5
|
}
|
|
19
|
-
|
|
20
|
-
return
|
|
21
|
-
let rpcTimeFrame;
|
|
22
|
-
if (typeof timeFrame === 'number') {
|
|
23
|
-
rpcTimeFrame = `0x${timeFrame.toString(16)}`;
|
|
24
|
-
}
|
|
25
|
-
else {
|
|
26
|
-
rpcTimeFrame = timeFrame;
|
|
27
|
-
}
|
|
28
|
-
const req = () => {
|
|
29
|
-
return post(this._rpcUrl, buildRPCPostBody('eth_getBlockByNumber', [
|
|
30
|
-
rpcTimeFrame,
|
|
31
|
-
returnTransactionObjects,
|
|
32
|
-
]));
|
|
33
|
-
};
|
|
34
|
-
const nodeResponse = (yield req());
|
|
35
|
-
return cleanBlock(nodeResponse, returnTransactionObjects);
|
|
36
|
-
});
|
|
6
|
+
post(body) {
|
|
7
|
+
return this._post(body);
|
|
37
8
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const req = () => {
|
|
41
|
-
return post(this._rpcUrl, buildRPCPostBody('eth_chainId', []));
|
|
42
|
-
};
|
|
43
|
-
const nodeResponse = (yield req());
|
|
44
|
-
const chainId = hexToDecimal(nodeResponse);
|
|
45
|
-
const info = chainsInfo[chainId];
|
|
46
|
-
return {
|
|
47
|
-
chainId: Number(chainId),
|
|
48
|
-
name: info[0] || 'unknown',
|
|
49
|
-
ensAddress: info[1] || null,
|
|
50
|
-
};
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
getGasPrice() {
|
|
54
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
55
|
-
const req = () => {
|
|
56
|
-
return post(this._rpcUrl, buildRPCPostBody('eth_gasPrice', []));
|
|
57
|
-
};
|
|
58
|
-
const nodeResponse = (yield req());
|
|
59
|
-
return tinyBig(hexToDecimal(nodeResponse));
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
getBalance(address, blockTag = 'latest') {
|
|
63
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
64
|
-
const req = () => {
|
|
65
|
-
return post(this._rpcUrl, buildRPCPostBody('eth_getBalance', [address, blockTag]));
|
|
66
|
-
};
|
|
67
|
-
const nodeResponse = (yield req());
|
|
68
|
-
return tinyBig(hexToDecimal(nodeResponse));
|
|
69
|
-
});
|
|
9
|
+
constructor(rpcUrl = 'https://free-eth-node.com/api/eth') {
|
|
10
|
+
super([rpcUrl]);
|
|
70
11
|
}
|
|
71
12
|
}
|
|
72
13
|
export function jsonRpcProvider(rpcUrl) {
|
|
@@ -3,6 +3,7 @@ export const fakeUrls = {
|
|
|
3
3
|
};
|
|
4
4
|
export const rpcUrls = {
|
|
5
5
|
mainnet: `${process.env.RPC_ORIGIN}/api/eth`,
|
|
6
|
+
matic: `${process.env.RPC_ORIGIN}/api/MATIC`,
|
|
6
7
|
gno: `${process.env.RPC_ORIGIN}/api/gno`,
|
|
7
8
|
bnb: `${process.env.RPC_ORIGIN}/api/bnb`,
|
|
8
9
|
arb1: `${process.env.RPC_ORIGIN}/api/arb1`,
|