@provex/utils 1.0.16

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 (75) hide show
  1. package/README.md +287 -0
  2. package/dist/scripts/convert-svg.d.ts +1 -0
  3. package/dist/scripts/convert-svg.js +17 -0
  4. package/dist/src/chain.d.ts +14 -0
  5. package/dist/src/chain.js +18 -0
  6. package/dist/src/contracts.d.ts +30 -0
  7. package/dist/src/contracts.js +64 -0
  8. package/dist/src/conversionRates.d.ts +124 -0
  9. package/dist/src/conversionRates.js +219 -0
  10. package/dist/src/currencies.d.ts +144 -0
  11. package/dist/src/currencies.js +234 -0
  12. package/dist/src/data/countries.json +1099 -0
  13. package/dist/src/deposit.d.ts +1 -0
  14. package/dist/src/deposit.js +1 -0
  15. package/dist/src/events.d.ts +3 -0
  16. package/dist/src/events.js +16 -0
  17. package/dist/src/flags.d.ts +2 -0
  18. package/dist/src/flags.js +3 -0
  19. package/dist/src/ids.d.ts +72 -0
  20. package/dist/src/ids.js +81 -0
  21. package/dist/src/index.d.ts +16 -0
  22. package/dist/src/index.js +16 -0
  23. package/dist/src/input.d.ts +7 -0
  24. package/dist/src/input.js +35 -0
  25. package/dist/src/intent.d.ts +14 -0
  26. package/dist/src/intent.js +1 -0
  27. package/dist/src/json.d.ts +18 -0
  28. package/dist/src/json.js +44 -0
  29. package/dist/src/participants.d.ts +7 -0
  30. package/dist/src/participants.js +13 -0
  31. package/dist/src/payment.d.ts +164 -0
  32. package/dist/src/payment.js +439 -0
  33. package/dist/src/profit.d.ts +28 -0
  34. package/dist/src/profit.js +34 -0
  35. package/dist/src/sort.d.ts +36 -0
  36. package/dist/src/sort.js +39 -0
  37. package/dist/src/stats.d.ts +7 -0
  38. package/dist/src/stats.js +8 -0
  39. package/dist/src/time.d.ts +54 -0
  40. package/dist/src/time.js +106 -0
  41. package/dist/src/tokens.d.ts +3675 -0
  42. package/dist/src/tokens.js +134 -0
  43. package/dist/src/units.d.ts +17 -0
  44. package/dist/src/units.js +79 -0
  45. package/dist/src/zkp2p-types.d.ts +48 -0
  46. package/dist/src/zkp2p-types.js +1 -0
  47. package/dist/tsconfig.tsbuildinfo +1 -0
  48. package/package.json +45 -0
  49. package/scripts/convert-svg.ts +22 -0
  50. package/src/chain.ts +27 -0
  51. package/src/contracts.ts +89 -0
  52. package/src/conversionRates.ts +356 -0
  53. package/src/currencies.ts +286 -0
  54. package/src/data/countries.json +1099 -0
  55. package/src/deposit.ts +2 -0
  56. package/src/events.ts +21 -0
  57. package/src/flags/eur.svg +4 -0
  58. package/src/flags/usd.svg +25 -0
  59. package/src/flags.ts +4 -0
  60. package/src/global.d.ts +9 -0
  61. package/src/ids.ts +137 -0
  62. package/src/index.ts +16 -0
  63. package/src/input.ts +35 -0
  64. package/src/intent.ts +15 -0
  65. package/src/json.ts +42 -0
  66. package/src/participants.ts +14 -0
  67. package/src/payment.ts +573 -0
  68. package/src/profit.ts +55 -0
  69. package/src/sort.ts +49 -0
  70. package/src/stats.ts +10 -0
  71. package/src/time.ts +123 -0
  72. package/src/tokens.ts +159 -0
  73. package/src/units.ts +120 -0
  74. package/src/zkp2p-types.ts +55 -0
  75. package/tsconfig.json +18 -0
