Skip to content

Commit ba4d205

Browse files
committed
Implement max caching in ramp plugins
1 parent ff48745 commit ba4d205

File tree

6 files changed

+232
-51
lines changed

6 files changed

+232
-51
lines changed

src/plugins/ramps/banxa/banxaRampPlugin.ts

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,20 @@ const pluginDisplayName = 'Banxa'
7373

7474
const TESTNET_ADDRESS = 'bc1qv752cnr3rcht3yyfq2nn6nv7zwczqjmcm80y6w'
7575

76+
// Cache for max amounts with 2 minute TTL
77+
const maxAmountCache = new Map<string, { amount: string; timestamp: number }>()
78+
const MAX_CACHE_TTL = 2 * 60 * 1000 // 2 minutes
79+
80+
const getCacheKey = (
81+
direction: FiatDirection,
82+
fiatCode: string,
83+
banxaCoin: string,
84+
paymentType: FiatPaymentType,
85+
amountType: 'fiat' | 'crypto'
86+
): string => {
87+
return `${direction}-${fiatCode}-${banxaCoin}-${paymentType}-${amountType}`
88+
}
89+
7690
type AllowedPaymentTypes = Record<
7791
FiatDirection,
7892
Partial<Record<FiatPaymentType, boolean>>
@@ -996,31 +1010,50 @@ export const banxaRampPlugin: RampPluginFactory = (
9961010

9971011
let maxAmountString = ''
9981012
if (isMaxAmount) {
999-
if (amountType === 'fiat') {
1000-
maxAmountString = paymentObj.max
1013+
const cacheKey = getCacheKey(
1014+
direction,
1015+
fiatCode,
1016+
banxaCoin,
1017+
paymentType,
1018+
amountType
1019+
)
1020+
const cached = maxAmountCache.get(cacheKey)
1021+
const now = Date.now()
1022+
1023+
if (cached != null && now - cached.timestamp < MAX_CACHE_TTL) {
1024+
maxAmountString = cached.amount
10011025
} else {
1002-
// For crypto, we need to fetch a quote with max fiat to get the crypto amount
1003-
const maxFiatQueryParams: any = {
1004-
account_reference: username,
1005-
payment_method_id: paymentObj.id,
1006-
source: direction === 'buy' ? fiatCode : banxaCoin,
1007-
target: direction === 'buy' ? banxaCoin : fiatCode
1008-
}
1009-
if (direction === 'buy') {
1010-
maxFiatQueryParams.source_amount = paymentObj.max
1026+
if (amountType === 'fiat') {
1027+
maxAmountString = paymentObj.max
10111028
} else {
1012-
maxFiatQueryParams.target_amount = paymentObj.max
1029+
// For crypto, we need to fetch a quote with max fiat to get the crypto amount
1030+
const maxFiatQueryParams: any = {
1031+
account_reference: username,
1032+
payment_method_id: paymentObj.id,
1033+
source: direction === 'buy' ? fiatCode : banxaCoin,
1034+
target: direction === 'buy' ? banxaCoin : fiatCode
1035+
}
1036+
if (direction === 'buy') {
1037+
maxFiatQueryParams.source_amount = paymentObj.max
1038+
} else {
1039+
maxFiatQueryParams.target_amount = paymentObj.max
1040+
}
1041+
const maxResponse = await banxaFetch({
1042+
method: 'GET',
1043+
url: apiUrl,
1044+
hmacUser,
1045+
path: 'api/prices',
1046+
apiKey,
1047+
queryParams: maxFiatQueryParams
1048+
})
1049+
const maxPrices = asBanxaPricesResponse(maxResponse)
1050+
maxAmountString = maxPrices.data.prices[0].coin_amount
10131051
}
1014-
const maxResponse = await banxaFetch({
1015-
method: 'GET',
1016-
url: apiUrl,
1017-
hmacUser,
1018-
path: 'api/prices',
1019-
apiKey,
1020-
queryParams: maxFiatQueryParams
1052+
// Cache the result
1053+
maxAmountCache.set(cacheKey, {
1054+
amount: maxAmountString,
1055+
timestamp: now
10211056
})
1022-
const maxPrices = asBanxaPricesResponse(maxResponse)
1023-
maxAmountString = maxPrices.data.prices[0].coin_amount
10241057
}
10251058
}
10261059

src/plugins/ramps/bity/bityRampPlugin.ts

Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,19 @@ const partnerFee = 0.005
6767
// Default Edge client ID for backward compatibility
6868
const EDGE_CLIENT_ID = '4949bf59-c23c-4d71-949e-f5fd56ff815b'
6969

70+
// Cache for max amounts with 2 minute TTL
71+
const maxAmountCache = new Map<string, { amount: string; timestamp: number }>()
72+
const MAX_CACHE_TTL = 2 * 60 * 1000 // 2 minutes
73+
74+
const getCacheKey = (
75+
direction: FiatDirection,
76+
fiatCode: string,
77+
cryptoCode: string,
78+
amountType: 'fiat' | 'crypto'
79+
): string => {
80+
return `${direction}-${fiatCode}-${cryptoCode}-${amountType}`
81+
}
82+
7083
const noKycCurrencyCodes: Record<FiatDirection, FiatProviderAssetMap> = {
7184
buy: {
7285
providerId: pluginId,
@@ -785,32 +798,50 @@ export const bityRampPlugin = (pluginConfig: RampPluginConfig): RampPlugin => {
785798

786799
let amount = ''
787800
if (isMaxAmount) {
788-
// Use 1000 as max fiat (their no-KYC limit)
789-
if (amountType === 'fiat') {
790-
amount = '1000'
801+
const cacheKey = getCacheKey(
802+
direction,
803+
fiatCode,
804+
cryptoCode,
805+
amountType
806+
)
807+
const cached = maxAmountCache.get(cacheKey)
808+
const now = Date.now()
809+
810+
if (cached != null && now - cached.timestamp < MAX_CACHE_TTL) {
811+
amount = cached.amount
791812
} else {
792-
// For crypto, fetch a quote with 1000 fiat to get crypto amount
793-
const maxFiatRequest: BityQuoteRequest = {
794-
input: {
795-
amount: isBuy ? '1000' : undefined,
796-
currency: isBuy ? fiatCode : cryptoCode
797-
},
798-
output: {
799-
amount: isBuy ? undefined : '1000',
800-
currency: isBuy ? cryptoCode : fiatCode
813+
// Use 1000 as max fiat (their no-KYC limit)
814+
if (amountType === 'fiat') {
815+
amount = '1000'
816+
} else {
817+
// For crypto, fetch a quote with 1000 fiat to get crypto amount
818+
const maxFiatRequest: BityQuoteRequest = {
819+
input: {
820+
amount: isBuy ? '1000' : undefined,
821+
currency: isBuy ? fiatCode : cryptoCode
822+
},
823+
output: {
824+
amount: isBuy ? undefined : '1000',
825+
currency: isBuy ? cryptoCode : fiatCode
826+
}
827+
}
828+
try {
829+
const maxRaw = await fetchBityQuote(maxFiatRequest, apiUrl)
830+
const maxQuote = asBityQuote(maxRaw)
831+
amount = isBuy ? maxQuote.output.amount : maxQuote.input.amount
832+
} catch (error) {
833+
console.error(
834+
'Bity fetchQuote error: Failed to fetch max quote',
835+
error
836+
)
837+
return []
801838
}
802839
}
803-
try {
804-
const maxRaw = await fetchBityQuote(maxFiatRequest, apiUrl)
805-
const maxQuote = asBityQuote(maxRaw)
806-
amount = isBuy ? maxQuote.output.amount : maxQuote.input.amount
807-
} catch (error) {
808-
console.error(
809-
'Bity fetchQuote error: Failed to fetch max quote',
810-
error
811-
)
812-
return []
813-
}
840+
// Cache the result
841+
maxAmountCache.set(cacheKey, {
842+
amount,
843+
timestamp: now
844+
})
814845
}
815846
} else {
816847
amount = toFixed(exchangeAmountString, amountPrecision)

src/plugins/ramps/moonpay/moonpayRampPlugin.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,19 @@ const partnerIcon = `${EDGE_CONTENT_SERVER_URI}/moonpay_symbol_prp.png`
7878
const pluginDisplayName = 'Moonpay'
7979
const supportEmail = '[email protected]'
8080

81+
// Cache for max amounts with 2 minute TTL
82+
const maxAmountCache = new Map<string, { amount: string; timestamp: number }>()
83+
const MAX_CACHE_TTL = 2 * 60 * 1000 // 2 minutes
84+
85+
const getCacheKey = (
86+
direction: FiatDirection,
87+
fiatCode: string,
88+
cryptoCode: string,
89+
amountType: 'fiat' | 'crypto'
90+
): string => {
91+
return `${direction}-${fiatCode}-${cryptoCode}-${amountType}`
92+
}
93+
8194
// Local asset map type
8295
interface AssetMap {
8396
providerId: string
@@ -634,8 +647,26 @@ export const moonpayRampPlugin: RampPluginFactory = (
634647

635648
let exchangeAmount: number
636649
if (isMaxAmount) {
637-
// Use the max amounts based on amountType
638-
exchangeAmount = request.amountType === 'fiat' ? maxFiat : maxCrypto
650+
const cacheKey = getCacheKey(
651+
direction,
652+
removeIsoPrefix(fiatCurrencyCode),
653+
cryptoCurrencyObj.code,
654+
request.amountType
655+
)
656+
const cached = maxAmountCache.get(cacheKey)
657+
const now = Date.now()
658+
659+
if (cached != null && now - cached.timestamp < MAX_CACHE_TTL) {
660+
exchangeAmount = parseFloat(cached.amount)
661+
} else {
662+
// Use the max amounts based on amountType
663+
exchangeAmount = request.amountType === 'fiat' ? maxFiat : maxCrypto
664+
// Cache the result
665+
maxAmountCache.set(cacheKey, {
666+
amount: exchangeAmount.toString(),
667+
timestamp: now
668+
})
669+
}
639670
} else {
640671
exchangeAmount = parseFloat(exchangeAmountString)
641672
}

src/plugins/ramps/paybis/paybisRampPlugin.ts

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,20 @@ import { asInitOptions } from './paybisRampTypes'
8383
const pluginId = 'paybis'
8484
const partnerIcon = `${EDGE_CONTENT_SERVER_URI}/paybis.png`
8585
const pluginDisplayName = 'Paybis'
86+
87+
// Cache for max amounts with 2 minute TTL
88+
const maxAmountCache = new Map<string, { amount: string; timestamp: number }>()
89+
const MAX_CACHE_TTL = 2 * 60 * 1000 // 2 minutes
90+
91+
const getCacheKey = (
92+
direction: FiatDirection,
93+
fiatCode: string,
94+
cryptoCode: string,
95+
amountType: 'fiat' | 'crypto',
96+
paymentMethod: string
97+
): string => {
98+
return `${direction}-${fiatCode}-${cryptoCode}-${amountType}-${paymentMethod}`
99+
}
86100
const providerDisplayName = pluginDisplayName
87101
const supportEmail = '[email protected]'
88102

@@ -813,8 +827,27 @@ export const paybisRampPlugin: RampPluginFactory = (
813827
let amount
814828

815829
if (isMaxAmount) {
816-
// Use default max amounts
817-
amount = amountType === 'fiat' ? '10000' : '10'
830+
const cacheKey = getCacheKey(
831+
direction,
832+
fiat,
833+
paybisCc,
834+
amountType,
835+
paymentMethod
836+
)
837+
const cached = maxAmountCache.get(cacheKey)
838+
const now = Date.now()
839+
840+
if (cached != null && now - cached.timestamp < MAX_CACHE_TTL) {
841+
amount = cached.amount
842+
} else {
843+
// Use default max amounts
844+
amount = amountType === 'fiat' ? '10000' : '10'
845+
// Cache the result
846+
maxAmountCache.set(cacheKey, {
847+
amount,
848+
timestamp: now
849+
})
850+
}
818851
} else {
819852
amount = exchangeAmountString
820853
}

src/plugins/ramps/revolut/revolutRampPlugin.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,14 @@ interface ProviderConfigCache {
4747

4848
const CACHE_TTL_MS = 60 * 60 * 1000 // 1 hour
4949

50+
// Cache for max amounts with 2 minute TTL
51+
const maxAmountCache = new Map<string, { amount: string; timestamp: number }>()
52+
const MAX_CACHE_TTL = 2 * 60 * 1000 // 2 minutes
53+
54+
const getCacheKey = (fiatCode: string, cryptoCode: string): string => {
55+
return `buy-${fiatCode}-${cryptoCode}-fiat` // Revolut only supports buy with fiat amount
56+
}
57+
5058
export const revolutRampPlugin: RampPluginFactory = (
5159
config: RampPluginConfig
5260
) => {
@@ -254,7 +262,20 @@ export const revolutRampPlugin: RampPluginFactory = (
254262
// Handle max amount
255263
let amount: string
256264
if (isMaxAmount) {
257-
amount = revolutFiat.max_limit.toString()
265+
const cacheKey = getCacheKey(revolutFiat.currency, revolutCrypto.id)
266+
const cached = maxAmountCache.get(cacheKey)
267+
const now = Date.now()
268+
269+
if (cached != null && now - cached.timestamp < MAX_CACHE_TTL) {
270+
amount = cached.amount
271+
} else {
272+
amount = revolutFiat.max_limit.toString()
273+
// Cache the result
274+
maxAmountCache.set(cacheKey, {
275+
amount,
276+
timestamp: now
277+
})
278+
}
258279
} else {
259280
amount = exchangeAmountString
260281
// Check if amount is within limits

src/plugins/ramps/simplex/simplexRampPlugin.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { EDGE_CONTENT_SERVER_URI } from '../../../constants/CdnConstants'
88
import { lstrings } from '../../../locales/strings'
99
import { CryptoAmount } from '../../../util/CryptoAmount'
1010
import { fetchInfo } from '../../../util/network'
11+
import type { FiatDirection } from '../../gui/fiatPluginTypes'
1112
import { FiatProviderError } from '../../gui/fiatProviderTypes'
1213
import { addExactRegion, validateExactRegion } from '../../gui/providers/common'
1314
import { addTokenToArray } from '../../gui/util/providerUtils'
@@ -46,6 +47,19 @@ const NOT_SUCCESS_TOAST_HIDE_MS = 3000
4647
// 24 hour TTL for provider config cache
4748
const PROVIDER_CONFIG_TTL_MS = 24 * 60 * 60 * 1000
4849

50+
// Cache for max amounts with 2 minute TTL
51+
const maxAmountCache = new Map<string, { amount: string; timestamp: number }>()
52+
const MAX_CACHE_TTL = 2 * 60 * 1000 // 2 minutes
53+
54+
const getCacheKey = (
55+
direction: FiatDirection,
56+
fiatCode: string,
57+
cryptoCode: string,
58+
amountType: 'fiat' | 'crypto'
59+
): string => {
60+
return `${direction}-${fiatCode}-${cryptoCode}-${amountType}`
61+
}
62+
4963
// https://integrations.simplex.com/docs/supported_currencies
5064
const SIMPLEX_ID_MAP: Record<string, Record<string, string>> = {
5165
algorand: { ALGO: 'ALGO' },
@@ -634,8 +648,26 @@ export const simplexRampPlugin: RampPluginFactory = (
634648
let soam: number
635649

636650
if (isMaxAmount) {
637-
// Use reasonable max amounts
638-
soam = amountType === 'fiat' ? 50000 : 100
651+
const cacheKey = getCacheKey(
652+
direction,
653+
simplexFiatCode,
654+
simplexCryptoCode,
655+
amountType
656+
)
657+
const cached = maxAmountCache.get(cacheKey)
658+
const now = Date.now()
659+
660+
if (cached != null && now - cached.timestamp < MAX_CACHE_TTL) {
661+
soam = parseFloat(cached.amount)
662+
} else {
663+
// Use reasonable max amounts
664+
soam = amountType === 'fiat' ? 50000 : 100
665+
// Cache the result
666+
maxAmountCache.set(cacheKey, {
667+
amount: soam.toString(),
668+
timestamp: now
669+
})
670+
}
639671
} else {
640672
soam = parseFloat(exchangeAmountString)
641673
}

0 commit comments

Comments
 (0)