@diviswap/sdk 1.7.6
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/LICENSE +21 -0
- package/README.md +510 -0
- package/bin/create-diviswap-app.js +25 -0
- package/bin/diviswap-sdk.js +4 -0
- package/dist/cli/index.js +1888 -0
- package/dist/cli/templates/nextjs-app/actions.ts.hbs +259 -0
- package/dist/cli/templates/nextjs-app/api-hooks.ts.hbs +439 -0
- package/dist/cli/templates/nextjs-app/api-route.ts.hbs +502 -0
- package/dist/cli/templates/nextjs-app/auth-context.tsx.hbs +59 -0
- package/dist/cli/templates/nextjs-app/client.ts.hbs +116 -0
- package/dist/cli/templates/nextjs-app/dashboard-hooks.ts.hbs +180 -0
- package/dist/cli/templates/nextjs-app/example-page.tsx.hbs +276 -0
- package/dist/cli/templates/nextjs-app/hooks.ts.hbs +252 -0
- package/dist/cli/templates/nextjs-app/kyc-hooks.ts.hbs +87 -0
- package/dist/cli/templates/nextjs-app/kyc-wizard.css.hbs +433 -0
- package/dist/cli/templates/nextjs-app/kyc-wizard.tsx.hbs +711 -0
- package/dist/cli/templates/nextjs-app/layout-wrapper.tsx.hbs +13 -0
- package/dist/cli/templates/nextjs-app/layout.tsx.hbs +13 -0
- package/dist/cli/templates/nextjs-app/middleware.ts.hbs +49 -0
- package/dist/cli/templates/nextjs-app/provider-wrapper.tsx.hbs +8 -0
- package/dist/cli/templates/nextjs-app/provider.tsx.hbs +408 -0
- package/dist/cli/templates/nextjs-app/setup-provider.tsx.hbs +25 -0
- package/dist/cli/templates/nextjs-app/types.ts.hbs +159 -0
- package/dist/cli/templates/react/api-client-wrapper.ts.hbs +89 -0
- package/dist/cli/templates/react/example.tsx.hbs +69 -0
- package/dist/cli/templates/react/tanstack-hooks.ts.hbs +185 -0
- package/dist/cli/templates/webhooks/nextjs.hbs +98 -0
- package/dist/index.d.mts +91 -0
- package/dist/index.d.ts +91 -0
- package/dist/index.js +2339 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2313 -0
- package/dist/index.mjs.map +1 -0
- package/dist/react/index.d.mts +192 -0
- package/dist/react/index.d.ts +192 -0
- package/dist/react/index.js +1083 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/index.mjs +1064 -0
- package/dist/react/index.mjs.map +1 -0
- package/dist/wallet-BEGvzNtB.d.mts +1614 -0
- package/dist/wallet-BEGvzNtB.d.ts +1614 -0
- package/package.json +102 -0
- package/src/cli/templates/index.ts +65 -0
- package/src/cli/templates/nextjs-app/actions.ts.hbs +259 -0
- package/src/cli/templates/nextjs-app/api-hooks.ts.hbs +439 -0
- package/src/cli/templates/nextjs-app/api-route.ts.hbs +502 -0
- package/src/cli/templates/nextjs-app/auth-context.tsx.hbs +59 -0
- package/src/cli/templates/nextjs-app/client.ts.hbs +116 -0
- package/src/cli/templates/nextjs-app/dashboard-hooks.ts.hbs +180 -0
- package/src/cli/templates/nextjs-app/example-page.tsx.hbs +276 -0
- package/src/cli/templates/nextjs-app/hooks.ts.hbs +252 -0
- package/src/cli/templates/nextjs-app/kyc-hooks.ts.hbs +87 -0
- package/src/cli/templates/nextjs-app/kyc-wizard.css.hbs +433 -0
- package/src/cli/templates/nextjs-app/kyc-wizard.tsx.hbs +711 -0
- package/src/cli/templates/nextjs-app/layout-wrapper.tsx.hbs +13 -0
- package/src/cli/templates/nextjs-app/layout.tsx.hbs +13 -0
- package/src/cli/templates/nextjs-app/middleware.ts.hbs +49 -0
- package/src/cli/templates/nextjs-app/provider-wrapper.tsx.hbs +8 -0
- package/src/cli/templates/nextjs-app/provider.tsx.hbs +408 -0
- package/src/cli/templates/nextjs-app/setup-provider.tsx.hbs +25 -0
- package/src/cli/templates/nextjs-app/types.ts.hbs +159 -0
- package/src/cli/templates/react/api-client-wrapper.ts.hbs +89 -0
- package/src/cli/templates/react/example.tsx.hbs +69 -0
- package/src/cli/templates/react/tanstack-hooks.ts.hbs +185 -0
- package/src/cli/templates/shared/client.ts +78 -0
- package/src/cli/templates/webhooks/nextjs.hbs +98 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,2339 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var crypto = require('crypto');
|
|
4
|
+
|
|
5
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
6
|
+
|
|
7
|
+
var crypto__default = /*#__PURE__*/_interopDefault(crypto);
|
|
8
|
+
|
|
9
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
10
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
11
|
+
}) : x)(function(x) {
|
|
12
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
13
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
// src/errors.ts
|
|
17
|
+
var DiviswapError = class _DiviswapError extends Error {
|
|
18
|
+
constructor(message, code, statusCode, details) {
|
|
19
|
+
super(message);
|
|
20
|
+
this.code = code;
|
|
21
|
+
this.statusCode = statusCode;
|
|
22
|
+
this.details = details;
|
|
23
|
+
this.name = "DiviswapError";
|
|
24
|
+
Object.setPrototypeOf(this, _DiviswapError.prototype);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
var AuthenticationError = class extends DiviswapError {
|
|
28
|
+
constructor(message, details) {
|
|
29
|
+
super(message, "AUTHENTICATION_ERROR", 401, details);
|
|
30
|
+
this.name = "AuthenticationError";
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
var ValidationError = class extends DiviswapError {
|
|
34
|
+
constructor(message, details) {
|
|
35
|
+
super(message, "VALIDATION_ERROR", 400, details);
|
|
36
|
+
this.name = "ValidationError";
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
var NetworkError = class extends DiviswapError {
|
|
40
|
+
constructor(message, details) {
|
|
41
|
+
super(message, "NETWORK_ERROR", void 0, details);
|
|
42
|
+
this.name = "NetworkError";
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
var ConfigurationError = class extends DiviswapError {
|
|
46
|
+
constructor(message, details) {
|
|
47
|
+
super(message, "CONFIGURATION_ERROR", void 0, details);
|
|
48
|
+
this.name = "ConfigurationError";
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
var LiberExError = DiviswapError;
|
|
52
|
+
|
|
53
|
+
// src/modules/auth.ts
|
|
54
|
+
var AuthModule = class {
|
|
55
|
+
constructor(client) {
|
|
56
|
+
this.client = client;
|
|
57
|
+
this.client.setRefreshCallback(this.refreshToken.bind(this));
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Register a new user
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* const { user, accessToken } = await diviswap.auth.register({
|
|
65
|
+
* email: 'user@example.com',
|
|
66
|
+
* password: 'secure-password',
|
|
67
|
+
* firstName: 'John',
|
|
68
|
+
* lastName: 'Doe'
|
|
69
|
+
* });
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
async register(data) {
|
|
73
|
+
const requestData = {
|
|
74
|
+
email: data.email,
|
|
75
|
+
password: data.password,
|
|
76
|
+
first_name: data.firstName || "Test",
|
|
77
|
+
last_name: data.lastName || "User",
|
|
78
|
+
// Individual object is REQUIRED by the backend
|
|
79
|
+
individual: {
|
|
80
|
+
// Use 'USA' (3-letter code) as seen in working lbx-landing implementation
|
|
81
|
+
residential_country_code: "USA",
|
|
82
|
+
residential_address_line_one: "123 Main Street",
|
|
83
|
+
residential_address_line_two: "",
|
|
84
|
+
residential_city: "Anytown",
|
|
85
|
+
residential_state: "CA",
|
|
86
|
+
residential_postal_code: "12345",
|
|
87
|
+
id_type: "ssn",
|
|
88
|
+
// Add id_type field as seen in lbx-landing
|
|
89
|
+
id_country_code: "USA",
|
|
90
|
+
dob: "1990-01-01",
|
|
91
|
+
id_number: "123456789"
|
|
92
|
+
// Remove dashes from SSN like lbx-landing does
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
if (data.individual) {
|
|
96
|
+
requestData.individual = data.individual;
|
|
97
|
+
}
|
|
98
|
+
if (data.phone) requestData.phone = data.phone;
|
|
99
|
+
if (data.referralCode) requestData.referral_code = data.referralCode;
|
|
100
|
+
const response = await this.client.post(
|
|
101
|
+
"/api/v1/register",
|
|
102
|
+
requestData,
|
|
103
|
+
{ useApiKey: true }
|
|
104
|
+
);
|
|
105
|
+
const authResponse = {
|
|
106
|
+
accessToken: response.access_token || response.accessToken,
|
|
107
|
+
refreshToken: response.refresh_token || response.refreshToken,
|
|
108
|
+
user: response.user || { id: response.user_id || response.id, email: data.email }
|
|
109
|
+
};
|
|
110
|
+
if (authResponse.accessToken) {
|
|
111
|
+
this.client.setTokens(authResponse.accessToken, authResponse.refreshToken);
|
|
112
|
+
}
|
|
113
|
+
return authResponse;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Login an existing user
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* const { user, accessToken } = await diviswap.auth.login({
|
|
121
|
+
* email: 'user@example.com',
|
|
122
|
+
* password: 'secure-password'
|
|
123
|
+
* });
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
async login(credentials) {
|
|
127
|
+
const response = await this.client.post(
|
|
128
|
+
"/api/v1/login",
|
|
129
|
+
credentials,
|
|
130
|
+
{ useApiKey: true }
|
|
131
|
+
// useApiKey: true means use API key auth, not JWT
|
|
132
|
+
);
|
|
133
|
+
const authResponse = {
|
|
134
|
+
accessToken: response.access_token || response.accessToken,
|
|
135
|
+
refreshToken: response.refresh_token || response.refreshToken,
|
|
136
|
+
user: response.user || { id: response.user_id || response.id, email: credentials.email }
|
|
137
|
+
};
|
|
138
|
+
if (authResponse.accessToken) {
|
|
139
|
+
this.client.setTokens(authResponse.accessToken, authResponse.refreshToken);
|
|
140
|
+
}
|
|
141
|
+
return authResponse;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Get current user profile
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* ```typescript
|
|
148
|
+
* const user = await diviswap.auth.getProfile();
|
|
149
|
+
* console.log(user.email, user.kycStatus);
|
|
150
|
+
* ```
|
|
151
|
+
*
|
|
152
|
+
* Note: This endpoint is not yet available in the v1 API
|
|
153
|
+
*/
|
|
154
|
+
async getProfile() {
|
|
155
|
+
throw new Error("User profile endpoint not available in v1 API yet");
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Update user profile
|
|
159
|
+
*
|
|
160
|
+
* @example
|
|
161
|
+
* ```typescript
|
|
162
|
+
* const updatedUser = await diviswap.auth.updateProfile({
|
|
163
|
+
* firstName: 'Jane',
|
|
164
|
+
* lastName: 'Smith'
|
|
165
|
+
* });
|
|
166
|
+
* ```
|
|
167
|
+
*
|
|
168
|
+
* Note: This endpoint is not yet available in the v1 API
|
|
169
|
+
*/
|
|
170
|
+
async updateProfile(_data) {
|
|
171
|
+
throw new Error("Update profile endpoint not available in v1 API yet");
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Request password reset
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```typescript
|
|
178
|
+
* await diviswap.auth.requestPasswordReset('user@example.com');
|
|
179
|
+
* ```
|
|
180
|
+
*
|
|
181
|
+
* Note: This endpoint is not yet available in the v1 API
|
|
182
|
+
*/
|
|
183
|
+
async requestPasswordReset(_email) {
|
|
184
|
+
throw new Error("Password reset endpoint not available in v1 API yet");
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Set new password with reset token
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```typescript
|
|
191
|
+
* await diviswap.auth.setPassword('reset-token', 'new-secure-password');
|
|
192
|
+
* ```
|
|
193
|
+
*
|
|
194
|
+
* Note: This endpoint is not yet available in the v1 API
|
|
195
|
+
*/
|
|
196
|
+
async setPassword(_token, _password) {
|
|
197
|
+
throw new Error("Set password endpoint not available in v1 API yet");
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Logout current user
|
|
201
|
+
*
|
|
202
|
+
* @example
|
|
203
|
+
* ```typescript
|
|
204
|
+
* await diviswap.auth.logout();
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
async logout() {
|
|
208
|
+
this.client.clearTokens();
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Get compliance status
|
|
212
|
+
* @deprecated Use diviswap.kyc.getComplianceStatus() instead
|
|
213
|
+
*/
|
|
214
|
+
async getComplianceStatus() {
|
|
215
|
+
console.warn("auth.getComplianceStatus() is deprecated. Use kyc.getComplianceStatus() instead.");
|
|
216
|
+
throw new Error("Compliance status endpoint not available in v1 API yet");
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Check if user is authenticated
|
|
220
|
+
*/
|
|
221
|
+
isAuthenticated() {
|
|
222
|
+
return !!this.client.tokenManager.getAccessToken();
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Refresh access token (internal)
|
|
226
|
+
*
|
|
227
|
+
* Note: This endpoint is not yet available in the v1 API
|
|
228
|
+
*/
|
|
229
|
+
async refreshToken(_refreshToken) {
|
|
230
|
+
throw new Error("Token refresh endpoint not available in v1 API yet");
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
// src/modules/payees.ts
|
|
235
|
+
var PayeesModule = class {
|
|
236
|
+
constructor(client) {
|
|
237
|
+
this.client = client;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Create a new payee (bank account)
|
|
241
|
+
*
|
|
242
|
+
* @example
|
|
243
|
+
* ```typescript
|
|
244
|
+
* // Bank account
|
|
245
|
+
* const bankAccount = await diviswap.payees.create({
|
|
246
|
+
* nickname: 'My Checking',
|
|
247
|
+
* accountNumber: '123456789',
|
|
248
|
+
* routingNumber: '021000021',
|
|
249
|
+
* accountType: 'checking',
|
|
250
|
+
* setAsDefault: true
|
|
251
|
+
* });
|
|
252
|
+
*
|
|
253
|
+
* // Debit card
|
|
254
|
+
* const debitCard = await diviswap.payees.create({
|
|
255
|
+
* nickname: 'My Debit Card',
|
|
256
|
+
* accountType: 'debit_card',
|
|
257
|
+
* debitCard: {
|
|
258
|
+
* number: '4111111111111111',
|
|
259
|
+
* expirationMonth: '12',
|
|
260
|
+
* expirationYear: '2025',
|
|
261
|
+
* cvv: '123'
|
|
262
|
+
* },
|
|
263
|
+
* setAsDefault: false
|
|
264
|
+
* });
|
|
265
|
+
* ```
|
|
266
|
+
*/
|
|
267
|
+
async create(data) {
|
|
268
|
+
try {
|
|
269
|
+
if (data.accountType === "debit_card") {
|
|
270
|
+
if (!data.debitCard) {
|
|
271
|
+
throw new Error("Debit card information is required for debit_card account type");
|
|
272
|
+
}
|
|
273
|
+
return await this.client.post("/api/v1/payees", {
|
|
274
|
+
name: data.nickname,
|
|
275
|
+
debit_card: {
|
|
276
|
+
number: data.debitCard.number,
|
|
277
|
+
expiration_month: data.debitCard.expirationMonth,
|
|
278
|
+
expiration_year: data.debitCard.expirationYear,
|
|
279
|
+
cvv: data.debitCard.cvv
|
|
280
|
+
},
|
|
281
|
+
set_as_default: data.setAsDefault || false
|
|
282
|
+
});
|
|
283
|
+
} else {
|
|
284
|
+
if (!data.accountNumber || !data.routingNumber) {
|
|
285
|
+
throw new Error("Account number and routing number are required for bank accounts");
|
|
286
|
+
}
|
|
287
|
+
return await this.client.post("/api/v1/payees", {
|
|
288
|
+
name: data.nickname,
|
|
289
|
+
account_number: data.accountNumber,
|
|
290
|
+
routing_number: data.routingNumber,
|
|
291
|
+
type: (data.accountType || "checking").toUpperCase(),
|
|
292
|
+
set_as_default: data.setAsDefault || false
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
} catch (error) {
|
|
296
|
+
throw new Error(`Failed to create payee: ${error.message}`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* List all payees
|
|
301
|
+
*
|
|
302
|
+
* @example
|
|
303
|
+
* ```typescript
|
|
304
|
+
* const payees = await diviswap.payees.list();
|
|
305
|
+
* const defaultPayee = payees.find(p => p.isDefault);
|
|
306
|
+
* ```
|
|
307
|
+
*/
|
|
308
|
+
async list() {
|
|
309
|
+
const response = await this.client.get("/api/v1/users/payees", { useApiKey: false });
|
|
310
|
+
return this.parsePayeesResponse(response);
|
|
311
|
+
}
|
|
312
|
+
parsePayeesResponse(response) {
|
|
313
|
+
if (Array.isArray(response)) {
|
|
314
|
+
return response;
|
|
315
|
+
}
|
|
316
|
+
if (response && typeof response === "object") {
|
|
317
|
+
if (response.data && Array.isArray(response.data)) {
|
|
318
|
+
return response.data;
|
|
319
|
+
}
|
|
320
|
+
if (response.payees && Array.isArray(response.payees)) {
|
|
321
|
+
return response.payees;
|
|
322
|
+
}
|
|
323
|
+
if (response.results && Array.isArray(response.results)) {
|
|
324
|
+
return response.results;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return [];
|
|
328
|
+
}
|
|
329
|
+
/**
|
|
330
|
+
* Get a specific payee
|
|
331
|
+
*
|
|
332
|
+
* @example
|
|
333
|
+
* ```typescript
|
|
334
|
+
* const payee = await diviswap.payees.get('payee-id');
|
|
335
|
+
* ```
|
|
336
|
+
*/
|
|
337
|
+
async get(payeeId) {
|
|
338
|
+
const payees = await this.list();
|
|
339
|
+
const payee = payees.find((p) => p.id === payeeId);
|
|
340
|
+
if (!payee) {
|
|
341
|
+
throw new Error(`Payee ${payeeId} not found`);
|
|
342
|
+
}
|
|
343
|
+
return payee;
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* Set a payee as default
|
|
347
|
+
*
|
|
348
|
+
* @example
|
|
349
|
+
* ```typescript
|
|
350
|
+
* await diviswap.payees.setDefault('payee-id');
|
|
351
|
+
* ```
|
|
352
|
+
*/
|
|
353
|
+
async setDefault(payeeId) {
|
|
354
|
+
return this.client.put("/api/v1/users/payees", {
|
|
355
|
+
payeeId,
|
|
356
|
+
setAsDefault: true
|
|
357
|
+
}, { useApiKey: false });
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Delete a payee
|
|
361
|
+
*
|
|
362
|
+
* @example
|
|
363
|
+
* ```typescript
|
|
364
|
+
* await diviswap.payees.delete('payee-id');
|
|
365
|
+
* ```
|
|
366
|
+
*/
|
|
367
|
+
async delete(payeeId) {
|
|
368
|
+
return this.client.delete(
|
|
369
|
+
`/api/v1/users/payees/${payeeId}`,
|
|
370
|
+
{ useApiKey: false }
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Get verification status of a payee
|
|
375
|
+
*
|
|
376
|
+
* @example
|
|
377
|
+
* ```typescript
|
|
378
|
+
* const status = await diviswap.payees.getVerificationStatus('payee-id');
|
|
379
|
+
* console.log(status.verified, status.microDepositsStatus);
|
|
380
|
+
* ```
|
|
381
|
+
*/
|
|
382
|
+
async getVerificationStatus(_payeeId) {
|
|
383
|
+
throw new Error("Payee verification status endpoint not available in v1 API yet");
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Verify a payee with micro-deposit amounts
|
|
387
|
+
*
|
|
388
|
+
* @example
|
|
389
|
+
* ```typescript
|
|
390
|
+
* const result = await diviswap.payees.verify('payee-id', {
|
|
391
|
+
* amount1: 0.32,
|
|
392
|
+
* amount2: 0.45
|
|
393
|
+
* });
|
|
394
|
+
* ```
|
|
395
|
+
*/
|
|
396
|
+
async verify(_payeeId, _data) {
|
|
397
|
+
throw new Error("Payee verification endpoint not available in v1 API yet");
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Get the default payee
|
|
401
|
+
*
|
|
402
|
+
* @example
|
|
403
|
+
* ```typescript
|
|
404
|
+
* const defaultPayee = await diviswap.payees.getDefault();
|
|
405
|
+
* if (!defaultPayee) {
|
|
406
|
+
* console.log('No default payee set');
|
|
407
|
+
* }
|
|
408
|
+
* ```
|
|
409
|
+
*/
|
|
410
|
+
async getDefault() {
|
|
411
|
+
const payees = await this.list();
|
|
412
|
+
return payees.find((p) => p.isDefault) || null;
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
// src/constants/addresses.ts
|
|
417
|
+
var PRODUCTION_DEPOSIT_ADDRESSES = {
|
|
418
|
+
ethereum: "0xa3da8ffC1D131F917f9D0Ac078D82914e75d9651",
|
|
419
|
+
base: "0xa3da8ffC1D131F917f9D0Ac078D82914e75d9651",
|
|
420
|
+
polygon: "0xa3da8ffC1D131F917f9D0Ac078D82914e75d9651",
|
|
421
|
+
solana: "EokHeEoZpGtBNeuJKRPvtxzXqaXz6bM5zsVB5TVPtNee"
|
|
422
|
+
};
|
|
423
|
+
var SANDBOX_DEPOSIT_ADDRESSES = {
|
|
424
|
+
ethereum: "0xa3da8ffC1D131F917f9D0Ac078D82914e75d9651",
|
|
425
|
+
// Same address for all environments
|
|
426
|
+
base: "0xa3da8ffC1D131F917f9D0Ac078D82914e75d9651",
|
|
427
|
+
polygon: "0xa3da8ffC1D131F917f9D0Ac078D82914e75d9651",
|
|
428
|
+
solana: "EokHeEoZpGtBNeuJKRPvtxzXqaXz6bM5zsVB5TVPtNee"
|
|
429
|
+
};
|
|
430
|
+
var DEVELOPMENT_DEPOSIT_ADDRESSES = {
|
|
431
|
+
ethereum: "0xa3da8ffC1D131F917f9D0Ac078D82914e75d9651",
|
|
432
|
+
// Same unified address
|
|
433
|
+
base: "0xa3da8ffC1D131F917f9D0Ac078D82914e75d9651",
|
|
434
|
+
polygon: "0xa3da8ffC1D131F917f9D0Ac078D82914e75d9651",
|
|
435
|
+
solana: "EokHeEoZpGtBNeuJKRPvtxzXqaXz6bM5zsVB5TVPtNee"
|
|
436
|
+
};
|
|
437
|
+
function getDepositAddresses(environment) {
|
|
438
|
+
switch (environment) {
|
|
439
|
+
case "production":
|
|
440
|
+
return PRODUCTION_DEPOSIT_ADDRESSES;
|
|
441
|
+
case "sandbox":
|
|
442
|
+
return SANDBOX_DEPOSIT_ADDRESSES;
|
|
443
|
+
case "development":
|
|
444
|
+
return DEVELOPMENT_DEPOSIT_ADDRESSES;
|
|
445
|
+
default:
|
|
446
|
+
return SANDBOX_DEPOSIT_ADDRESSES;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
var CHAIN_ID_TO_NAME = {
|
|
450
|
+
1: "ethereum",
|
|
451
|
+
5: "goerli",
|
|
452
|
+
11155111: "sepolia",
|
|
453
|
+
137: "polygon",
|
|
454
|
+
80001: "mumbai",
|
|
455
|
+
8453: "base",
|
|
456
|
+
84531: "base-goerli",
|
|
457
|
+
84532: "base-sepolia"
|
|
458
|
+
};
|
|
459
|
+
var CHAIN_NAME_TO_ID = {
|
|
460
|
+
"ethereum": 1,
|
|
461
|
+
"eth": 1,
|
|
462
|
+
"goerli": 5,
|
|
463
|
+
"sepolia": 11155111,
|
|
464
|
+
"polygon": 137,
|
|
465
|
+
"matic": 137,
|
|
466
|
+
"mumbai": 80001,
|
|
467
|
+
"base": 8453,
|
|
468
|
+
"base-goerli": 84531,
|
|
469
|
+
"base-sepolia": 84532,
|
|
470
|
+
"solana": 999999,
|
|
471
|
+
// Solana mainnet (custom ID for database compatibility)
|
|
472
|
+
"sol": 999999
|
|
473
|
+
};
|
|
474
|
+
var STABLECOIN_ADDRESSES = {
|
|
475
|
+
ethereum: {
|
|
476
|
+
USDT: "0xdac17f958d2ee523a2206206994597c13d831ec7",
|
|
477
|
+
USDC: "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48",
|
|
478
|
+
DAI: "0x6b175474e89094c44da98b954eedeac495271d0f"
|
|
479
|
+
},
|
|
480
|
+
base: {
|
|
481
|
+
USDC: "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913",
|
|
482
|
+
USDbC: "0xd9aaec86b65d86f6a7b5b1b0c42ffa531710b6ca"
|
|
483
|
+
// Bridged USDC
|
|
484
|
+
},
|
|
485
|
+
polygon: {
|
|
486
|
+
USDT: "0xc2132d05d31c914a87c6611c10748aeb04b58e8f",
|
|
487
|
+
USDC: "0x2791bca1f2de4661ed88a30c99a7a9449aa84174",
|
|
488
|
+
DAI: "0x8f3cf7ad23cd3cadbd9735aff958023239c6a063"
|
|
489
|
+
},
|
|
490
|
+
solana: {
|
|
491
|
+
USDC: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
|
|
492
|
+
// USDC SPL token
|
|
493
|
+
USDT: "Es9vMFrzaCERmJfrF4H2FYD4KCoNkY11McCe8BenwNYB",
|
|
494
|
+
// USDT SPL token
|
|
495
|
+
SOL: "So11111111111111111111111111111111111111112"
|
|
496
|
+
// Wrapped SOL
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
|
|
500
|
+
// src/modules/transactions.ts
|
|
501
|
+
var TransactionsModule = class {
|
|
502
|
+
constructor(client, environment = "sandbox") {
|
|
503
|
+
this.client = client;
|
|
504
|
+
this.depositAddresses = getDepositAddresses(environment);
|
|
505
|
+
}
|
|
506
|
+
/**
|
|
507
|
+
* Map chain name to chain ID
|
|
508
|
+
* @private
|
|
509
|
+
*/
|
|
510
|
+
getChainId(chain) {
|
|
511
|
+
const chainId = CHAIN_NAME_TO_ID[chain.toLowerCase()];
|
|
512
|
+
return chainId ? chainId.toString() : chain;
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Get deposit address for a given chain
|
|
516
|
+
* @private
|
|
517
|
+
*/
|
|
518
|
+
getDepositAddress(chain) {
|
|
519
|
+
const normalizedChain = chain.toLowerCase();
|
|
520
|
+
const chainName = normalizedChain === "eth" ? "ethereum" : normalizedChain === "matic" ? "polygon" : normalizedChain;
|
|
521
|
+
const address = this.depositAddresses[chainName];
|
|
522
|
+
if (!address || address === "0x..." || address.includes("TODO")) {
|
|
523
|
+
throw new Error(`Deposit address not configured for chain: ${chain}. Please contact support.`);
|
|
524
|
+
}
|
|
525
|
+
return address;
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Get all configured deposit addresses
|
|
529
|
+
* @returns Object mapping chain names to deposit addresses
|
|
530
|
+
*/
|
|
531
|
+
getDepositAddresses() {
|
|
532
|
+
return { ...this.depositAddresses };
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Get deposit address for a specific chain
|
|
536
|
+
* @param chain - Chain name (e.g., 'ethereum', 'base', 'polygon')
|
|
537
|
+
* @returns The deposit address for the specified chain
|
|
538
|
+
* @throws Error if chain is not supported
|
|
539
|
+
*/
|
|
540
|
+
getDepositAddressForChain(chain) {
|
|
541
|
+
return this.getDepositAddress(chain);
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Create an onramp transaction (fiat to crypto)
|
|
545
|
+
*
|
|
546
|
+
* @example
|
|
547
|
+
* ```typescript
|
|
548
|
+
* const transaction = await diviswap.transactions.onramp({
|
|
549
|
+
* amount: 100,
|
|
550
|
+
* currency: 'USD',
|
|
551
|
+
* payeeId: 'payee-id',
|
|
552
|
+
* toAddress: '0xa3da8ffC1D131F917f9D0Ac078D82914e75d9651',
|
|
553
|
+
* chain: 'ethereum'
|
|
554
|
+
* });
|
|
555
|
+
* ```
|
|
556
|
+
*
|
|
557
|
+
* @throws {Error} If user is not KYC approved
|
|
558
|
+
*/
|
|
559
|
+
async onramp(_data) {
|
|
560
|
+
throw new Error("Onramp endpoint not available in v1 API yet");
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Create an offramp transaction (crypto to fiat)
|
|
564
|
+
*
|
|
565
|
+
* ⚠️ IMPORTANT: Follow the production pattern:
|
|
566
|
+
* 1. Send crypto transaction on blockchain FIRST
|
|
567
|
+
* 2. Get the transaction hash
|
|
568
|
+
* 3. Call this method with the hash
|
|
569
|
+
*
|
|
570
|
+
* @example
|
|
571
|
+
* ```typescript
|
|
572
|
+
* import { extractTransactionHash } from '@diviswap/sdk';
|
|
573
|
+
*
|
|
574
|
+
* // 1. Send crypto transaction first and get tx hash
|
|
575
|
+
* const txResult = await sendTransactionAsync({
|
|
576
|
+
* to: depositAddress,
|
|
577
|
+
* value: parseEther('0.5')
|
|
578
|
+
* });
|
|
579
|
+
*
|
|
580
|
+
* // 2. Extract hash (handles different wallet return types)
|
|
581
|
+
* const txHash = extractTransactionHash(txResult);
|
|
582
|
+
*
|
|
583
|
+
* // 3. Record the transaction
|
|
584
|
+
* const transaction = await diviswap.transactions.offramp({
|
|
585
|
+
* amount: 0.5,
|
|
586
|
+
* currency: 'ETH',
|
|
587
|
+
* fromAddress: '0xa3da8ffC1D131F917f9D0Ac078D82914e75d9651',
|
|
588
|
+
* payeeId: 'payee-id',
|
|
589
|
+
* chain: 'ethereum',
|
|
590
|
+
* txHash: txHash
|
|
591
|
+
* });
|
|
592
|
+
* ```
|
|
593
|
+
*
|
|
594
|
+
* @throws {Error} If user is not KYC approved
|
|
595
|
+
*/
|
|
596
|
+
async offramp(data) {
|
|
597
|
+
if (!data.txHash || data.txHash.trim() === "") {
|
|
598
|
+
throw new Error(
|
|
599
|
+
"txHash is required for offramp transactions."
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
const payload = {
|
|
603
|
+
payee_id: data.payeeId,
|
|
604
|
+
tx_hash: data.txHash,
|
|
605
|
+
// Required: must send crypto first
|
|
606
|
+
from_address: data.fromAddress,
|
|
607
|
+
to_address: data.toAddress || this.getDepositAddress(data.chain || "ethereum"),
|
|
608
|
+
amount: data.amount,
|
|
609
|
+
currency: data.currency,
|
|
610
|
+
chain_id: this.getChainId(data.chain || "ethereum")
|
|
611
|
+
};
|
|
612
|
+
if (data.memo) {
|
|
613
|
+
payload.memo = data.memo;
|
|
614
|
+
}
|
|
615
|
+
return this.client.post(
|
|
616
|
+
`/api/v1/transactions/offramp`,
|
|
617
|
+
payload,
|
|
618
|
+
{ useApiKey: false }
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
/**
|
|
622
|
+
* Create a test offramp transaction using the same production flow.
|
|
623
|
+
* Requires a transaction hash - send crypto first, then call this method.
|
|
624
|
+
*
|
|
625
|
+
* ⚠️ IMPORTANT: Follow the production pattern:
|
|
626
|
+
* 1. Send crypto transaction on blockchain FIRST
|
|
627
|
+
* 2. Get the transaction hash
|
|
628
|
+
* 3. Call this method with the hash
|
|
629
|
+
*
|
|
630
|
+
* @example
|
|
631
|
+
* ```typescript
|
|
632
|
+
* // 1. Send crypto transaction first and get tx hash
|
|
633
|
+
* const txHash = await sendCryptoTransaction({...});
|
|
634
|
+
*
|
|
635
|
+
* // 2. Record the transaction using production endpoint
|
|
636
|
+
* const transaction = await diviswap.transactions.offrampTest({
|
|
637
|
+
* amount: 0.1,
|
|
638
|
+
* currency: 'USDC',
|
|
639
|
+
* fromAddress: '0x...',
|
|
640
|
+
* toAddress: '0x...',
|
|
641
|
+
* payeeId: 'payee-id',
|
|
642
|
+
* chain: 'base',
|
|
643
|
+
* txHash: txHash
|
|
644
|
+
* });
|
|
645
|
+
* ```
|
|
646
|
+
*/
|
|
647
|
+
async offrampTest(data) {
|
|
648
|
+
if (!data.txHash || data.txHash.trim() === "") {
|
|
649
|
+
throw new Error(
|
|
650
|
+
"txHash is required for offramp transactions."
|
|
651
|
+
);
|
|
652
|
+
}
|
|
653
|
+
const payload = {
|
|
654
|
+
payee_id: data.payeeId,
|
|
655
|
+
tx_hash: data.txHash,
|
|
656
|
+
from_address: data.fromAddress,
|
|
657
|
+
to_address: data.toAddress || this.getDepositAddress(data.chain || "ethereum"),
|
|
658
|
+
amount: data.amount,
|
|
659
|
+
currency: data.currency,
|
|
660
|
+
chain_id: this.getChainId(data.chain || "ethereum")
|
|
661
|
+
};
|
|
662
|
+
if (data.memo) {
|
|
663
|
+
payload.memo = data.memo;
|
|
664
|
+
}
|
|
665
|
+
return this.client.post(
|
|
666
|
+
`/api/v1/transactions/offramp`,
|
|
667
|
+
payload,
|
|
668
|
+
{ useApiKey: false }
|
|
669
|
+
);
|
|
670
|
+
}
|
|
671
|
+
/**
|
|
672
|
+
* List transactions with optional filters
|
|
673
|
+
*
|
|
674
|
+
* @example
|
|
675
|
+
* ```typescript
|
|
676
|
+
* // Get all transactions
|
|
677
|
+
* const allTransactions = await diviswap.transactions.list();
|
|
678
|
+
*
|
|
679
|
+
* // Get only completed onramp transactions
|
|
680
|
+
* const completedOnramps = await diviswap.transactions.list({
|
|
681
|
+
* type: 'onramp',
|
|
682
|
+
* status: 'completed'
|
|
683
|
+
* });
|
|
684
|
+
* ```
|
|
685
|
+
*/
|
|
686
|
+
async list(filters) {
|
|
687
|
+
const params = new URLSearchParams();
|
|
688
|
+
if (filters) {
|
|
689
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
690
|
+
if (value !== void 0 && value !== null) {
|
|
691
|
+
params.append(key, value.toString());
|
|
692
|
+
}
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
const queryString = params.toString();
|
|
696
|
+
const path = `/api/v1/users/transactions${queryString ? `?${queryString}` : ""}`;
|
|
697
|
+
const response = await this.client.get(path, { useApiKey: false });
|
|
698
|
+
if (Array.isArray(response)) {
|
|
699
|
+
return response;
|
|
700
|
+
}
|
|
701
|
+
if (response && typeof response === "object") {
|
|
702
|
+
if (response.data && Array.isArray(response.data)) {
|
|
703
|
+
return response.data;
|
|
704
|
+
}
|
|
705
|
+
if (response.transactions && Array.isArray(response.transactions)) {
|
|
706
|
+
return response.transactions;
|
|
707
|
+
}
|
|
708
|
+
if (response.results && Array.isArray(response.results)) {
|
|
709
|
+
return response.results;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
return [];
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Get a specific transaction by ID
|
|
716
|
+
*
|
|
717
|
+
* @example
|
|
718
|
+
* ```typescript
|
|
719
|
+
* const transaction = await diviswap.transactions.get('transaction-id');
|
|
720
|
+
* console.log(transaction.status, transaction.amount);
|
|
721
|
+
* ```
|
|
722
|
+
*/
|
|
723
|
+
async get(transactionId) {
|
|
724
|
+
const transactions = await this.list();
|
|
725
|
+
const transaction = transactions.find((t) => t.id === transactionId);
|
|
726
|
+
if (!transaction) {
|
|
727
|
+
throw new Error(`Transaction ${transactionId} not found`);
|
|
728
|
+
}
|
|
729
|
+
return transaction;
|
|
730
|
+
}
|
|
731
|
+
/**
|
|
732
|
+
* Get fee estimate for a transaction
|
|
733
|
+
*
|
|
734
|
+
* @example
|
|
735
|
+
* ```typescript
|
|
736
|
+
* const estimate = await diviswap.transactions.estimateFees({
|
|
737
|
+
* amount: 100,
|
|
738
|
+
* currency: 'USD',
|
|
739
|
+
* type: 'onramp'
|
|
740
|
+
* });
|
|
741
|
+
* console.log(`Fee: $${estimate.fee}, Total: $${estimate.total}`);
|
|
742
|
+
* ```
|
|
743
|
+
*/
|
|
744
|
+
async estimateFees(params) {
|
|
745
|
+
return this.client.post("/api/v1/fees", params);
|
|
746
|
+
}
|
|
747
|
+
/**
|
|
748
|
+
* Get recent transactions (convenience method)
|
|
749
|
+
*
|
|
750
|
+
* @example
|
|
751
|
+
* ```typescript
|
|
752
|
+
* const recentTransactions = await diviswap.transactions.getRecent(10);
|
|
753
|
+
* ```
|
|
754
|
+
*/
|
|
755
|
+
async getRecent(limit = 10) {
|
|
756
|
+
return this.list({ limit });
|
|
757
|
+
}
|
|
758
|
+
/**
|
|
759
|
+
* Get transaction statistics
|
|
760
|
+
*
|
|
761
|
+
* @example
|
|
762
|
+
* ```typescript
|
|
763
|
+
* const stats = await diviswap.transactions.getStats();
|
|
764
|
+
* console.log(`Total volume: $${stats.totalVolume}`);
|
|
765
|
+
* ```
|
|
766
|
+
*/
|
|
767
|
+
async getStats() {
|
|
768
|
+
const transactions = await this.list();
|
|
769
|
+
const stats = transactions.reduce((acc, tx) => {
|
|
770
|
+
acc.totalTransactions++;
|
|
771
|
+
acc.totalVolume += tx.amount || 0;
|
|
772
|
+
if (tx.status === "pending" || tx.status === "processing") {
|
|
773
|
+
acc.pendingTransactions++;
|
|
774
|
+
} else if (tx.status === "completed") {
|
|
775
|
+
acc.completedTransactions++;
|
|
776
|
+
}
|
|
777
|
+
return acc;
|
|
778
|
+
}, {
|
|
779
|
+
totalTransactions: 0,
|
|
780
|
+
totalVolume: 0,
|
|
781
|
+
pendingTransactions: 0,
|
|
782
|
+
completedTransactions: 0
|
|
783
|
+
});
|
|
784
|
+
return stats;
|
|
785
|
+
}
|
|
786
|
+
/**
|
|
787
|
+
* Get stablecoin addresses for a specific chain
|
|
788
|
+
* @param chain - Chain name (e.g., 'ethereum', 'base', 'polygon')
|
|
789
|
+
* @returns Object mapping stablecoin symbols to contract addresses
|
|
790
|
+
*/
|
|
791
|
+
getStablecoinAddresses(chain) {
|
|
792
|
+
const normalizedChain = chain.toLowerCase();
|
|
793
|
+
const chainName = normalizedChain === "eth" ? "ethereum" : normalizedChain === "matic" ? "polygon" : normalizedChain;
|
|
794
|
+
return STABLECOIN_ADDRESSES[chainName] || {};
|
|
795
|
+
}
|
|
796
|
+
};
|
|
797
|
+
|
|
798
|
+
// src/modules/kyc.ts
|
|
799
|
+
var KycModule = class {
|
|
800
|
+
constructor(client) {
|
|
801
|
+
this.client = client;
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* Get current compliance status including KYC and KYB
|
|
805
|
+
*
|
|
806
|
+
* @example
|
|
807
|
+
* ```typescript
|
|
808
|
+
* const status = await diviswap.kyc.getComplianceStatus();
|
|
809
|
+
*
|
|
810
|
+
* if (!status.canTransact) {
|
|
811
|
+
* if (status.nextStep === 'COMPLETE_KYC') {
|
|
812
|
+
* // Redirect to KYC flow
|
|
813
|
+
* }
|
|
814
|
+
* }
|
|
815
|
+
* ```
|
|
816
|
+
*/
|
|
817
|
+
async getComplianceStatus() {
|
|
818
|
+
try {
|
|
819
|
+
const profile = await this.client.get("/api/v1/users/profile");
|
|
820
|
+
const kycData = profile.kyc;
|
|
821
|
+
const kycStatus = kycData?.status || (profile.is_verified ? "APPROVED" : "PENDING");
|
|
822
|
+
const canTransact = kycData?.onramp_verified || profile.onramp_verified || false;
|
|
823
|
+
const isVerified = kycData?.is_verified || profile.is_verified || false;
|
|
824
|
+
return {
|
|
825
|
+
kycStatus: kycStatus.toUpperCase(),
|
|
826
|
+
kybStatus: "NOT_REQUIRED",
|
|
827
|
+
canTransact,
|
|
828
|
+
requiresAction: !canTransact,
|
|
829
|
+
verificationLevel: canTransact ? "full" : isVerified ? "basic" : "none",
|
|
830
|
+
nextStep: !canTransact ? "COMPLETE_KYC" : void 0,
|
|
831
|
+
kycMetadata: kycData?.metadata
|
|
832
|
+
};
|
|
833
|
+
} catch (error) {
|
|
834
|
+
throw new Error(`Failed to get compliance status: ${error.message}`);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
838
|
+
* Start KYC verification session (opens Sumsub widget)
|
|
839
|
+
*
|
|
840
|
+
* @example
|
|
841
|
+
* ```typescript
|
|
842
|
+
* const session = await diviswap.kyc.startKycSession();
|
|
843
|
+
*
|
|
844
|
+
* // Redirect user to session URL
|
|
845
|
+
* window.location.href = session.sessionUrl;
|
|
846
|
+
*
|
|
847
|
+
* // Or embed in iframe
|
|
848
|
+
* const iframe = document.createElement('iframe');
|
|
849
|
+
* iframe.src = session.sessionUrl;
|
|
850
|
+
* ```
|
|
851
|
+
*/
|
|
852
|
+
async startKycSession() {
|
|
853
|
+
throw new Error("KYC session endpoint not available in v1 API yet");
|
|
854
|
+
}
|
|
855
|
+
/**
|
|
856
|
+
* Submit KYC documents programmatically
|
|
857
|
+
*
|
|
858
|
+
* @example
|
|
859
|
+
* ```typescript
|
|
860
|
+
* // Convert file to base64
|
|
861
|
+
* const toBase64 = (file: File) => new Promise<string>((resolve, reject) => {
|
|
862
|
+
* const reader = new FileReader();
|
|
863
|
+
* reader.readAsDataURL(file);
|
|
864
|
+
* reader.onload = () => resolve(reader.result as string);
|
|
865
|
+
* reader.onerror = reject;
|
|
866
|
+
* });
|
|
867
|
+
*
|
|
868
|
+
* const frontImage = await toBase64(frontFile);
|
|
869
|
+
* const backImage = await toBase64(backFile);
|
|
870
|
+
*
|
|
871
|
+
* await diviswap.kyc.submitDocuments({
|
|
872
|
+
* type: 'DRIVERS_LICENSE',
|
|
873
|
+
* frontImage,
|
|
874
|
+
* backImage
|
|
875
|
+
* });
|
|
876
|
+
* ```
|
|
877
|
+
*/
|
|
878
|
+
async submitDocuments(documents) {
|
|
879
|
+
if (!documents.frontImage) {
|
|
880
|
+
throw new ValidationError("Front image is required");
|
|
881
|
+
}
|
|
882
|
+
if (["DRIVERS_LICENSE", "ID_CARD"].includes(documents.type) && !documents.backImage) {
|
|
883
|
+
throw new ValidationError(`Back image is required for ${documents.type}`);
|
|
884
|
+
}
|
|
885
|
+
throw new Error("KYC documents endpoint not available in v1 API yet");
|
|
886
|
+
}
|
|
887
|
+
/**
|
|
888
|
+
* Submit personal information for KYC
|
|
889
|
+
*
|
|
890
|
+
* @example
|
|
891
|
+
* ```typescript
|
|
892
|
+
* await diviswap.kyc.submitPersonalInfo({
|
|
893
|
+
* firstName: 'John',
|
|
894
|
+
* lastName: 'Doe',
|
|
895
|
+
* dateOfBirth: '1990-01-01',
|
|
896
|
+
* ssn: '123-45-6789',
|
|
897
|
+
* address: {
|
|
898
|
+
* street: '123 Main St',
|
|
899
|
+
* city: 'New York',
|
|
900
|
+
* state: 'NY',
|
|
901
|
+
* postalCode: '10001',
|
|
902
|
+
* country: 'US'
|
|
903
|
+
* }
|
|
904
|
+
* });
|
|
905
|
+
* ```
|
|
906
|
+
*/
|
|
907
|
+
async submitPersonalInfo(info) {
|
|
908
|
+
const requiredFields = ["firstName", "lastName", "dateOfBirth"];
|
|
909
|
+
for (const field of requiredFields) {
|
|
910
|
+
if (!info[field]) {
|
|
911
|
+
throw new ValidationError(`${field} is required`);
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
if (!info.address || !info.address.street || !info.address.city || !info.address.state || !info.address.postalCode || !info.address.country) {
|
|
915
|
+
throw new ValidationError("Complete address is required");
|
|
916
|
+
}
|
|
917
|
+
try {
|
|
918
|
+
const response = await this.client.post("/api/v1/kyc/personal-info", {
|
|
919
|
+
first_name: info.firstName,
|
|
920
|
+
last_name: info.lastName,
|
|
921
|
+
dob: info.dateOfBirth,
|
|
922
|
+
country: info.address.country,
|
|
923
|
+
...info.phone && { phone: info.phone },
|
|
924
|
+
...info.address.street && { address: info.address.street },
|
|
925
|
+
...info.address.city && { city: info.address.city },
|
|
926
|
+
...info.address.state && { state: info.address.state },
|
|
927
|
+
...info.address.postalCode && { postal_code: info.address.postalCode },
|
|
928
|
+
...info.ssn && { ssn: info.ssn }
|
|
929
|
+
});
|
|
930
|
+
return response;
|
|
931
|
+
} catch (error) {
|
|
932
|
+
throw new Error(`Failed to submit KYC info: ${error.message}`);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
/**
|
|
936
|
+
* Check if user can transact (convenience method)
|
|
937
|
+
*
|
|
938
|
+
* @example
|
|
939
|
+
* ```typescript
|
|
940
|
+
* const canTransact = await diviswap.kyc.canTransact();
|
|
941
|
+
* if (!canTransact) {
|
|
942
|
+
* // Show KYC prompt
|
|
943
|
+
* }
|
|
944
|
+
* ```
|
|
945
|
+
*/
|
|
946
|
+
async canTransact() {
|
|
947
|
+
const status = await this.getComplianceStatus();
|
|
948
|
+
return status.canTransact;
|
|
949
|
+
}
|
|
950
|
+
/**
|
|
951
|
+
* Check if KYC is approved
|
|
952
|
+
*
|
|
953
|
+
* @example
|
|
954
|
+
* ```typescript
|
|
955
|
+
* const isApproved = await diviswap.kyc.isKycApproved();
|
|
956
|
+
* ```
|
|
957
|
+
*/
|
|
958
|
+
async isKycApproved() {
|
|
959
|
+
const status = await this.getComplianceStatus();
|
|
960
|
+
return status.kycStatus === "APPROVED";
|
|
961
|
+
}
|
|
962
|
+
/**
|
|
963
|
+
* Check if KYB is approved (for business accounts)
|
|
964
|
+
*
|
|
965
|
+
* @example
|
|
966
|
+
* ```typescript
|
|
967
|
+
* const isBusinessApproved = await diviswap.kyc.isKybApproved();
|
|
968
|
+
* ```
|
|
969
|
+
*/
|
|
970
|
+
async isKybApproved() {
|
|
971
|
+
const status = await this.getComplianceStatus();
|
|
972
|
+
return status.kybStatus === "APPROVED";
|
|
973
|
+
}
|
|
974
|
+
/**
|
|
975
|
+
* Get rejection reasons if KYC/KYB was rejected
|
|
976
|
+
*
|
|
977
|
+
* @example
|
|
978
|
+
* ```typescript
|
|
979
|
+
* const reasons = await diviswap.kyc.getRejectionReasons();
|
|
980
|
+
* if (reasons.length > 0) {
|
|
981
|
+
* console.log('Rejected because:', reasons.join(', '));
|
|
982
|
+
* }
|
|
983
|
+
* ```
|
|
984
|
+
*/
|
|
985
|
+
async getRejectionReasons() {
|
|
986
|
+
const status = await this.getComplianceStatus();
|
|
987
|
+
const reasons = [];
|
|
988
|
+
if (status.kycStatus === "REJECTED" && status.kycMetadata?.rejectLabels) {
|
|
989
|
+
reasons.push(...status.kycMetadata.rejectLabels);
|
|
990
|
+
}
|
|
991
|
+
return reasons;
|
|
992
|
+
}
|
|
993
|
+
/**
|
|
994
|
+
* Wait for KYC approval (polling)
|
|
995
|
+
*
|
|
996
|
+
* @example
|
|
997
|
+
* ```typescript
|
|
998
|
+
* // Start KYC session
|
|
999
|
+
* const session = await diviswap.kyc.startKycSession();
|
|
1000
|
+
* window.open(session.sessionUrl);
|
|
1001
|
+
*
|
|
1002
|
+
* // Wait for approval (polls every 5 seconds for up to 10 minutes)
|
|
1003
|
+
* try {
|
|
1004
|
+
* await diviswap.kyc.waitForApproval();
|
|
1005
|
+
* console.log('KYC approved!');
|
|
1006
|
+
* } catch (error) {
|
|
1007
|
+
* console.log('KYC not approved:', error.message);
|
|
1008
|
+
* }
|
|
1009
|
+
* ```
|
|
1010
|
+
*/
|
|
1011
|
+
async waitForApproval(options) {
|
|
1012
|
+
const pollInterval = options?.pollInterval || 5e3;
|
|
1013
|
+
const maxAttempts = options?.maxAttempts || 120;
|
|
1014
|
+
let attempts = 0;
|
|
1015
|
+
while (attempts < maxAttempts) {
|
|
1016
|
+
const status = await this.getComplianceStatus();
|
|
1017
|
+
if (status.kycStatus === "APPROVED") {
|
|
1018
|
+
return status;
|
|
1019
|
+
}
|
|
1020
|
+
if (status.kycStatus === "REJECTED") {
|
|
1021
|
+
throw new Error(`KYC rejected: ${status.kycMetadata?.rejectLabels?.join(", ") || "Unknown reason"}`);
|
|
1022
|
+
}
|
|
1023
|
+
attempts++;
|
|
1024
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval));
|
|
1025
|
+
}
|
|
1026
|
+
throw new Error("KYC approval timeout");
|
|
1027
|
+
}
|
|
1028
|
+
};
|
|
1029
|
+
|
|
1030
|
+
// src/modules/fees.ts
|
|
1031
|
+
var FeesModule = class {
|
|
1032
|
+
constructor(client) {
|
|
1033
|
+
this.client = client;
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Set integrator fee percentage
|
|
1037
|
+
*
|
|
1038
|
+
* @example
|
|
1039
|
+
* ```typescript
|
|
1040
|
+
* // Set global integrator fee to 0.75% (applies to all your users)
|
|
1041
|
+
* await diviswap.fees.setFee({ percentage: 0.75 });
|
|
1042
|
+
*
|
|
1043
|
+
* // Set fee for specific user (overrides global)
|
|
1044
|
+
* await diviswap.fees.setFee({
|
|
1045
|
+
* percentage: 1.0,
|
|
1046
|
+
* userId: 123
|
|
1047
|
+
* });
|
|
1048
|
+
* ```
|
|
1049
|
+
*/
|
|
1050
|
+
async setFee(data) {
|
|
1051
|
+
if (data.userId) {
|
|
1052
|
+
await this.client.put(`/api/v1/partner/users/${data.userId}/fee`, {
|
|
1053
|
+
percentage: data.percentage
|
|
1054
|
+
});
|
|
1055
|
+
return {
|
|
1056
|
+
integratorFeePercentage: data.percentage,
|
|
1057
|
+
baseFeePercentage: 1.5,
|
|
1058
|
+
totalFeePercentage: 1.5 + data.percentage,
|
|
1059
|
+
userId: data.userId.toString()
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
const response = await this.client.put("/api/v1/partner/fee", {
|
|
1063
|
+
percentage: data.percentage
|
|
1064
|
+
});
|
|
1065
|
+
return {
|
|
1066
|
+
integratorFeePercentage: response.integrator_fee_percentage,
|
|
1067
|
+
baseFeePercentage: response.base_fee_percentage,
|
|
1068
|
+
totalFeePercentage: response.total_fee_percentage
|
|
1069
|
+
};
|
|
1070
|
+
}
|
|
1071
|
+
/**
|
|
1072
|
+
* Get current fee settings
|
|
1073
|
+
*
|
|
1074
|
+
* @example
|
|
1075
|
+
* ```typescript
|
|
1076
|
+
* // Get global fee settings (your default)
|
|
1077
|
+
* const fees = await diviswap.fees.getFees();
|
|
1078
|
+
* console.log(`Total fee: ${fees.totalFeePercentage}%`);
|
|
1079
|
+
* ```
|
|
1080
|
+
*/
|
|
1081
|
+
async getFees() {
|
|
1082
|
+
const response = await this.client.get("/api/v1/partner/fee");
|
|
1083
|
+
return {
|
|
1084
|
+
integratorFeePercentage: response.integrator_fee_percentage,
|
|
1085
|
+
baseFeePercentage: response.base_fee_percentage,
|
|
1086
|
+
totalFeePercentage: response.total_fee_percentage
|
|
1087
|
+
};
|
|
1088
|
+
}
|
|
1089
|
+
/**
|
|
1090
|
+
* Calculate fees for a transaction amount
|
|
1091
|
+
*
|
|
1092
|
+
* @example
|
|
1093
|
+
* ```typescript
|
|
1094
|
+
* const calc = await diviswap.fees.calculateFees({
|
|
1095
|
+
* amount: 100,
|
|
1096
|
+
* userId: 123 // Optional: checks for user-specific override
|
|
1097
|
+
* });
|
|
1098
|
+
*
|
|
1099
|
+
* console.log(`Base fee: $${calc.baseFee}`);
|
|
1100
|
+
* console.log(`Your fee: $${calc.integratorFee}`);
|
|
1101
|
+
* console.log(`Total fee: $${calc.totalFee}`);
|
|
1102
|
+
* console.log(`User receives: $${calc.netAmount}`);
|
|
1103
|
+
* ```
|
|
1104
|
+
*/
|
|
1105
|
+
async calculateFees(params) {
|
|
1106
|
+
const response = await this.client.post("/api/v1/partner/fees/calculate", {
|
|
1107
|
+
amount: params.amount,
|
|
1108
|
+
user_id: params.userId
|
|
1109
|
+
});
|
|
1110
|
+
return {
|
|
1111
|
+
amount: response.amount,
|
|
1112
|
+
baseFee: response.base_fee,
|
|
1113
|
+
integratorFee: response.integrator_fee,
|
|
1114
|
+
totalFee: response.total_fee,
|
|
1115
|
+
netAmount: response.net_amount
|
|
1116
|
+
};
|
|
1117
|
+
}
|
|
1118
|
+
/**
|
|
1119
|
+
* Remove custom fee for a user (reverts to partner default)
|
|
1120
|
+
*
|
|
1121
|
+
* @example
|
|
1122
|
+
* ```typescript
|
|
1123
|
+
* // Remove VIP user's custom fee, they'll use your default fee again
|
|
1124
|
+
* await diviswap.fees.removeFee(123);
|
|
1125
|
+
* ```
|
|
1126
|
+
*/
|
|
1127
|
+
async removeFee(userId) {
|
|
1128
|
+
await this.client.delete(`/api/v1/partner/users/${userId}/fee`);
|
|
1129
|
+
}
|
|
1130
|
+
};
|
|
1131
|
+
|
|
1132
|
+
// src/types/addresses.ts
|
|
1133
|
+
var CHAIN_IDS = {
|
|
1134
|
+
// Mainnets
|
|
1135
|
+
ethereum: 1,
|
|
1136
|
+
optimism: 10,
|
|
1137
|
+
base: 8453,
|
|
1138
|
+
polygon: 137,
|
|
1139
|
+
arbitrum: 42161,
|
|
1140
|
+
// Testnets
|
|
1141
|
+
sepolia: 11155111,
|
|
1142
|
+
optimism_sepolia: 11155420,
|
|
1143
|
+
base_sepolia: 84532,
|
|
1144
|
+
polygon_mumbai: 80001,
|
|
1145
|
+
arbitrum_sepolia: 421614
|
|
1146
|
+
};
|
|
1147
|
+
|
|
1148
|
+
// src/modules/addresses.ts
|
|
1149
|
+
var AddressesModule = class {
|
|
1150
|
+
constructor(client) {
|
|
1151
|
+
this.client = client;
|
|
1152
|
+
}
|
|
1153
|
+
/**
|
|
1154
|
+
* Get all addresses for the authenticated user
|
|
1155
|
+
*
|
|
1156
|
+
* @example
|
|
1157
|
+
* ```typescript
|
|
1158
|
+
* const addresses = await diviswap.addresses.list();
|
|
1159
|
+
* console.log('User addresses:', addresses);
|
|
1160
|
+
* ```
|
|
1161
|
+
*/
|
|
1162
|
+
async list() {
|
|
1163
|
+
const response = await this.client.get("/api/v1/addresses");
|
|
1164
|
+
return Array.isArray(response) ? response : [];
|
|
1165
|
+
}
|
|
1166
|
+
/**
|
|
1167
|
+
* Create a new crypto address for the user
|
|
1168
|
+
*
|
|
1169
|
+
* @example
|
|
1170
|
+
* ```typescript
|
|
1171
|
+
* const address = await diviswap.addresses.create({
|
|
1172
|
+
* chain_id: 1, // Ethereum mainnet
|
|
1173
|
+
* address: '0x742d35Cc6647C9532c9fc77C68076aFb1e5AAc05',
|
|
1174
|
+
* is_default: true
|
|
1175
|
+
* });
|
|
1176
|
+
* ```
|
|
1177
|
+
*/
|
|
1178
|
+
async create(data) {
|
|
1179
|
+
const response = await this.client.post("/api/v1/addresses", data);
|
|
1180
|
+
const addresses = await this.list();
|
|
1181
|
+
const newAddress = addresses.find((addr) => addr.id === response.id);
|
|
1182
|
+
if (!newAddress) {
|
|
1183
|
+
throw new Error("Failed to retrieve created address");
|
|
1184
|
+
}
|
|
1185
|
+
return newAddress;
|
|
1186
|
+
}
|
|
1187
|
+
/**
|
|
1188
|
+
* Set a specific address as the default for its chain
|
|
1189
|
+
*
|
|
1190
|
+
* @example
|
|
1191
|
+
* ```typescript
|
|
1192
|
+
* await diviswap.addresses.setDefault({
|
|
1193
|
+
* chain_id: 1,
|
|
1194
|
+
* address: '0x742d35Cc6647C9532c9fc77C68076aFb1e5AAc05'
|
|
1195
|
+
* });
|
|
1196
|
+
* ```
|
|
1197
|
+
*/
|
|
1198
|
+
async setDefault(data) {
|
|
1199
|
+
await this.client.put("/api/v1/addresses/default", data);
|
|
1200
|
+
}
|
|
1201
|
+
/**
|
|
1202
|
+
* Delete a crypto address
|
|
1203
|
+
*
|
|
1204
|
+
* @example
|
|
1205
|
+
* ```typescript
|
|
1206
|
+
* await diviswap.addresses.delete({
|
|
1207
|
+
* chain_id: 1,
|
|
1208
|
+
* address: '0x742d35Cc6647C9532c9fc77C68076aFb1e5AAc05'
|
|
1209
|
+
* });
|
|
1210
|
+
* ```
|
|
1211
|
+
*/
|
|
1212
|
+
async delete(data) {
|
|
1213
|
+
await this.client.delete("/api/v1/addresses", { body: data });
|
|
1214
|
+
}
|
|
1215
|
+
/**
|
|
1216
|
+
* Get addresses for a specific chain
|
|
1217
|
+
*
|
|
1218
|
+
* @example
|
|
1219
|
+
* ```typescript
|
|
1220
|
+
* const ethAddresses = await diviswap.addresses.getByChain(1);
|
|
1221
|
+
* const baseAddresses = await diviswap.addresses.getByChain('base');
|
|
1222
|
+
* ```
|
|
1223
|
+
*/
|
|
1224
|
+
async getByChain(chainIdOrName) {
|
|
1225
|
+
const chainId = typeof chainIdOrName === "string" ? CHAIN_IDS[chainIdOrName] : chainIdOrName;
|
|
1226
|
+
const addresses = await this.list();
|
|
1227
|
+
return addresses.filter((addr) => addr.chain_id === chainId);
|
|
1228
|
+
}
|
|
1229
|
+
/**
|
|
1230
|
+
* Get the default address for a specific chain
|
|
1231
|
+
*
|
|
1232
|
+
* @example
|
|
1233
|
+
* ```typescript
|
|
1234
|
+
* const defaultEthAddress = await diviswap.addresses.getDefault(1);
|
|
1235
|
+
* const defaultBaseAddress = await diviswap.addresses.getDefault('base');
|
|
1236
|
+
* ```
|
|
1237
|
+
*/
|
|
1238
|
+
async getDefault(chainIdOrName) {
|
|
1239
|
+
const chainId = typeof chainIdOrName === "string" ? CHAIN_IDS[chainIdOrName] : chainIdOrName;
|
|
1240
|
+
const addresses = await this.list();
|
|
1241
|
+
return addresses.find((addr) => addr.chain_id === chainId && addr.is_default) || null;
|
|
1242
|
+
}
|
|
1243
|
+
/**
|
|
1244
|
+
* Check if an address exists for the user
|
|
1245
|
+
*
|
|
1246
|
+
* @example
|
|
1247
|
+
* ```typescript
|
|
1248
|
+
* const exists = await diviswap.addresses.exists({
|
|
1249
|
+
* chain_id: 1,
|
|
1250
|
+
* address: '0x742d35Cc6647C9532c9fc77C68076aFb1e5AAc05'
|
|
1251
|
+
* });
|
|
1252
|
+
* ```
|
|
1253
|
+
*/
|
|
1254
|
+
async exists(data) {
|
|
1255
|
+
const addresses = await this.list();
|
|
1256
|
+
return addresses.some(
|
|
1257
|
+
(addr) => addr.chain_id === data.chain_id && addr.address.toLowerCase() === data.address.toLowerCase()
|
|
1258
|
+
);
|
|
1259
|
+
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Automatically track a wallet connection
|
|
1262
|
+
* This is the main method for automatic address tracking
|
|
1263
|
+
*
|
|
1264
|
+
* @example
|
|
1265
|
+
* ```typescript
|
|
1266
|
+
* // When user connects wallet
|
|
1267
|
+
* const connection = await diviswap.addresses.trackWallet({
|
|
1268
|
+
* address: account,
|
|
1269
|
+
* chainId: chainId,
|
|
1270
|
+
* chainName: 'ethereum' // optional
|
|
1271
|
+
* });
|
|
1272
|
+
* ```
|
|
1273
|
+
*/
|
|
1274
|
+
async trackWallet(connection) {
|
|
1275
|
+
const existsAlready = await this.exists({
|
|
1276
|
+
chain_id: connection.chainId,
|
|
1277
|
+
address: connection.address
|
|
1278
|
+
});
|
|
1279
|
+
if (existsAlready) {
|
|
1280
|
+
const addresses = await this.list();
|
|
1281
|
+
const existingAddress = addresses.find(
|
|
1282
|
+
(addr) => addr.chain_id === connection.chainId && addr.address.toLowerCase() === connection.address.toLowerCase()
|
|
1283
|
+
);
|
|
1284
|
+
if (!existingAddress) {
|
|
1285
|
+
throw new Error("Address exists but could not be retrieved");
|
|
1286
|
+
}
|
|
1287
|
+
return existingAddress;
|
|
1288
|
+
}
|
|
1289
|
+
const existingOnChain = await this.getByChain(connection.chainId);
|
|
1290
|
+
const isDefault = existingOnChain.length === 0;
|
|
1291
|
+
return await this.create({
|
|
1292
|
+
chain_id: connection.chainId,
|
|
1293
|
+
address: connection.address,
|
|
1294
|
+
is_default: isDefault
|
|
1295
|
+
});
|
|
1296
|
+
}
|
|
1297
|
+
/**
|
|
1298
|
+
* Auto-track multiple wallet connections (useful for multi-chain wallets)
|
|
1299
|
+
*
|
|
1300
|
+
* @example
|
|
1301
|
+
* ```typescript
|
|
1302
|
+
* // When user connects a multi-chain wallet
|
|
1303
|
+
* const addresses = await diviswap.addresses.trackMultipleWallets([
|
|
1304
|
+
* { address: account, chainId: 1 }, // Ethereum
|
|
1305
|
+
* { address: account, chainId: 8453 }, // Base
|
|
1306
|
+
* { address: account, chainId: 10 } // Optimism
|
|
1307
|
+
* ]);
|
|
1308
|
+
* ```
|
|
1309
|
+
*/
|
|
1310
|
+
async trackMultipleWallets(connections) {
|
|
1311
|
+
const results = [];
|
|
1312
|
+
for (const connection of connections) {
|
|
1313
|
+
try {
|
|
1314
|
+
const address = await this.trackWallet(connection);
|
|
1315
|
+
results.push(address);
|
|
1316
|
+
} catch (error) {
|
|
1317
|
+
console.error(`Failed to track wallet for chain ${connection.chainId}:`, error);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
return results;
|
|
1321
|
+
}
|
|
1322
|
+
/**
|
|
1323
|
+
* Helper to get chain name from chain ID
|
|
1324
|
+
*/
|
|
1325
|
+
getChainName(chainId) {
|
|
1326
|
+
return Object.entries(CHAIN_IDS).find(([_, id]) => id === chainId)?.[0];
|
|
1327
|
+
}
|
|
1328
|
+
/**
|
|
1329
|
+
* Helper to get chain ID from chain name
|
|
1330
|
+
*/
|
|
1331
|
+
getChainId(chainName) {
|
|
1332
|
+
return CHAIN_IDS[chainName];
|
|
1333
|
+
}
|
|
1334
|
+
/**
|
|
1335
|
+
* Get all supported chains
|
|
1336
|
+
*/
|
|
1337
|
+
getSupportedChains() {
|
|
1338
|
+
return { ...CHAIN_IDS };
|
|
1339
|
+
}
|
|
1340
|
+
};
|
|
1341
|
+
|
|
1342
|
+
// src/modules/webhooks.ts
|
|
1343
|
+
var WebhooksModule = class {
|
|
1344
|
+
constructor(client) {
|
|
1345
|
+
this.client = client;
|
|
1346
|
+
}
|
|
1347
|
+
/**
|
|
1348
|
+
* Set webhook URL and secret for your partner account
|
|
1349
|
+
*
|
|
1350
|
+
* @example
|
|
1351
|
+
* ```typescript
|
|
1352
|
+
* await diviswap.webhooks.setConfig({
|
|
1353
|
+
* webhook_url: 'https://myapp.com/api/webhooks/diviswap',
|
|
1354
|
+
* webhook_secret: 'whsec_...' // Optional, auto-generated if not provided
|
|
1355
|
+
* });
|
|
1356
|
+
* ```
|
|
1357
|
+
*/
|
|
1358
|
+
async setConfig(data) {
|
|
1359
|
+
const response = await this.client.put("/api/v1/partner/webhook", {
|
|
1360
|
+
webhook_url: data.webhook_url,
|
|
1361
|
+
webhook_secret: data.webhook_secret
|
|
1362
|
+
});
|
|
1363
|
+
return response;
|
|
1364
|
+
}
|
|
1365
|
+
/**
|
|
1366
|
+
* Set webhook for a specific partner (user-owned partner)
|
|
1367
|
+
*
|
|
1368
|
+
* @example
|
|
1369
|
+
* ```typescript
|
|
1370
|
+
* await diviswap.webhooks.setConfigForPartner(4, {
|
|
1371
|
+
* webhook_url: 'https://myapp.com/webhooks'
|
|
1372
|
+
* });
|
|
1373
|
+
* ```
|
|
1374
|
+
*/
|
|
1375
|
+
async setConfigForPartner(partnerId, data) {
|
|
1376
|
+
const response = await this.client.put(`/api/v1/partners/${partnerId}/webhook`, {
|
|
1377
|
+
webhook_url: data.webhook_url,
|
|
1378
|
+
webhook_secret: data.webhook_secret
|
|
1379
|
+
});
|
|
1380
|
+
return response;
|
|
1381
|
+
}
|
|
1382
|
+
/**
|
|
1383
|
+
* Get current webhook configuration
|
|
1384
|
+
*
|
|
1385
|
+
* @example
|
|
1386
|
+
* ```typescript
|
|
1387
|
+
* const config = await diviswap.webhooks.getConfig();
|
|
1388
|
+
* console.log(`Webhook enabled: ${config.enabled}`);
|
|
1389
|
+
* console.log(`URL: ${config.webhook_url}`);
|
|
1390
|
+
* ```
|
|
1391
|
+
*/
|
|
1392
|
+
async getConfig() {
|
|
1393
|
+
const response = await this.client.get("/api/v1/partner/webhook");
|
|
1394
|
+
return response;
|
|
1395
|
+
}
|
|
1396
|
+
/**
|
|
1397
|
+
* Get webhook config for a specific partner (user-owned)
|
|
1398
|
+
*/
|
|
1399
|
+
async getConfigForPartner(partnerId) {
|
|
1400
|
+
const response = await this.client.get(`/api/v1/partners/${partnerId}/webhook`);
|
|
1401
|
+
return response;
|
|
1402
|
+
}
|
|
1403
|
+
/**
|
|
1404
|
+
* List webhook delivery events
|
|
1405
|
+
*
|
|
1406
|
+
* @example
|
|
1407
|
+
* ```typescript
|
|
1408
|
+
* const events = await diviswap.webhooks.listEvents({
|
|
1409
|
+
* limit: 100,
|
|
1410
|
+
* status: 'failed'
|
|
1411
|
+
* });
|
|
1412
|
+
*
|
|
1413
|
+
* events.forEach(event => {
|
|
1414
|
+
* console.log(`${event.event_type}: ${event.status}`);
|
|
1415
|
+
* });
|
|
1416
|
+
* ```
|
|
1417
|
+
*/
|
|
1418
|
+
async listEvents(options) {
|
|
1419
|
+
const params = new URLSearchParams();
|
|
1420
|
+
if (options?.limit) params.append("limit", options.limit.toString());
|
|
1421
|
+
if (options?.status) params.append("status", options.status);
|
|
1422
|
+
const path = options?.partnerId ? `/api/v1/partners/${options.partnerId}/webhook/events?${params}` : `/api/v1/partner/webhook/events?${params}`;
|
|
1423
|
+
const response = await this.client.get(path);
|
|
1424
|
+
return response;
|
|
1425
|
+
}
|
|
1426
|
+
/**
|
|
1427
|
+
* Send a test webhook to verify your endpoint is working
|
|
1428
|
+
*
|
|
1429
|
+
* @example
|
|
1430
|
+
* ```typescript
|
|
1431
|
+
* const result = await diviswap.webhooks.test();
|
|
1432
|
+
* if (result.success) {
|
|
1433
|
+
* console.log('Webhook endpoint is working!');
|
|
1434
|
+
* }
|
|
1435
|
+
* ```
|
|
1436
|
+
*/
|
|
1437
|
+
async test(partnerId) {
|
|
1438
|
+
const path = partnerId ? `/api/v1/partners/${partnerId}/webhook/test` : "/api/v1/partner/webhook/test";
|
|
1439
|
+
return await this.client.post(path);
|
|
1440
|
+
}
|
|
1441
|
+
/**
|
|
1442
|
+
* Verify a webhook signature (static helper for your webhook endpoint)
|
|
1443
|
+
*
|
|
1444
|
+
* @example
|
|
1445
|
+
* ```typescript
|
|
1446
|
+
* import crypto from 'crypto';
|
|
1447
|
+
*
|
|
1448
|
+
* const isValid = WebhooksModule.verifySignature(
|
|
1449
|
+
* rawBody,
|
|
1450
|
+
* request.headers['x-signature'],
|
|
1451
|
+
* process.env.WEBHOOK_SECRET
|
|
1452
|
+
* );
|
|
1453
|
+
* ```
|
|
1454
|
+
*/
|
|
1455
|
+
static verifySignature(payload, signature, secret) {
|
|
1456
|
+
const crypto2 = __require("crypto");
|
|
1457
|
+
const expectedSignature = crypto2.createHmac("sha256", secret).update(payload).digest("hex");
|
|
1458
|
+
return crypto2.timingSafeEqual(
|
|
1459
|
+
Buffer.from(signature),
|
|
1460
|
+
Buffer.from(expectedSignature)
|
|
1461
|
+
);
|
|
1462
|
+
}
|
|
1463
|
+
};
|
|
1464
|
+
|
|
1465
|
+
// src/api/token-manager.ts
|
|
1466
|
+
var MemoryTokenStorage = class {
|
|
1467
|
+
constructor() {
|
|
1468
|
+
this.data = null;
|
|
1469
|
+
}
|
|
1470
|
+
get() {
|
|
1471
|
+
return this.data;
|
|
1472
|
+
}
|
|
1473
|
+
set(data) {
|
|
1474
|
+
this.data = data;
|
|
1475
|
+
}
|
|
1476
|
+
clear() {
|
|
1477
|
+
this.data = null;
|
|
1478
|
+
}
|
|
1479
|
+
};
|
|
1480
|
+
var LocalStorageTokenStorage = class {
|
|
1481
|
+
constructor() {
|
|
1482
|
+
this.key = "liberex_tokens";
|
|
1483
|
+
}
|
|
1484
|
+
get() {
|
|
1485
|
+
if (typeof globalThis.window === "undefined") return null;
|
|
1486
|
+
const data = globalThis.localStorage.getItem(this.key);
|
|
1487
|
+
if (!data) return null;
|
|
1488
|
+
try {
|
|
1489
|
+
return JSON.parse(data);
|
|
1490
|
+
} catch {
|
|
1491
|
+
return null;
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
set(data) {
|
|
1495
|
+
if (typeof globalThis.window === "undefined") return;
|
|
1496
|
+
globalThis.localStorage.setItem(this.key, JSON.stringify(data));
|
|
1497
|
+
}
|
|
1498
|
+
clear() {
|
|
1499
|
+
if (typeof globalThis.window === "undefined") return;
|
|
1500
|
+
globalThis.localStorage.removeItem(this.key);
|
|
1501
|
+
}
|
|
1502
|
+
};
|
|
1503
|
+
var TokenManager = class {
|
|
1504
|
+
constructor(useLocalStorage = false) {
|
|
1505
|
+
this.refreshPromise = null;
|
|
1506
|
+
this.storage = useLocalStorage && typeof globalThis.window !== "undefined" ? new LocalStorageTokenStorage() : new MemoryTokenStorage();
|
|
1507
|
+
}
|
|
1508
|
+
/**
|
|
1509
|
+
* Parse JWT token to extract expiration
|
|
1510
|
+
*/
|
|
1511
|
+
parseToken(token) {
|
|
1512
|
+
try {
|
|
1513
|
+
const payload = token.split(".")[1];
|
|
1514
|
+
const decoded = atob(payload.replace(/-/g, "+").replace(/_/g, "/"));
|
|
1515
|
+
return JSON.parse(decoded);
|
|
1516
|
+
} catch {
|
|
1517
|
+
return {};
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
/**
|
|
1521
|
+
* Store tokens
|
|
1522
|
+
*/
|
|
1523
|
+
setTokens(accessToken, refreshToken) {
|
|
1524
|
+
const parsed = this.parseToken(accessToken);
|
|
1525
|
+
const expiresAt = parsed.exp ? parsed.exp * 1e3 : void 0;
|
|
1526
|
+
this.storage.set({
|
|
1527
|
+
accessToken,
|
|
1528
|
+
refreshToken,
|
|
1529
|
+
expiresAt
|
|
1530
|
+
});
|
|
1531
|
+
}
|
|
1532
|
+
/**
|
|
1533
|
+
* Get current access token
|
|
1534
|
+
*/
|
|
1535
|
+
getAccessToken() {
|
|
1536
|
+
const data = this.storage.get();
|
|
1537
|
+
return data?.accessToken || null;
|
|
1538
|
+
}
|
|
1539
|
+
/**
|
|
1540
|
+
* Get refresh token
|
|
1541
|
+
*/
|
|
1542
|
+
getRefreshToken() {
|
|
1543
|
+
const data = this.storage.get();
|
|
1544
|
+
return data?.refreshToken || null;
|
|
1545
|
+
}
|
|
1546
|
+
/**
|
|
1547
|
+
* Check if token is expired or about to expire (5 min buffer)
|
|
1548
|
+
*/
|
|
1549
|
+
isTokenExpired() {
|
|
1550
|
+
const data = this.storage.get();
|
|
1551
|
+
if (!data?.expiresAt) return true;
|
|
1552
|
+
const bufferTime = 5 * 60 * 1e3;
|
|
1553
|
+
return Date.now() >= data.expiresAt - bufferTime;
|
|
1554
|
+
}
|
|
1555
|
+
/**
|
|
1556
|
+
* Clear all tokens
|
|
1557
|
+
*/
|
|
1558
|
+
clearTokens() {
|
|
1559
|
+
this.storage.clear();
|
|
1560
|
+
this.refreshPromise = null;
|
|
1561
|
+
}
|
|
1562
|
+
/**
|
|
1563
|
+
* Refresh access token
|
|
1564
|
+
*/
|
|
1565
|
+
async refreshAccessToken(refreshCallback) {
|
|
1566
|
+
if (this.refreshPromise) {
|
|
1567
|
+
const result = await this.refreshPromise;
|
|
1568
|
+
return result.accessToken;
|
|
1569
|
+
}
|
|
1570
|
+
const refreshToken = this.getRefreshToken();
|
|
1571
|
+
if (!refreshToken) {
|
|
1572
|
+
throw new Error("No refresh token available");
|
|
1573
|
+
}
|
|
1574
|
+
this.refreshPromise = refreshCallback(refreshToken);
|
|
1575
|
+
try {
|
|
1576
|
+
const newTokenData = await this.refreshPromise;
|
|
1577
|
+
this.setTokens(newTokenData.accessToken, newTokenData.refreshToken || refreshToken);
|
|
1578
|
+
return newTokenData.accessToken;
|
|
1579
|
+
} finally {
|
|
1580
|
+
this.refreshPromise = null;
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1583
|
+
/**
|
|
1584
|
+
* Get valid access token (refresh if needed)
|
|
1585
|
+
*/
|
|
1586
|
+
async getValidAccessToken(refreshCallback) {
|
|
1587
|
+
const token = this.getAccessToken();
|
|
1588
|
+
if (!token) return null;
|
|
1589
|
+
if (this.isTokenExpired() && refreshCallback) {
|
|
1590
|
+
try {
|
|
1591
|
+
return await this.refreshAccessToken(refreshCallback);
|
|
1592
|
+
} catch {
|
|
1593
|
+
this.clearTokens();
|
|
1594
|
+
return null;
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
return token;
|
|
1598
|
+
}
|
|
1599
|
+
};
|
|
1600
|
+
var PartnerAuth = class {
|
|
1601
|
+
constructor(credentials) {
|
|
1602
|
+
this.credentials = credentials;
|
|
1603
|
+
}
|
|
1604
|
+
/**
|
|
1605
|
+
* Generate HMAC authentication headers for a request
|
|
1606
|
+
*/
|
|
1607
|
+
generateHMACHeaders(method, path, queryString = "", body = "") {
|
|
1608
|
+
const timestamp = Math.floor((/* @__PURE__ */ new Date()).getTime() / 1e3);
|
|
1609
|
+
const nonce = this.generateNonce();
|
|
1610
|
+
const bodyHash = crypto__default.default.createHash("sha256").update(body).digest("hex");
|
|
1611
|
+
const canonical = [
|
|
1612
|
+
method,
|
|
1613
|
+
path,
|
|
1614
|
+
queryString,
|
|
1615
|
+
bodyHash,
|
|
1616
|
+
timestamp,
|
|
1617
|
+
nonce
|
|
1618
|
+
].join("\n");
|
|
1619
|
+
const signature = crypto__default.default.createHmac("sha256", this.credentials.secretKey).update(canonical).digest("base64");
|
|
1620
|
+
const headers = {
|
|
1621
|
+
"Authorization": `HMAC ${this.credentials.keyId}:${signature}:${timestamp}:${nonce}`,
|
|
1622
|
+
"X-Client-Id": this.credentials.keyId
|
|
1623
|
+
};
|
|
1624
|
+
if (this.credentials.customerId) {
|
|
1625
|
+
headers["X-Customer-Id"] = this.credentials.customerId;
|
|
1626
|
+
}
|
|
1627
|
+
if (this.credentials.customerEmail) {
|
|
1628
|
+
headers["X-Customer-Email"] = this.credentials.customerEmail;
|
|
1629
|
+
}
|
|
1630
|
+
return headers;
|
|
1631
|
+
}
|
|
1632
|
+
/**
|
|
1633
|
+
* Generate a unique nonce for replay protection
|
|
1634
|
+
*/
|
|
1635
|
+
generateNonce() {
|
|
1636
|
+
return crypto__default.default.randomBytes(32).toString("base64url");
|
|
1637
|
+
}
|
|
1638
|
+
/**
|
|
1639
|
+
* Generate a JWT token for partner authentication
|
|
1640
|
+
*/
|
|
1641
|
+
generateJWT(options = {}) {
|
|
1642
|
+
const {
|
|
1643
|
+
audience = "api.diviswap.io",
|
|
1644
|
+
expiresIn = 300,
|
|
1645
|
+
// 5 minutes max
|
|
1646
|
+
scopes = []
|
|
1647
|
+
} = options;
|
|
1648
|
+
const now = Math.floor(Date.now() / 1e3);
|
|
1649
|
+
const payload = {
|
|
1650
|
+
iss: this.credentials.keyId,
|
|
1651
|
+
// Issuer: partner key ID
|
|
1652
|
+
aud: audience,
|
|
1653
|
+
// Audience: API domain
|
|
1654
|
+
exp: now + Math.min(expiresIn, 300),
|
|
1655
|
+
// Expiration (max 5 minutes)
|
|
1656
|
+
iat: now,
|
|
1657
|
+
// Issued at
|
|
1658
|
+
...this.credentials.customerId && { sub: this.credentials.customerId },
|
|
1659
|
+
...this.credentials.customerEmail && { email: this.credentials.customerEmail },
|
|
1660
|
+
...scopes.length > 0 && { scope: scopes }
|
|
1661
|
+
};
|
|
1662
|
+
const header = { alg: "HS256", typ: "JWT" };
|
|
1663
|
+
const encodedHeader = Buffer.from(JSON.stringify(header)).toString("base64url");
|
|
1664
|
+
const encodedPayload = Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
1665
|
+
const signature = crypto__default.default.createHmac("sha256", this.credentials.secretKey).update(`${encodedHeader}.${encodedPayload}`).digest("base64url");
|
|
1666
|
+
return `${encodedHeader}.${encodedPayload}.${signature}`;
|
|
1667
|
+
}
|
|
1668
|
+
/**
|
|
1669
|
+
* Set customer context for shadow user linking
|
|
1670
|
+
*/
|
|
1671
|
+
setCustomer(customerId, customerEmail) {
|
|
1672
|
+
this.credentials.customerId = customerId;
|
|
1673
|
+
this.credentials.customerEmail = customerEmail;
|
|
1674
|
+
}
|
|
1675
|
+
/**
|
|
1676
|
+
* Clear customer context
|
|
1677
|
+
*/
|
|
1678
|
+
clearCustomer() {
|
|
1679
|
+
delete this.credentials.customerId;
|
|
1680
|
+
delete this.credentials.customerEmail;
|
|
1681
|
+
}
|
|
1682
|
+
};
|
|
1683
|
+
|
|
1684
|
+
// src/api/unified-client.ts
|
|
1685
|
+
var UnifiedApiClient = class _UnifiedApiClient {
|
|
1686
|
+
constructor(config, useLocalStorage = true) {
|
|
1687
|
+
this.config = config;
|
|
1688
|
+
this.tokenManager = new TokenManager(useLocalStorage);
|
|
1689
|
+
if (config.mode === "partner" && config.keyId && config.secretKey) {
|
|
1690
|
+
this.partnerAuth = new PartnerAuth({
|
|
1691
|
+
keyId: config.keyId,
|
|
1692
|
+
secretKey: config.secretKey,
|
|
1693
|
+
customerId: config.customerId,
|
|
1694
|
+
customerEmail: config.customerEmail
|
|
1695
|
+
});
|
|
1696
|
+
}
|
|
1697
|
+
}
|
|
1698
|
+
/**
|
|
1699
|
+
* Create client from legacy user config (backward compatibility)
|
|
1700
|
+
*/
|
|
1701
|
+
static fromUserConfig(config, useLocalStorage = true) {
|
|
1702
|
+
const baseUrl = config.apiUrl || this.getDefaultApiUrl(config.environment || "production");
|
|
1703
|
+
return new _UnifiedApiClient({
|
|
1704
|
+
baseUrl,
|
|
1705
|
+
timeout: config.timeout || 3e4,
|
|
1706
|
+
debug: config.debug || false,
|
|
1707
|
+
mode: "user",
|
|
1708
|
+
apiKey: config.apiKey,
|
|
1709
|
+
clientId: config.clientId
|
|
1710
|
+
}, useLocalStorage);
|
|
1711
|
+
}
|
|
1712
|
+
/**
|
|
1713
|
+
* Create client from partner config
|
|
1714
|
+
*/
|
|
1715
|
+
static fromPartnerConfig(config, useLocalStorage = true) {
|
|
1716
|
+
const baseUrl = config.apiUrl || this.getDefaultApiUrl(config.environment || "production");
|
|
1717
|
+
return new _UnifiedApiClient({
|
|
1718
|
+
baseUrl,
|
|
1719
|
+
timeout: config.timeout || 3e4,
|
|
1720
|
+
debug: config.debug || false,
|
|
1721
|
+
mode: "partner",
|
|
1722
|
+
keyId: config.keyId,
|
|
1723
|
+
secretKey: config.secretKey,
|
|
1724
|
+
authMethod: config.authMethod || "hmac",
|
|
1725
|
+
customerId: config.customerId,
|
|
1726
|
+
customerEmail: config.customerEmail
|
|
1727
|
+
}, useLocalStorage);
|
|
1728
|
+
}
|
|
1729
|
+
/**
|
|
1730
|
+
* Create client from any config (auto-detect mode)
|
|
1731
|
+
*/
|
|
1732
|
+
static fromConfig(config, useLocalStorage = true) {
|
|
1733
|
+
if ("mode" in config && config.mode === "partner" || "keyId" in config && "secretKey" in config) {
|
|
1734
|
+
return this.fromPartnerConfig(config, useLocalStorage);
|
|
1735
|
+
} else {
|
|
1736
|
+
return this.fromUserConfig(config, useLocalStorage);
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
static getDefaultApiUrl(environment) {
|
|
1740
|
+
switch (environment) {
|
|
1741
|
+
case "production":
|
|
1742
|
+
return "https://api.diviswap.io";
|
|
1743
|
+
case "sandbox":
|
|
1744
|
+
return "https://dev-api.diviswap.io";
|
|
1745
|
+
default:
|
|
1746
|
+
return "https://dev-api.diviswap.io";
|
|
1747
|
+
}
|
|
1748
|
+
}
|
|
1749
|
+
/**
|
|
1750
|
+
* Update customer context for partner auth
|
|
1751
|
+
*/
|
|
1752
|
+
setCustomer(customerId, customerEmail) {
|
|
1753
|
+
if (this.partnerAuth) {
|
|
1754
|
+
this.partnerAuth.setCustomer(customerId, customerEmail);
|
|
1755
|
+
}
|
|
1756
|
+
this.config.customerId = customerId;
|
|
1757
|
+
this.config.customerEmail = customerEmail;
|
|
1758
|
+
}
|
|
1759
|
+
/**
|
|
1760
|
+
* Clear customer context
|
|
1761
|
+
*/
|
|
1762
|
+
clearCustomer() {
|
|
1763
|
+
if (this.partnerAuth) {
|
|
1764
|
+
this.partnerAuth.clearCustomer();
|
|
1765
|
+
}
|
|
1766
|
+
delete this.config.customerId;
|
|
1767
|
+
delete this.config.customerEmail;
|
|
1768
|
+
}
|
|
1769
|
+
/**
|
|
1770
|
+
* Get authentication mode
|
|
1771
|
+
*/
|
|
1772
|
+
getAuthMode() {
|
|
1773
|
+
return this.config.mode || "user";
|
|
1774
|
+
}
|
|
1775
|
+
/**
|
|
1776
|
+
* Get current customer ID (partner mode only)
|
|
1777
|
+
*/
|
|
1778
|
+
getCustomerId() {
|
|
1779
|
+
return this.config.customerId;
|
|
1780
|
+
}
|
|
1781
|
+
/**
|
|
1782
|
+
* Set refresh callback for automatic token refresh (user mode only)
|
|
1783
|
+
*/
|
|
1784
|
+
setRefreshCallback(callback) {
|
|
1785
|
+
this.refreshCallback = callback;
|
|
1786
|
+
}
|
|
1787
|
+
/**
|
|
1788
|
+
* Set access token directly (user mode only)
|
|
1789
|
+
*/
|
|
1790
|
+
setTokens(accessToken, refreshToken) {
|
|
1791
|
+
this.tokenManager.setTokens(accessToken, refreshToken);
|
|
1792
|
+
}
|
|
1793
|
+
/**
|
|
1794
|
+
* Get current access token (user mode only)
|
|
1795
|
+
*/
|
|
1796
|
+
async getAccessToken() {
|
|
1797
|
+
if (this.config.mode === "partner") {
|
|
1798
|
+
return null;
|
|
1799
|
+
}
|
|
1800
|
+
return this.tokenManager.getValidAccessToken(this.refreshCallback);
|
|
1801
|
+
}
|
|
1802
|
+
/**
|
|
1803
|
+
* Clear stored tokens (user mode only)
|
|
1804
|
+
*/
|
|
1805
|
+
clearTokens() {
|
|
1806
|
+
this.tokenManager.clearTokens();
|
|
1807
|
+
}
|
|
1808
|
+
/**
|
|
1809
|
+
* Make authenticated API request
|
|
1810
|
+
*/
|
|
1811
|
+
async request(options) {
|
|
1812
|
+
const { method, path, body, headers = {}, useApiKey = false, skipAuth = false } = options;
|
|
1813
|
+
const url = `${this.config.baseUrl}${path}`;
|
|
1814
|
+
const requestHeaders = {
|
|
1815
|
+
"Content-Type": "application/json",
|
|
1816
|
+
"User-Agent": "Diviswap-SDK/2.0",
|
|
1817
|
+
...headers
|
|
1818
|
+
};
|
|
1819
|
+
if (!skipAuth) {
|
|
1820
|
+
if (this.config.mode === "partner") {
|
|
1821
|
+
await this.addPartnerAuth(method, path, body, requestHeaders);
|
|
1822
|
+
} else {
|
|
1823
|
+
await this.addUserAuth(useApiKey, requestHeaders);
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
try {
|
|
1827
|
+
const controller = new AbortController();
|
|
1828
|
+
const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
|
|
1829
|
+
const response = await fetch(url, {
|
|
1830
|
+
method,
|
|
1831
|
+
headers: requestHeaders,
|
|
1832
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
1833
|
+
signal: controller.signal
|
|
1834
|
+
});
|
|
1835
|
+
clearTimeout(timeoutId);
|
|
1836
|
+
const responseText = await response.text();
|
|
1837
|
+
let responseData;
|
|
1838
|
+
try {
|
|
1839
|
+
responseData = responseText ? JSON.parse(responseText) : null;
|
|
1840
|
+
} catch {
|
|
1841
|
+
responseData = responseText;
|
|
1842
|
+
}
|
|
1843
|
+
if (!response.ok) {
|
|
1844
|
+
await this.handleErrorResponse(response, responseData);
|
|
1845
|
+
}
|
|
1846
|
+
return responseData;
|
|
1847
|
+
} catch (error) {
|
|
1848
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
1849
|
+
throw new NetworkError("Request timeout");
|
|
1850
|
+
}
|
|
1851
|
+
if (error instanceof DiviswapError) {
|
|
1852
|
+
throw error;
|
|
1853
|
+
}
|
|
1854
|
+
throw new NetworkError(`Network request failed: ${error}`);
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
/**
|
|
1858
|
+
* Add partner authentication headers
|
|
1859
|
+
*/
|
|
1860
|
+
async addPartnerAuth(method, path, body, headers) {
|
|
1861
|
+
if (!this.partnerAuth) {
|
|
1862
|
+
throw new AuthenticationError("Partner authentication not configured");
|
|
1863
|
+
}
|
|
1864
|
+
const bodyString = body ? JSON.stringify(body) : "";
|
|
1865
|
+
const urlParts = path.split("?");
|
|
1866
|
+
const pathOnly = urlParts[0];
|
|
1867
|
+
const queryString = urlParts.length > 1 ? urlParts[1] : "";
|
|
1868
|
+
if (this.config.authMethod === "jwt") {
|
|
1869
|
+
const jwt = this.partnerAuth.generateJWT({
|
|
1870
|
+
audience: "api.diviswap.io",
|
|
1871
|
+
expiresIn: 300
|
|
1872
|
+
});
|
|
1873
|
+
headers["Authorization"] = `Bearer ${jwt}`;
|
|
1874
|
+
} else {
|
|
1875
|
+
const hmacHeaders = this.partnerAuth.generateHMACHeaders(
|
|
1876
|
+
method,
|
|
1877
|
+
pathOnly,
|
|
1878
|
+
queryString,
|
|
1879
|
+
bodyString
|
|
1880
|
+
);
|
|
1881
|
+
Object.assign(headers, hmacHeaders);
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
/**
|
|
1885
|
+
* Add user authentication headers (legacy)
|
|
1886
|
+
*/
|
|
1887
|
+
async addUserAuth(useApiKey, headers) {
|
|
1888
|
+
if (!this.config.apiKey || !this.config.clientId) {
|
|
1889
|
+
throw new AuthenticationError("User authentication not configured");
|
|
1890
|
+
}
|
|
1891
|
+
headers["X-CLIENT-ID"] = this.config.clientId;
|
|
1892
|
+
headers["X-TIMESTAMP"] = Math.floor(Date.now() / 1e3).toString();
|
|
1893
|
+
headers["X-API-Key"] = this.config.apiKey;
|
|
1894
|
+
if (!useApiKey) {
|
|
1895
|
+
const accessToken = await this.tokenManager.getValidAccessToken(this.refreshCallback);
|
|
1896
|
+
if (accessToken) {
|
|
1897
|
+
headers["Authorization"] = `Bearer ${accessToken}`;
|
|
1898
|
+
}
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
async handleErrorResponse(response, data) {
|
|
1902
|
+
const status = response.status;
|
|
1903
|
+
const message = data?.error || data?.message || `HTTP ${status}`;
|
|
1904
|
+
if (status === 403 && data?.kyc_uri) {
|
|
1905
|
+
const error = new AuthenticationError(message);
|
|
1906
|
+
error.kycUri = data.kyc_uri;
|
|
1907
|
+
error.requiredLevel = data.required_level;
|
|
1908
|
+
throw error;
|
|
1909
|
+
}
|
|
1910
|
+
switch (status) {
|
|
1911
|
+
case 400:
|
|
1912
|
+
throw new ValidationError(message);
|
|
1913
|
+
case 401:
|
|
1914
|
+
case 403:
|
|
1915
|
+
throw new AuthenticationError(message);
|
|
1916
|
+
case 404:
|
|
1917
|
+
throw new DiviswapError(`Resource not found: ${message}`);
|
|
1918
|
+
case 429:
|
|
1919
|
+
throw new DiviswapError(`Rate limit exceeded: ${message}`);
|
|
1920
|
+
case 500:
|
|
1921
|
+
case 502:
|
|
1922
|
+
case 503:
|
|
1923
|
+
case 504:
|
|
1924
|
+
throw new NetworkError(`Server error: ${message}`);
|
|
1925
|
+
default:
|
|
1926
|
+
throw new DiviswapError(`API error: ${message}`);
|
|
1927
|
+
}
|
|
1928
|
+
}
|
|
1929
|
+
// Convenience methods
|
|
1930
|
+
async get(path, options = {}) {
|
|
1931
|
+
return this.request({ method: "GET", path, ...options });
|
|
1932
|
+
}
|
|
1933
|
+
async post(path, body, options = {}) {
|
|
1934
|
+
return this.request({ method: "POST", path, body, ...options });
|
|
1935
|
+
}
|
|
1936
|
+
async put(path, body, options = {}) {
|
|
1937
|
+
return this.request({ method: "PUT", path, body, ...options });
|
|
1938
|
+
}
|
|
1939
|
+
async delete(path, options = {}) {
|
|
1940
|
+
return this.request({ method: "DELETE", path, ...options });
|
|
1941
|
+
}
|
|
1942
|
+
};
|
|
1943
|
+
|
|
1944
|
+
// src/client.ts
|
|
1945
|
+
var _Diviswap = class _Diviswap {
|
|
1946
|
+
constructor(config) {
|
|
1947
|
+
this.config = config;
|
|
1948
|
+
this.validateConfig(config);
|
|
1949
|
+
const useLocalStorage = config.tokenStorage === "localStorage" || !config.tokenStorage;
|
|
1950
|
+
this.apiClient = UnifiedApiClient.fromConfig(config, useLocalStorage);
|
|
1951
|
+
this.auth = new AuthModule(this.apiClient);
|
|
1952
|
+
this.payees = new PayeesModule(this.apiClient);
|
|
1953
|
+
this.transactions = new TransactionsModule(this.apiClient, config.environment || "sandbox");
|
|
1954
|
+
this.kyc = new KycModule(this.apiClient);
|
|
1955
|
+
this.fees = new FeesModule(this.apiClient);
|
|
1956
|
+
this.addresses = new AddressesModule(this.apiClient);
|
|
1957
|
+
this.webhooks = new WebhooksModule(this.apiClient);
|
|
1958
|
+
}
|
|
1959
|
+
/**
|
|
1960
|
+
* Initialize the Diviswap SDK
|
|
1961
|
+
*
|
|
1962
|
+
* @param config - SDK configuration
|
|
1963
|
+
* @returns Diviswap SDK instance
|
|
1964
|
+
*
|
|
1965
|
+
* @example
|
|
1966
|
+
* ```typescript
|
|
1967
|
+
* const diviswap = Diviswap.init({
|
|
1968
|
+
* apiKey: 'your-api-key',
|
|
1969
|
+
* clientId: 'your-client-id'
|
|
1970
|
+
* });
|
|
1971
|
+
* ```
|
|
1972
|
+
*/
|
|
1973
|
+
static init(config) {
|
|
1974
|
+
if (!_Diviswap.instance) {
|
|
1975
|
+
_Diviswap.instance = new _Diviswap(config);
|
|
1976
|
+
}
|
|
1977
|
+
return _Diviswap.instance;
|
|
1978
|
+
}
|
|
1979
|
+
/**
|
|
1980
|
+
* Get the current SDK instance
|
|
1981
|
+
* @throws {ConfigurationError} If SDK hasn't been initialized
|
|
1982
|
+
*/
|
|
1983
|
+
static getInstance() {
|
|
1984
|
+
if (!_Diviswap.instance) {
|
|
1985
|
+
throw new ConfigurationError("Diviswap SDK not initialized. Call Diviswap.init() first.");
|
|
1986
|
+
}
|
|
1987
|
+
return _Diviswap.instance;
|
|
1988
|
+
}
|
|
1989
|
+
/**
|
|
1990
|
+
* Reset the SDK instance (useful for testing)
|
|
1991
|
+
*/
|
|
1992
|
+
static reset() {
|
|
1993
|
+
_Diviswap.instance = null;
|
|
1994
|
+
}
|
|
1995
|
+
/**
|
|
1996
|
+
* Update SDK configuration
|
|
1997
|
+
* @deprecated Configuration updates require re-initialization. Call Diviswap.reset() then Diviswap.init() with new config.
|
|
1998
|
+
*/
|
|
1999
|
+
updateConfig(_config) {
|
|
2000
|
+
throw new ConfigurationError("Configuration updates require re-initialization. Call Diviswap.reset() then Diviswap.init() with new config.");
|
|
2001
|
+
}
|
|
2002
|
+
/**
|
|
2003
|
+
* Get current configuration (excluding sensitive data)
|
|
2004
|
+
*/
|
|
2005
|
+
getConfig() {
|
|
2006
|
+
return {
|
|
2007
|
+
environment: this.config.environment,
|
|
2008
|
+
apiUrl: this.config.apiUrl,
|
|
2009
|
+
debug: this.config.debug,
|
|
2010
|
+
timeout: this.config.timeout
|
|
2011
|
+
};
|
|
2012
|
+
}
|
|
2013
|
+
/**
|
|
2014
|
+
* Get current access token (for developers who need it for custom API calls)
|
|
2015
|
+
* Only available in user authentication mode.
|
|
2016
|
+
*
|
|
2017
|
+
* @example
|
|
2018
|
+
* ```typescript
|
|
2019
|
+
* const token = await diviswap.getAccessToken();
|
|
2020
|
+
* if (token) {
|
|
2021
|
+
* // Use token for custom API calls
|
|
2022
|
+
* fetch('https://api.diviswap.io/custom-endpoint', {
|
|
2023
|
+
* headers: { 'Authorization': `Bearer ${token}` }
|
|
2024
|
+
* });
|
|
2025
|
+
* }
|
|
2026
|
+
* ```
|
|
2027
|
+
*/
|
|
2028
|
+
async getAccessToken() {
|
|
2029
|
+
return this.apiClient.getAccessToken();
|
|
2030
|
+
}
|
|
2031
|
+
/**
|
|
2032
|
+
* Set access token (for server-side usage where tokens are stored externally)
|
|
2033
|
+
* Only available in user authentication mode.
|
|
2034
|
+
*
|
|
2035
|
+
* @example
|
|
2036
|
+
* ```typescript
|
|
2037
|
+
* // In a Next.js API route where token is stored in cookies
|
|
2038
|
+
* const token = cookies().get('diviswap_session')?.value;
|
|
2039
|
+
* if (token) {
|
|
2040
|
+
* diviswap.setAccessToken(token);
|
|
2041
|
+
* }
|
|
2042
|
+
* ```
|
|
2043
|
+
*/
|
|
2044
|
+
setAccessToken(accessToken, refreshToken) {
|
|
2045
|
+
this.apiClient.setTokens(accessToken, refreshToken);
|
|
2046
|
+
}
|
|
2047
|
+
/**
|
|
2048
|
+
* Set customer context for partner authentication mode
|
|
2049
|
+
*
|
|
2050
|
+
* @example
|
|
2051
|
+
* ```typescript
|
|
2052
|
+
* // For partner auth mode - link requests to a specific customer
|
|
2053
|
+
* diviswap.setCustomer('user-123', 'user@example.com');
|
|
2054
|
+
*
|
|
2055
|
+
* // Now all API calls will be made on behalf of this customer
|
|
2056
|
+
* const payees = await diviswap.payees.getAll();
|
|
2057
|
+
* ```
|
|
2058
|
+
*/
|
|
2059
|
+
setCustomer(customerId, customerEmail) {
|
|
2060
|
+
this.apiClient.setCustomer(customerId, customerEmail);
|
|
2061
|
+
}
|
|
2062
|
+
/**
|
|
2063
|
+
* Clear customer context for partner authentication mode
|
|
2064
|
+
*/
|
|
2065
|
+
clearCustomer() {
|
|
2066
|
+
this.apiClient.clearCustomer();
|
|
2067
|
+
}
|
|
2068
|
+
validateConfig(config) {
|
|
2069
|
+
const isPartnerMode = "mode" in config && config.mode === "partner" || "keyId" in config && "secretKey" in config;
|
|
2070
|
+
if (isPartnerMode) {
|
|
2071
|
+
const partnerConfig = config;
|
|
2072
|
+
if (!partnerConfig.keyId) {
|
|
2073
|
+
throw new ConfigurationError("Partner keyId is required for partner authentication");
|
|
2074
|
+
}
|
|
2075
|
+
if (!partnerConfig.secretKey) {
|
|
2076
|
+
throw new ConfigurationError("Partner secretKey is required for partner authentication");
|
|
2077
|
+
}
|
|
2078
|
+
if (partnerConfig.authMethod && !["hmac", "jwt"].includes(partnerConfig.authMethod)) {
|
|
2079
|
+
throw new ConfigurationError('Invalid authMethod. Must be either "hmac" or "jwt"');
|
|
2080
|
+
}
|
|
2081
|
+
} else {
|
|
2082
|
+
const userConfig = config;
|
|
2083
|
+
if (!userConfig.apiKey) {
|
|
2084
|
+
throw new ConfigurationError("API Key is required for user authentication");
|
|
2085
|
+
}
|
|
2086
|
+
if (!userConfig.clientId) {
|
|
2087
|
+
throw new ConfigurationError("Client ID is required for user authentication");
|
|
2088
|
+
}
|
|
2089
|
+
}
|
|
2090
|
+
if (config.environment && !["production", "sandbox", "development"].includes(config.environment)) {
|
|
2091
|
+
throw new ConfigurationError("Invalid environment. Must be one of: production, sandbox, development");
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
};
|
|
2095
|
+
_Diviswap.instance = null;
|
|
2096
|
+
var Diviswap = _Diviswap;
|
|
2097
|
+
|
|
2098
|
+
// src/integrations/wallet.ts
|
|
2099
|
+
var _WalletTracker = class _WalletTracker {
|
|
2100
|
+
constructor(config = {}) {
|
|
2101
|
+
this.wallet = null;
|
|
2102
|
+
this.diviswap = null;
|
|
2103
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
2104
|
+
this.config = {
|
|
2105
|
+
trackAccountChanges: true,
|
|
2106
|
+
trackChainChanges: true,
|
|
2107
|
+
setAsDefault: true,
|
|
2108
|
+
...config
|
|
2109
|
+
};
|
|
2110
|
+
}
|
|
2111
|
+
/**
|
|
2112
|
+
* Get or create the wallet tracker instance
|
|
2113
|
+
*/
|
|
2114
|
+
static getInstance(config) {
|
|
2115
|
+
if (!_WalletTracker.instance) {
|
|
2116
|
+
_WalletTracker.instance = new _WalletTracker(config);
|
|
2117
|
+
}
|
|
2118
|
+
return _WalletTracker.instance;
|
|
2119
|
+
}
|
|
2120
|
+
/**
|
|
2121
|
+
* Initialize wallet tracking with Diviswap SDK instance
|
|
2122
|
+
*/
|
|
2123
|
+
init(diviswap, wallet) {
|
|
2124
|
+
this.diviswap = diviswap;
|
|
2125
|
+
if (wallet) {
|
|
2126
|
+
this.wallet = wallet;
|
|
2127
|
+
} else if (typeof window !== "undefined" && window.ethereum) {
|
|
2128
|
+
this.wallet = window.ethereum;
|
|
2129
|
+
}
|
|
2130
|
+
if (this.wallet && this.config.trackAccountChanges) {
|
|
2131
|
+
this.setupAccountChangeListener();
|
|
2132
|
+
}
|
|
2133
|
+
if (this.wallet && this.config.trackChainChanges) {
|
|
2134
|
+
this.setupChainChangeListener();
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
/**
|
|
2138
|
+
* Connect and track a wallet
|
|
2139
|
+
*/
|
|
2140
|
+
async connect() {
|
|
2141
|
+
if (!this.wallet) {
|
|
2142
|
+
throw new Error("No wallet provider available");
|
|
2143
|
+
}
|
|
2144
|
+
if (!this.diviswap) {
|
|
2145
|
+
throw new Error("Diviswap SDK not initialized. Call init() first.");
|
|
2146
|
+
}
|
|
2147
|
+
try {
|
|
2148
|
+
const accounts = await this.wallet.request({
|
|
2149
|
+
method: "eth_requestAccounts"
|
|
2150
|
+
});
|
|
2151
|
+
const chainId = await this.wallet.request({
|
|
2152
|
+
method: "eth_chainId"
|
|
2153
|
+
});
|
|
2154
|
+
const numericChainId = parseInt(chainId, 16);
|
|
2155
|
+
const connections = [];
|
|
2156
|
+
for (const account of accounts) {
|
|
2157
|
+
const connection = {
|
|
2158
|
+
address: account,
|
|
2159
|
+
chainId: numericChainId,
|
|
2160
|
+
chainName: this.getChainName(numericChainId)
|
|
2161
|
+
};
|
|
2162
|
+
await this.diviswap.addresses.trackWallet(connection);
|
|
2163
|
+
connections.push(connection);
|
|
2164
|
+
}
|
|
2165
|
+
return connections;
|
|
2166
|
+
} catch (error) {
|
|
2167
|
+
console.error("Failed to connect wallet:", error);
|
|
2168
|
+
throw error;
|
|
2169
|
+
}
|
|
2170
|
+
}
|
|
2171
|
+
/**
|
|
2172
|
+
* Track current wallet state without requesting connection
|
|
2173
|
+
*/
|
|
2174
|
+
async trackCurrent() {
|
|
2175
|
+
if (!this.wallet) {
|
|
2176
|
+
throw new Error("No wallet provider available");
|
|
2177
|
+
}
|
|
2178
|
+
if (!this.diviswap) {
|
|
2179
|
+
throw new Error("Diviswap SDK not initialized. Call init() first.");
|
|
2180
|
+
}
|
|
2181
|
+
try {
|
|
2182
|
+
const accounts = await this.wallet.request({
|
|
2183
|
+
method: "eth_accounts"
|
|
2184
|
+
});
|
|
2185
|
+
if (accounts.length === 0) {
|
|
2186
|
+
return [];
|
|
2187
|
+
}
|
|
2188
|
+
const chainId = await this.wallet.request({
|
|
2189
|
+
method: "eth_chainId"
|
|
2190
|
+
});
|
|
2191
|
+
const numericChainId = parseInt(chainId, 16);
|
|
2192
|
+
const connections = [];
|
|
2193
|
+
for (const account of accounts) {
|
|
2194
|
+
const connection = {
|
|
2195
|
+
address: account,
|
|
2196
|
+
chainId: numericChainId,
|
|
2197
|
+
chainName: this.getChainName(numericChainId)
|
|
2198
|
+
};
|
|
2199
|
+
await this.diviswap.addresses.trackWallet(connection);
|
|
2200
|
+
connections.push(connection);
|
|
2201
|
+
}
|
|
2202
|
+
return connections;
|
|
2203
|
+
} catch (error) {
|
|
2204
|
+
console.error("Failed to track current wallet state:", error);
|
|
2205
|
+
throw error;
|
|
2206
|
+
}
|
|
2207
|
+
}
|
|
2208
|
+
/**
|
|
2209
|
+
* Setup listener for account changes
|
|
2210
|
+
*/
|
|
2211
|
+
setupAccountChangeListener() {
|
|
2212
|
+
if (!this.wallet?.on) return;
|
|
2213
|
+
const handler = async (accounts) => {
|
|
2214
|
+
if (!this.diviswap) return;
|
|
2215
|
+
try {
|
|
2216
|
+
const chainId = await this.wallet.request({
|
|
2217
|
+
method: "eth_chainId"
|
|
2218
|
+
});
|
|
2219
|
+
const numericChainId = parseInt(chainId, 16);
|
|
2220
|
+
for (const account of accounts) {
|
|
2221
|
+
const connection = {
|
|
2222
|
+
address: account,
|
|
2223
|
+
chainId: numericChainId,
|
|
2224
|
+
chainName: this.getChainName(numericChainId)
|
|
2225
|
+
};
|
|
2226
|
+
await this.diviswap.addresses.trackWallet(connection);
|
|
2227
|
+
}
|
|
2228
|
+
} catch (error) {
|
|
2229
|
+
console.error("Failed to handle account change:", error);
|
|
2230
|
+
}
|
|
2231
|
+
};
|
|
2232
|
+
this.wallet.on("accountsChanged", handler);
|
|
2233
|
+
this.listeners.set("accountsChanged", handler);
|
|
2234
|
+
}
|
|
2235
|
+
/**
|
|
2236
|
+
* Setup listener for chain changes
|
|
2237
|
+
*/
|
|
2238
|
+
setupChainChangeListener() {
|
|
2239
|
+
if (!this.wallet?.on) return;
|
|
2240
|
+
const handler = async (chainId) => {
|
|
2241
|
+
if (!this.diviswap) return;
|
|
2242
|
+
try {
|
|
2243
|
+
const accounts = await this.wallet.request({
|
|
2244
|
+
method: "eth_accounts"
|
|
2245
|
+
});
|
|
2246
|
+
const numericChainId = parseInt(chainId, 16);
|
|
2247
|
+
for (const account of accounts) {
|
|
2248
|
+
const connection = {
|
|
2249
|
+
address: account,
|
|
2250
|
+
chainId: numericChainId,
|
|
2251
|
+
chainName: this.getChainName(numericChainId)
|
|
2252
|
+
};
|
|
2253
|
+
await this.diviswap.addresses.trackWallet(connection);
|
|
2254
|
+
}
|
|
2255
|
+
} catch (error) {
|
|
2256
|
+
console.error("Failed to handle chain change:", error);
|
|
2257
|
+
}
|
|
2258
|
+
};
|
|
2259
|
+
this.wallet.on("chainChanged", handler);
|
|
2260
|
+
this.listeners.set("chainChanged", handler);
|
|
2261
|
+
}
|
|
2262
|
+
/**
|
|
2263
|
+
* Get chain name from chain ID
|
|
2264
|
+
*/
|
|
2265
|
+
getChainName(chainId) {
|
|
2266
|
+
const builtInChain = Object.entries(CHAIN_IDS).find(([_, id]) => id === chainId)?.[0];
|
|
2267
|
+
if (builtInChain) return builtInChain;
|
|
2268
|
+
return this.config.customChains?.[chainId];
|
|
2269
|
+
}
|
|
2270
|
+
/**
|
|
2271
|
+
* Cleanup listeners
|
|
2272
|
+
*/
|
|
2273
|
+
cleanup() {
|
|
2274
|
+
if (this.wallet?.removeListener) {
|
|
2275
|
+
for (const [event, handler] of this.listeners) {
|
|
2276
|
+
this.wallet.removeListener(event, handler);
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
this.listeners.clear();
|
|
2280
|
+
}
|
|
2281
|
+
/**
|
|
2282
|
+
* Update configuration
|
|
2283
|
+
*/
|
|
2284
|
+
updateConfig(config) {
|
|
2285
|
+
this.config = { ...this.config, ...config };
|
|
2286
|
+
}
|
|
2287
|
+
};
|
|
2288
|
+
_WalletTracker.instance = null;
|
|
2289
|
+
var WalletTracker = _WalletTracker;
|
|
2290
|
+
async function connectWallet(diviswap, wallet, config) {
|
|
2291
|
+
const tracker = WalletTracker.getInstance(config);
|
|
2292
|
+
tracker.init(diviswap, wallet);
|
|
2293
|
+
return tracker.connect();
|
|
2294
|
+
}
|
|
2295
|
+
async function trackCurrentWallet(diviswap, wallet, config) {
|
|
2296
|
+
const tracker = WalletTracker.getInstance(config);
|
|
2297
|
+
tracker.init(diviswap, wallet);
|
|
2298
|
+
return tracker.trackCurrent();
|
|
2299
|
+
}
|
|
2300
|
+
function setupWalletTracking(diviswap, wallet, config) {
|
|
2301
|
+
const tracker = WalletTracker.getInstance(config);
|
|
2302
|
+
tracker.init(diviswap, wallet);
|
|
2303
|
+
return tracker;
|
|
2304
|
+
}
|
|
2305
|
+
|
|
2306
|
+
// src/utils/web3.ts
|
|
2307
|
+
function extractTransactionHash(result) {
|
|
2308
|
+
if (typeof result === "string") {
|
|
2309
|
+
return result;
|
|
2310
|
+
}
|
|
2311
|
+
if (typeof result === "object" && result !== null && "hash" in result) {
|
|
2312
|
+
return result.hash;
|
|
2313
|
+
}
|
|
2314
|
+
return result;
|
|
2315
|
+
}
|
|
2316
|
+
|
|
2317
|
+
exports.AuthenticationError = AuthenticationError;
|
|
2318
|
+
exports.CHAIN_IDS = CHAIN_IDS;
|
|
2319
|
+
exports.CHAIN_ID_TO_NAME = CHAIN_ID_TO_NAME;
|
|
2320
|
+
exports.CHAIN_NAME_TO_ID = CHAIN_NAME_TO_ID;
|
|
2321
|
+
exports.ConfigurationError = ConfigurationError;
|
|
2322
|
+
exports.DEVELOPMENT_DEPOSIT_ADDRESSES = DEVELOPMENT_DEPOSIT_ADDRESSES;
|
|
2323
|
+
exports.Diviswap = Diviswap;
|
|
2324
|
+
exports.DiviswapError = DiviswapError;
|
|
2325
|
+
exports.LiberEx = Diviswap;
|
|
2326
|
+
exports.LiberExError = LiberExError;
|
|
2327
|
+
exports.NetworkError = NetworkError;
|
|
2328
|
+
exports.PRODUCTION_DEPOSIT_ADDRESSES = PRODUCTION_DEPOSIT_ADDRESSES;
|
|
2329
|
+
exports.SANDBOX_DEPOSIT_ADDRESSES = SANDBOX_DEPOSIT_ADDRESSES;
|
|
2330
|
+
exports.STABLECOIN_ADDRESSES = STABLECOIN_ADDRESSES;
|
|
2331
|
+
exports.ValidationError = ValidationError;
|
|
2332
|
+
exports.WalletTracker = WalletTracker;
|
|
2333
|
+
exports.connectWallet = connectWallet;
|
|
2334
|
+
exports.extractTransactionHash = extractTransactionHash;
|
|
2335
|
+
exports.getDepositAddresses = getDepositAddresses;
|
|
2336
|
+
exports.setupWalletTracking = setupWalletTracking;
|
|
2337
|
+
exports.trackCurrentWallet = trackCurrentWallet;
|
|
2338
|
+
//# sourceMappingURL=index.js.map
|
|
2339
|
+
//# sourceMappingURL=index.js.map
|