package/src/payment.ts ADDED
@@ -0,0 +1,573 @@
1
+ import { type Chain, getAddress, parseUnits, zeroAddress, type Hex } from "viem"
2
+ import { base, pulsechain } from "viem/chains"
3
+
4
+ import { contractsByChainId, getContracts } from "./contracts.js"
5
+ import { formatUnits } from "./units.js"
6
+ import type { TokenInfo } from "./tokens.js"
7
+ import type { ConversionRateInfo, ProviderRates } from "./conversionRates.js"
8
+ import { SUPPORTED_CURRENCIES } from "./currencies.js"
9
+ import { ChainId } from "./chain.js"
10
+
11
+ /**
12
+ * Payment providers, including manual
13
+ */
14
+ export const providers = {
15
+ VENMO: 'venmo',
16
+ ZELLE: 'zelle',
17
+ CASHAPP: 'cashapp',
18
+ REVOLUT: 'revolut',
19
+ WISE: 'wise',
20
+ MERCADOPAGO: 'mercadopago',
21
+ MANUAL: 'manual',
22
+ PAYPAL: 'paypal',
23
+ MONZO: 'monzo',
24
+ } as const
25
+
26
+ export type ProviderKey = typeof providers[keyof typeof providers]
27
+
28
+ /** Distinct keys for payment sub-providers (currently only used by Zelle) */
29
+ export const subProviders = {
30
+ CHASE: 'chase',
31
+ BANK_OF_AMERICA: 'bank_of_america',
32
+ CITI: 'citi',
33
+ } as const
34
+
35
+ /** Sub-provider key (providers within providers) */
36
+ export type SubProviderKey = typeof subProviders[keyof typeof subProviders]
37
+
38
+ /** Action type for a provider */
39
+ export type ProviderKeyActionType = 'transfer' | 'send'
40
+
41
+ /** Validatable provider key */
42
+ export type ValidatableProviderKey = Exclude<ProviderKey, typeof providers.MANUAL>
43
+
44
+ /** Transparent platforms */
45
+ export type TransparentPlatforms = typeof providers.ZELLE
46
+
47
+ /** Platform key */
48
+ export type PlatformKey = Exclude<ValidatableProviderKey, TransparentPlatforms> | SubProviderKey
49
+
50
+ /** Action type */
51
+ export type ActionType = `${ProviderKeyActionType}_${ProviderKey}`
52
+
53
+ /** Provider key to validation key */
54
+ export const providerKeyToValidationKey = {
55
+ venmo: 'venmoUsername',
56
+ zelle: 'zelleEmail',
57
+ cashapp: 'cashtag',
58
+ revolut: 'revolutUsername',
59
+ wise: 'wisetag',
60
+ mercadopago: 'cvu',
61
+ paypal: 'paypalEmail',
62
+ monzo: 'monzoMeUsername',
63
+ } as Record<ValidatableProviderKey, string>
64
+
65
+ /** Validation key */
66
+ export type ValidationKey = typeof providerKeyToValidationKey[keyof typeof providerKeyToValidationKey]
67
+
68
+ /** Limits for a payment method */
69
+ export type Limits = {
70
+ min: number
71
+ }
72
+
73
+ /** Send link options */
74
+ export type SendLinkOptions = {
75
+ username: string
76
+ amount: bigint
77
+ subProvider?: SubProviderKey
78
+ qrCode?: boolean
79
+ }
80
+
81
+ /** Send link */
82
+ export type SendLink = (options: SendLinkOptions) => string | null
83
+
84
+ /** Payment sub-provider config */
85
+ export type PaymentSubProviderConfig = {
86
+ key: SubProviderKey
87
+ name: string
88
+ icon?: string
89
+ color?: string
90
+ usernameType?: string
91
+ verifiers: (chain: ChainId) => Hex[]
92
+ sendLink: SendLink
93
+ paymentMethod: number
94
+ }
95
+
96
+ /** Payment config */
97
+ export type PaymentConfig = {
98
+ icon: string
99
+ key: ProviderKey
100
+ name: string
101
+ color: string
102
+ usernameType: string
103
+ validationKey: ValidationKey | null
104
+ verifiers: string[]
105
+ limits: Limits
106
+ /**
107
+ * Set of sub-provider keys that this payment method supports. Empty when none.
108
+ */
109
+ subProviders: Set<PaymentSubProviderConfig>
110
+ list: Hex[]
111
+ sendLink?: SendLink
112
+ }
113
+
114
+ /** Validation deposit data payment identifier */
115
+ export type ValidationDepositDataPaymentIdentifier = Partial<{
116
+ [key in Exclude<ValidationKey, null>]: string
117
+ }>
118
+
119
+ /** Validation deposit data */
120
+ export type ValidationDepositData = ValidationDepositDataPaymentIdentifier & {
121
+ telegramUsername: string
122
+ }
123
+
124
+ /** Data encoding for zelle urls */
125
+ export const dataEncoding = (data: string) => {
126
+ return btoa(JSON.stringify({
127
+ name: '',
128
+ action: 'payment',
129
+ token: data,
130
+ }))
131
+ }
132
+
133
+ /** Default Zelle send link */
134
+ export const defaultZelleSendLink = (options: SendLinkOptions) => (
135
+ !options.username ? null
136
+ : `https://enroll.zellepay.com/qr-codes?data=${dataEncoding(options.username)}`
137
+ )
138
+
139
+ /** Global configuration for all supported sub-providers. Other modules can import this directly. */
140
+ export const subProviderConfigs: Partial<Record<ProviderKey, Record<SubProviderKey, PaymentSubProviderConfig>>> = {
141
+ zelle: {
142
+ chase: {
143
+ paymentMethod: 0,
144
+ key: subProviders.CHASE,
145
+ name: 'Chase',
146
+ icon: 'simple-icons:chase',
147
+ verifiers: (chain) => getContracts(chain)!.zelleChaseReclaimVerifier,
148
+ sendLink: (opts) => {
149
+ if (opts.qrCode) {
150
+ return defaultZelleSendLink(opts)
151
+ }
152
+ return 'https://secure.chase.com/web/auth/dashboard#/dashboard/singleDoor/singleDoorController/index'
153
+ },
154
+ },
155
+ bank_of_america: {
156
+ paymentMethod: 1,
157
+ key: subProviders.BANK_OF_AMERICA,
158
+ name: 'Bank of America',
159
+ icon: 'simple-icons:bankofamerica',
160
+ verifiers: (chain) => getContracts(chain)!.zelleBoAReclaimVerifier,
161
+ sendLink: (opts) => {
162
+ if (opts.qrCode) {
163
+ return `https://www.bankofamerica.com/movemoney`
164
+ }
165
+ return 'https://www.bankofamerica.com/'
166
+ },
167
+ },
168
+ citi: {
169
+ paymentMethod: 2,
170
+ key: subProviders.CITI,
171
+ name: 'Citi',
172
+ icon: 'arcticons:citi-mobile',
173
+ verifiers: (chain) => getContracts(chain)!.zelleCitiReclaimVerifier,
174
+ sendLink: (opts) => {
175
+ if (opts.qrCode) {
176
+ return defaultZelleSendLink(opts)
177
+ }
178
+ return 'https://online.citi.com/US/nga/zelle/transfer'
179
+ },
180
+ },
181
+ },
182
+ }
183
+
184
+ /** Payment method icon mappings */
185
+ export const providerConfigs = (chainId: ChainId) => {
186
+ const contracts = getContracts(chainId)!
187
+ return {
188
+ venmo: {
189
+ key: providers.VENMO,
190
+ icon: 'ion:logo-venmo',
191
+ name: 'Venmo',
192
+ usernameType: 'Venmo Username',
193
+ validationKey: providerKeyToValidationKey.venmo,
194
+ color: 'rgb(0, 116, 222)',
195
+ verifiers: contracts.venmoReclaimVerifier,
196
+ limits: {
197
+ min: 1.0,
198
+ },
199
+ subProviders: new Set(),
200
+ sendLink: (options) => {
201
+ if (options.qrCode) {
202
+ return `venmo://paycharge?txn=pay&recipients=${options.username}&note=cash&amount=${options.amount}`
203
+ }
204
+ return `https://account.venmo.com/pay?recipients=${options.username}&note=cash&amount=${options.amount}`
205
+ },
206
+ list: [
207
+ SUPPORTED_CURRENCIES.USD.contractId,
208
+ ],
209
+ },
210
+ zelle: {
211
+ key: providers.ZELLE,
212
+ icon: 'simple-icons:zelle',
213
+ name: 'Zelle',
214
+ color: '#6d1fd4',
215
+ usernameType: 'Zelle Email',
216
+ validationKey: providerKeyToValidationKey.zelle,
217
+ verifiers: contracts.zelleBaseVerifier,
218
+ limits: {
219
+ min: 1.0,
220
+ },
221
+ subProviders: new Set([
222
+ subProviderConfigs.zelle![subProviders.CHASE],
223
+ subProviderConfigs.zelle![subProviders.BANK_OF_AMERICA],
224
+ subProviderConfigs.zelle![subProviders.CITI],
225
+ ]),
226
+ // Delegate to sub-provider specific link when provided, otherwise fall back to generic QR URL
227
+ sendLink: (options) => {
228
+ if (options.subProvider) {
229
+ return subProviderConfigs.zelle![options.subProvider]!.sendLink!(options)
230
+ }
231
+ return defaultZelleSendLink(options)
232
+ },
233
+ list: [
234
+ SUPPORTED_CURRENCIES.USD.contractId,
235
+ ],
236
+ },
237
+ cashapp: {
238
+ key: providers.CASHAPP,
239
+ icon: 'simple-icons:cashapp',
240
+ name: 'Cash App',
241
+ color: 'rgba(0,224,19,1.0)',
242
+ usernameType: 'CashTag',
243
+ validationKey: providerKeyToValidationKey.cashapp,
244
+ verifiers: contracts.cashappReclaimVerifier,
245
+ limits: {
246
+ min: 1.0,
247
+ },
248
+ subProviders: new Set(),
249
+ list: [
250
+ SUPPORTED_CURRENCIES.USD.contractId,
251
+ ],
252
+ sendLink: (options) => {
253
+ const u = options.username.startsWith('$') ? options.username : `$${options.username}`
254
+ return `https://cash.app/qr/${u}?size=288&margin=0`
255
+ },
256
+ },
257
+ revolut: {
258
+ key: providers.REVOLUT,
259
+ icon: 'simple-icons:revolut',
260
+ name: 'Revolut',
261
+ color: '#191c1f',
262
+ usernameType: 'RevTag',
263
+ validationKey: providerKeyToValidationKey.revolut,
264
+ verifiers: contracts.revolutReclaimVerifier,
265
+ limits: {
266
+ min: 1.0,
267
+ },
268
+ subProviders: new Set(),
269
+ sendLink: (options) => `https://revolut.me/${options.username}`,
270
+ list: [
271
+ SUPPORTED_CURRENCIES.USD.contractId,
272
+ SUPPORTED_CURRENCIES.EUR.contractId,
273
+ SUPPORTED_CURRENCIES.GBP.contractId,
274
+ SUPPORTED_CURRENCIES.AUD.contractId,
275
+ SUPPORTED_CURRENCIES.CAD.contractId,
276
+ SUPPORTED_CURRENCIES.HKD.contractId,
277
+ SUPPORTED_CURRENCIES.MXN.contractId,
278
+ SUPPORTED_CURRENCIES.NZD.contractId,
279
+ SUPPORTED_CURRENCIES.PLN.contractId,
280
+ SUPPORTED_CURRENCIES.SAR.contractId,
281
+ SUPPORTED_CURRENCIES.SGD.contractId,
282
+ SUPPORTED_CURRENCIES.ZAR.contractId,
283
+ SUPPORTED_CURRENCIES.CHF.contractId,
284
+ SUPPORTED_CURRENCIES.THB.contractId,
285
+ SUPPORTED_CURRENCIES.TRY.contractId,
286
+ SUPPORTED_CURRENCIES.AED.contractId,
287
+ ],
288
+ },
289
+ wise: {
290
+ key: providers.WISE,
291
+ icon: 'simple-icons:wise',
292
+ name: 'Wise',
293
+ color: '#9fe870',
294
+ usernameType: 'WiseTag',
295
+ validationKey: providerKeyToValidationKey.wise,
296
+ verifiers: contracts.wiseReclaimVerifier,
297
+ limits: {
298
+ min: 1.0,
299
+ },
300
+ subProviders: new Set(),
301
+ sendLink: (options) => `https://wise.com/pay/me/${options.username}`,
302
+ list: [
303
+ SUPPORTED_CURRENCIES.USD.contractId,
304
+ SUPPORTED_CURRENCIES.EUR.contractId,
305
+ SUPPORTED_CURRENCIES.GBP.contractId,
306
+ SUPPORTED_CURRENCIES.AUD.contractId,
307
+ SUPPORTED_CURRENCIES.CAD.contractId,
308
+ SUPPORTED_CURRENCIES.CNY.contractId,
309
+ SUPPORTED_CURRENCIES.HKD.contractId,
310
+ SUPPORTED_CURRENCIES.IDR.contractId,
311
+ SUPPORTED_CURRENCIES.ILS.contractId,
312
+ SUPPORTED_CURRENCIES.JPY.contractId,
313
+ SUPPORTED_CURRENCIES.KES.contractId,
314
+ SUPPORTED_CURRENCIES.MYR.contractId,
315
+ SUPPORTED_CURRENCIES.MXN.contractId,
316
+ SUPPORTED_CURRENCIES.NZD.contractId,
317
+ SUPPORTED_CURRENCIES.PLN.contractId,
318
+ SUPPORTED_CURRENCIES.SGD.contractId,
319
+ SUPPORTED_CURRENCIES.ZAR.contractId,
320
+ SUPPORTED_CURRENCIES.CHF.contractId,
321
+ SUPPORTED_CURRENCIES.THB.contractId,
322
+ SUPPORTED_CURRENCIES.TRY.contractId,
323
+ SUPPORTED_CURRENCIES.UGX.contractId,
324
+ SUPPORTED_CURRENCIES.AED.contractId,
325
+ SUPPORTED_CURRENCIES.VND.contractId,
326
+ ],
327
+ },
328
+ mercadopago: {
329
+ key: providers.MERCADOPAGO,
330
+ icon: 'simple-icons:mercadopago',
331
+ name: 'Mercado Pago',
332
+ usernameType: 'Mercado Pago / Bank CVU',
333
+ color: '#ffe600',
334
+ validationKey: providerKeyToValidationKey.mercadopago,
335
+ verifiers: contracts.mercadopagoReclaimVerifier,
336
+ limits: {
337
+ min: 1.0,
338
+ },
339
+ subProviders: new Set(),
340
+ sendLink: () => `https://www.mercadopago.com.ar/money-out/transfer/`,
341
+ list: [
342
+ SUPPORTED_CURRENCIES.ARS.contractId,
343
+ ],
344
+ },
345
+ paypal: {
346
+ key: providers.PAYPAL,
347
+ icon: 'simple-icons:paypal',
348
+ name: 'PayPal',
349
+ usernameType: 'PayPal Email',
350
+ validationKey: providerKeyToValidationKey.paypal,
351
+ verifiers: contracts.paypalReclaimVerifier,
352
+ limits: {
353
+ min: 1.0,
354
+ },
355
+ subProviders: new Set(),
356
+ color: '#0070BA',
357
+ sendLink: (options) => {
358
+ if (options.qrCode) {
359
+ return `paypal://`
360
+ }
361
+ return `https://www.paypal.com/myaccount/transfer/homepage`
362
+ },
363
+ list: [
364
+ SUPPORTED_CURRENCIES.USD.contractId,
365
+ SUPPORTED_CURRENCIES.EUR.contractId,
366
+ SUPPORTED_CURRENCIES.GBP.contractId,
367
+ SUPPORTED_CURRENCIES.AUD.contractId,
368
+ SUPPORTED_CURRENCIES.NZD.contractId,
369
+ SUPPORTED_CURRENCIES.CAD.contractId,
370
+ SUPPORTED_CURRENCIES.SGD.contractId,
371
+ ],
372
+ },
373
+ monzo: {
374
+ key: providers.MONZO,
375
+ icon: 'simple-icons:monzo',
376
+ name: 'Monzo',
377
+ usernameType: 'Monzo Me Username',
378
+ validationKey: providerKeyToValidationKey.monzo,
379
+ verifiers: contracts.monzoReclaimVerifier,
380
+ limits: {
381
+ min: 1.0,
382
+ },
383
+ subProviders: new Set(),
384
+ sendLink: (options) => `https://monzo.me/${options.username}`,
385
+ list: [
386
+ SUPPORTED_CURRENCIES.GBP.contractId,
387
+ ],
388
+ color: '#FC427B',
389
+ },
390
+ manual: {
391
+ key: providers.MANUAL,
392
+ icon: 'mdi:help-circle',
393
+ name: 'Manual Release',
394
+ color: 'gray',
395
+ usernameType: '',
396
+ validationKey: null,
397
+ verifiers: [zeroAddress],
398
+ limits: {
399
+ min: 0.0,
400
+ },
401
+ subProviders: new Set(),
402
+ list: [],
403
+ },
404
+ } as Record<ProviderKey, PaymentConfig>
405
+ }
406
+
407
+ /** Payment verifier to key map */
408
+ export const paymentVerifierToKey = (chainId: ChainId | null) => (
409
+ new Map<string, ProviderKey>(
410
+ Object.values(chainId ? [chainId] : [...contractsByChainId.keys()]).flatMap(chainId => (
411
+ Object.values(providerConfigs(chainId)).flatMap(config => {
412
+ return config.verifiers.map(verifier => [getAddress(verifier), config.key])
413
+ })
414
+ ))
415
+ )
416
+ )
417
+
418
+ /** Provider key to verifiers map */
419
+ export const providerKeyToVerifiersMap = (chainId: ChainId) => (
420
+ new Map<ProviderKey, Hex[]>(
421
+ Object.entries(providerConfigs(chainId)).map(([key, config]) => (
422
+ [key, config.verifiers] as [ProviderKey, Hex[]]
423
+ ))
424
+ )
425
+ )
426
+
427
+ /** Provider key to verifiers */
428
+ export const providerKeyToVerifiers = (chainId: ChainId, providerKey: ProviderKey): Hex[] | null => {
429
+ return providerKeyToVerifiersMap(chainId).get(providerKey) ?? null
430
+ }
431
+
432
+ /** Verifier gets key */
433
+ export const verifierGetsKey = (chainId: ChainId | null, verifierAddress: string): ProviderKey => {
434
+ try {
435
+ return paymentVerifierToKey(chainId).get(getAddress(verifierAddress)) ?? providers.MANUAL
436
+ } catch (error) {
437
+ return providers.MANUAL
438
+ }
439
+ }
440
+
441
+ /**
442
+ * Utility function to get payment method icon
443
+ * @param key - The provider key
444
+ * @returns The icon string used for iconify
445
+ */
446
+ export const getPaymentIcon = (chainId: ChainId | null, key: ProviderKey): string => {
447
+ const config = providerConfigs(chainId ?? pulsechain.id)
448
+ return config[key]?.icon || config[providers.MANUAL].icon
449
+ }
450
+
451
+ /**
452
+ * Utility function to get payment method configuration by verifier address
453
+ * @param verifierAddress - The verifier address
454
+ * @returns The payment method configuration
455
+ */
456
+ export const getPaymentMethodConfig = (chainId: ChainId | null, verifierAddress: string): PaymentConfig | null => {
457
+ return (chainId ? [chainId] : [...contractsByChainId.keys()]).reduce((result, chainId) => (
458
+ result ?? Object.values(providerConfigs(chainId)).reduce((r, config) => (
459
+ r ?? (config.verifiers.includes(getAddress(verifierAddress)) ? config : null)
460
+ ), result as null | PaymentConfig)
461
+ ), null as null | PaymentConfig)
462
+ }
463
+
464
+ /**
465
+ * Utility function to get payment method minimum limit by verifier address
466
+ * @param key - The provider key
467
+ * @returns The minimum limit
468
+ */
469
+ export const getPaymentMethodMinimum = (chainId: ChainId | null, key: ProviderKey): number => {
470
+ const config = providerConfigs(chainId ?? base.id)[key]
471
+ return config?.limits?.min ?? 0
472
+ }
473
+
474
+ /**
475
+ * Utility function to get payment method name by verifier address
476
+ */
477
+ export const getPaymentMethodName = (chainId: ChainId | null, verifierAddress: string | ProviderKey): string => {
478
+ const providerKey = verifierAddress as ProviderKey
479
+ const providerConfig = providerConfigs(chainId ?? base.id)[providerKey]
480
+ if (providerConfig) {
481
+ return providerConfig.name
482
+ }
483
+ const config = providerConfigs(chainId ?? base.id)[verifierAddress as ProviderKey] ?? getPaymentMethodConfig(chainId ?? base.id, verifierAddress)
484
+ return config?.name || 'Unknown'
485
+ }
486
+
487
+ /**
488
+ * Calculate effective minimum amount (higher of user minimum or payment provider minimum)
489
+ * @param userMinAmountWei - The user minimum amount
490
+ * @param tokenInfo - The token info
491
+ * @param providerRates - The provider rates
492
+ * @returns The effective minimum amount
493
+ */
494
+ export function calculateEffectiveMinimum(
495
+ chainId: ChainId,
496
+ userMinAmountWei: string | bigint,
497
+ tokenInfo: TokenInfo,
498
+ providerRates?: ProviderRates<ConversionRateInfo>
499
+ ): {
500
+ userMinAmountWei: bigint
501
+ providerMinAmountWei: bigint
502
+ effectiveMinAmountWei: bigint
503
+ formattedEffectiveMin: string
504
+ } {
505
+ const userMinAmountWeiBigInt = BigInt(userMinAmountWei)
506
+ let providerMinAmountWei = 0n
507
+
508
+ if (providerRates) {
509
+ // Get unique payment providers from the rates
510
+ const paymentProviders = new Set<ProviderKey>()
511
+ for (const [providerKey] of providerRates.entries()) {
512
+ paymentProviders.add(providerKey)
513
+ }
514
+
515
+ // Calculate the highest provider minimum limit
516
+ for (const providerKey of paymentProviders) {
517
+ const providerConfig = providerConfigs(chainId)[providerKey]
518
+ if (providerConfig?.limits?.min) {
519
+ const providerMinWei = parseUnits(providerConfig.limits.min.toString(), tokenInfo.decimals)
520
+ if (providerMinWei > providerMinAmountWei) {
521
+ providerMinAmountWei = providerMinWei
522
+ }
523
+ }
524
+ }
525
+ }
526
+
527
+ const effectiveMinAmountWei = userMinAmountWeiBigInt > providerMinAmountWei
528
+ ? userMinAmountWeiBigInt
529
+ : providerMinAmountWei
530
+
531
+ const formattedEffectiveMin = formatUnits(effectiveMinAmountWei, { decimals: tokenInfo.decimals })
532
+ return {
533
+ userMinAmountWei: userMinAmountWeiBigInt,
534
+ providerMinAmountWei,
535
+ effectiveMinAmountWei,
536
+ formattedEffectiveMin
537
+ }
538
+ }
539
+
540
+ /**
541
+ * Helper function to get payment provider minimum limit (returns decimal number for config)
542
+ * @param key - The provider key
543
+ * @returns The minimum limit
544
+ */
545
+ export function getPaymentProviderMinimum(chainId: ChainId, key: ProviderKey): number {
546
+ return getPaymentMethodMinimum(chainId, key) ?? 0
547
+ }
548
+
549
+ /**
550
+ * Check if a payment method is known
551
+ * @param chainId - The chain ID
552
+ * @param verifierAddress - The verifier address
553
+ * @returns True if the payment method is known, false otherwise
554
+ */
555
+ export const isPaymentMethodKnown = (chainId: ChainId | null, verifierAddress: string): boolean => {
556
+ return !!getPaymentMethodConfig(chainId, verifierAddress)
557
+ }
558
+
559
+ /**
560
+ * Get all payment methods
561
+ * @returns All payment methods
562
+ */
563
+ export const getAllPaymentMethods = (chainId: ChainId): ProviderKey[] => {
564
+ return Object.keys(providerConfigs(chainId)) as ProviderKey[]
565
+ }
566
+
567
+ /**
568
+ * Get all verifiable payment methods
569
+ * @returns All verifiable payment methods
570
+ */
571
+ export const verifiablePaymentMethods = (chainId: ChainId): ProviderKey[] => {
572
+ return getAllPaymentMethods(chainId).filter(key => key !== providers.MANUAL)
573
+ }
package/src/profit.ts ADDED
@@ -0,0 +1,55 @@
1
+ import { getCurrencyByContractId } from "./currencies.js"
2
+ import { getDefaultToken } from "./tokens.js"
3
+ import type { ChainId } from "./chain.js"
4
+
5
+ /** BigIntish type */
6
+ export type BigIntish = string | bigint | number
7
+
8
+ /** Profit calculation input */
9
+ export interface ProfitCalculationInput {
10
+ amount: BigIntish
11
+ chainId: ChainId
12
+ conversionRate: {
13
+ value: BigIntish
14
+ currency: string
15
+ }
16
+ }
17
+
18
+ /**
19
+ * Calculate the profit of an intent fulfilled event
20
+ * @param param0.amount - The amount
21
+ * @param param0.conversionRate - The conversion rate
22
+ * @returns The profit
23
+ */
24
+ export const calculateProfit = ({
25
+ amount: amountInput,
26
+ conversionRate,
27
+ chainId,
28
+ }: ProfitCalculationInput) => {
29
+ const rate = BigInt(conversionRate.value)
30
+ const amount = BigInt(amountInput)
31
+ const valueReceived = amount * rate / 10n ** 18n
32
+ const currency = getCurrencyByContractId(conversionRate.currency)
33
+ const inputTokenInfo = getDefaultToken(chainId)
34
+ const isOneForOne = currency!.ticker === 'USD'
35
+
36
+ if (inputTokenInfo && isOneForOne) {
37
+ return valueReceived - amount
38
+ }
39
+ return null
40
+ }
41
+
42
+ /**
43
+ * Calculate the profits for a list of inputs
44
+ * @param inputs - The inputs to calculate the profits for a series of intents
45
+ * @returns The profits
46
+ */
47
+ export const calculateProfits = (inputs: ProfitCalculationInput[]) => {
48
+ const profitAmounts = inputs.map(calculateProfit)
49
+ const nullAmounts = profitAmounts.filter((amount) => amount === null).length
50
+ const profit = profitAmounts.reduce((acc: bigint, curr) => !!curr ? acc + curr : acc, 0n)
51
+ return {
52
+ profit,
53
+ nullAmounts,
54
+ }
55
+ }
package/src/sort.ts ADDED
@@ -0,0 +1,49 @@
1
+ export type SortDirection = 'asc' | 'desc'
2
+
3
+ export type Sortable = string | number | bigint
4
+
5
+ /**
6
+ * Ordered sort
7
+ * @param aVal - The first value
8
+ * @param bVal - The second value
9
+ * @param orderDirection - The order direction
10
+ * @returns The sorted value
11
+ */
12
+ export const orderedSort = (aVal: Sortable, bVal: Sortable, orderDirection: SortDirection): number => {
13
+ if (typeof aVal === 'bigint' && typeof bVal === 'bigint') {
14
+ const compareResult = aVal < bVal ? -1 : aVal > bVal ? 1 : 0;
15
+ return orderDirection === 'asc' ? compareResult : -compareResult;
16
+ } else if (typeof aVal === 'string' && typeof bVal === 'string') {
17
+ const compareResult = aVal.localeCompare(bVal);
18
+ return orderDirection === 'asc' ? compareResult : -compareResult;
19
+ } else if (typeof aVal === 'number' && typeof bVal === 'number') {
20
+ const compareResult = aVal - bVal;
21
+ return orderDirection === 'asc' ? compareResult : -compareResult;
22
+ } else {
23
+ const compareResult = String(aVal).localeCompare(String(bVal));
24
+ return orderDirection === 'asc' ? compareResult : -compareResult;
25
+ }
26
+ }
27
+
28
+ /**
29
+ * Ordered sort then by deposit ID
30
+ * @param param0 - The parameters
31
+ * @returns The sorted value
32
+ */
33
+ export const orderedSortThenById = ({
34
+ aVal,
35
+ bVal,
36
+ orderDirection,
37
+ a,
38
+ b,
39
+ }: {
40
+ aVal: Sortable, bVal: Sortable, orderDirection: SortDirection,
41
+ a: { depositId: bigint, transaction: { block: { timestamp: string } } },
42
+ b: { depositId: bigint, transaction: { block: { timestamp: string } } },
43
+ }): number => {
44
+ let result = orderedSort(aVal, bVal, orderDirection)
45
+ if (result !== 0) return result
46
+ result = orderedSort(BigInt(a.transaction.block.timestamp), BigInt(b.transaction.block.timestamp), 'asc')
47
+ if (result !== 0) return result
48
+ return orderedSort(a.depositId, b.depositId, 'asc')
49
+ }
package/src/stats.ts ADDED
@@ -0,0 +1,10 @@
1
+ export const statAction = {
2
+ deposit: 'deposit',
3
+ withdrawal: 'withdrawal',
4
+ exchange: 'exchange',
5
+ } as const
6
+ export type StatAction = (typeof statAction)[keyof typeof statAction]
7
+
8
+ export const isStatAction = (action: string): action is StatAction => {
9
+ return action in statAction
10
+ }