@provex/utils 1.0.16 → 1.2.4
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.
- package/dist/chain.d.ts +446 -0
- package/dist/chain.js +98 -0
- package/dist/chain.test.js +112 -0
- package/dist/contracts.d.ts +206 -0
- package/dist/contracts.js +292 -0
- package/dist/contracts.test.js +243 -0
- package/dist/conversionRates.d.ts +215 -0
- package/dist/{src/conversionRates.js → conversionRates.js} +74 -4
- package/dist/conversionRates.test.js +473 -0
- package/dist/currencies.d.ts +248 -0
- package/dist/{src/currencies.js → currencies.js} +119 -38
- package/dist/currencies.test.js +343 -0
- package/dist/data/countries.json +1099 -0
- package/dist/deposit.d.ts +69 -0
- package/dist/deposit.js +52 -0
- package/dist/depositKeys.d.ts +154 -0
- package/dist/depositKeys.js +104 -0
- package/dist/depositKeys.test.d.ts +1 -0
- package/dist/depositKeys.test.js +231 -0
- package/dist/events.d.ts +41 -0
- package/dist/events.js +92 -0
- package/dist/events.test.d.ts +1 -0
- package/dist/events.test.js +111 -0
- package/dist/fees.d.ts +136 -0
- package/dist/fees.js +178 -0
- package/dist/fees.test.d.ts +1 -0
- package/dist/fees.test.js +165 -0
- package/dist/ids.d.ts +175 -0
- package/dist/ids.js +231 -0
- package/dist/ids.test.d.ts +1 -0
- package/dist/ids.test.js +607 -0
- package/dist/index.d.ts +45 -0
- package/dist/index.js +45 -0
- package/dist/input.d.ts +26 -0
- package/dist/{src/input.js → input.js} +23 -4
- package/dist/intent.d.ts +50 -0
- package/dist/intent.js +28 -0
- package/dist/intent.test.d.ts +1 -0
- package/dist/intent.test.js +119 -0
- package/dist/json.d.ts +55 -0
- package/dist/json.js +80 -0
- package/dist/participants.d.ts +22 -0
- package/dist/participants.js +28 -0
- package/dist/payment.d.ts +481 -0
- package/dist/payment.js +1149 -0
- package/dist/payment.test.d.ts +1 -0
- package/dist/payment.test.js +272 -0
- package/dist/peer-types.d.ts +327 -0
- package/dist/peer-types.js +169 -0
- package/dist/profit.d.ts +49 -0
- package/dist/profit.js +57 -0
- package/dist/profit.test.d.ts +1 -0
- package/dist/profit.test.js +315 -0
- package/dist/reputation.d.ts +125 -0
- package/dist/reputation.js +188 -0
- package/dist/reputation.test.d.ts +1 -0
- package/dist/reputation.test.js +156 -0
- package/dist/sort.d.ts +75 -0
- package/dist/sort.js +70 -0
- package/dist/sort.test.d.ts +1 -0
- package/dist/sort.test.js +216 -0
- package/dist/stateKey.d.ts +35 -0
- package/dist/stateKey.js +36 -0
- package/dist/stats.d.ts +61 -0
- package/dist/stats.js +53 -0
- package/dist/stats.test.d.ts +1 -0
- package/dist/stats.test.js +104 -0
- package/dist/time.d.ts +104 -0
- package/dist/time.js +162 -0
- package/dist/time.test.d.ts +1 -0
- package/dist/time.test.js +231 -0
- package/dist/tokens.d.ts +15502 -0
- package/dist/{src/tokens.js → tokens.js} +98 -17
- package/dist/tokens.test.d.ts +1 -0
- package/dist/tokens.test.js +193 -0
- package/dist/units.d.ts +200 -0
- package/dist/units.js +279 -0
- package/dist/units.test.d.ts +1 -0
- package/dist/units.test.js +327 -0
- package/package.json +119 -29
- package/dist/scripts/convert-svg.js +0 -17
- package/dist/src/chain.d.ts +0 -14
- package/dist/src/chain.js +0 -18
- package/dist/src/contracts.d.ts +0 -30
- package/dist/src/contracts.js +0 -64
- package/dist/src/conversionRates.d.ts +0 -124
- package/dist/src/currencies.d.ts +0 -144
- package/dist/src/data/countries.json +0 -1099
- package/dist/src/deposit.d.ts +0 -1
- package/dist/src/events.d.ts +0 -3
- package/dist/src/events.js +0 -16
- package/dist/src/ids.d.ts +0 -72
- package/dist/src/ids.js +0 -81
- package/dist/src/index.d.ts +0 -16
- package/dist/src/index.js +0 -16
- package/dist/src/input.d.ts +0 -7
- package/dist/src/intent.d.ts +0 -14
- package/dist/src/json.d.ts +0 -18
- package/dist/src/json.js +0 -44
- package/dist/src/participants.d.ts +0 -7
- package/dist/src/participants.js +0 -13
- package/dist/src/payment.d.ts +0 -164
- package/dist/src/payment.js +0 -439
- package/dist/src/profit.d.ts +0 -28
- package/dist/src/profit.js +0 -34
- package/dist/src/sort.d.ts +0 -36
- package/dist/src/sort.js +0 -39
- package/dist/src/stats.d.ts +0 -7
- package/dist/src/stats.js +0 -8
- package/dist/src/time.d.ts +0 -54
- package/dist/src/time.js +0 -106
- package/dist/src/tokens.d.ts +0 -3675
- package/dist/src/units.d.ts +0 -17
- package/dist/src/units.js +0 -79
- package/dist/src/zkp2p-types.d.ts +0 -48
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/scripts/convert-svg.ts +0 -22
- package/src/chain.ts +0 -27
- package/src/contracts.ts +0 -89
- package/src/conversionRates.ts +0 -356
- package/src/currencies.ts +0 -286
- package/src/data/countries.json +0 -1099
- package/src/deposit.ts +0 -2
- package/src/events.ts +0 -21
- package/src/flags/eur.svg +0 -4
- package/src/flags/usd.svg +0 -25
- package/src/flags.ts +0 -4
- package/src/global.d.ts +0 -9
- package/src/ids.ts +0 -137
- package/src/index.ts +0 -16
- package/src/input.ts +0 -35
- package/src/intent.ts +0 -15
- package/src/json.ts +0 -42
- package/src/participants.ts +0 -14
- package/src/payment.ts +0 -573
- package/src/profit.ts +0 -55
- package/src/sort.ts +0 -49
- package/src/stats.ts +0 -10
- package/src/time.ts +0 -123
- package/src/tokens.ts +0 -159
- package/src/units.ts +0 -120
- package/src/zkp2p-types.ts +0 -55
- package/tsconfig.json +0 -18
- /package/dist/{scripts/convert-svg.d.ts → chain.test.d.ts} +0 -0
- /package/dist/{src/deposit.js → contracts.test.d.ts} +0 -0
- /package/dist/{src/intent.js → conversionRates.test.d.ts} +0 -0
- /package/dist/{src/zkp2p-types.js → currencies.test.d.ts} +0 -0
- /package/dist/{src/flags.d.ts → flags.d.ts} +0 -0
- /package/dist/{src/flags.js → flags.js} +0 -0
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { base } from 'viem/chains';
|
|
4
|
+
import { processConversionRates, getConversionRate, extractCurrencies, getLatestRateForCurrency, getPrimaryConversionRate, getPrimaryRateForCurrency, getPrimaryVerifier, getPrimaryCurrency, convertTokenInputToCurrency, convertCurrencyToTokenOutput, } from './conversionRates.js';
|
|
5
|
+
import { SUPPORTED_CURRENCIES } from './currencies.js';
|
|
6
|
+
import { v2BaseContracts } from './contracts.js';
|
|
7
|
+
describe('conversionRates', () => {
|
|
8
|
+
// Test data
|
|
9
|
+
const USD_CONTRACT_ID = SUPPORTED_CURRENCIES.USD.contractId;
|
|
10
|
+
const EUR_CONTRACT_ID = SUPPORTED_CURRENCIES.EUR.contractId;
|
|
11
|
+
// Use actual v2 verifier addresses from contracts
|
|
12
|
+
const VENMO_VERIFIER = v2BaseContracts.venmoReclaimVerifier[0];
|
|
13
|
+
const ZELLE_VERIFIER = v2BaseContracts.zelleBaseVerifier[0];
|
|
14
|
+
const createMockEvent = (overrides = {}) => ({
|
|
15
|
+
depositConversionRateUpdatedId: 'rate-1',
|
|
16
|
+
currency: USD_CONTRACT_ID,
|
|
17
|
+
verifier: VENMO_VERIFIER,
|
|
18
|
+
value: '1000000000000000000', // 1.0
|
|
19
|
+
orderId: '0x0001',
|
|
20
|
+
depositId: 'deposit-1',
|
|
21
|
+
transaction: {
|
|
22
|
+
hash: '0xhash1',
|
|
23
|
+
block: { timestamp: '1700000000' },
|
|
24
|
+
},
|
|
25
|
+
currentDepositConversionRateUpdatedId: 'rate-1',
|
|
26
|
+
currentDepositConversionRateUpdated: {
|
|
27
|
+
value: '1000000000000000000',
|
|
28
|
+
},
|
|
29
|
+
...overrides,
|
|
30
|
+
});
|
|
31
|
+
const MOCK_TOKEN = {
|
|
32
|
+
address: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
|
|
33
|
+
decimals: 6,
|
|
34
|
+
symbol: 'USDC',
|
|
35
|
+
name: 'USD Coin',
|
|
36
|
+
chainId: base.id,
|
|
37
|
+
};
|
|
38
|
+
describe('processConversionRates', () => {
|
|
39
|
+
it('should process empty events array', () => {
|
|
40
|
+
const result = processConversionRates({
|
|
41
|
+
chainId: base.id,
|
|
42
|
+
events: [],
|
|
43
|
+
});
|
|
44
|
+
assert.equal(result.size, 0);
|
|
45
|
+
});
|
|
46
|
+
it('should process single event', () => {
|
|
47
|
+
const events = [createMockEvent()];
|
|
48
|
+
const result = processConversionRates({
|
|
49
|
+
chainId: base.id,
|
|
50
|
+
events,
|
|
51
|
+
});
|
|
52
|
+
assert.equal(result.size, 1);
|
|
53
|
+
const venmoRates = result.get('venmo');
|
|
54
|
+
assert.ok(venmoRates, 'Should have venmo rates');
|
|
55
|
+
const usdRates = venmoRates.get(USD_CONTRACT_ID);
|
|
56
|
+
assert.ok(usdRates, 'Should have USD rates');
|
|
57
|
+
assert.equal(usdRates.length, 1);
|
|
58
|
+
});
|
|
59
|
+
it('should skip events without currentDepositConversionRateUpdated', () => {
|
|
60
|
+
const events = [
|
|
61
|
+
createMockEvent({ currentDepositConversionRateUpdated: undefined }),
|
|
62
|
+
];
|
|
63
|
+
const result = processConversionRates({
|
|
64
|
+
chainId: base.id,
|
|
65
|
+
events,
|
|
66
|
+
});
|
|
67
|
+
assert.equal(result.size, 0);
|
|
68
|
+
});
|
|
69
|
+
it('should sort events by orderId in ascending order by default', () => {
|
|
70
|
+
const events = [
|
|
71
|
+
createMockEvent({ orderId: '0x0002' }),
|
|
72
|
+
createMockEvent({ orderId: '0x0001' }),
|
|
73
|
+
createMockEvent({ orderId: '0x0003' }),
|
|
74
|
+
];
|
|
75
|
+
const result = processConversionRates({
|
|
76
|
+
chainId: base.id,
|
|
77
|
+
events,
|
|
78
|
+
includeHistorical: true,
|
|
79
|
+
});
|
|
80
|
+
const venmoRates = result.get('venmo')?.get(USD_CONTRACT_ID);
|
|
81
|
+
assert.ok(venmoRates);
|
|
82
|
+
assert.equal(venmoRates[0].orderId, '0x0001');
|
|
83
|
+
assert.equal(venmoRates[1].orderId, '0x0002');
|
|
84
|
+
assert.equal(venmoRates[2].orderId, '0x0003');
|
|
85
|
+
});
|
|
86
|
+
it('should sort events in descending order when specified', () => {
|
|
87
|
+
const events = [
|
|
88
|
+
createMockEvent({ orderId: '0x0002' }),
|
|
89
|
+
createMockEvent({ orderId: '0x0001' }),
|
|
90
|
+
createMockEvent({ orderId: '0x0003' }),
|
|
91
|
+
];
|
|
92
|
+
const result = processConversionRates({
|
|
93
|
+
chainId: base.id,
|
|
94
|
+
events,
|
|
95
|
+
sortOrder: 'desc',
|
|
96
|
+
includeHistorical: true,
|
|
97
|
+
});
|
|
98
|
+
const venmoRates = result.get('venmo')?.get(USD_CONTRACT_ID);
|
|
99
|
+
assert.ok(venmoRates);
|
|
100
|
+
assert.equal(venmoRates[0].orderId, '0x0003');
|
|
101
|
+
});
|
|
102
|
+
it('should keep only latest rate when includeHistorical is false', () => {
|
|
103
|
+
const events = [
|
|
104
|
+
createMockEvent({
|
|
105
|
+
orderId: '0x0001',
|
|
106
|
+
currentDepositConversionRateUpdated: { value: '1000000000000000000' },
|
|
107
|
+
}),
|
|
108
|
+
createMockEvent({
|
|
109
|
+
orderId: '0x0002',
|
|
110
|
+
currentDepositConversionRateUpdated: { value: '1050000000000000000' },
|
|
111
|
+
}),
|
|
112
|
+
];
|
|
113
|
+
const result = processConversionRates({
|
|
114
|
+
chainId: base.id,
|
|
115
|
+
events,
|
|
116
|
+
includeHistorical: false,
|
|
117
|
+
});
|
|
118
|
+
const venmoRates = result.get('venmo')?.get(USD_CONTRACT_ID);
|
|
119
|
+
assert.ok(venmoRates);
|
|
120
|
+
assert.equal(venmoRates.length, 1);
|
|
121
|
+
// Should have the latest rate (sorted asc, so last one replaces)
|
|
122
|
+
assert.equal(venmoRates[0].value, '1050000000000000000');
|
|
123
|
+
});
|
|
124
|
+
it('should group rates by provider', () => {
|
|
125
|
+
const events = [
|
|
126
|
+
createMockEvent({ verifier: VENMO_VERIFIER }),
|
|
127
|
+
createMockEvent({ verifier: ZELLE_VERIFIER }),
|
|
128
|
+
];
|
|
129
|
+
const result = processConversionRates({
|
|
130
|
+
chainId: base.id,
|
|
131
|
+
events,
|
|
132
|
+
});
|
|
133
|
+
assert.ok(result.get('venmo'), 'Should have venmo rates');
|
|
134
|
+
assert.ok(result.get('zelle'), 'Should have zelle rates');
|
|
135
|
+
});
|
|
136
|
+
it('should group rates by currency', () => {
|
|
137
|
+
const events = [
|
|
138
|
+
createMockEvent({ currency: USD_CONTRACT_ID }),
|
|
139
|
+
createMockEvent({ currency: EUR_CONTRACT_ID }),
|
|
140
|
+
];
|
|
141
|
+
const result = processConversionRates({
|
|
142
|
+
chainId: base.id,
|
|
143
|
+
events,
|
|
144
|
+
});
|
|
145
|
+
const venmoRates = result.get('venmo');
|
|
146
|
+
assert.ok(venmoRates);
|
|
147
|
+
assert.ok(venmoRates.get(USD_CONTRACT_ID), 'Should have USD rates');
|
|
148
|
+
assert.ok(venmoRates.get(EUR_CONTRACT_ID), 'Should have EUR rates');
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
describe('getConversionRate', () => {
|
|
152
|
+
it('should return null for empty events', () => {
|
|
153
|
+
const result = getConversionRate({
|
|
154
|
+
events: [],
|
|
155
|
+
currency: USD_CONTRACT_ID,
|
|
156
|
+
verifier: VENMO_VERIFIER,
|
|
157
|
+
chainId: base.id,
|
|
158
|
+
});
|
|
159
|
+
assert.equal(result, null);
|
|
160
|
+
});
|
|
161
|
+
it('should return rate for matching currency and verifier', () => {
|
|
162
|
+
const events = [createMockEvent()];
|
|
163
|
+
const result = getConversionRate({
|
|
164
|
+
events,
|
|
165
|
+
currency: USD_CONTRACT_ID,
|
|
166
|
+
verifier: VENMO_VERIFIER,
|
|
167
|
+
chainId: base.id,
|
|
168
|
+
});
|
|
169
|
+
assert.ok(result, 'Should return a rate');
|
|
170
|
+
assert.ok(!Array.isArray(result), 'Should return single rate');
|
|
171
|
+
assert.equal(result.value, '1000000000000000000');
|
|
172
|
+
});
|
|
173
|
+
it('should return null for non-matching currency', () => {
|
|
174
|
+
const events = [createMockEvent({ currency: USD_CONTRACT_ID })];
|
|
175
|
+
const result = getConversionRate({
|
|
176
|
+
events,
|
|
177
|
+
currency: EUR_CONTRACT_ID,
|
|
178
|
+
verifier: VENMO_VERIFIER,
|
|
179
|
+
chainId: base.id,
|
|
180
|
+
});
|
|
181
|
+
assert.equal(result, null);
|
|
182
|
+
});
|
|
183
|
+
it('should return array when includeHistory is true', () => {
|
|
184
|
+
const events = [
|
|
185
|
+
createMockEvent({ orderId: '0x0001' }),
|
|
186
|
+
createMockEvent({ orderId: '0x0002' }),
|
|
187
|
+
];
|
|
188
|
+
const result = getConversionRate({
|
|
189
|
+
events,
|
|
190
|
+
currency: USD_CONTRACT_ID,
|
|
191
|
+
verifier: VENMO_VERIFIER,
|
|
192
|
+
chainId: base.id,
|
|
193
|
+
includeHistory: true,
|
|
194
|
+
});
|
|
195
|
+
assert.ok(Array.isArray(result), 'Should return array');
|
|
196
|
+
assert.equal(result.length, 2);
|
|
197
|
+
});
|
|
198
|
+
it('should use fallback rate when no matching rate found', () => {
|
|
199
|
+
const fallbackRate = {
|
|
200
|
+
currency: USD_CONTRACT_ID,
|
|
201
|
+
value: '999000000000000000',
|
|
202
|
+
verifier: VENMO_VERIFIER,
|
|
203
|
+
};
|
|
204
|
+
const result = getConversionRate({
|
|
205
|
+
events: [],
|
|
206
|
+
currency: USD_CONTRACT_ID,
|
|
207
|
+
verifier: VENMO_VERIFIER,
|
|
208
|
+
chainId: base.id,
|
|
209
|
+
fallbackRate,
|
|
210
|
+
});
|
|
211
|
+
assert.ok(result, 'Should return fallback rate');
|
|
212
|
+
assert.ok(!Array.isArray(result));
|
|
213
|
+
assert.equal(result.value, '999000000000000000');
|
|
214
|
+
});
|
|
215
|
+
it('should not use fallback rate when currency does not match', () => {
|
|
216
|
+
const fallbackRate = {
|
|
217
|
+
currency: EUR_CONTRACT_ID,
|
|
218
|
+
value: '999000000000000000',
|
|
219
|
+
verifier: VENMO_VERIFIER,
|
|
220
|
+
};
|
|
221
|
+
const result = getConversionRate({
|
|
222
|
+
events: [],
|
|
223
|
+
currency: USD_CONTRACT_ID,
|
|
224
|
+
verifier: VENMO_VERIFIER,
|
|
225
|
+
chainId: base.id,
|
|
226
|
+
fallbackRate,
|
|
227
|
+
});
|
|
228
|
+
assert.equal(result, null);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
describe('extractCurrencies', () => {
|
|
232
|
+
it('should extract currencies from provider rates', () => {
|
|
233
|
+
const providerRates = new Map([
|
|
234
|
+
[
|
|
235
|
+
'venmo',
|
|
236
|
+
new Map([
|
|
237
|
+
[USD_CONTRACT_ID, [createMockEvent()]],
|
|
238
|
+
[EUR_CONTRACT_ID, [createMockEvent({ currency: EUR_CONTRACT_ID })]],
|
|
239
|
+
]),
|
|
240
|
+
],
|
|
241
|
+
]);
|
|
242
|
+
const currencies = extractCurrencies({ providerRates });
|
|
243
|
+
assert.equal(currencies.length, 2);
|
|
244
|
+
assert.ok(currencies.includes(USD_CONTRACT_ID));
|
|
245
|
+
assert.ok(currencies.includes(EUR_CONTRACT_ID));
|
|
246
|
+
});
|
|
247
|
+
it('should filter by providers when specified', () => {
|
|
248
|
+
const providerRates = new Map([
|
|
249
|
+
['venmo', new Map([[USD_CONTRACT_ID, [createMockEvent()]]])],
|
|
250
|
+
['zelle', new Map([[EUR_CONTRACT_ID, [createMockEvent({ currency: EUR_CONTRACT_ID })]]])],
|
|
251
|
+
]);
|
|
252
|
+
const currencies = extractCurrencies({
|
|
253
|
+
providerRates,
|
|
254
|
+
providersOnly: ['venmo'],
|
|
255
|
+
});
|
|
256
|
+
assert.equal(currencies.length, 1);
|
|
257
|
+
assert.ok(currencies.includes(USD_CONTRACT_ID));
|
|
258
|
+
});
|
|
259
|
+
it('should filter by currencies when specified', () => {
|
|
260
|
+
const providerRates = new Map([
|
|
261
|
+
[
|
|
262
|
+
'venmo',
|
|
263
|
+
new Map([
|
|
264
|
+
[USD_CONTRACT_ID, [createMockEvent()]],
|
|
265
|
+
[EUR_CONTRACT_ID, [createMockEvent({ currency: EUR_CONTRACT_ID })]],
|
|
266
|
+
]),
|
|
267
|
+
],
|
|
268
|
+
]);
|
|
269
|
+
const currencies = extractCurrencies({
|
|
270
|
+
providerRates,
|
|
271
|
+
currenciesOnly: [USD_CONTRACT_ID],
|
|
272
|
+
});
|
|
273
|
+
assert.equal(currencies.length, 1);
|
|
274
|
+
assert.ok(currencies.includes(USD_CONTRACT_ID));
|
|
275
|
+
});
|
|
276
|
+
it('should return empty array for empty provider rates', () => {
|
|
277
|
+
const currencies = extractCurrencies({ providerRates: new Map() });
|
|
278
|
+
assert.equal(currencies.length, 0);
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
describe('getLatestRateForCurrency', () => {
|
|
282
|
+
it('should return null for empty provider rates', () => {
|
|
283
|
+
const result = getLatestRateForCurrency({
|
|
284
|
+
providerRates: new Map(),
|
|
285
|
+
currency: USD_CONTRACT_ID,
|
|
286
|
+
});
|
|
287
|
+
assert.equal(result, null);
|
|
288
|
+
});
|
|
289
|
+
it('should return latest rate by timestamp', () => {
|
|
290
|
+
const oldRate = createMockEvent({
|
|
291
|
+
transaction: { hash: '0x1', block: { timestamp: '1700000000' } },
|
|
292
|
+
});
|
|
293
|
+
const newRate = createMockEvent({
|
|
294
|
+
transaction: { hash: '0x2', block: { timestamp: '1700001000' } },
|
|
295
|
+
verifier: ZELLE_VERIFIER,
|
|
296
|
+
});
|
|
297
|
+
const providerRates = new Map([
|
|
298
|
+
['venmo', new Map([[USD_CONTRACT_ID, oldRate]])],
|
|
299
|
+
['zelle', new Map([[USD_CONTRACT_ID, newRate]])],
|
|
300
|
+
]);
|
|
301
|
+
const result = getLatestRateForCurrency({
|
|
302
|
+
providerRates,
|
|
303
|
+
currency: USD_CONTRACT_ID,
|
|
304
|
+
});
|
|
305
|
+
assert.ok(result);
|
|
306
|
+
assert.equal(result.transaction.block.timestamp, '1700001000');
|
|
307
|
+
});
|
|
308
|
+
it('should prefer specified provider when timestamps match', () => {
|
|
309
|
+
const rate = createMockEvent({
|
|
310
|
+
transaction: { hash: '0x1', block: { timestamp: '1700000000' } },
|
|
311
|
+
});
|
|
312
|
+
const providerRates = new Map([
|
|
313
|
+
['venmo', new Map([[USD_CONTRACT_ID, rate]])],
|
|
314
|
+
['zelle', new Map([[USD_CONTRACT_ID, { ...rate, verifier: ZELLE_VERIFIER }]])],
|
|
315
|
+
]);
|
|
316
|
+
const result = getLatestRateForCurrency({
|
|
317
|
+
providerRates,
|
|
318
|
+
currency: USD_CONTRACT_ID,
|
|
319
|
+
preferredProvider: 'venmo',
|
|
320
|
+
});
|
|
321
|
+
assert.ok(result);
|
|
322
|
+
assert.equal(result.verifier, VENMO_VERIFIER);
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
describe('getPrimaryConversionRate', () => {
|
|
326
|
+
it('should return null for empty provider rates', () => {
|
|
327
|
+
const result = getPrimaryConversionRate(new Map());
|
|
328
|
+
assert.equal(result, null);
|
|
329
|
+
});
|
|
330
|
+
it('should prioritize USD over other currencies', () => {
|
|
331
|
+
const usdRate = createMockEvent({ currency: USD_CONTRACT_ID });
|
|
332
|
+
const eurRate = createMockEvent({ currency: EUR_CONTRACT_ID });
|
|
333
|
+
const providerRates = new Map([
|
|
334
|
+
['venmo', new Map([[EUR_CONTRACT_ID, eurRate]])],
|
|
335
|
+
['zelle', new Map([[USD_CONTRACT_ID, usdRate]])],
|
|
336
|
+
]);
|
|
337
|
+
const result = getPrimaryConversionRate(providerRates);
|
|
338
|
+
assert.ok(result);
|
|
339
|
+
assert.equal(result.currency, USD_CONTRACT_ID);
|
|
340
|
+
});
|
|
341
|
+
it('should return first available rate if no USD', () => {
|
|
342
|
+
const eurRate = createMockEvent({ currency: EUR_CONTRACT_ID });
|
|
343
|
+
const providerRates = new Map([
|
|
344
|
+
['venmo', new Map([[EUR_CONTRACT_ID, eurRate]])],
|
|
345
|
+
]);
|
|
346
|
+
const result = getPrimaryConversionRate(providerRates);
|
|
347
|
+
assert.ok(result);
|
|
348
|
+
assert.equal(result.currency, EUR_CONTRACT_ID);
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
describe('getPrimaryRateForCurrency', () => {
|
|
352
|
+
it('should return rate for specified currency', () => {
|
|
353
|
+
const eurRate = createMockEvent({ currency: EUR_CONTRACT_ID });
|
|
354
|
+
const providerRates = new Map([
|
|
355
|
+
['venmo', new Map([[EUR_CONTRACT_ID, eurRate]])],
|
|
356
|
+
]);
|
|
357
|
+
const result = getPrimaryRateForCurrency(providerRates, EUR_CONTRACT_ID);
|
|
358
|
+
assert.ok(result);
|
|
359
|
+
assert.equal(result.currency, EUR_CONTRACT_ID);
|
|
360
|
+
});
|
|
361
|
+
it('should return null if currency not found', () => {
|
|
362
|
+
const usdRate = createMockEvent({ currency: USD_CONTRACT_ID });
|
|
363
|
+
const providerRates = new Map([
|
|
364
|
+
['venmo', new Map([[USD_CONTRACT_ID, usdRate]])],
|
|
365
|
+
]);
|
|
366
|
+
const result = getPrimaryRateForCurrency(providerRates, EUR_CONTRACT_ID);
|
|
367
|
+
assert.equal(result, null);
|
|
368
|
+
});
|
|
369
|
+
});
|
|
370
|
+
describe('getPrimaryVerifier', () => {
|
|
371
|
+
it('should return verifier from primary rate', () => {
|
|
372
|
+
const rate = createMockEvent({ verifier: VENMO_VERIFIER });
|
|
373
|
+
const providerRates = new Map([
|
|
374
|
+
['venmo', new Map([[USD_CONTRACT_ID, rate]])],
|
|
375
|
+
]);
|
|
376
|
+
const result = getPrimaryVerifier(providerRates);
|
|
377
|
+
assert.equal(result, VENMO_VERIFIER);
|
|
378
|
+
});
|
|
379
|
+
it('should return null for empty rates', () => {
|
|
380
|
+
const result = getPrimaryVerifier(new Map());
|
|
381
|
+
assert.equal(result, null);
|
|
382
|
+
});
|
|
383
|
+
});
|
|
384
|
+
describe('getPrimaryCurrency', () => {
|
|
385
|
+
it('should return currency from primary rate', () => {
|
|
386
|
+
const rate = createMockEvent({ currency: USD_CONTRACT_ID });
|
|
387
|
+
const providerRates = new Map([
|
|
388
|
+
['venmo', new Map([[USD_CONTRACT_ID, rate]])],
|
|
389
|
+
]);
|
|
390
|
+
const result = getPrimaryCurrency(providerRates);
|
|
391
|
+
assert.equal(result, USD_CONTRACT_ID);
|
|
392
|
+
});
|
|
393
|
+
it('should return null for empty rates', () => {
|
|
394
|
+
const result = getPrimaryCurrency(new Map());
|
|
395
|
+
assert.equal(result, null);
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
describe('convertTokenInputToCurrency', () => {
|
|
399
|
+
it('should convert token amount at 1:1 rate', () => {
|
|
400
|
+
const rate = 10n ** 18n; // 1.0 rate
|
|
401
|
+
const amountOutInt = 100000000n; // 100 USDC
|
|
402
|
+
const result = convertTokenInputToCurrency({
|
|
403
|
+
token: MOCK_TOKEN,
|
|
404
|
+
amountOutInt,
|
|
405
|
+
rate,
|
|
406
|
+
});
|
|
407
|
+
// At 1:1, 100 tokens should give ~100 fiat units
|
|
408
|
+
// Result is rounded up to nearest cent (10^4 for USDC with 6 decimals)
|
|
409
|
+
assert.equal(result, 100000000n);
|
|
410
|
+
});
|
|
411
|
+
it('should convert token amount at 1.05 rate', () => {
|
|
412
|
+
const rate = 1050000000000000000n; // 1.05 rate
|
|
413
|
+
const amountOutInt = 100000000n; // 100 USDC
|
|
414
|
+
const result = convertTokenInputToCurrency({
|
|
415
|
+
token: MOCK_TOKEN,
|
|
416
|
+
amountOutInt,
|
|
417
|
+
rate,
|
|
418
|
+
});
|
|
419
|
+
// 100 * 1.05 = 105, rounded up to nearest cent
|
|
420
|
+
assert.equal(result, 105000000n);
|
|
421
|
+
});
|
|
422
|
+
it('should round up to nearest cent', () => {
|
|
423
|
+
const rate = 10n ** 18n;
|
|
424
|
+
const amountOutInt = 100000001n; // 100.000001 USDC
|
|
425
|
+
const result = convertTokenInputToCurrency({
|
|
426
|
+
token: MOCK_TOKEN,
|
|
427
|
+
amountOutInt,
|
|
428
|
+
rate,
|
|
429
|
+
});
|
|
430
|
+
// Should round up from 100.000001 to 100.01 (nearest cent in 6 decimals)
|
|
431
|
+
assert.equal(result, 100010000n);
|
|
432
|
+
});
|
|
433
|
+
});
|
|
434
|
+
describe('convertCurrencyToTokenOutput', () => {
|
|
435
|
+
it('should convert fiat to tokens at 1:1 rate', () => {
|
|
436
|
+
const rate = 10n ** 18n;
|
|
437
|
+
const currencyAmountInt = 10000n; // $100.00 in cents
|
|
438
|
+
const result = convertCurrencyToTokenOutput({
|
|
439
|
+
token: MOCK_TOKEN,
|
|
440
|
+
currency: SUPPORTED_CURRENCIES.USD,
|
|
441
|
+
currencyAmountInt,
|
|
442
|
+
rate,
|
|
443
|
+
});
|
|
444
|
+
// At 1:1, $100 should give 100 USDC = 100_000000
|
|
445
|
+
assert.equal(result, 100000000n);
|
|
446
|
+
});
|
|
447
|
+
it('should convert fiat to tokens at 1.05 rate', () => {
|
|
448
|
+
const rate = 1050000000000000000n; // 1.05 rate
|
|
449
|
+
const currencyAmountInt = 10500n; // $105.00 in cents
|
|
450
|
+
const result = convertCurrencyToTokenOutput({
|
|
451
|
+
token: MOCK_TOKEN,
|
|
452
|
+
currency: SUPPORTED_CURRENCIES.USD,
|
|
453
|
+
currencyAmountInt,
|
|
454
|
+
rate,
|
|
455
|
+
});
|
|
456
|
+
// $105 at 1.05 rate should give 100 USDC
|
|
457
|
+
assert.equal(result, 100000000n);
|
|
458
|
+
});
|
|
459
|
+
it('should floor to smallest token unit', () => {
|
|
460
|
+
const rate = 10n ** 18n;
|
|
461
|
+
const currencyAmountInt = 10001n; // $100.01
|
|
462
|
+
const result = convertCurrencyToTokenOutput({
|
|
463
|
+
token: MOCK_TOKEN,
|
|
464
|
+
currency: SUPPORTED_CURRENCIES.USD,
|
|
465
|
+
currencyAmountInt,
|
|
466
|
+
rate,
|
|
467
|
+
});
|
|
468
|
+
// $100.01 at 1:1 = 100.01 USDC = 100_010000 base units
|
|
469
|
+
// Floored to smallest unit (10^4 for 6-2 decimal difference)
|
|
470
|
+
assert.equal(result, 100010000n);
|
|
471
|
+
});
|
|
472
|
+
});
|
|
473
|
+
});
|