@@ -2,7 +2,108 @@ import type { EventRecord } from "@polkadot/types/interfaces";
2
2
import { strictEqual } from "node:assert" ;
3
3
import type { ApiPromise } from "@polkadot/api" ;
4
4
import type { AugmentedEvent } from "@polkadot/api/types" ;
5
+ import type { BspNetApi } from "./bspNet" ;
5
6
7
+ /**
8
+ * Asserts that a specific extrinsic (module.method) is present in a blockchain block or transaction pool.
9
+ *
10
+ * @param {BspNetApi } api - The API instance connected to the blockchain network.
11
+ * @param {Object } options - Configuration options for the extrinsic check.
12
+ * @param {string } [options.blockHeight] - The block height to check. If not provided, the latest block will be used.
13
+ * @param {string } [options.blockHash] - The block hash to check. Takes precedence over blockHeight if provided.
14
+ * @param {boolean } [options.skipSuccessCheck=false] - If true, skips the check for an associated `ExtrinsicSuccess` event.
15
+ * @param {boolean } [options.checkTxPool=false] - If true, checks the pending transaction pool instead of a finalized block.
16
+ * @param {string } options.module - The module name of the extrinsic to check (e.g., "balances").
17
+ * @param {string } options.method - The method name of the extrinsic to check (e.g., "transfer").
18
+ * @param {boolean } [options.ignoreParamCheck=false] - If true, skips the validation check for the module.method existence in the API metadata.
19
+ *
20
+ * @returns {Promise<Object[]> } - Returns a list of objects representing the extrinsics that match the module.method criteria.
21
+ * @throws {Error } - Throws an error if no matching extrinsic is found, or if the success check fails (unless skipped).
22
+ *
23
+ * TODO: add ability to search nested extrinsics e.g. sudo.sudo(balance.forceTransfer(...))
24
+ */
25
+ export const assertExtrinsicPresent = async (
26
+ api : BspNetApi ,
27
+ options : {
28
+ blockHeight ?: string ;
29
+ blockHash ?: string ;
30
+ skipSuccessCheck ?: boolean ;
31
+ checkTxPool ?: boolean ;
32
+ module : string ;
33
+ method : string ;
34
+ ignoreParamCheck ?: boolean ;
35
+ }
36
+ ) : Promise <
37
+ {
38
+ module : string ;
39
+ method : string ;
40
+ extIndex : number ;
41
+ } [ ]
42
+ > => {
43
+ if ( options . ignoreParamCheck !== true ) {
44
+ strictEqual (
45
+ options . module in api . tx ,
46
+ true ,
47
+ `Module ${ options . module } not found in API metadata. Turn off this check with "ignoreParamCheck: true" if you are sure this exists`
48
+ ) ;
49
+ strictEqual (
50
+ options . method in api . tx [ options . module ] ,
51
+ true ,
52
+ `Method ${ options . module } .${ options . method } not found in metadata. Turn off this check with "ignoreParamCheck: true" if you are sure this exists`
53
+ ) ;
54
+ }
55
+
56
+ const blockHash = options ?. blockHash
57
+ ? options . blockHash
58
+ : options ?. blockHeight
59
+ ? await api . rpc . chain . getBlockHash ( options ?. blockHeight )
60
+ : await api . rpc . chain . getBlockHash ( ) ;
61
+
62
+ const extrinsics = ! options . checkTxPool
63
+ ? await ( async ( ) => {
64
+ const response = await api . rpc . chain . getBlock ( blockHash ) ;
65
+
66
+ if ( ! options . blockHeight && ! options . blockHash ) {
67
+ console . log (
68
+ `No block height provided, using latest at ${ response . block . header . number . toNumber ( ) } `
69
+ ) ;
70
+ }
71
+ return response . block . extrinsics ;
72
+ } ) ( )
73
+ : await api . rpc . author . pendingExtrinsics ( ) ;
74
+ const transformed = extrinsics . map ( ( { method : { method, section } } , index ) => {
75
+ return { module : section , method, extIndex : index } ;
76
+ } ) ;
77
+
78
+ const matches = transformed . filter (
79
+ ( { method, module } ) => method === options ?. method && module === options ?. module
80
+ ) ;
81
+
82
+ strictEqual (
83
+ matches . length > 0 ,
84
+ true ,
85
+ `No extrinsics matching ${ options ?. module } .${ options ?. method } found. \n Extrinsics in block ${ options . blockHeight || blockHash } : ${ extrinsics . map ( ( { method : { method, section } } ) => `${ section } .${ method } ` ) . join ( " | " ) } `
86
+ ) ;
87
+
88
+ if ( options ?. skipSuccessCheck !== true && options . checkTxPool !== true ) {
89
+ const events = await ( await api . at ( blockHash ) ) . query . system . events ( ) ;
90
+ assertEventPresent ( api , "system" , "ExtrinsicSuccess" , events ) ;
91
+ }
92
+
93
+ return matches ;
94
+ } ;
95
+
96
+ /**
97
+ * Asserts that a specific event (module.method) is present in the provided list of events.
98
+ *
99
+ * @param {ApiPromise } api - The API instance connected to the blockchain network.
100
+ * @param {string } module - The module name of the event to check (e.g., "system").
101
+ * @param {string } method - The method name of the event to check (e.g., "ExtrinsicSuccess").
102
+ * @param {EventRecord[] } [events] - The list of events to search through. If not provided or empty, an error is thrown.
103
+ *
104
+ * @returns {Object } - Returns an object containing the matching event and its data.
105
+ * @throws {Error } - Throws an error if no matching event is found, or if the event does not match the expected structure.
106
+ */
6
107
export const assertEventPresent = (
7
108
api : ApiPromise ,
8
109
module : string ,
@@ -27,6 +128,17 @@ export const assertEventPresent = (
27
128
return { event : event . event , data : event . event . data } ;
28
129
} ;
29
130
131
+ /**
132
+ * Asserts that multiple instances of a specific event (module.method) are present in the provided list of events.
133
+ *
134
+ * @param {ApiPromise } api - The API instance connected to the blockchain network.
135
+ * @param {string } module - The module name of the event to check (e.g., "system").
136
+ * @param {string } method - The method name of the event to check (e.g., "ExtrinsicSuccess").
137
+ * @param {EventRecord[] } [events] - The list of events to search through. If not provided or empty, an error is thrown.
138
+ *
139
+ * @returns {EventRecord[] } - Returns an array of matching events.
140
+ * @throws {Error } - Throws an error if no matching events are found.
141
+ */
30
142
export const assertEventMany = (
31
143
api : ApiPromise ,
32
144
module : string ,
0 commit comments