@sentio/sdk 1.30.2 → 1.31.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.
Files changed (108) hide show
  1. package/lib/aptos/aptos-processor.d.ts +9 -2
  2. package/lib/aptos/aptos-processor.js +12 -3
  3. package/lib/aptos/aptos-processor.js.map +1 -1
  4. package/lib/builtin/erc1155/index.d.ts +2 -0
  5. package/lib/builtin/erc1155/index.js +22 -0
  6. package/lib/builtin/erc1155/index.js.map +1 -0
  7. package/lib/builtin/erc1155/test-utils.d.ts +6 -0
  8. package/lib/builtin/erc1155/test-utils.js +57 -0
  9. package/lib/builtin/erc1155/test-utils.js.map +1 -0
  10. package/lib/builtin/erc721/index.d.ts +2 -0
  11. package/lib/builtin/erc721/index.js +22 -0
  12. package/lib/builtin/erc721/index.js.map +1 -0
  13. package/lib/builtin/erc721/test-utils.d.ts +5 -0
  14. package/lib/builtin/erc721/test-utils.js +46 -0
  15. package/lib/builtin/erc721/test-utils.js.map +1 -0
  16. package/lib/builtin/internal/ERC1155.d.ts +199 -0
  17. package/lib/builtin/internal/ERC1155.js +3 -0
  18. package/lib/builtin/internal/ERC1155.js.map +1 -0
  19. package/lib/builtin/internal/ERC721.d.ts +252 -0
  20. package/lib/builtin/internal/ERC721.js +3 -0
  21. package/lib/builtin/internal/ERC721.js.map +1 -0
  22. package/lib/builtin/internal/erc1155_processor.d.ts +134 -0
  23. package/lib/builtin/internal/erc1155_processor.js +337 -0
  24. package/lib/builtin/internal/erc1155_processor.js.map +1 -0
  25. package/lib/builtin/internal/erc721_processor.d.ts +169 -0
  26. package/lib/builtin/internal/erc721_processor.js +479 -0
  27. package/lib/builtin/internal/erc721_processor.js.map +1 -0
  28. package/lib/builtin/internal/factories/ERC1155__factory.d.ts +35 -0
  29. package/lib/builtin/internal/factories/ERC1155__factory.js +332 -0
  30. package/lib/builtin/internal/factories/ERC1155__factory.js.map +1 -0
  31. package/lib/builtin/internal/factories/ERC721__factory.d.ts +51 -0
  32. package/lib/builtin/internal/factories/ERC721__factory.js +364 -0
  33. package/lib/builtin/internal/factories/ERC721__factory.js.map +1 -0
  34. package/lib/builtin/internal/factories/index.d.ts +2 -0
  35. package/lib/builtin/internal/factories/index.js +5 -1
  36. package/lib/builtin/internal/factories/index.js.map +1 -1
  37. package/lib/builtin/internal/index.d.ts +4 -0
  38. package/lib/builtin/internal/index.js +5 -1
  39. package/lib/builtin/internal/index.js.map +1 -1
  40. package/lib/core/account-processor.d.ts +58 -0
  41. package/lib/core/account-processor.js +147 -0
  42. package/lib/core/account-processor.js.map +1 -0
  43. package/lib/core/base-processor.d.ts +5 -2
  44. package/lib/core/base-processor.js.map +1 -1
  45. package/lib/core/bind-options.d.ts +5 -0
  46. package/lib/core/bind-options.js +7 -1
  47. package/lib/core/bind-options.js.map +1 -1
  48. package/lib/core/context.d.ts +7 -1
  49. package/lib/core/context.js +30 -18
  50. package/lib/core/context.js.map +1 -1
  51. package/lib/core/event-tracker.d.ts +5 -1
  52. package/lib/core/event-tracker.js +8 -5
  53. package/lib/core/event-tracker.js.map +1 -1
  54. package/lib/core/meter.js +6 -0
  55. package/lib/core/meter.js.map +1 -1
  56. package/lib/gen/chainquery/protos/chainquery.d.ts +1 -0
  57. package/lib/gen/chainquery/protos/chainquery.js +17 -1
  58. package/lib/gen/chainquery/protos/chainquery.js.map +1 -1
  59. package/lib/gen/processor/protos/processor.d.ts +11 -0
  60. package/lib/gen/processor/protos/processor.js +84 -3
  61. package/lib/gen/processor/protos/processor.js.map +1 -1
  62. package/lib/index.d.ts +0 -1
  63. package/lib/index.js +2 -3
  64. package/lib/index.js.map +1 -1
  65. package/lib/service.d.ts +1 -0
  66. package/lib/service.js +72 -45
  67. package/lib/service.js.map +1 -1
  68. package/lib/state/processor-state.d.ts +1 -5
  69. package/lib/state/processor-state.js +1 -3
  70. package/lib/state/processor-state.js.map +1 -1
  71. package/lib/state/state-storage.d.ts +5 -0
  72. package/lib/state/state-storage.js +15 -1
  73. package/lib/state/state-storage.js.map +1 -1
  74. package/lib/testing/test-processor-server.d.ts +6 -2
  75. package/lib/testing/test-processor-server.js +66 -5
  76. package/lib/testing/test-processor-server.js.map +1 -1
  77. package/lib/utils/price.js +11 -4
  78. package/lib/utils/price.js.map +1 -1
  79. package/package.json +1 -1
  80. package/src/abis/ERC1155.json +314 -0
  81. package/src/abis/ERC721.json +346 -0
  82. package/src/aptos/aptos-processor.ts +15 -6
  83. package/src/builtin/erc1155/index.ts +6 -0
  84. package/src/builtin/erc1155/test-utils.ts +89 -0
  85. package/src/builtin/erc721/index.ts +6 -0
  86. package/src/builtin/erc721/test-utils.ts +71 -0
  87. package/src/builtin/internal/ERC1155.ts +529 -0
  88. package/src/builtin/internal/ERC721.ts +639 -0
  89. package/src/builtin/internal/erc1155_processor.ts +580 -0
  90. package/src/builtin/internal/erc721_processor.ts +768 -0
  91. package/src/builtin/internal/factories/ERC1155__factory.ts +335 -0
  92. package/src/builtin/internal/factories/ERC721__factory.ts +364 -0
  93. package/src/builtin/internal/factories/index.ts +2 -0
  94. package/src/builtin/internal/index.ts +4 -0
  95. package/src/core/account-processor.ts +217 -0
  96. package/src/core/base-processor.ts +6 -2
  97. package/src/core/bind-options.ts +6 -0
  98. package/src/core/context.ts +42 -27
  99. package/src/core/event-tracker.ts +8 -5
  100. package/src/core/meter.ts +9 -3
  101. package/src/gen/chainquery/protos/chainquery.ts +18 -1
  102. package/src/gen/processor/protos/processor.ts +88 -1
  103. package/src/index.ts +1 -1
  104. package/src/service.ts +80 -49
  105. package/src/state/processor-state.ts +1 -6
  106. package/src/state/state-storage.ts +16 -0
  107. package/src/testing/test-processor-server.ts +71 -5
  108. package/src/utils/price.ts +12 -4
