@mentaproject/client 0.1.23 → 0.1.24
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/dist/managers/PersistenceManager.d.ts +3 -3
- package/dist/managers/TransactionManager.d.ts +1 -1
- package/dist/structures/Account.js +2 -1
- package/dist/types/PersistenceAdapter.d.ts +3 -2
- package/package.json +2 -2
- package/src/index.ts +21 -0
- package/src/managers/AccountManager.ts +51 -0
- package/src/managers/BlockManager.ts +51 -0
- package/src/managers/ContractManager.ts +60 -0
- package/src/managers/PersistenceManager.ts +59 -0
- package/src/managers/TransactionManager.ts +92 -0
- package/src/managers/index.ts +4 -0
- package/src/structures/Account.ts +206 -0
- package/src/structures/Block.ts +185 -0
- package/src/structures/Cache.ts +126 -0
- package/src/structures/MentaClient.ts +127 -0
- package/src/structures/Transaction.ts +220 -0
- package/src/structures/index.ts +5 -0
- package/src/types/Account.ts +44 -0
- package/src/types/Block.ts +14 -0
- package/src/types/Cache.ts +55 -0
- package/src/types/JsonRPC.ts +126 -0
- package/src/types/MentaClient.ts +67 -0
- package/src/types/PersistenceAdapter.ts +44 -0
- package/src/types/Transaction.ts +52 -0
- package/src/types/Utils.ts +30 -0
- package/src/types/index.ts +8 -0
- package/src/utils/bigint.ts +59 -0
- package/src/utils/toJSON.ts +123 -0
- package/src/utils/withCache.ts +50 -0
- package/test.ts +0 -89
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import { Block as RawBlock, Hash, Hex, Withdrawal } from "@mentaproject/core";
|
|
2
|
+
|
|
3
|
+
import { Account } from "./Account";
|
|
4
|
+
import { Transaction } from "./Transaction";
|
|
5
|
+
import { JSONBlock } from "../types/Block";
|
|
6
|
+
import { toJSON } from "../utils/toJSON";
|
|
7
|
+
import { MentaClient } from "./MentaClient";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @description Represents a blockchain block with its properties and methods.
|
|
11
|
+
* This class provides a structured way to access block-related data and interact with the blockchain client.
|
|
12
|
+
*/
|
|
13
|
+
export class Block implements Omit<RawBlock, "miner" | "transactions"> {
|
|
14
|
+
/**
|
|
15
|
+
* @description The base fee per gas for the block.
|
|
16
|
+
*/
|
|
17
|
+
baseFeePerGas: bigint | null
|
|
18
|
+
/**
|
|
19
|
+
* @description The gas used for blobs in the block.
|
|
20
|
+
*/
|
|
21
|
+
blobGasUsed: bigint
|
|
22
|
+
/**
|
|
23
|
+
* @description The block's difficulty.
|
|
24
|
+
*/
|
|
25
|
+
difficulty: bigint
|
|
26
|
+
/**
|
|
27
|
+
* @description The excess blob gas in the block.
|
|
28
|
+
*/
|
|
29
|
+
excessBlobGas: bigint
|
|
30
|
+
/**
|
|
31
|
+
* @description Extra data included in the block.
|
|
32
|
+
*/
|
|
33
|
+
extraData: Hex
|
|
34
|
+
/**
|
|
35
|
+
* @description The gas limit for the block.
|
|
36
|
+
*/
|
|
37
|
+
gasLimit: bigint
|
|
38
|
+
/**
|
|
39
|
+
* @description The gas used in the block.
|
|
40
|
+
*/
|
|
41
|
+
gasUsed: bigint
|
|
42
|
+
/**
|
|
43
|
+
* @description The hash of the block.
|
|
44
|
+
*/
|
|
45
|
+
hash: Hash | null
|
|
46
|
+
/**
|
|
47
|
+
* @description The logs bloom filter for the block.
|
|
48
|
+
*/
|
|
49
|
+
logsBloom: Hex | null
|
|
50
|
+
/**
|
|
51
|
+
* @description The mix hash of the block.
|
|
52
|
+
*/
|
|
53
|
+
mixHash: Hash
|
|
54
|
+
/**
|
|
55
|
+
* @description The nonce of the block.
|
|
56
|
+
*/
|
|
57
|
+
nonce: Hex | null
|
|
58
|
+
/**
|
|
59
|
+
* @description The block number.
|
|
60
|
+
*/
|
|
61
|
+
number: bigint | null
|
|
62
|
+
/**
|
|
63
|
+
* @description The parent beacon block root.
|
|
64
|
+
*/
|
|
65
|
+
parentBeaconBlockRoot?: Hex
|
|
66
|
+
/**
|
|
67
|
+
* @description The hash of the parent block.
|
|
68
|
+
*/
|
|
69
|
+
parentHash: Hash
|
|
70
|
+
/**
|
|
71
|
+
* @description The root of the receipts trie.
|
|
72
|
+
*/
|
|
73
|
+
receiptsRoot: Hex
|
|
74
|
+
/**
|
|
75
|
+
* @description The seal fields of the block.
|
|
76
|
+
*/
|
|
77
|
+
sealFields: Hex[]
|
|
78
|
+
/**
|
|
79
|
+
* @description The SHA3 uncles hash.
|
|
80
|
+
*/
|
|
81
|
+
sha3Uncles: Hash
|
|
82
|
+
/**
|
|
83
|
+
* @description The size of the block in bytes.
|
|
84
|
+
*/
|
|
85
|
+
size: bigint
|
|
86
|
+
/**
|
|
87
|
+
* @description The state root of the block.
|
|
88
|
+
*/
|
|
89
|
+
stateRoot: Hash
|
|
90
|
+
/**
|
|
91
|
+
* @description The timestamp of the block.
|
|
92
|
+
*/
|
|
93
|
+
timestamp: bigint
|
|
94
|
+
/**
|
|
95
|
+
* @description The total difficulty of the chain up to this block.
|
|
96
|
+
*/
|
|
97
|
+
totalDifficulty: bigint | null
|
|
98
|
+
/**
|
|
99
|
+
* @description The root of the transactions trie.
|
|
100
|
+
*/
|
|
101
|
+
transactionsRoot: Hash
|
|
102
|
+
/**
|
|
103
|
+
* @description The list of uncle hashes.
|
|
104
|
+
*/
|
|
105
|
+
uncles: Hash[]
|
|
106
|
+
/**
|
|
107
|
+
* @description The list of withdrawals.
|
|
108
|
+
*/
|
|
109
|
+
withdrawals?: Withdrawal[]
|
|
110
|
+
/**
|
|
111
|
+
* @description The root of the withdrawals trie.
|
|
112
|
+
*/
|
|
113
|
+
withdrawalsRoot?: Hex
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* @description The miner of the block, represented as an Account instance.
|
|
117
|
+
*/
|
|
118
|
+
miner: Account
|
|
119
|
+
/**
|
|
120
|
+
* @description The transactions included in the block, represented as an array of Transaction instances.
|
|
121
|
+
*/
|
|
122
|
+
transactions?: Transaction[] | Hash[]
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* @description Creates an instance of Block.
|
|
126
|
+
* @param client - The instance of MentaClient used to interact with the blockchain.
|
|
127
|
+
* @param data The raw block data conforming to IBlockData.
|
|
128
|
+
* @param includeTransactions Whether to include full transaction objects. Defaults to false.
|
|
129
|
+
*/
|
|
130
|
+
constructor(public client: MentaClient, data: RawBlock) {
|
|
131
|
+
this.baseFeePerGas = data.baseFeePerGas;
|
|
132
|
+
this.blobGasUsed = data.blobGasUsed;
|
|
133
|
+
this.difficulty = data.difficulty;
|
|
134
|
+
this.excessBlobGas = data.excessBlobGas;
|
|
135
|
+
this.extraData = data.extraData;
|
|
136
|
+
this.gasLimit = data.gasLimit;
|
|
137
|
+
this.gasUsed = data.gasUsed;
|
|
138
|
+
this.hash = data.hash;
|
|
139
|
+
this.logsBloom = data.logsBloom;
|
|
140
|
+
this.mixHash = data.mixHash;
|
|
141
|
+
this.nonce = data.nonce;
|
|
142
|
+
this.number = data.number;
|
|
143
|
+
this.parentBeaconBlockRoot = data.parentBeaconBlockRoot;
|
|
144
|
+
this.parentHash = data.parentHash;
|
|
145
|
+
this.receiptsRoot = data.receiptsRoot;
|
|
146
|
+
this.sealFields = data.sealFields;
|
|
147
|
+
this.sha3Uncles = data.sha3Uncles;
|
|
148
|
+
this.size = data.size;
|
|
149
|
+
this.stateRoot = data.stateRoot;
|
|
150
|
+
this.timestamp = data.timestamp;
|
|
151
|
+
this.totalDifficulty = data.totalDifficulty;
|
|
152
|
+
this.transactionsRoot = data.transactionsRoot;
|
|
153
|
+
this.uncles = data.uncles;
|
|
154
|
+
this.withdrawals = data.withdrawals;
|
|
155
|
+
this.withdrawalsRoot = data.withdrawalsRoot;
|
|
156
|
+
|
|
157
|
+
this.miner = new Account(this.client, { address: data.miner});
|
|
158
|
+
|
|
159
|
+
if (!data.transactions || data.transactions.length === 0) {
|
|
160
|
+
const parsed = data.transactions.map((data) => typeof data === "string" ? data : new Transaction(this.client, data))
|
|
161
|
+
this.transactions = parsed as Transaction[] | Hash[];
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
protected includeTransactions(): this is this & { transactions: Transaction[] } {
|
|
166
|
+
if (!this.transactions || this.transactions.length === 0) return false;
|
|
167
|
+
return true
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* @description Converts the Block instance to a JSON representation.
|
|
172
|
+
* This method serializes the block's properties into a plain JavaScript object,
|
|
173
|
+
* suitable for JSON serialization.
|
|
174
|
+
* @param depth The depth of the conversion. Defaults to 1.
|
|
175
|
+
* @returns A promise that resolves to the JSON representation of the block.
|
|
176
|
+
*/
|
|
177
|
+
async toJSON<D extends number = 1>(depth: D): Promise<JSONBlock<D>> {
|
|
178
|
+
return await toJSON({
|
|
179
|
+
obj: {
|
|
180
|
+
...this,
|
|
181
|
+
},
|
|
182
|
+
depth
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
};
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module MemoryCache
|
|
3
|
+
*/
|
|
4
|
+
import { ICache, ICacheEntry, ICacheConfig } from '../types/Cache';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
/**
|
|
8
|
+
* @class MemoryCache
|
|
9
|
+
* @description A simple in-memory cache implementation that adheres to the ICache interface.
|
|
10
|
+
* It stores key-value pairs with an associated time-to-live (TTL) based on block numbers.
|
|
11
|
+
* The cache automatically evicts the oldest entries when its maximum size is reached.
|
|
12
|
+
*/
|
|
13
|
+
export class MemoryCache implements ICache {
|
|
14
|
+
/**
|
|
15
|
+
* @property {Map<string, ICacheEntry<any>>} cache - The internal Map used to store cache entries.
|
|
16
|
+
* @private
|
|
17
|
+
*/
|
|
18
|
+
private cache = new Map<string, ICacheEntry<any>>();
|
|
19
|
+
/**
|
|
20
|
+
* @property {ICacheConfig} config - The configuration object for the cache, including maxSize, defaultTtl, and ttlPolicies.
|
|
21
|
+
*/
|
|
22
|
+
public config: ICacheConfig;
|
|
23
|
+
/**
|
|
24
|
+
* @property {bigint} blockNumber - The current block number used for TTL calculations.
|
|
25
|
+
* @private
|
|
26
|
+
*/
|
|
27
|
+
private blockNumber: bigint;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @constructor
|
|
31
|
+
* @description Creates an instance of MemoryCache.
|
|
32
|
+
* @param {bigint} blockNumber - The current block number to use for TTL calculations.
|
|
33
|
+
* @param {Partial<ICacheConfig>} [options] - Optional configuration for the cache.
|
|
34
|
+
* @param {number} [options.maxSize=500] - The maximum number of entries the cache can hold.
|
|
35
|
+
* @param {number} [options.defaultTtl=1] - The default time-to-live in blocks for cache entries if not specified.
|
|
36
|
+
* @param {Object.<string, number>} [options.ttlPolicies={}] - A map of specific TTL policies for different keys.
|
|
37
|
+
*/
|
|
38
|
+
constructor(blockNumber: bigint, options?: Partial<ICacheConfig>) {
|
|
39
|
+
this.blockNumber = blockNumber;
|
|
40
|
+
this.config = {
|
|
41
|
+
maxSize: 500,
|
|
42
|
+
defaultTtl: 1,
|
|
43
|
+
ttlPolicies: options?.ttlPolicies || {},
|
|
44
|
+
...options,
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @method isExpired
|
|
50
|
+
* @description Checks if a cache entry has expired based on the current block number and the entry's expiry block.
|
|
51
|
+
* @param {bigint} expiry - The expiry block number of the cache entry.
|
|
52
|
+
* @returns {boolean} `true` if the entry has expired, `false` otherwise.
|
|
53
|
+
* @protected
|
|
54
|
+
*/
|
|
55
|
+
protected isExpired(expiry: bigint): boolean {
|
|
56
|
+
return this.blockNumber > expiry;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @method setBlockNumber
|
|
61
|
+
* @description Sets the current block number for TTL calculations. This is crucial for managing cache entry expiry.
|
|
62
|
+
* @param {bigint} blockNumber - The new current block number.
|
|
63
|
+
* @returns {void}
|
|
64
|
+
*/
|
|
65
|
+
setBlockNumber(blockNumber: bigint): void {
|
|
66
|
+
this.blockNumber = blockNumber;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* @method set
|
|
71
|
+
* @description Sets a value in the cache. If the key already exists, its entry will be updated.
|
|
72
|
+
* If the cache reaches its maximum size, the oldest entry will be evicted before adding the new one.
|
|
73
|
+
* @template T - The type of the value being stored.
|
|
74
|
+
* @param {string} key - The unique key for the cache entry.
|
|
75
|
+
* @param {T} value - The value to store in the cache.
|
|
76
|
+
* @param {number} [ttl=this.config.defaultTtl] - The time-to-live (in blocks) for this specific entry. Defaults to the cache's `defaultTtl`.
|
|
77
|
+
* @returns {void}
|
|
78
|
+
*/
|
|
79
|
+
set<T>(key: string, value: T, ttl: number = this.config.defaultTtl): void {
|
|
80
|
+
if (this.cache.has(key)) {
|
|
81
|
+
this.cache.delete(key);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (this.cache.size >= this.config.maxSize) this.evict();
|
|
85
|
+
|
|
86
|
+
const expiry = this.blockNumber + BigInt(ttl);
|
|
87
|
+
this.cache.set(key, { value, expiry });
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @method get
|
|
92
|
+
* @description Retrieves a value from the cache. If the entry is found and has not expired,
|
|
93
|
+
* it is moved to the end of the cache (making it the most recently used) to prevent premature eviction.
|
|
94
|
+
* @template T - The expected type of the value.
|
|
95
|
+
* @param {string} key - The key of the cache entry to retrieve.
|
|
96
|
+
* @returns {T | undefined} The cached value if found and not expired, otherwise `undefined`.
|
|
97
|
+
*/
|
|
98
|
+
get<T>(key: string): T | undefined {
|
|
99
|
+
const entry = this.cache.get(key);
|
|
100
|
+
if (!entry) return undefined;
|
|
101
|
+
|
|
102
|
+
if (this.isExpired(entry.expiry)) {
|
|
103
|
+
this.cache.delete(key);
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
this.cache.delete(key);
|
|
108
|
+
this.cache.set(key, entry);
|
|
109
|
+
|
|
110
|
+
return entry.value as T;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* @method evict
|
|
115
|
+
* @description Evicts the oldest entry from the cache. This method is called internally when the cache
|
|
116
|
+
* reaches its `maxSize` to make room for new entries.
|
|
117
|
+
* @returns {void}
|
|
118
|
+
* @private
|
|
119
|
+
*/
|
|
120
|
+
private evict(): void {
|
|
121
|
+
const oldestKey = this.cache.keys().next().value;
|
|
122
|
+
if (!oldestKey) return;
|
|
123
|
+
|
|
124
|
+
this.cache.delete(oldestKey);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module MentaClient
|
|
3
|
+
*/
|
|
4
|
+
import type { CoreClient } from "@mentaproject/core/types";
|
|
5
|
+
import { createClient } from "@mentaproject/core";
|
|
6
|
+
|
|
7
|
+
import { BlockManager } from "../managers/BlockManager";
|
|
8
|
+
import { TransactionManager } from "../managers/TransactionManager";
|
|
9
|
+
import { ContractManager } from "../managers/ContractManager";
|
|
10
|
+
import { AccountManager } from "../managers/AccountManager";
|
|
11
|
+
import { PersistenceManager } from "../managers/PersistenceManager";
|
|
12
|
+
import { ClientEvents, GetListenerCallback, MentaClientConfig } from "../types/MentaClient";
|
|
13
|
+
import { withCache } from "../utils/withCache";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The main client for interacting with the Menta API.
|
|
17
|
+
* It provides managers for blocks, transactions, contracts, and accounts.
|
|
18
|
+
*
|
|
19
|
+
* @description This class serves as the primary entry point for interacting with the Menta blockchain.
|
|
20
|
+
* It encapsulates the core RPC client and provides specialized managers for various blockchain entities,
|
|
21
|
+
* simplifying common operations.
|
|
22
|
+
*/
|
|
23
|
+
export class MentaClient {
|
|
24
|
+
/**
|
|
25
|
+
* The underlying RPC client used for blockchain interactions.
|
|
26
|
+
* @description This client is responsible for low-level communication with the RPC node.
|
|
27
|
+
*/
|
|
28
|
+
public rpc: CoreClient;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Manager for block-related operations.
|
|
32
|
+
* @description Provides methods to query and interact with blockchain blocks.
|
|
33
|
+
*/
|
|
34
|
+
public blocks!: BlockManager;
|
|
35
|
+
/**
|
|
36
|
+
* Manager for transaction-related operations.
|
|
37
|
+
* @description Provides methods to send, query, and manage blockchain transactions.
|
|
38
|
+
*/
|
|
39
|
+
public transactions!: TransactionManager;
|
|
40
|
+
/**
|
|
41
|
+
* Manager for contract-related operations.
|
|
42
|
+
* @description Provides methods to deploy, interact with, and query smart contracts.
|
|
43
|
+
*/
|
|
44
|
+
public contracts!: ContractManager;
|
|
45
|
+
/**
|
|
46
|
+
* Manager for account-related operations.
|
|
47
|
+
* @description Provides methods to manage and interact with blockchain accounts.
|
|
48
|
+
*/
|
|
49
|
+
public accounts!: AccountManager;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Subscribes to a specific client event.
|
|
53
|
+
* @template TEvent The type of the event to listen for.
|
|
54
|
+
* @param {TEvent} event - The event to listen for (e.g., 'block', 'transaction').
|
|
55
|
+
* @param {GetListenerCallback<TEvent>} callback - The callback function to execute when the event is triggered.
|
|
56
|
+
* @returns {() => void} An unsubscribe function to stop listening to the event.
|
|
57
|
+
* @description This method allows the client to listen for real-time events from the blockchain, such as new blocks or transactions.
|
|
58
|
+
* @example
|
|
59
|
+
* import { MentaClient } from '@mentaproject/client';
|
|
60
|
+
*
|
|
61
|
+
* const client = new MentaClient({ url: 'http://rpcurlhere.com' });
|
|
62
|
+
*
|
|
63
|
+
* // Subscribe to new blocks
|
|
64
|
+
* const unsubscribe = client.on('block', (block) => {
|
|
65
|
+
* console.log('New block received:', block);
|
|
66
|
+
* });
|
|
67
|
+
*
|
|
68
|
+
* // To stop listening
|
|
69
|
+
* // unsubscribe();
|
|
70
|
+
*/
|
|
71
|
+
on<TEvent extends keyof typeof ClientEvents>(
|
|
72
|
+
event: TEvent,
|
|
73
|
+
callback: GetListenerCallback<TEvent>
|
|
74
|
+
) {
|
|
75
|
+
const eventFunction = ClientEvents[event];
|
|
76
|
+
const capitalizedEvent = event.charAt(0).toUpperCase() + event.slice(1);
|
|
77
|
+
const params = {
|
|
78
|
+
[`on${capitalizedEvent}`]: callback,
|
|
79
|
+
pollingInterval: 1000,
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
return (eventFunction as any)(this.rpc, params);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Creates an instance of MentaClient.
|
|
87
|
+
* @param {MentaClientConfig} params - The configuration parameters for the client.
|
|
88
|
+
* @description The constructor initializes the RPC client and the various managers based on the provided configuration.
|
|
89
|
+
* It also applies caching and persistence if specified in the configuration.
|
|
90
|
+
* @example
|
|
91
|
+
* import { MentaClient } from '@mentaproject/client';
|
|
92
|
+
*
|
|
93
|
+
* // Basic initialization
|
|
94
|
+
* const client = new MentaClient({
|
|
95
|
+
* url: 'http://rpcurlhere.com',
|
|
96
|
+
* });
|
|
97
|
+
*
|
|
98
|
+
* // Initialization with a persistent cache
|
|
99
|
+
* const clientWithCache = new MentaClient({
|
|
100
|
+
* url: 'http://rpcurlhere.com',
|
|
101
|
+
* cache: {
|
|
102
|
+
* ttl: 60000, // 1 minute
|
|
103
|
+
* },
|
|
104
|
+
* });
|
|
105
|
+
*/
|
|
106
|
+
constructor(params: MentaClientConfig) {
|
|
107
|
+
this.rpc = createClient(params) as CoreClient;
|
|
108
|
+
if (params.cache) this.rpc = withCache(this.rpc, params.cache);
|
|
109
|
+
|
|
110
|
+
this.blocks = new BlockManager(this);
|
|
111
|
+
this.transactions = new TransactionManager(this);
|
|
112
|
+
this.contracts = new ContractManager(this);
|
|
113
|
+
if (params.persistenceAdapter) {
|
|
114
|
+
this.persistenceManager = new PersistenceManager(this, params.persistenceAdapter);
|
|
115
|
+
this.accounts = new AccountManager(this, this.persistenceManager);
|
|
116
|
+
} else {
|
|
117
|
+
this.accounts = new AccountManager(this);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Optional manager for persistence-related operations.
|
|
123
|
+
* @description This manager is initialized if a persistence adapter is provided in the client configuration,
|
|
124
|
+
* allowing for data storage and retrieval.
|
|
125
|
+
*/
|
|
126
|
+
public persistenceManager?: PersistenceManager;
|
|
127
|
+
}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { AccessList, Address, Hash, Hex, Transaction as RawTransaction, WaitForTransactionReceiptReturnType } from '@mentaproject/core/types';
|
|
2
|
+
import { getBlock, getTransactionReceipt, traceTransaction, waitForTransactionReceipt } from '@mentaproject/core/actions';
|
|
3
|
+
import { hexToBigInt } from '@mentaproject/core/utils';
|
|
4
|
+
import { TransactionReceiptNotFoundError } from 'viem';
|
|
5
|
+
|
|
6
|
+
import { Account } from './Account';
|
|
7
|
+
import { Block } from './Block';
|
|
8
|
+
import { MentaClient } from './MentaClient';
|
|
9
|
+
|
|
10
|
+
import { toJSON } from '../utils/toJSON';
|
|
11
|
+
import { JSONTransaction, TransactionCall } from '../types';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Represents a blockchain transaction with its properties and methods.
|
|
15
|
+
*
|
|
16
|
+
* @description This class encapsulates the data and functionalities related to an Ethereum-like transaction,
|
|
17
|
+
* providing methods to interact with the blockchain to retrieve transaction-related information such as
|
|
18
|
+
* internal calls, receipts, and the block it belongs to.
|
|
19
|
+
*/
|
|
20
|
+
export class Transaction implements Omit<RawTransaction, "from" | "to"> {
|
|
21
|
+
/**
|
|
22
|
+
* @description The access list for the transaction.
|
|
23
|
+
*/
|
|
24
|
+
public accessList?: AccessList;
|
|
25
|
+
/**
|
|
26
|
+
* @description The blob versioned hashes.
|
|
27
|
+
*/
|
|
28
|
+
public blobVersionedHashes?: readonly Hex[];
|
|
29
|
+
/**
|
|
30
|
+
* @description The gas limit for the transaction.
|
|
31
|
+
*/
|
|
32
|
+
public gas: bigint;
|
|
33
|
+
/**
|
|
34
|
+
* @description The gas price for the transaction.
|
|
35
|
+
*/
|
|
36
|
+
public gasPrice?: bigint;
|
|
37
|
+
/**
|
|
38
|
+
* @description The hash of the transaction.
|
|
39
|
+
*/
|
|
40
|
+
public hash: Hash;
|
|
41
|
+
/**
|
|
42
|
+
* @description The input data for the transaction.
|
|
43
|
+
*/
|
|
44
|
+
public input: Hex;
|
|
45
|
+
/**
|
|
46
|
+
* @description The maximum fee per gas.
|
|
47
|
+
*/
|
|
48
|
+
public maxFeePerGas?: bigint;
|
|
49
|
+
/**
|
|
50
|
+
* @description The maximum priority fee per gas.
|
|
51
|
+
*/
|
|
52
|
+
public maxPriorityFeePerGas?: bigint;
|
|
53
|
+
/**
|
|
54
|
+
* @description The nonce of the transaction.
|
|
55
|
+
*/
|
|
56
|
+
public nonce: number;
|
|
57
|
+
/**
|
|
58
|
+
* @description The r value of the signature.
|
|
59
|
+
*/
|
|
60
|
+
public r: Hex;
|
|
61
|
+
/**
|
|
62
|
+
* @description The s value of the signature.
|
|
63
|
+
*/
|
|
64
|
+
public s: Hex;
|
|
65
|
+
/**
|
|
66
|
+
* @description The index of the transaction within the block.
|
|
67
|
+
*/
|
|
68
|
+
public transactionIndex: number | null;
|
|
69
|
+
/**
|
|
70
|
+
* @description The type of the transaction.
|
|
71
|
+
*/
|
|
72
|
+
public type: "legacy" | "eip2930" | "eip1559" | "eip4844" | "eip7702";
|
|
73
|
+
/**
|
|
74
|
+
* @description The v value of the signature.
|
|
75
|
+
*/
|
|
76
|
+
public v: bigint;
|
|
77
|
+
/**
|
|
78
|
+
* @description The value transferred in the transaction.
|
|
79
|
+
*/
|
|
80
|
+
public value: bigint;
|
|
81
|
+
/**
|
|
82
|
+
* @description The y parity of the signature.
|
|
83
|
+
*/
|
|
84
|
+
public yParity?: number;
|
|
85
|
+
/**
|
|
86
|
+
* @description The hash of the block containing this transaction.
|
|
87
|
+
*/
|
|
88
|
+
public blockHash: Hash | null;
|
|
89
|
+
/**
|
|
90
|
+
* @description The number of the block containing this transaction.
|
|
91
|
+
*/
|
|
92
|
+
public blockNumber: bigint | null;
|
|
93
|
+
/**
|
|
94
|
+
* @description The hex representation of the type of the transaction.
|
|
95
|
+
*/
|
|
96
|
+
public typeHex: `0x${string}` | null;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* @description The sender account of the transaction.
|
|
100
|
+
*/
|
|
101
|
+
public from?: Account;
|
|
102
|
+
/**
|
|
103
|
+
* @description The recipient account of the transaction.
|
|
104
|
+
*/
|
|
105
|
+
public to?: Account;
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Creates an instance of Transaction.
|
|
110
|
+
* @description Initializes a new Transaction instance with the provided RPC client and transaction data.
|
|
111
|
+
* @param {MentaClient} client - The instance of MentaClient used to interact with the blockchain.
|
|
112
|
+
* @param {ITransactionData} data The raw transaction data.
|
|
113
|
+
*/
|
|
114
|
+
constructor(protected client: MentaClient, data: RawTransaction) {
|
|
115
|
+
this.accessList = data.accessList;
|
|
116
|
+
this.blobVersionedHashes = data.blobVersionedHashes;
|
|
117
|
+
this.gas = data.gas;
|
|
118
|
+
this.gasPrice = data.gasPrice;
|
|
119
|
+
this.hash = data.hash;
|
|
120
|
+
this.input = data.input;
|
|
121
|
+
this.maxFeePerGas = data.maxFeePerGas;
|
|
122
|
+
this.maxPriorityFeePerGas = data.maxPriorityFeePerGas;
|
|
123
|
+
this.nonce = data.nonce;
|
|
124
|
+
this.r = data.r;
|
|
125
|
+
this.s = data.s;
|
|
126
|
+
this.transactionIndex = data.transactionIndex;
|
|
127
|
+
this.type = data.type;
|
|
128
|
+
this.v = data.v;
|
|
129
|
+
this.value = data.value;
|
|
130
|
+
this.yParity = data.yParity;
|
|
131
|
+
this.blockHash = data.blockHash;
|
|
132
|
+
this.blockNumber = data.blockNumber;
|
|
133
|
+
this.typeHex = data.typeHex;
|
|
134
|
+
|
|
135
|
+
this.from = data.from ? this.client.accounts.get(data.from) : undefined;
|
|
136
|
+
this.to = data.to ? this.client.accounts.get(data.to) : undefined;
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Retrieves the internal calls made by this transaction.
|
|
141
|
+
* @description Fetches and processes the transaction traces to extract internal call details.
|
|
142
|
+
* @returns {Promise<TransactionCall[] | undefined>} A promise that resolves to an array of call objects, each representing an internal call with sender, recipient, value, input data, gas used, and call type.
|
|
143
|
+
*/
|
|
144
|
+
public async calls(): Promise<TransactionCall[] | undefined> {
|
|
145
|
+
const traces = await traceTransaction(this.client.rpc, this.hash);
|
|
146
|
+
if (!traces) return undefined;
|
|
147
|
+
|
|
148
|
+
const calls = traces.filter(t => t.type === "call" && t.action !== undefined);
|
|
149
|
+
|
|
150
|
+
return calls.map(c => ({
|
|
151
|
+
from: new Account(this.client, { address: c.action!.from as Address }),
|
|
152
|
+
to: new Account(this.client, { address: c.action!.to as Address }),
|
|
153
|
+
value: hexToBigInt(c.action!.value as Hex),
|
|
154
|
+
input: c.action!.input as Hex,
|
|
155
|
+
gas: hexToBigInt(c.action!.gas as Hex),
|
|
156
|
+
callType: c.action!.callType,
|
|
157
|
+
})) as TransactionCall[];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Waits for the transaction receipt to be available.
|
|
162
|
+
* @description Asynchronously waits for the transaction to be confirmed on the blockchain and its receipt to be available.
|
|
163
|
+
* @param {number} [confirmations] The number of confirmations to wait for. Defaults to 1.
|
|
164
|
+
* @returns {Promise<WaitForTransactionReceiptReturnType>} A promise that resolves to the transaction receipt once the specified number of confirmations are met.
|
|
165
|
+
*/
|
|
166
|
+
async waitForReceipt(confirmations?: number): Promise<WaitForTransactionReceiptReturnType> {
|
|
167
|
+
return await waitForTransactionReceipt(this.client.rpc, {
|
|
168
|
+
hash: this.hash,
|
|
169
|
+
confirmations: confirmations || 1,
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Retrieves the transaction receipt.
|
|
175
|
+
* @description Fetches the transaction receipt for the current transaction hash.
|
|
176
|
+
* @returns {Promise<WaitForTransactionReceiptReturnType>} A promise that resolves to the transaction receipt.
|
|
177
|
+
*/
|
|
178
|
+
async receipt(): Promise<WaitForTransactionReceiptReturnType | undefined> {
|
|
179
|
+
try {
|
|
180
|
+
return await getTransactionReceipt(this.client.rpc, { hash: this.hash });
|
|
181
|
+
} catch (error) {
|
|
182
|
+
if (error instanceof TransactionReceiptNotFoundError) {
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Retrieves the block containing this transaction.
|
|
190
|
+
* @description Fetches the block data using the transaction's block hash and returns a Block instance.
|
|
191
|
+
* @returns {Promise<Block>} A promise that resolves to a Block instance representing the block that includes this transaction.
|
|
192
|
+
*/
|
|
193
|
+
async block(): Promise<Block> {
|
|
194
|
+
const data = await getBlock(this.client.rpc, { blockHash: this.blockHash! });
|
|
195
|
+
return new Block(this.client, data);
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Converts the Transaction instance to a JSON representation.
|
|
200
|
+
* @description Serializes the transaction instance into a JSON object, including nested representations of related entities like block, receipt, and internal calls based on the specified depth.
|
|
201
|
+
* @param {number} [depth=1] The depth of the conversion. Controls how deeply nested objects are serialized.
|
|
202
|
+
* @returns {Promise<object>} A promise that resolves to the JSON representation of the transaction.
|
|
203
|
+
*/
|
|
204
|
+
async toJSON<D extends number = 1>(depth: D): Promise<JSONTransaction<D>> {
|
|
205
|
+
return await toJSON({
|
|
206
|
+
obj: {
|
|
207
|
+
...this,
|
|
208
|
+
block: this.block,
|
|
209
|
+
receipt: this.receipt,
|
|
210
|
+
calls: async () => {
|
|
211
|
+
const calls = await this.calls();
|
|
212
|
+
if (!calls) return undefined;
|
|
213
|
+
|
|
214
|
+
return Promise.all(calls.map(async c => await toJSON({ obj: c, depth: depth })));
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
depth
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
};
|