1
1
import { Account } from "./account" ;
2
2
import { EncryptedRecord , OwnedRecord , RecordProvider , RecordSearchParams , RecordsResponseFilter } from "./record-provider" ;
3
3
import { RecordPlaintext } from "./wasm" ;
4
+ import { RegistrationRequest } from "./models/record-scanner/registrationRequest" ;
5
+ import { RecordsFilter } from "./models/record-scanner/recordsFilter" ;
6
+ import { OwnedFilter } from "./models/record-scanner/ownedFilter" ;
4
7
5
- type RegistrationRequest = {
6
- viewKey : string ;
7
- start : number ;
8
- }
9
-
10
- interface RecordsFilter extends RecordSearchParams {
11
- start : number ;
12
- end ?: number ;
13
- program ?: string ;
14
- record ?: string ;
15
- function ?: string ;
16
- }
17
-
18
- interface OwnedFilter extends RecordSearchParams {
19
- decrypt ?: boolean ;
20
- filter ?: RecordsFilter ;
21
- responseFilter ?: RecordsResponseFilter ;
22
- }
23
-
24
- interface OwnedFilterWithUuid extends OwnedFilter {
25
- uuid : string ;
26
- }
27
-
8
+ /**
9
+ * RecordScanner is a RecordProvider implementation that uses the record scanner service to find records.
10
+ *
11
+ * @example
12
+ * const account = new Account({ privateKey: 'APrivateKey1...' });
13
+ *
14
+ * const recordScanner = new RecordScanner("https://record-scanner.aleo.org");
15
+ * recordScanner.setAccount(account);
16
+ * await recordScanner.register(0);
17
+ *
18
+ * const filter = {
19
+ * start: 0,
20
+ * end: 100,
21
+ * program: "credits.aleo",
22
+ * record: "credits",
23
+ * };
24
+ *
25
+ * const responseFilter = {
26
+ * program: true,
27
+ * record: true,
28
+ * function: true,
29
+ * transition: true,
30
+ * blockHeight: true,
31
+ * transactionId: true,
32
+ * };
33
+ *
34
+ * const records = await recordScanner.findRecords({ filter, responseFilter });
35
+ */
28
36
class RecordScanner implements RecordProvider {
29
37
readonly url : string ;
30
38
private account ?: Account ;
@@ -35,10 +43,21 @@ class RecordScanner implements RecordProvider {
35
43
this . url = url ;
36
44
}
37
45
46
+ /**
47
+ * Set the account to use for the record scanner.
48
+ *
49
+ * @param {Account } account The account to use for the record scanner.
50
+ */
38
51
async setAccount ( account : Account ) : Promise < void > {
52
+ this . uuid = undefined ;
39
53
this . account = account ;
40
54
}
41
55
56
+ /**
57
+ * Register the account with the record scanner service.
58
+ *
59
+ * @param {number } startBlock The block height to start scanning from.
60
+ */
42
61
async register ( startBlock : number ) : Promise < void > {
43
62
let request : RegistrationRequest ;
44
63
if ( ! this . account ) {
@@ -67,7 +86,14 @@ class RecordScanner implements RecordProvider {
67
86
}
68
87
}
69
88
70
- async getEncryptedRecords ( recordsFilter : RecordsFilter , responseFilter : RecordsResponseFilter ) : Promise < EncryptedRecord [ ] > {
89
+ /**
90
+ * Get encrypted records from the record scanner service.
91
+ *
92
+ * @param {RecordsFilter } recordsFilter The filter to use to find the records
93
+ * @param {RecordsResponseFilter } responseFilter The filter to use to filter the response
94
+ * @returns {Promise<EncryptedRecord[]> } The encrypted records
95
+ */
96
+ async encryptedRecords ( recordsFilter : RecordsFilter , responseFilter : RecordsResponseFilter ) : Promise < EncryptedRecord [ ] > {
71
97
try {
72
98
const response = await this . recordScannerServiceRequest (
73
99
new Request ( `${ this . url } /records/encrypted?${ this . buildQueryString ( recordsFilter , responseFilter ) } ` , {
@@ -84,7 +110,13 @@ class RecordScanner implements RecordProvider {
84
110
}
85
111
}
86
112
87
- async serialNumbersExist ( serialNumbers : string [ ] ) : Promise < Record < string , boolean > > {
113
+ /**
114
+ * Check if a list of serial numbers exist in the record scanner service.
115
+ *
116
+ * @param {string[] } serialNumbers The serial numbers to check
117
+ * @returns {Promise<Record<string, boolean>> } A record of serial numbers and whether they exist
118
+ */
119
+ async checkSerialNumbers ( serialNumbers : string [ ] ) : Promise < Record < string , boolean > > {
88
120
try {
89
121
const response = await this . recordScannerServiceRequest (
90
122
new Request ( `${ this . url } /records/sns` , {
@@ -101,7 +133,13 @@ class RecordScanner implements RecordProvider {
101
133
}
102
134
}
103
135
104
- async tagsExist ( tags : string [ ] ) : Promise < Record < string , boolean > > {
136
+ /**
137
+ * Check if a list of tags exist in the record scanner service.
138
+ *
139
+ * @param {string[] } tags The tags to check
140
+ * @returns {Promise<Record<string, boolean>> } A record of tags and whether they exist
141
+ */
142
+ async checkTags ( tags : string [ ] ) : Promise < Record < string , boolean > > {
105
143
try {
106
144
const response = await this . recordScannerServiceRequest (
107
145
new Request ( `${ this . url } /records/tags` , {
@@ -118,9 +156,15 @@ class RecordScanner implements RecordProvider {
118
156
}
119
157
}
120
158
121
- async findRecord ( searchParameters : OwnedFilter , filterFn ?: ( record : RecordPlaintext ) => boolean ) : Promise < OwnedRecord > {
159
+ /**
160
+ * Find a record in the record scanner service.
161
+ *
162
+ * @param {OwnedFilter } searchParameters The filter to use to find the record
163
+ * @returns {Promise<OwnedRecord> } The record
164
+ */
165
+ async findRecord ( searchParameters : OwnedFilter ) : Promise < OwnedRecord > {
122
166
try {
123
- const records = await this . findRecords ( searchParameters , filterFn ) ;
167
+ const records = await this . findRecords ( searchParameters ) ;
124
168
125
169
if ( records . length > 0 ) {
126
170
return records [ 0 ] ;
@@ -133,34 +177,43 @@ class RecordScanner implements RecordProvider {
133
177
}
134
178
}
135
179
136
- async findRecords ( searchParameters : OwnedFilter , filterFn ?: ( record : RecordPlaintext ) => boolean ) : Promise < OwnedRecord [ ] > {
180
+ /**
181
+ * Find records in the record scanner service.
182
+ *
183
+ * @param {OwnedFilter } filter The filter to use to find the records
184
+ * @returns {Promise<OwnedRecord[]> } The records
185
+ */
186
+ async findRecords ( filter : OwnedFilter ) : Promise < OwnedRecord [ ] > {
137
187
if ( ! this . uuid ) {
138
188
throw new Error ( "Not registered" ) ;
139
189
}
140
190
141
- const filterWithUuid : OwnedFilterWithUuid = {
142
- ...searchParameters ,
143
- uuid : this . uuid ,
144
- } ;
191
+ filter . uuid = this . uuid ;
145
192
146
193
try {
147
194
const response = await this . recordScannerServiceRequest (
148
195
new Request ( `${ this . url } /records/owned` , {
149
196
method : "POST" ,
150
197
headers : { "Content-Type" : "application/json" } ,
151
- body : JSON . stringify ( filterWithUuid ) ,
198
+ body : JSON . stringify ( filter ) ,
152
199
} ) ,
153
200
) ;
154
201
155
- const records = await response . json ( ) ;
156
- return filterFn ? records . filter ( filterFn ) : records ;
202
+ return await response . json ( ) ;
157
203
} catch ( error ) {
158
204
console . error ( `Failed to get owned records: ${ error } ` ) ;
159
205
throw error ;
160
206
}
161
207
}
162
208
163
- async findCreditsRecord ( microcredits : number , searchParameters : OwnedFilter , nonces ?: string [ ] ) : Promise < OwnedRecord > {
209
+ /**
210
+ * Find a credits record in the record scanner service.
211
+ *
212
+ * @param {number } microcredits The amount of microcredits to find
213
+ * @param {OwnedFilter } searchParameters The filter to use to find the record
214
+ * @returns {Promise<OwnedRecord> } The record
215
+ */
216
+ async findCreditsRecord ( microcredits : number , searchParameters : OwnedFilter ) : Promise < OwnedRecord > {
164
217
try {
165
218
const records = await this . findRecords ( {
166
219
...searchParameters ,
@@ -171,8 +224,9 @@ class RecordScanner implements RecordProvider {
171
224
172
225
const record = records . find ( record => {
173
226
const plaintext = RecordPlaintext . fromString ( record . recordPlaintext ) ;
174
- const amount = plaintext . getMember ( "microcredits" ) . toString ( ) ;
175
- return amount === `${ microcredits } u64` ;
227
+ const amountStr = plaintext . getMember ( "microcredits" ) . toString ( ) ;
228
+ const amount = parseInt ( amountStr . replace ( "u64" , "" ) ) ;
229
+ return amount >= microcredits ;
176
230
} ) ;
177
231
178
232
if ( ! record ) {
@@ -186,7 +240,14 @@ class RecordScanner implements RecordProvider {
186
240
}
187
241
}
188
242
189
- async findCreditsRecords ( microcreditAmounts : number [ ] , searchParameters : OwnedFilter , nonces ?: string [ ] ) : Promise < OwnedRecord [ ] > {
243
+ /**
244
+ * Find credits records in the record scanner service.
245
+ *
246
+ * @param {number[] } microcreditAmounts The amounts of microcredits to find
247
+ * @param {OwnedFilter } searchParameters The filter to use to find the records
248
+ * @returns {Promise<OwnedRecord[]> } The records
249
+ */
250
+ async findCreditsRecords ( microcreditAmounts : number [ ] , searchParameters : OwnedFilter ) : Promise < OwnedRecord [ ] > {
190
251
try {
191
252
const records = await this . findRecords ( {
192
253
...searchParameters ,
@@ -205,7 +266,12 @@ class RecordScanner implements RecordProvider {
205
266
}
206
267
}
207
268
208
-
269
+ /**
270
+ * Wrapper function to make a request to the record scanner service and handle any errors
271
+ *
272
+ * @param {Request } req The request to make
273
+ * @returns {Promise<Response> } The response
274
+ */
209
275
private async recordScannerServiceRequest ( req : Request ) : Promise < Response > {
210
276
try {
211
277
const response = await fetch ( req ) ;
@@ -221,6 +287,13 @@ class RecordScanner implements RecordProvider {
221
287
}
222
288
}
223
289
290
+ /**
291
+ * Helper function to build a query string from the records filter and response filter.
292
+ *
293
+ * @param {RecordSearchParams } recordsFilter The filter to use to find the records
294
+ * @param {RecordsResponseFilter } responseFilter The filter to use to filter the response
295
+ * @returns {string } The query string
296
+ */
224
297
private buildQueryString ( recordsFilter : RecordSearchParams , responseFilter : RecordsResponseFilter ) : string {
225
298
return Object . entries ( { ...recordsFilter , ...responseFilter } )
226
299
. map ( ( [ key , value ] ) => `${ key } =${ value } ` )
0 commit comments