package/src/service.ts CHANGED
@@ -33,10 +33,15 @@ import Long from 'long'
33
33
  import { TextDecoder } from 'util'
34
34
  import { Trace } from './core'
35
35
  import { Instruction } from '@project-serum/anchor'
36
- import { MoveResourcesWithVersionPayload } from './aptos/aptos-processor'
37
36
  import { MetricState } from './core/meter'
38
37
  import { ExporterState } from './core/exporter'
39
-
38
+ import { EventTrackerState } from './core/event-tracker'
39
+ import {
40
+ AptosAccountProcessorState,
41
+ AptosProcessorState,
42
+ MoveResourcesWithVersionPayload,
43
+ } from './aptos/aptos-processor'
44
+ import { AccountProcessorState } from './core/account-processor'
40
45
  ;(BigInt.prototype as any).toJSON = function () {
41
46
  return this.toString()
42
47
  }
@@ -109,7 +114,7 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
109
114
  })
110
115
  }
111
116
 
112
- for (const eventTracker of global.PROCESSOR_STATE.eventTrackers) {
117
+ for (const eventTracker of EventTrackerState.INSTANCE.getValues()) {
113
118
  this.eventTrackingConfigs.push({
114
119
  distinctAggregationByDays: eventTracker.options.distinctByDays || [],
115
120
  eventName: eventTracker.name,
@@ -127,7 +132,7 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
127
132
  })
128
133
  }
129
134
 
130
- // Part 1, prepare EVM processors
135
+ // Part 1.a, prepare EVM processors
131
136
  for (const processor of global.PROCESSOR_STATE.processors) {
132
137
  // If server favor incremental update this need to change
133
138
  // Start basic config for contract
@@ -191,6 +196,8 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
191
196
  throw new ServerError(Status.INVALID_ARGUMENT, 'Topic should not be null')
192
197
  }
193
198
  const logFilter: LogFilter = {
199
+ addressType: undefined,
200
+ address: contractConfig.contract?.address,
194
201
  topics: [],
195
202
  }
196
203
 
@@ -212,6 +219,52 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
212
219
  this.contractConfigs.push(contractConfig)
213
220
  }
