@@ -4,9 +4,40 @@ import { TransportDependencies } from '@chainlink/external-adapter-framework/tra
4
4
import { deferredPromise , LoggerFactoryProvider } from '@chainlink/external-adapter-framework/util'
5
5
import { makeStub } from '@chainlink/external-adapter-framework/util/testing-utils'
6
6
import Decimal from 'decimal.js'
7
+ import { ethers } from 'ethers'
7
8
import { BaseEndpointTypes , inputParameters } from '../../src/endpoint/xrpl'
8
9
import { XrplTransport } from '../../src/transport/xrpl'
9
10
11
+ const originalEnv = { ...process . env }
12
+
13
+ const restoreEnv = ( ) => {
14
+ for ( const key of Object . keys ( process . env ) ) {
15
+ if ( key in originalEnv ) {
16
+ process . env [ key ] = originalEnv [ key ]
17
+ } else {
18
+ delete process . env [ key ]
19
+ }
20
+ }
21
+ }
22
+
23
+ const ethersNewContract = jest . fn ( )
24
+ const ethersNewJsonRpcProvider = jest . fn ( )
25
+
26
+ const makeEthers = ( ) => {
27
+ return {
28
+ JsonRpcProvider : function ( ...args : [ string , number ] ) {
29
+ return ethersNewJsonRpcProvider ( ...args )
30
+ } ,
31
+ Contract : function ( ...args : [ string , unknown , ethers . JsonRpcProvider ] ) {
32
+ return ethersNewContract ( ...args )
33
+ } ,
34
+ }
35
+ }
36
+
37
+ jest . mock ( 'ethers' , ( ) => ( {
38
+ ethers : makeEthers ( ) ,
39
+ } ) )
40
+
10
41
const log = jest . fn ( )
11
42
const logger = {
12
43
fatal : log ,
@@ -127,6 +158,7 @@ describe('XrplTransport', () => {
127
158
}
128
159
129
160
beforeEach ( async ( ) => {
161
+ restoreEnv ( )
130
162
jest . resetAllMocks ( )
131
163
jest . useFakeTimers ( )
132
164
@@ -172,14 +204,36 @@ describe('XrplTransport', () => {
172
204
173
205
describe ( 'handleRequest' , ( ) => {
174
206
it ( 'should cache response' , async ( ) => {
207
+ const priceOracleAddress = '0x123'
208
+ const priceOracleNetwork = 'arbitrum'
209
+ const arbitrumRpcUrl = 'https://arb.rpc.url'
210
+ const arbitrumChainId = 42161
211
+ const tokenPrice = 200_000_000n
212
+ const tokenDecimals = 8
175
213
const address = 'r101'
214
+ const tokenIssuerAddress = 'r456'
215
+ const balance = 123
216
+
217
+ process . env . ARBITRUM_RPC_URL = arbitrumRpcUrl
218
+ process . env . ARBITRUM_RPC_CHAIN_ID = arbitrumChainId . toString ( )
219
+
220
+ const contract = makeStub ( 'contract' , {
221
+ decimals : jest . fn ( ) . mockResolvedValue ( tokenDecimals ) ,
222
+ latestAnswer : jest . fn ( ) . mockResolvedValue ( tokenPrice ) ,
223
+ } )
224
+ ethersNewContract . mockReturnValue ( contract )
225
+
226
+ mockLineBalances ( [ balance . toString ( ) ] )
176
227
177
228
const param = makeStub ( 'param' , {
229
+ priceOracleAddress,
230
+ priceOracleNetwork,
231
+ tokenIssuerAddress,
178
232
addresses : [ { address } ] ,
179
233
} )
180
234
await transport . handleRequest ( context , param )
181
235
182
- const expectedResult = '0'
236
+ const expectedResult = ( 246 * 10 ** 18 ) . toString ( )
183
237
const expectedResponse = {
184
238
statusCode : 200 ,
185
239
result : expectedResult ,
@@ -201,19 +255,48 @@ describe('XrplTransport', () => {
201
255
} ,
202
256
] )
203
257
expect ( responseCache . write ) . toBeCalledTimes ( 1 )
258
+
259
+ expect ( log ) . toBeCalledWith ( expect . stringContaining ( 'Generated HTTP request queue key:' ) )
260
+ expect ( log ) . toBeCalledTimes ( 1 )
261
+ log . mockClear ( )
204
262
} )
205
263
} )
206
264
207
265
describe ( '_handleRequest' , ( ) => {
208
- it ( 'should return a response' , async ( ) => {
209
- const address = 'r101'
266
+ it ( 'should add balances and multiply by token price' , async ( ) => {
267
+ const priceOracleAddress = '0x123'
268
+ const priceOracleNetwork = 'arbitrum'
269
+ const arbitrumRpcUrl = 'https://arb.rpc.url'
270
+ const arbitrumChainId = 42161
271
+ const tokenPrice = 200_000_000n
272
+ const tokenDecimals = 8
273
+ const address1 = 'r101'
274
+ const address2 = 'r102'
275
+ const tokenIssuerAddress = 'r456'
276
+ const balance1 = 100
277
+ const balance2 = 200
278
+
279
+ process . env . ARBITRUM_RPC_URL = arbitrumRpcUrl
280
+ process . env . ARBITRUM_RPC_CHAIN_ID = arbitrumChainId . toString ( )
281
+
282
+ const contract = makeStub ( 'contract' , {
283
+ decimals : jest . fn ( ) . mockResolvedValue ( tokenDecimals ) ,
284
+ latestAnswer : jest . fn ( ) . mockResolvedValue ( tokenPrice ) ,
285
+ } )
286
+ ethersNewContract . mockReturnValue ( contract )
287
+
288
+ mockLineBalances ( [ balance1 . toString ( ) ] )
289
+ mockLineBalances ( [ balance2 . toString ( ) ] )
210
290
211
291
const param = makeStub ( 'param' , {
212
- addresses : [ { address } ] ,
292
+ priceOracleAddress,
293
+ priceOracleNetwork,
294
+ tokenIssuerAddress,
295
+ addresses : [ { address : address1 } , { address : address2 } ] ,
213
296
} )
214
297
const response = await transport . _handleRequest ( param )
215
298
216
- const expectedResult = '0'
299
+ const expectedResult = ( 600 * 10 ** 18 ) . toString ( )
217
300
expect ( response ) . toEqual ( {
218
301
statusCode : 200 ,
219
302
result : expectedResult ,
@@ -227,6 +310,73 @@ describe('XrplTransport', () => {
227
310
providerIndicatedTimeUnixMs : undefined ,
228
311
} ,
229
312
} )
313
+
314
+ expect ( log ) . toHaveBeenNthCalledWith (
315
+ 1 ,
316
+ expect . stringContaining ( 'Generated HTTP request queue key:' ) ,
317
+ )
318
+ expect ( log ) . toHaveBeenNthCalledWith (
319
+ 2 ,
320
+ expect . stringContaining ( 'Generated HTTP request queue key:' ) ,
321
+ )
322
+ expect ( log ) . toBeCalledTimes ( 2 )
323
+ log . mockClear ( )
324
+ } )
325
+
326
+ it ( 'should record received timestamp separate from requested timestamp' , async ( ) => {
327
+ const priceOracleAddress = '0x123'
328
+ const priceOracleNetwork = 'arbitrum'
329
+ const arbitrumRpcUrl = 'https://arb.rpc.url'
330
+ const arbitrumChainId = 42161
331
+ const tokenPrice = 200_000_000n
332
+ const tokenDecimals = 8
333
+ const address = 'r101'
334
+ const tokenIssuerAddress = 'r456'
335
+ const balance = 100
336
+
337
+ process . env . ARBITRUM_RPC_URL = arbitrumRpcUrl
338
+ process . env . ARBITRUM_RPC_CHAIN_ID = arbitrumChainId . toString ( )
339
+
340
+ const contract = makeStub ( 'contract' , {
341
+ decimals : jest . fn ( ) . mockResolvedValue ( tokenDecimals ) ,
342
+ latestAnswer : jest . fn ( ) . mockResolvedValue ( tokenPrice ) ,
343
+ } )
344
+ ethersNewContract . mockReturnValue ( contract )
345
+
346
+ const [ balancePromise , resolveBalance ] = deferredPromise < string [ ] > ( )
347
+ mockLineBalances ( balancePromise )
348
+
349
+ const param = makeStub ( 'param' , {
350
+ priceOracleAddress,
351
+ priceOracleNetwork,
352
+ tokenIssuerAddress,
353
+ addresses : [ { address } ] ,
354
+ } )
355
+
356
+ const requestTimestamp = Date . now ( )
357
+ const responsePromise = transport . _handleRequest ( param )
358
+ jest . advanceTimersByTime ( 1234 )
359
+ const responseTimestamp = Date . now ( )
360
+ expect ( responseTimestamp ) . toBeGreaterThan ( requestTimestamp )
361
+
362
+ resolveBalance ( [ balance . toString ( ) ] )
363
+
364
+ const expectedResult = ( 200 * 10 ** 18 ) . toString ( )
365
+ expect ( await responsePromise ) . toEqual ( {
366
+ statusCode : 200 ,
367
+ result : expectedResult ,
368
+ data : {
369
+ decimals : 18 ,
370
+ result : expectedResult ,
371
+ } ,
372
+ timestamps : {
373
+ providerDataRequestedUnixMs : requestTimestamp ,
374
+ providerDataReceivedUnixMs : responseTimestamp ,
375
+ providerIndicatedTimeUnixMs : undefined ,
376
+ } ,
377
+ } )
378
+
379
+ log . mockClear ( )
230
380
} )
231
381
} )
232
382
0 commit comments