@@ -40,12 +40,17 @@ export async function loadPricingProviderAsync<Config extends PricingProviderCon
40
40
) as unknown as PricingProvider < Config > ;
41
41
}
42
42
43
+ interface CachedPriceData {
44
+ price : number ;
45
+ timestamp : number ;
46
+ }
47
+
43
48
44
49
export abstract class PricingProvider < Config extends PricingProviderConfig > {
45
50
readonly abstract pricingProviderType : string ;
46
51
47
- protected lastPriceUpdateTimestamp : number = 0 ;
48
- protected cachedCoinPrice : number = 0 ;
52
+ protected cachedGasPrice : CachedPriceData | undefined ;
53
+ protected cachedTokenPrices : Record < string , CachedPriceData > = { } ;
49
54
50
55
constructor (
51
56
protected readonly config : Config ,
@@ -72,26 +77,38 @@ export abstract class PricingProvider<Config extends PricingProviderConfig> {
72
77
// Pricing functions
73
78
// ********************************************************************************************
74
79
75
- abstract queryCoinPrice ( ) : Promise < number > ;
80
+ abstract queryCoinPrice ( tokenId ?: string ) : Promise < number > ;
76
81
77
- async getPrice ( amount : bigint ) : Promise < number > {
78
- const cacheValidUntilTimestamp = this . lastPriceUpdateTimestamp + this . config . cacheDuration ;
79
- const isCacheValid = Date . now ( ) < cacheValidUntilTimestamp ;
80
- if ( ! isCacheValid ) {
81
- await this . updateCoinPrice ( ) ;
82
- }
82
+ async getPrice ( amount : bigint , tokenId ?: string ) : Promise < number > {
83
+ const cachedPriceData = tokenId == undefined
84
+ ? this . cachedGasPrice
85
+ : this . cachedTokenPrices [ tokenId ] ;
86
+
87
+ const cacheValidUntilTimestamp = cachedPriceData != undefined
88
+ ? cachedPriceData . timestamp + this . config . cacheDuration
89
+ : null ;
90
+
91
+ const isCacheValid = cacheValidUntilTimestamp != null && Date . now ( ) < cacheValidUntilTimestamp ;
83
92
84
- return this . cachedCoinPrice * Number ( amount ) / 10 ** this . config . coinDecimals ;
93
+ const latestPriceData = isCacheValid
94
+ ? cachedPriceData !
95
+ : await this . updateCoinPrice ( tokenId ) ;
96
+
97
+ return latestPriceData . price * Number ( amount ) / 10 ** this . config . coinDecimals ;
85
98
}
86
99
87
- private async updateCoinPrice ( ) : Promise < number > {
100
+ private async updateCoinPrice ( tokenId ?: string ) : Promise < CachedPriceData > {
101
+
102
+ const cachedPriceData = tokenId == undefined
103
+ ? this . cachedGasPrice
104
+ : this . cachedTokenPrices [ tokenId ] ;
88
105
89
106
let latestPrice : number | undefined ;
90
107
91
108
let tryCount = 0 ;
92
109
while ( latestPrice == undefined ) {
93
110
try {
94
- latestPrice = await this . queryCoinPrice ( ) ;
111
+ latestPrice = await this . queryCoinPrice ( tokenId ) ;
95
112
}
96
113
catch ( error ) {
97
114
this . logger . warn (
@@ -104,33 +121,46 @@ export abstract class PricingProvider<Config extends PricingProviderConfig> {
104
121
105
122
// Skip update and continue with 'stale' pricing info if 'maxTries' is reached, unless
106
123
// the price has never been successfully queried from the provider.
107
- if ( tryCount >= this . config . maxTries && this . lastPriceUpdateTimestamp != 0 ) {
124
+ if ( tryCount >= this . config . maxTries && cachedPriceData != undefined ) {
108
125
this . logger . warn (
109
126
{
110
127
try : tryCount ,
111
128
maxTries : this . config . maxTries ,
112
- price : this . cachedCoinPrice ,
129
+ price : cachedPriceData . price ,
130
+ pricingDenomination : this . config . pricingDenomination ,
131
+ lastUpdate : cachedPriceData . timestamp ,
132
+ tokenId,
113
133
} ,
114
- `Failed to query coin price. Max tries reached. Continuing with stale data.`
134
+ `Failed to query token price. Max tries reached. Continuing with stale data.`
115
135
) ;
116
- return this . cachedCoinPrice ;
136
+ return cachedPriceData ;
117
137
}
118
138
119
139
await wait ( this . config . retryInterval ) ;
120
140
}
121
141
}
122
142
123
- this . lastPriceUpdateTimestamp = Date . now ( ) ;
124
- this . cachedCoinPrice = latestPrice ;
143
+ const latestPriceData : CachedPriceData = {
144
+ price : latestPrice ,
145
+ timestamp : Date . now ( ) ,
146
+ } ;
147
+
148
+ if ( tokenId == undefined ) {
149
+ this . cachedGasPrice = latestPriceData ;
150
+ }
151
+ else {
152
+ this . cachedTokenPrices [ tokenId ] = latestPriceData ;
153
+ }
125
154
126
155
this . logger . info (
127
156
{
128
157
price : latestPrice ,
129
- pricingDenomination : this . config . pricingDenomination
158
+ pricingDenomination : this . config . pricingDenomination ,
159
+ tokenId,
130
160
} ,
131
- 'Coin price updated.'
161
+ 'Token price updated.'
132
162
)
133
- return latestPrice ;
163
+ return latestPriceData ;
134
164
}
135
165
136
166
}
0 commit comments