214
221
 
222
+ // part 1.b prepare EVM account processors
223
+ for (const processor of AccountProcessorState.INSTANCE.getValues()) {
224
+ const accountConfig: AccountConfig = {
225
+ address: processor.config.address,
226
+ chainId: processor.getChainId().toString(),
227
+ startBlock: processor.config.startBlock ? Long.fromValue(processor.config.startBlock) : Long.ZERO,
228
+ aptosIntervalConfigs: [],
229
+ intervalConfigs: [],
230
+ logConfigs: [],
231
+ }
232
+ // TODO add interval
233
+ for (const eventsHandler of processor.eventHandlers) {
234
+ // associate id with filter
235
+ const handlerId = this.eventHandlers.push(eventsHandler.handler) - 1
236
+ const logConfig: LogHandlerConfig = {
237
+ handlerId: handlerId,
238
+ filters: [],
239
+ }
240
+
241
+ for (const filter of eventsHandler.filters) {
242
+ if (!filter.topics) {
243
+ throw new ServerError(Status.INVALID_ARGUMENT, 'Topic should not be null')
244
+ }
245
+ const logFilter: LogFilter = {
246
+ addressType: filter.addressType,
247
+ address: filter.address,
248
+ topics: [],
249
+ }
250
+
251
+ for (const ts of filter.topics) {
252
+ let hashes: string[] = []
253
+ if (Array.isArray(ts)) {
254
+ hashes = hashes.concat(ts)
255
+ } else if (ts) {
256
+ hashes.push(ts)
257
+ }
258
+ logFilter.topics.push({ hashes: hashes })
259
+ }
260
+ logConfig.filters.push(logFilter)
261
+ }
262
+ accountConfig.logConfigs.push(logConfig)
263
+ }
264
+
265
+ this.accountConfigs.push(accountConfig)
266
+ }
267
+
215
268
  // Part 2, prepare solana constractors
216
269
  for (const solanaProcessor of global.PROCESSOR_STATE.solanaProcessors) {
217
270
  const contractConfig: ContractConfig = {
@@ -263,7 +316,7 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
263
316
  }
264
317
 
265
318
  // Part 4, prepare aptos constractors
266
- for (const aptosProcessor of global.PROCESSOR_STATE.aptosProcessors) {
319
+ for (const aptosProcessor of AptosProcessorState.INSTANCE.getValues()) {
267
320
  const contractConfig: ContractConfig = {
268
321
  processorType: USER_PROCESSOR,
269
322
  contract: {
@@ -316,13 +369,14 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
316
369
  this.contractConfigs.push(contractConfig)
317
370
  }
318
371
 
319
- for (const aptosProcessor of global.PROCESSOR_STATE.aptosAccountProcessors) {
372
+ for (const aptosProcessor of AptosAccountProcessorState.INSTANCE.getValues()) {
320
373
  const accountConfig: AccountConfig = {
321
374
  address: aptosProcessor.config.address,
322
375
  chainId: aptosProcessor.getChainId(),
323
376
  startBlock: Long.fromValue(aptosProcessor.config.startVersion.toString()),
324
377
  aptosIntervalConfigs: [],
325
378
  intervalConfigs: [],
379
+ logConfigs: [],
326
380
  }
327
381
  for (const handler of aptosProcessor.resourcesHandlers) {
328
382
  const handlerId = this.aptosResourceHandlers.push(handler.handler) - 1
@@ -414,6 +468,8 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
414
468
  return this.processAptosEvent(request)
415
469
  case HandlerType.APT_RESOURCE:
416
470
  return this.processAptosResource(request)
471
+ case HandlerType.ETH_LOG:
472
+ return this.processLog(request)
417
473
  default:
418
474
  throw new ServerError(Status.INVALID_ARGUMENT, 'No handle type registered ' + request.handlerType)
419
475
  }
@@ -426,24 +482,7 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
426
482
 
427
483
  const promises: Promise<ProcessResult>[] = []
428
484
  for (const l of request.bindings) {
429
- if (!l.data) {
430
- throw new ServerError(Status.INVALID_ARGUMENT, "Log can't be null")
431
- }
432
- // const jsonString = Buffer.from(l.log.raw.buffer).toString("utf-8")
433
- // const jsonString = String.fromCharCode.apply(null, l.log.raw)
434
-
435
- try {
436
- const jsonString = Utf8ArrayToStr(l.data.raw)
437
- const log: Log = JSON.parse(jsonString)
438
- const handler = this.eventHandlers[l.handlerId]
439
- const promise = handler(log).catch((e) => {
440
- throw new ServerError(Status.INTERNAL, 'error processing log: ' + jsonString + '\n' + errorString(e))
441
- })
442
-
443
- promises.push(promise)
444
- } catch (e) {
445
- throw new ServerError(Status.INTERNAL, 'error parse log: ' + l)
446
- }
485
+ promises.push(this.processLog(l))
447
486
  }
448
487
 
449
488
  const result = mergeProcessResults(await Promise.all(promises))
@@ -464,6 +503,23 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
464
503
  }
465
504
  }
466
505
 
506
+ async processLog(l: DataBinding): Promise<ProcessResult> {
507
+ if (!l.data) {
508
+ throw new ServerError(Status.INVALID_ARGUMENT, "Log can't be null")
509
+ }
510
+
511
+ try {
512
+ const jsonString = Utf8ArrayToStr(l.data.raw)
513
+ const log: Log = JSON.parse(jsonString)
514
+ const handler = this.eventHandlers[l.handlerId]
515
+ return handler(log).catch((e) => {
516
+ throw new ServerError(Status.INTERNAL, 'error processing log: ' + jsonString + '\n' + errorString(e))
517
+ })
518
+ } catch (e) {
519
+ throw new ServerError(Status.INTERNAL, 'error parse log: ' + l)
520
+ }
521
+ }
522
+
467
523
  async processTransactions(
468
524
  request: ProcessTransactionsRequest,
469
525
  context: CallContext
@@ -497,31 +553,6 @@ export class ProcessorServiceImpl implements ProcessorServiceImplementation {
497
553
  await Promise.all(processorPromises)
498
554
  }
499
555
 
500
- // if (request.chainId.toLowerCase().startsWith('apt') && global.PROCESSOR_STATE.aptosProcessors) {
501
- // const processorPromises: Promise<void>[] = []
502
- // for (const txn of request.transactions) {
503
- // processorPromises.push(
504
- // new Promise((resolve, _) => {
505
- // for (const processor of global.PROCESSOR_STATE.aptosProcessors) {
506
- // if (processor.address === txn.programAccountId!) {
507
- // const res = processor.handleTransaction(
508
- // JSON.parse(new TextDecoder().decode(txn.raw)),
509
- // txn.slot ?? Long.fromNumber(0)
510
- // )
511
- // if (res) {
512
- // res.gauges.forEach((g) => result.gauges.push(g))
513
- // res.counters.forEach((c) => result.counters.push(c))
514
- // res.logs.forEach((l) => result.logs.push(l))
515
- // }
516
- // }
517
- // }
518
- // resolve()
519
- // })
520
- // )
521
- // }
522
- // await Promise.all(processorPromises)
523
- // }
524
-
525
556
  recordRuntimeInfo(result, HandlerType.TRANSACTION)
526
557
  return {
527
558
  result,
@@ -5,12 +5,10 @@ import {
5
5
  BaseProcessorTemplate,
6
6
  SolanaBaseProcessor,
7
7
  SuiBaseProcessor,
8
- EventTracker,
9
8
  } from '../core'
10
9
 
11
10
  import { BaseContract } from 'ethers'
12
11
  import { TemplateInstance } from '../gen'
13
- import { AptosBaseProcessor, AptosAccountProcessor } from '../aptos/aptos-processor'
14
12
 
15
13
  export class ProcessorState {
16
14
  // from abiName_address_chainId => contract wrapper
@@ -28,10 +26,7 @@ export class ProcessorState {
28
26
 
29
27
  suiProcessors: SuiBaseProcessor[] = []
30
28
 
31
- aptosProcessors: AptosBaseProcessor[] = []
32
- aptosAccountProcessors: AptosAccountProcessor[] = []
33
-
34
- eventTrackers: EventTracker[] = []
29
+ // TODO move above to state map
35
30
 
36
31
  stateMap = new Map<string, any>()
37
32
  }
@@ -47,3 +47,19 @@ export abstract class MapStateStorage<T> extends StateStorage<Map<string, T>> {
47
47
  return value
48
48
  }
49
49
  }
50
+
51
+ export abstract class ListStateStorage<T> extends StateStorage<T[]> {
52
+ initValue() {
53
+ return []
54
+ }
55
+
56
+ getValues(): T[] {
57
+ return this.getOrRegister()
58
+ }
59
+
60
+ addValue(value: T): T {
61
+ const m = this.getOrRegister()
62
+ m.push(value)
63
+ return value
64
+ }
65
+ }
@@ -1,4 +1,5 @@
1
1
  import {
2
+ AccountConfig,
2
3
  BlockBinding,
3
4
  ContractConfig,
4
5
  DataBinding,
@@ -25,6 +26,7 @@ import { ProcessorState } from '../state/processor-state'
25
26
  import { ProcessorServiceImpl } from '../service'
26
27
  import { Trace } from '../core/trace'
27
28
  import { setProvider } from '../provider'
29
+ import { account } from '../builtin/aptos/0x1'
28
30
 
29
31
  export const TEST_CONTEXT: CallContext = <CallContext>{}
30
32
 
@@ -37,7 +39,8 @@ export function cleanTest() {
37
39
 
38
40
  export class TestProcessorServer implements ProcessorServiceImplementation {
39
41
  service: ProcessorServiceImpl
40
- contractConfig: ContractConfig[]
42
+ contractConfigs: ContractConfig[]
43
+ accountConfigs: AccountConfig[]
41
44
 
42
45
  constructor(loader: () => void, httpEndpoints: Record<string, string> = {}) {
43
46
  cleanTest()
@@ -58,7 +61,9 @@ export class TestProcessorServer implements ProcessorServiceImplementation {
58
61
 
59
62
  async start(request: StartRequest = { templateInstances: [] }, context = TEST_CONTEXT): Promise<Empty> {
60
63
  const res = await this.service.start(request, context)
61
- this.contractConfig = (await this.getConfig({})).contractConfigs
64
+ const config = await this.getConfig({})
65
+ this.contractConfigs = config.contractConfigs
66
+ this.accountConfigs = config.accountConfigs
62
67
  return res
63
68
  }
64
69
 
@@ -114,7 +119,7 @@ export class TestProcessorServer implements ProcessorServiceImplementation {
114
119
  }
115
120
  const signature = trace.action.input.slice(0, 10)
116
121
 
117
- for (const contract of this.contractConfig) {
122
+ for (const contract of this.contractConfigs) {
118
123
  if (contract.contract?.chainId !== getNetwork(network).chainId.toString()) {
119
124
  continue
120
125
  }
@@ -155,7 +160,7 @@ export class TestProcessorServer implements ProcessorServiceImplementation {
155
160
  }
156
161
 
157
162
  buildLogBinding(log: Log, network: Networkish = 1): DataBinding | undefined {
158
- for (const contract of this.contractConfig) {
163
+ for (const contract of this.contractConfigs) {
159
164
  if (contract.contract?.chainId !== getNetwork(network).chainId.toString()) {
160
165
  continue
161
166
  }
@@ -197,6 +202,67 @@ export class TestProcessorServer implements ProcessorServiceImplementation {
197
202
  }
198
203
  return undefined
199
204
  }
205
+ testAccountLog(address: string, log: Log, network: Networkish = 1): Promise<ProcessBindingResponse> {
206
+ return this.testAccountLogs(address, [log], network)
207
+ }
208
+
209
+ testAccountLogs(address: string, logs: Log[], network: Networkish = 1): Promise<ProcessBindingResponse> {
210
+ const bindings = []
211
+ for (const log of logs) {
212
+ const binding = this.buildAccountLogBinding(address, log, network)
213
+ if (!binding) {
214
+ throw Error('Invalid test log: ' + JSON.stringify(log))
215
+ }
216
+ bindings.push(binding)
217
+ }
218
+ return this.processLogs({
219
+ bindings: bindings,
220
+ })
221
+ }
222
+
223
+ buildAccountLogBinding(address: string, log: Log, network: Networkish = 1): DataBinding | undefined {
224
+ for (const account of this.accountConfigs) {
225
+ if (account.chainId !== getNetwork(network).chainId.toString()) {
226
+ continue
227
+ }
228
+ if (address.toLowerCase() !== account.address.toLowerCase()) {
229
+ continue
230
+ }
231
+ for (const config of account.logConfigs) {
232
+ for (const filter of config.filters) {
233
+ // if (filter.topics.length != log.topics.length) {
234
+ // continue
235
+ // }
236
+
237
+ let match = true
238
+ for (const topicIdx in filter.topics) {
239
+ const logTopic = log.topics[topicIdx]
240
+ const possibleTopic = filter.topics[topicIdx].hashes
241
+ if (possibleTopic.length === 0) {
242
+ // match all
243
+ continue
244
+ }
245
+ if (possibleTopic.find((e) => e.toLowerCase() === logTopic.toLowerCase())) {
246
+ // find one
247
+ continue
248
+ }
249
+ match = false
250
+ break
251
+ }
252
+ if (match) {
253
+ return {
254
+ data: {
255
+ raw: toBytes(log),
256
+ },
257
+ handlerId: config.handlerId,
258
+ handlerType: HandlerType.ETH_LOG,
259
+ }
260
+ }
261
+ }
262
+ }
263
+ }
264
+ return undefined
265
+ }
200
266
 
201
267
  testBlock(block: Partial<Block> & { number: number }, network: Networkish = 1): Promise<ProcessBindingResponse> {
202
268
  return this.testBlocks([block], network)
@@ -223,7 +289,7 @@ export class TestProcessorServer implements ProcessorServiceImplementation {
223
289
  },
224
290
  handlerIds: [],
225
291
  }
226
- for (const contract of this.contractConfig) {
292
+ for (const contract of this.contractConfigs) {
227
293
  if (contract.contract?.chainId !== getNetwork(network).chainId.toString()) {
228
294
  continue
229
295
  }
@@ -25,7 +25,7 @@ export async function getPriceByType(chainId: string, coinType: string, date: Da
25
25
  priceClient = getPriceClient()
26
26
  }
27
27
 
28
- const dateStr = [date.getUTCDate(), date.getUTCMonth() + 1, date.getUTCFullYear()].join('-')
28
+ const dateStr = dateString(date)
29
29
  const key = `${coinType}-${dateStr}`
30
30
  let price = priceMap.get(key)
31
31
  if (price) {
@@ -48,7 +48,9 @@ export async function getPriceByType(chainId: string, coinType: string, date: Da
48
48
  }
49
49
  )
50
50
  price = response.price
51
- priceMap.set(key, price)
51
+ if (response.timestamp && dateString(response.timestamp) === dateStr) {
52
+ priceMap.set(key, price)
53
+ }
52
54
  return price
53
55
  }
54
56
 
@@ -62,7 +64,7 @@ export async function getPriceBySymbol(symbol: string, date: Date): Promise<numb
62
64
  priceClient = getPriceClient()
63
65
  }
64
66
 
65
- const dateStr = [date.getUTCDate(), date.getUTCMonth() + 1, date.getUTCFullYear()].join('-')
67
+ const dateStr = dateString(date)
66
68
  const key = `${symbol}-${dateStr}`
67
69
  let price = priceMap.get(key)
68
70
  if (price) {
@@ -82,6 +84,12 @@ export async function getPriceBySymbol(symbol: string, date: Date): Promise<numb
82
84
  }
83
85
  )
84
86
  price = response.price
85
- priceMap.set(key, price)
87
+ if (response.timestamp && dateString(response.timestamp) === dateStr) {
88
+ priceMap.set(key, price)
89
+ }
86
90
  return price
87
91
  }
92
+
93
+ function dateString(date: Date) {
94
+ return [date.getUTCDate(), date.getUTCMonth() + 1, date.getUTCFullYear()].join('-')
95
+ }