@zubari/sdk 0.2.8 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{TransactionService-8xSEGoWA.d.mts → TransactionService-DURp3bRL.d.ts} +34 -10
- package/dist/{TransactionService-CaIcCoqY.d.ts → TransactionService-DuMJmrG3.d.mts} +34 -10
- package/dist/{WalletManager-CCs4Jsv7.d.ts → WalletManager-CEjN-YBF.d.ts} +12 -12
- package/dist/{WalletManager-B1qvFF4K.d.mts → WalletManager-bo35aHOJ.d.mts} +12 -12
- package/dist/{index-BOc9U2TK.d.mts → index-BpjMiC3n.d.ts} +22 -11
- package/dist/{index-Cx389p_j.d.mts → index-DF0Gf8NK.d.mts} +7 -1
- package/dist/{index-Cx389p_j.d.ts → index-DF0Gf8NK.d.ts} +7 -1
- package/dist/{index-Cqrpp3XA.d.ts → index-DJnsirV5.d.mts} +22 -11
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +3064 -1770
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3064 -1770
- package/dist/index.mjs.map +1 -1
- package/dist/protocols/index.d.mts +54 -22
- package/dist/protocols/index.d.ts +54 -22
- package/dist/protocols/index.js +1008 -76
- package/dist/protocols/index.js.map +1 -1
- package/dist/protocols/index.mjs +1008 -76
- package/dist/protocols/index.mjs.map +1 -1
- package/dist/react/index.d.mts +3 -3
- package/dist/react/index.d.ts +3 -3
- package/dist/react/index.js +884 -884
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +884 -884
- package/dist/react/index.mjs.map +1 -1
- package/dist/services/index.d.mts +2 -2
- package/dist/services/index.d.ts +2 -2
- package/dist/services/index.js +152 -75
- package/dist/services/index.js.map +1 -1
- package/dist/services/index.mjs +152 -75
- package/dist/services/index.mjs.map +1 -1
- package/dist/wallet/index.d.mts +3 -3
- package/dist/wallet/index.d.ts +3 -3
- package/dist/wallet/index.js +1352 -1105
- package/dist/wallet/index.js.map +1 -1
- package/dist/wallet/index.mjs +1352 -1105
- package/dist/wallet/index.mjs.map +1 -1
- package/package.json +13 -12
package/dist/protocols/index.mjs
CHANGED
|
@@ -42,18 +42,702 @@ var CURRENCY_ADDRESSES = {
|
|
|
42
42
|
}
|
|
43
43
|
};
|
|
44
44
|
|
|
45
|
+
// src/services/ZubariApiClient.ts
|
|
46
|
+
var ZubariApiClient = class {
|
|
47
|
+
config;
|
|
48
|
+
constructor(config) {
|
|
49
|
+
this.config = {
|
|
50
|
+
baseUrl: config.baseUrl.replace(/\/$/, ""),
|
|
51
|
+
// Remove trailing slash
|
|
52
|
+
timeout: config.timeout || 3e4,
|
|
53
|
+
authToken: config.authToken
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Set the authentication token
|
|
58
|
+
*/
|
|
59
|
+
setAuthToken(token) {
|
|
60
|
+
this.config.authToken = token;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Clear the authentication token
|
|
64
|
+
*/
|
|
65
|
+
clearAuthToken() {
|
|
66
|
+
this.config.authToken = void 0;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Make an authenticated request to the API
|
|
70
|
+
*/
|
|
71
|
+
async request(method, path, body) {
|
|
72
|
+
const headers = {
|
|
73
|
+
"Content-Type": "application/json"
|
|
74
|
+
};
|
|
75
|
+
if (this.config.authToken) {
|
|
76
|
+
headers["Authorization"] = `Bearer ${this.config.authToken}`;
|
|
77
|
+
}
|
|
78
|
+
const response = await fetch(`${this.config.baseUrl}${path}`, {
|
|
79
|
+
method,
|
|
80
|
+
headers,
|
|
81
|
+
body: body ? JSON.stringify(body) : void 0
|
|
82
|
+
});
|
|
83
|
+
if (!response.ok) {
|
|
84
|
+
const errorData = await response.json().catch(() => ({}));
|
|
85
|
+
throw new Error(errorData.error || `HTTP ${response.status}: ${response.statusText}`);
|
|
86
|
+
}
|
|
87
|
+
return response.json();
|
|
88
|
+
}
|
|
89
|
+
// ============ NFT Methods ============
|
|
90
|
+
/**
|
|
91
|
+
* Get all NFTs with optional filters
|
|
92
|
+
*/
|
|
93
|
+
async getNFTs(filters) {
|
|
94
|
+
try {
|
|
95
|
+
const params = new URLSearchParams();
|
|
96
|
+
if (filters) {
|
|
97
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
98
|
+
if (value !== void 0) {
|
|
99
|
+
params.append(key, String(value));
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
const queryString = params.toString();
|
|
104
|
+
const path = `/api/nfts${queryString ? `?${queryString}` : ""}`;
|
|
105
|
+
return await this.request("GET", path);
|
|
106
|
+
} catch (error) {
|
|
107
|
+
return {
|
|
108
|
+
success: false,
|
|
109
|
+
error: error instanceof Error ? error.message : "Failed to get NFTs"
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Get a single NFT by ID
|
|
115
|
+
*/
|
|
116
|
+
async getNFT(nftId) {
|
|
117
|
+
try {
|
|
118
|
+
const nft = await this.request("GET", `/api/nfts/${nftId}`);
|
|
119
|
+
return { success: true, nft };
|
|
120
|
+
} catch (error) {
|
|
121
|
+
return {
|
|
122
|
+
success: false,
|
|
123
|
+
error: error instanceof Error ? error.message : "Failed to get NFT"
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Create a new NFT (lazy minted)
|
|
129
|
+
*/
|
|
130
|
+
async createNFT(data, image) {
|
|
131
|
+
try {
|
|
132
|
+
const formData = new FormData();
|
|
133
|
+
formData.append("image", image);
|
|
134
|
+
formData.append("name", data.name);
|
|
135
|
+
if (data.description) formData.append("description", data.description);
|
|
136
|
+
formData.append("price", data.price);
|
|
137
|
+
formData.append("currency", data.currency);
|
|
138
|
+
if (data.royaltyBps !== void 0) formData.append("royaltyBps", String(data.royaltyBps));
|
|
139
|
+
if (data.attributes) formData.append("attributes", JSON.stringify(data.attributes));
|
|
140
|
+
if (data.externalUrl) formData.append("externalUrl", data.externalUrl);
|
|
141
|
+
const headers = {};
|
|
142
|
+
if (this.config.authToken) {
|
|
143
|
+
headers["Authorization"] = `Bearer ${this.config.authToken}`;
|
|
144
|
+
}
|
|
145
|
+
const response = await fetch(`${this.config.baseUrl}/api/nfts`, {
|
|
146
|
+
method: "POST",
|
|
147
|
+
headers,
|
|
148
|
+
body: formData
|
|
149
|
+
});
|
|
150
|
+
if (!response.ok) {
|
|
151
|
+
const errorData = await response.json().catch(() => ({}));
|
|
152
|
+
throw new Error(errorData.error || `HTTP ${response.status}`);
|
|
153
|
+
}
|
|
154
|
+
const nft = await response.json();
|
|
155
|
+
return { success: true, nft };
|
|
156
|
+
} catch (error) {
|
|
157
|
+
return {
|
|
158
|
+
success: false,
|
|
159
|
+
error: error instanceof Error ? error.message : "Failed to create NFT"
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Create a voucher for an NFT (EIP-712 signed)
|
|
165
|
+
*/
|
|
166
|
+
async createVoucher(nftId, params) {
|
|
167
|
+
try {
|
|
168
|
+
return await this.request("POST", `/api/nfts/${nftId}/voucher`, params);
|
|
169
|
+
} catch (error) {
|
|
170
|
+
return {
|
|
171
|
+
success: false,
|
|
172
|
+
error: error instanceof Error ? error.message : "Failed to create voucher"
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Redeem an NFT voucher (buy/mint)
|
|
178
|
+
*/
|
|
179
|
+
async redeemVoucher(nftId, params) {
|
|
180
|
+
try {
|
|
181
|
+
return await this.request("POST", `/api/nfts/${nftId}/redeem`, params);
|
|
182
|
+
} catch (error) {
|
|
183
|
+
return {
|
|
184
|
+
success: false,
|
|
185
|
+
error: error instanceof Error ? error.message : "Failed to redeem voucher"
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Get voucher status for an NFT
|
|
191
|
+
*/
|
|
192
|
+
async getVoucherStatus(nftId) {
|
|
193
|
+
try {
|
|
194
|
+
return await this.request("GET", `/api/nfts/${nftId}/voucher/status`);
|
|
195
|
+
} catch (error) {
|
|
196
|
+
return {
|
|
197
|
+
success: false,
|
|
198
|
+
error: error instanceof Error ? error.message : "Failed to get voucher status"
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
// ============ Marketplace Methods ============
|
|
203
|
+
/**
|
|
204
|
+
* Get all active listings
|
|
205
|
+
*/
|
|
206
|
+
async getListings(filters) {
|
|
207
|
+
try {
|
|
208
|
+
const params = new URLSearchParams();
|
|
209
|
+
if (filters) {
|
|
210
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
211
|
+
if (value !== void 0) {
|
|
212
|
+
params.append(key, String(value));
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
const queryString = params.toString();
|
|
217
|
+
const path = `/api/market/listings${queryString ? `?${queryString}` : ""}`;
|
|
218
|
+
return await this.request("GET", path);
|
|
219
|
+
} catch (error) {
|
|
220
|
+
return {
|
|
221
|
+
success: false,
|
|
222
|
+
error: error instanceof Error ? error.message : "Failed to get listings"
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* List an NFT for sale
|
|
228
|
+
*/
|
|
229
|
+
async listItem(params) {
|
|
230
|
+
try {
|
|
231
|
+
return await this.request("POST", "/api/market/list", params);
|
|
232
|
+
} catch (error) {
|
|
233
|
+
return {
|
|
234
|
+
success: false,
|
|
235
|
+
error: error instanceof Error ? error.message : "Failed to list item"
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Buy a listed NFT
|
|
241
|
+
*/
|
|
242
|
+
async buyItem(params) {
|
|
243
|
+
try {
|
|
244
|
+
return await this.request("POST", "/api/market/buy", params);
|
|
245
|
+
} catch (error) {
|
|
246
|
+
return {
|
|
247
|
+
success: false,
|
|
248
|
+
error: error instanceof Error ? error.message : "Failed to buy item"
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Cancel a listing
|
|
254
|
+
*/
|
|
255
|
+
async cancelListing(params) {
|
|
256
|
+
try {
|
|
257
|
+
return await this.request("POST", "/api/market/cancel", params);
|
|
258
|
+
} catch (error) {
|
|
259
|
+
return {
|
|
260
|
+
success: false,
|
|
261
|
+
error: error instanceof Error ? error.message : "Failed to cancel listing"
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Update listing price
|
|
267
|
+
*/
|
|
268
|
+
async updateListingPrice(params) {
|
|
269
|
+
try {
|
|
270
|
+
return await this.request("PATCH", "/api/market/price", params);
|
|
271
|
+
} catch (error) {
|
|
272
|
+
return {
|
|
273
|
+
success: false,
|
|
274
|
+
error: error instanceof Error ? error.message : "Failed to update price"
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Get current user's listings
|
|
280
|
+
*/
|
|
281
|
+
async getMyListings(filters) {
|
|
282
|
+
try {
|
|
283
|
+
const params = new URLSearchParams();
|
|
284
|
+
if (filters) {
|
|
285
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
286
|
+
if (value !== void 0) {
|
|
287
|
+
params.append(key, String(value));
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
const queryString = params.toString();
|
|
292
|
+
const path = `/api/market/my/listings${queryString ? `?${queryString}` : ""}`;
|
|
293
|
+
return await this.request("GET", path);
|
|
294
|
+
} catch (error) {
|
|
295
|
+
return {
|
|
296
|
+
success: false,
|
|
297
|
+
error: error instanceof Error ? error.message : "Failed to get my listings"
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Get marketplace statistics
|
|
303
|
+
*/
|
|
304
|
+
async getMarketStats() {
|
|
305
|
+
try {
|
|
306
|
+
return await this.request("GET", "/api/market/stats");
|
|
307
|
+
} catch (error) {
|
|
308
|
+
return {
|
|
309
|
+
success: false,
|
|
310
|
+
error: error instanceof Error ? error.message : "Failed to get market stats"
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// ============ Tips Methods ============
|
|
315
|
+
/**
|
|
316
|
+
* Send a tip to a creator
|
|
317
|
+
*/
|
|
318
|
+
async sendTip(params) {
|
|
319
|
+
try {
|
|
320
|
+
return await this.request("POST", "/api/tips", params);
|
|
321
|
+
} catch (error) {
|
|
322
|
+
return {
|
|
323
|
+
success: false,
|
|
324
|
+
error: error instanceof Error ? error.message : "Failed to send tip"
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Get tip statistics for current user
|
|
330
|
+
*/
|
|
331
|
+
async getTipStats() {
|
|
332
|
+
try {
|
|
333
|
+
const data = await this.request("GET", "/api/tips/my/stats");
|
|
334
|
+
return { success: true, ...data };
|
|
335
|
+
} catch (error) {
|
|
336
|
+
return {
|
|
337
|
+
success: false,
|
|
338
|
+
error: error instanceof Error ? error.message : "Failed to get tip stats"
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Get tips sent by current user
|
|
344
|
+
*/
|
|
345
|
+
async getSentTips(filters) {
|
|
346
|
+
try {
|
|
347
|
+
const params = new URLSearchParams();
|
|
348
|
+
if (filters) {
|
|
349
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
350
|
+
if (value !== void 0) {
|
|
351
|
+
params.append(key, String(value));
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
const queryString = params.toString();
|
|
356
|
+
const path = `/api/tips/sent${queryString ? `?${queryString}` : ""}`;
|
|
357
|
+
const data = await this.request("GET", path);
|
|
358
|
+
return { success: true, ...data };
|
|
359
|
+
} catch (error) {
|
|
360
|
+
return {
|
|
361
|
+
success: false,
|
|
362
|
+
error: error instanceof Error ? error.message : "Failed to get sent tips"
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Get tips received by current user
|
|
368
|
+
*/
|
|
369
|
+
async getReceivedTips(filters) {
|
|
370
|
+
try {
|
|
371
|
+
const params = new URLSearchParams();
|
|
372
|
+
if (filters) {
|
|
373
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
374
|
+
if (value !== void 0) {
|
|
375
|
+
params.append(key, String(value));
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
const queryString = params.toString();
|
|
380
|
+
const path = `/api/tips/received${queryString ? `?${queryString}` : ""}`;
|
|
381
|
+
const data = await this.request("GET", path);
|
|
382
|
+
return { success: true, ...data };
|
|
383
|
+
} catch (error) {
|
|
384
|
+
return {
|
|
385
|
+
success: false,
|
|
386
|
+
error: error instanceof Error ? error.message : "Failed to get received tips"
|
|
387
|
+
};
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Get a single tip by ID
|
|
392
|
+
*/
|
|
393
|
+
async getTip(tipId) {
|
|
394
|
+
try {
|
|
395
|
+
const data = await this.request("GET", `/api/tips/${tipId}`);
|
|
396
|
+
return { success: true, tip: data.tip };
|
|
397
|
+
} catch (error) {
|
|
398
|
+
return {
|
|
399
|
+
success: false,
|
|
400
|
+
error: error instanceof Error ? error.message : "Failed to get tip"
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Update tip status (for transaction confirmation)
|
|
406
|
+
*/
|
|
407
|
+
async updateTipStatus(tipId, params) {
|
|
408
|
+
try {
|
|
409
|
+
const data = await this.request(
|
|
410
|
+
"PATCH",
|
|
411
|
+
`/api/tips/${tipId}/status`,
|
|
412
|
+
params
|
|
413
|
+
);
|
|
414
|
+
return { success: true, ...data };
|
|
415
|
+
} catch (error) {
|
|
416
|
+
return {
|
|
417
|
+
success: false,
|
|
418
|
+
error: error instanceof Error ? error.message : "Failed to update tip status"
|
|
419
|
+
};
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
// ============ Subscription Methods ============
|
|
423
|
+
/**
|
|
424
|
+
* Create a new subscription plan (creator only)
|
|
425
|
+
*/
|
|
426
|
+
async createSubscriptionPlan(params) {
|
|
427
|
+
try {
|
|
428
|
+
return await this.request("POST", "/api/subscriptions/plans", params);
|
|
429
|
+
} catch (error) {
|
|
430
|
+
return {
|
|
431
|
+
success: false,
|
|
432
|
+
error: error instanceof Error ? error.message : "Failed to create subscription plan"
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Get current user's subscription plans
|
|
438
|
+
*/
|
|
439
|
+
async getMySubscriptionPlans() {
|
|
440
|
+
try {
|
|
441
|
+
const data = await this.request("GET", "/api/subscriptions/plans");
|
|
442
|
+
return { success: true, plans: data.plans };
|
|
443
|
+
} catch (error) {
|
|
444
|
+
return {
|
|
445
|
+
success: false,
|
|
446
|
+
error: error instanceof Error ? error.message : "Failed to get subscription plans"
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Get subscription plan by ID
|
|
452
|
+
*/
|
|
453
|
+
async getSubscriptionPlan(planId) {
|
|
454
|
+
try {
|
|
455
|
+
const plan = await this.request(
|
|
456
|
+
"GET",
|
|
457
|
+
`/api/subscriptions/plans/${planId}`
|
|
458
|
+
);
|
|
459
|
+
return { success: true, plan };
|
|
460
|
+
} catch (error) {
|
|
461
|
+
return {
|
|
462
|
+
success: false,
|
|
463
|
+
error: error instanceof Error ? error.message : "Failed to get subscription plan"
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Delete/deactivate subscription plan
|
|
469
|
+
*/
|
|
470
|
+
async deleteSubscriptionPlan(planId) {
|
|
471
|
+
try {
|
|
472
|
+
const data = await this.request(
|
|
473
|
+
"DELETE",
|
|
474
|
+
`/api/subscriptions/plans/${planId}`
|
|
475
|
+
);
|
|
476
|
+
return { success: true, ...data };
|
|
477
|
+
} catch (error) {
|
|
478
|
+
return {
|
|
479
|
+
success: false,
|
|
480
|
+
error: error instanceof Error ? error.message : "Failed to delete subscription plan"
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* Subscribe to a plan
|
|
486
|
+
*/
|
|
487
|
+
async subscribe(params) {
|
|
488
|
+
try {
|
|
489
|
+
return await this.request("POST", "/api/subscriptions/subscribe", params);
|
|
490
|
+
} catch (error) {
|
|
491
|
+
return {
|
|
492
|
+
success: false,
|
|
493
|
+
error: error instanceof Error ? error.message : "Failed to subscribe"
|
|
494
|
+
};
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Get current user's subscriptions (as subscriber)
|
|
499
|
+
*/
|
|
500
|
+
async getMySubscriptions(filters) {
|
|
501
|
+
try {
|
|
502
|
+
const params = new URLSearchParams();
|
|
503
|
+
if (filters) {
|
|
504
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
505
|
+
if (value !== void 0) {
|
|
506
|
+
params.append(key, String(value));
|
|
507
|
+
}
|
|
508
|
+
});
|
|
509
|
+
}
|
|
510
|
+
const queryString = params.toString();
|
|
511
|
+
const path = `/api/subscriptions${queryString ? `?${queryString}` : ""}`;
|
|
512
|
+
const data = await this.request("GET", path);
|
|
513
|
+
return { success: true, ...data };
|
|
514
|
+
} catch (error) {
|
|
515
|
+
return {
|
|
516
|
+
success: false,
|
|
517
|
+
error: error instanceof Error ? error.message : "Failed to get subscriptions"
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
/**
|
|
522
|
+
* Get subscribers to current user's plans (as creator)
|
|
523
|
+
*/
|
|
524
|
+
async getMySubscribers(filters) {
|
|
525
|
+
try {
|
|
526
|
+
const params = new URLSearchParams();
|
|
527
|
+
if (filters) {
|
|
528
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
529
|
+
if (value !== void 0) {
|
|
530
|
+
params.append(key, String(value));
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
}
|
|
534
|
+
const queryString = params.toString();
|
|
535
|
+
const path = `/api/subscriptions/subscribers${queryString ? `?${queryString}` : ""}`;
|
|
536
|
+
const data = await this.request("GET", path);
|
|
537
|
+
return { success: true, ...data };
|
|
538
|
+
} catch (error) {
|
|
539
|
+
return {
|
|
540
|
+
success: false,
|
|
541
|
+
error: error instanceof Error ? error.message : "Failed to get subscribers"
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Cancel subscription
|
|
547
|
+
*/
|
|
548
|
+
async cancelSubscription(subscriptionId) {
|
|
549
|
+
try {
|
|
550
|
+
const data = await this.request("DELETE", `/api/subscriptions/${subscriptionId}`);
|
|
551
|
+
return { success: true, ...data };
|
|
552
|
+
} catch (error) {
|
|
553
|
+
return {
|
|
554
|
+
success: false,
|
|
555
|
+
error: error instanceof Error ? error.message : "Failed to cancel subscription"
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Create a subscription plan on-chain
|
|
561
|
+
*/
|
|
562
|
+
async createSubscriptionPlanOnChain(params) {
|
|
563
|
+
try {
|
|
564
|
+
return await this.request("POST", "/api/subscriptions/contract/plans", params);
|
|
565
|
+
} catch (error) {
|
|
566
|
+
return {
|
|
567
|
+
success: false,
|
|
568
|
+
error: error instanceof Error ? error.message : "Failed to create plan on-chain"
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Subscribe to a plan on-chain
|
|
574
|
+
*/
|
|
575
|
+
async subscribeOnChain(params) {
|
|
576
|
+
try {
|
|
577
|
+
return await this.request("POST", "/api/subscriptions/contract/subscribe", params);
|
|
578
|
+
} catch (error) {
|
|
579
|
+
return {
|
|
580
|
+
success: false,
|
|
581
|
+
error: error instanceof Error ? error.message : "Failed to subscribe on-chain"
|
|
582
|
+
};
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Cancel subscription on-chain
|
|
587
|
+
*/
|
|
588
|
+
async cancelSubscriptionOnChain(subscriptionId, seed) {
|
|
589
|
+
try {
|
|
590
|
+
return await this.request(
|
|
591
|
+
"POST",
|
|
592
|
+
"/api/subscriptions/contract/cancel",
|
|
593
|
+
{ subscriptionId, seed }
|
|
594
|
+
);
|
|
595
|
+
} catch (error) {
|
|
596
|
+
return {
|
|
597
|
+
success: false,
|
|
598
|
+
error: error instanceof Error ? error.message : "Failed to cancel subscription on-chain"
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Check if user is subscribed to a creator on-chain
|
|
604
|
+
*/
|
|
605
|
+
async isSubscribed(subscriber, creator) {
|
|
606
|
+
try {
|
|
607
|
+
return await this.request(
|
|
608
|
+
"GET",
|
|
609
|
+
`/api/subscriptions/contract/is-subscribed?subscriber=${subscriber}&creator=${creator}`
|
|
610
|
+
);
|
|
611
|
+
} catch (error) {
|
|
612
|
+
return {
|
|
613
|
+
subscriber,
|
|
614
|
+
creator,
|
|
615
|
+
isSubscribed: false
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* Get subscription platform fee
|
|
621
|
+
*/
|
|
622
|
+
async getSubscriptionPlatformFee() {
|
|
623
|
+
try {
|
|
624
|
+
return await this.request("GET", "/api/subscriptions/platform-fee");
|
|
625
|
+
} catch (error) {
|
|
626
|
+
return {
|
|
627
|
+
feeBps: 0,
|
|
628
|
+
feePercent: "0"
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
// ============ Payouts Methods ============
|
|
633
|
+
/**
|
|
634
|
+
* Get pending and claimed earnings for the authenticated user
|
|
635
|
+
*/
|
|
636
|
+
async getEarnings() {
|
|
637
|
+
try {
|
|
638
|
+
const data = await this.request("GET", "/api/payouts/earnings");
|
|
639
|
+
return { success: true, ...data };
|
|
640
|
+
} catch (error) {
|
|
641
|
+
return {
|
|
642
|
+
success: false,
|
|
643
|
+
error: error instanceof Error ? error.message : "Failed to get earnings"
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* Claim pending earnings
|
|
649
|
+
*/
|
|
650
|
+
async claimEarnings(params) {
|
|
651
|
+
try {
|
|
652
|
+
return await this.request("POST", "/api/payouts/claim", params);
|
|
653
|
+
} catch (error) {
|
|
654
|
+
return {
|
|
655
|
+
success: false,
|
|
656
|
+
error: error instanceof Error ? error.message : "Failed to claim earnings"
|
|
657
|
+
};
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* Get payout history for the authenticated user
|
|
662
|
+
*/
|
|
663
|
+
async getPayoutHistory(filters) {
|
|
664
|
+
try {
|
|
665
|
+
const params = new URLSearchParams();
|
|
666
|
+
if (filters) {
|
|
667
|
+
Object.entries(filters).forEach(([key, value]) => {
|
|
668
|
+
if (value !== void 0) {
|
|
669
|
+
params.append(key, String(value));
|
|
670
|
+
}
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
const queryString = params.toString();
|
|
674
|
+
const path = `/api/payouts/history${queryString ? `?${queryString}` : ""}`;
|
|
675
|
+
const data = await this.request("GET", path);
|
|
676
|
+
return { success: true, ...data };
|
|
677
|
+
} catch (error) {
|
|
678
|
+
return {
|
|
679
|
+
success: false,
|
|
680
|
+
error: error instanceof Error ? error.message : "Failed to get payout history"
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Get earnings breakdown by source
|
|
686
|
+
*/
|
|
687
|
+
async getEarningsBreakdown() {
|
|
688
|
+
try {
|
|
689
|
+
const data = await this.request("GET", "/api/payouts/breakdown");
|
|
690
|
+
return { success: true, ...data };
|
|
691
|
+
} catch (error) {
|
|
692
|
+
return {
|
|
693
|
+
success: false,
|
|
694
|
+
error: error instanceof Error ? error.message : "Failed to get earnings breakdown"
|
|
695
|
+
};
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Get current platform fee for payouts
|
|
700
|
+
*/
|
|
701
|
+
async getPayoutsPlatformFee() {
|
|
702
|
+
try {
|
|
703
|
+
return await this.request("GET", "/api/payouts/platform-fee");
|
|
704
|
+
} catch (error) {
|
|
705
|
+
return {
|
|
706
|
+
feeBps: 0,
|
|
707
|
+
feePercent: "0"
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
};
|
|
712
|
+
var DEFAULT_API_URL = process.env.NEXT_PUBLIC_API_URL || "https://ckgwifsxka.us-east-2.awsapprunner.com";
|
|
713
|
+
var zubariApiClient = null;
|
|
714
|
+
function getZubariApiClient(config) {
|
|
715
|
+
if (!zubariApiClient || config?.baseUrl && zubariApiClient["config"].baseUrl !== config.baseUrl) {
|
|
716
|
+
zubariApiClient = new ZubariApiClient({
|
|
717
|
+
baseUrl: config?.baseUrl || DEFAULT_API_URL,
|
|
718
|
+
timeout: config?.timeout,
|
|
719
|
+
authToken: config?.authToken
|
|
720
|
+
});
|
|
721
|
+
} else if (config?.authToken) {
|
|
722
|
+
zubariApiClient.setAuthToken(config.authToken);
|
|
723
|
+
}
|
|
724
|
+
return zubariApiClient;
|
|
725
|
+
}
|
|
726
|
+
|
|
45
727
|
// src/protocols/NFTProtocol.ts
|
|
46
728
|
var ZubariNFTProtocol = class {
|
|
47
729
|
contractAddress;
|
|
48
730
|
_marketplaceAddress;
|
|
49
731
|
chainId;
|
|
50
732
|
network;
|
|
733
|
+
apiClient;
|
|
51
734
|
nonceCounter = 0;
|
|
52
|
-
constructor(contractAddress, marketplaceAddress, chainId, network = "testnet") {
|
|
735
|
+
constructor(contractAddress, marketplaceAddress, chainId, network = "testnet", apiUrl) {
|
|
53
736
|
this.contractAddress = contractAddress;
|
|
54
737
|
this._marketplaceAddress = marketplaceAddress;
|
|
55
738
|
this.chainId = chainId;
|
|
56
739
|
this.network = network;
|
|
740
|
+
this.apiClient = getZubariApiClient(apiUrl ? { baseUrl: apiUrl } : void 0);
|
|
57
741
|
}
|
|
58
742
|
/**
|
|
59
743
|
* Convert human-readable price to wei
|
|
@@ -170,52 +854,153 @@ var ZubariNFTProtocol = class {
|
|
|
170
854
|
}
|
|
171
855
|
/**
|
|
172
856
|
* Redeem a lazy mint voucher to mint the NFT on-chain
|
|
857
|
+
* Uses the backend API which handles the on-chain transaction
|
|
173
858
|
*/
|
|
174
|
-
async redeemVoucher(voucher,
|
|
859
|
+
async redeemVoucher(voucher, buyerAddress, nftId, authToken) {
|
|
175
860
|
if (voucher.deadline < Math.floor(Date.now() / 1e3)) {
|
|
176
861
|
throw new Error("Voucher has expired");
|
|
177
862
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
863
|
+
try {
|
|
864
|
+
const result = await this.apiClient.redeemVoucher(nftId, {
|
|
865
|
+
buyerAddress
|
|
866
|
+
});
|
|
867
|
+
if (result.success && result.transactionHash) {
|
|
868
|
+
return {
|
|
869
|
+
hash: result.transactionHash,
|
|
870
|
+
network: "ethereum",
|
|
871
|
+
status: "pending",
|
|
872
|
+
metadata: {
|
|
873
|
+
nftId: result.nftId,
|
|
874
|
+
tokenId: voucher.tokenId,
|
|
875
|
+
buyer: buyerAddress
|
|
876
|
+
}
|
|
877
|
+
};
|
|
878
|
+
}
|
|
879
|
+
throw new Error(result.error || "Failed to redeem voucher");
|
|
880
|
+
} catch (error) {
|
|
881
|
+
console.error("Failed to redeem voucher:", error);
|
|
882
|
+
throw new Error(`Voucher redemption failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
883
|
+
}
|
|
183
884
|
}
|
|
184
885
|
/**
|
|
185
|
-
* List an NFT for sale on the marketplace
|
|
886
|
+
* List an NFT for sale on the marketplace via backend API
|
|
186
887
|
*/
|
|
187
|
-
async listForSale(
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
888
|
+
async listForSale(params, authToken) {
|
|
889
|
+
try {
|
|
890
|
+
const currency = params.paymentToken === ZERO_ADDRESS ? "ETH" : "USDT";
|
|
891
|
+
const result = await this.apiClient.listItem({
|
|
892
|
+
nftId: params.tokenId,
|
|
893
|
+
// Using tokenId as nftId
|
|
894
|
+
price: params.price.toString(),
|
|
895
|
+
currency,
|
|
896
|
+
duration: params.duration || 30 * 24 * 60 * 60
|
|
897
|
+
// 30 days default
|
|
898
|
+
});
|
|
899
|
+
if (result.success && result.listing) {
|
|
900
|
+
return {
|
|
901
|
+
hash: result.listing.id || "",
|
|
902
|
+
network: "ethereum",
|
|
903
|
+
status: "pending",
|
|
904
|
+
metadata: {
|
|
905
|
+
listingId: result.listing.id,
|
|
906
|
+
price: params.price.toString(),
|
|
907
|
+
tokenId: params.tokenId
|
|
908
|
+
}
|
|
909
|
+
};
|
|
910
|
+
}
|
|
911
|
+
throw new Error(result.error || "Failed to list NFT");
|
|
912
|
+
} catch (error) {
|
|
913
|
+
console.error("Failed to list NFT:", error);
|
|
914
|
+
throw new Error(`Listing failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
915
|
+
}
|
|
193
916
|
}
|
|
194
917
|
/**
|
|
195
|
-
* Buy an NFT from the marketplace
|
|
918
|
+
* Buy an NFT from the marketplace via backend API
|
|
196
919
|
*/
|
|
197
|
-
async buyNFT(
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
920
|
+
async buyNFT(listingId, price, buyerAddress) {
|
|
921
|
+
try {
|
|
922
|
+
const result = await this.apiClient.buyItem({
|
|
923
|
+
listingId,
|
|
924
|
+
buyerAddress
|
|
925
|
+
});
|
|
926
|
+
if (result.success && result.transactionHash) {
|
|
927
|
+
return {
|
|
928
|
+
hash: result.transactionHash,
|
|
929
|
+
network: "ethereum",
|
|
930
|
+
status: "pending",
|
|
931
|
+
metadata: {
|
|
932
|
+
listingId,
|
|
933
|
+
price: price.toString(),
|
|
934
|
+
buyer: buyerAddress
|
|
935
|
+
}
|
|
936
|
+
};
|
|
937
|
+
}
|
|
938
|
+
throw new Error(result.error || "Failed to buy NFT");
|
|
939
|
+
} catch (error) {
|
|
940
|
+
console.error("Failed to buy NFT:", error);
|
|
941
|
+
throw new Error(`Purchase failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
942
|
+
}
|
|
203
943
|
}
|
|
204
944
|
/**
|
|
205
945
|
* Transfer an NFT to another address
|
|
946
|
+
* Note: This requires direct contract interaction via wallet
|
|
206
947
|
*/
|
|
207
|
-
async transfer(
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
948
|
+
async transfer(tokenId, to, from, signer) {
|
|
949
|
+
try {
|
|
950
|
+
const functionSelector = "0x23b872dd";
|
|
951
|
+
const encodedFrom = from.toLowerCase().replace("0x", "").padStart(64, "0");
|
|
952
|
+
const encodedTo = to.toLowerCase().replace("0x", "").padStart(64, "0");
|
|
953
|
+
const encodedTokenId = BigInt(tokenId).toString(16).padStart(64, "0");
|
|
954
|
+
const data = `${functionSelector}${encodedFrom}${encodedTo}${encodedTokenId}`;
|
|
955
|
+
const tx = await signer.sendTransaction({
|
|
956
|
+
to: this.contractAddress,
|
|
957
|
+
data,
|
|
958
|
+
value: "0x0"
|
|
959
|
+
});
|
|
960
|
+
return {
|
|
961
|
+
hash: tx.hash,
|
|
962
|
+
network: "ethereum",
|
|
963
|
+
status: "pending",
|
|
964
|
+
metadata: {
|
|
965
|
+
tokenId,
|
|
966
|
+
from,
|
|
967
|
+
to
|
|
968
|
+
}
|
|
969
|
+
};
|
|
970
|
+
} catch (error) {
|
|
971
|
+
console.error("Failed to transfer NFT:", error);
|
|
972
|
+
throw new Error(`Transfer failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
973
|
+
}
|
|
213
974
|
}
|
|
214
975
|
/**
|
|
215
|
-
* Get NFTs owned by an address
|
|
976
|
+
* Get NFTs owned by an address via backend API
|
|
216
977
|
*/
|
|
217
|
-
async getOwnedNFTs(
|
|
218
|
-
|
|
978
|
+
async getOwnedNFTs(address) {
|
|
979
|
+
try {
|
|
980
|
+
const result = await this.apiClient.getNFTs({ ownerId: address });
|
|
981
|
+
if (result.success && result.nfts) {
|
|
982
|
+
return result.nfts.map((nft) => ({
|
|
983
|
+
tokenId: nft.tokenId || nft.id,
|
|
984
|
+
contractAddress: nft.contractAddress || this.contractAddress,
|
|
985
|
+
owner: nft.ownerId || address,
|
|
986
|
+
creator: nft.creatorId || "",
|
|
987
|
+
uri: nft.imageUrl || nft.animationUrl || "",
|
|
988
|
+
metadata: nft.name ? {
|
|
989
|
+
name: nft.name,
|
|
990
|
+
description: nft.description || "",
|
|
991
|
+
image: nft.imageUrl || "",
|
|
992
|
+
royaltyBps: 0
|
|
993
|
+
// Default royalty, actual value from contract
|
|
994
|
+
} : void 0,
|
|
995
|
+
isLazyMinted: !nft.tokenId
|
|
996
|
+
// If no tokenId, it's lazy minted
|
|
997
|
+
}));
|
|
998
|
+
}
|
|
999
|
+
return [];
|
|
1000
|
+
} catch (error) {
|
|
1001
|
+
console.error("Failed to get owned NFTs:", error);
|
|
1002
|
+
return [];
|
|
1003
|
+
}
|
|
219
1004
|
}
|
|
220
1005
|
/**
|
|
221
1006
|
* Generate a random tokenId (32 bytes hex)
|
|
@@ -3134,26 +3919,65 @@ var ZubariSubscriptionProtocol = class {
|
|
|
3134
3919
|
};
|
|
3135
3920
|
|
|
3136
3921
|
// src/protocols/PayoutsProtocol.ts
|
|
3922
|
+
var PAYOUTS_SELECTORS = {
|
|
3923
|
+
getEarningsBreakdown: "0xd4e9329c",
|
|
3924
|
+
// getEarningsBreakdown(address)
|
|
3925
|
+
claimEarnings: "0x48c54b9d",
|
|
3926
|
+
// claimEarnings(address)
|
|
3927
|
+
claimPartialEarnings: "0x7e3bfb5a",
|
|
3928
|
+
// claimPartialEarnings(address,uint256)
|
|
3929
|
+
setRevenueSplit: "0x92a8e3f5",
|
|
3930
|
+
// setRevenueSplit((address,uint256)[])
|
|
3931
|
+
getRevenueSplit: "0x6c8a4fd0",
|
|
3932
|
+
// getRevenueSplit(address)
|
|
3933
|
+
removeRevenueSplit: "0x8a4e3c5b"
|
|
3934
|
+
// removeRevenueSplit()
|
|
3935
|
+
};
|
|
3137
3936
|
var ZubariPayoutsProtocol = class {
|
|
3138
3937
|
contractAddress;
|
|
3139
3938
|
chainId;
|
|
3140
3939
|
apiBaseUrl;
|
|
3940
|
+
apiClient;
|
|
3141
3941
|
constructor(contractAddress, chainId, apiBaseUrl) {
|
|
3142
3942
|
this.contractAddress = contractAddress;
|
|
3143
3943
|
this.chainId = chainId;
|
|
3144
3944
|
this.apiBaseUrl = apiBaseUrl || "https://ckgwifsxka.us-east-2.awsapprunner.com";
|
|
3945
|
+
this.apiClient = getZubariApiClient({ baseUrl: this.apiBaseUrl });
|
|
3145
3946
|
}
|
|
3146
3947
|
/**
|
|
3147
|
-
* Get pending earnings breakdown for the current user
|
|
3948
|
+
* Get pending earnings breakdown for the current user via API
|
|
3949
|
+
* Uses backend API which reads from contract/database
|
|
3148
3950
|
*/
|
|
3149
|
-
async getPendingEarnings() {
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3951
|
+
async getPendingEarnings(authToken) {
|
|
3952
|
+
try {
|
|
3953
|
+
const response = await this.apiClient.getEarnings();
|
|
3954
|
+
if (response.success && response.earningsBreakdown) {
|
|
3955
|
+
const breakdown = response.earningsBreakdown;
|
|
3956
|
+
return {
|
|
3957
|
+
tips: BigInt(breakdown.tips || "0"),
|
|
3958
|
+
subscriptions: BigInt(breakdown.subscriptions || "0"),
|
|
3959
|
+
nftSales: BigInt(breakdown.nftSales || "0"),
|
|
3960
|
+
royalties: BigInt(breakdown.royalties || "0"),
|
|
3961
|
+
total: BigInt(breakdown.tips || "0") + BigInt(breakdown.subscriptions || "0") + BigInt(breakdown.nftSales || "0") + BigInt(breakdown.royalties || "0")
|
|
3962
|
+
};
|
|
3963
|
+
}
|
|
3964
|
+
return {
|
|
3965
|
+
tips: BigInt(0),
|
|
3966
|
+
subscriptions: BigInt(0),
|
|
3967
|
+
nftSales: BigInt(0),
|
|
3968
|
+
royalties: BigInt(0),
|
|
3969
|
+
total: BigInt(0)
|
|
3970
|
+
};
|
|
3971
|
+
} catch (error) {
|
|
3972
|
+
console.error("Failed to get pending earnings:", error);
|
|
3973
|
+
return {
|
|
3974
|
+
tips: BigInt(0),
|
|
3975
|
+
subscriptions: BigInt(0),
|
|
3976
|
+
nftSales: BigInt(0),
|
|
3977
|
+
royalties: BigInt(0),
|
|
3978
|
+
total: BigInt(0)
|
|
3979
|
+
};
|
|
3980
|
+
}
|
|
3157
3981
|
}
|
|
3158
3982
|
/**
|
|
3159
3983
|
* Get earnings data from API (includes pending, total, breakdown, and recent payouts)
|
|
@@ -3225,10 +4049,30 @@ var ZubariPayoutsProtocol = class {
|
|
|
3225
4049
|
return response.json();
|
|
3226
4050
|
}
|
|
3227
4051
|
/**
|
|
3228
|
-
* Get historical earnings for a time period
|
|
4052
|
+
* Get historical earnings for a time period via API
|
|
3229
4053
|
*/
|
|
3230
|
-
async getEarningsHistory(period = "all") {
|
|
3231
|
-
|
|
4054
|
+
async getEarningsHistory(authToken, period = "all") {
|
|
4055
|
+
try {
|
|
4056
|
+
const response = await this.apiClient.getPayoutHistory({
|
|
4057
|
+
limit: period === "day" ? 24 : period === "week" ? 7 : period === "month" ? 30 : 100
|
|
4058
|
+
});
|
|
4059
|
+
if (response.success && response.payouts) {
|
|
4060
|
+
return response.payouts.map((payout) => ({
|
|
4061
|
+
tips: BigInt(0),
|
|
4062
|
+
// Individual payouts don't have breakdown
|
|
4063
|
+
subscriptions: BigInt(0),
|
|
4064
|
+
nftSales: BigInt(0),
|
|
4065
|
+
royalties: BigInt(0),
|
|
4066
|
+
total: BigInt(payout.amount || "0"),
|
|
4067
|
+
timestamp: payout.createdAt,
|
|
4068
|
+
status: payout.status
|
|
4069
|
+
}));
|
|
4070
|
+
}
|
|
4071
|
+
return [];
|
|
4072
|
+
} catch (error) {
|
|
4073
|
+
console.error("Failed to get earnings history:", error);
|
|
4074
|
+
return [];
|
|
4075
|
+
}
|
|
3232
4076
|
}
|
|
3233
4077
|
/**
|
|
3234
4078
|
* Claim all pending earnings via API
|
|
@@ -3251,32 +4095,62 @@ var ZubariPayoutsProtocol = class {
|
|
|
3251
4095
|
}
|
|
3252
4096
|
/**
|
|
3253
4097
|
* Claim all pending earnings (direct contract call)
|
|
4098
|
+
* Requires a signer with sendTransaction capability
|
|
3254
4099
|
*/
|
|
3255
|
-
async claimEarnings() {
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
4100
|
+
async claimEarnings(tokenAddress, signer) {
|
|
4101
|
+
try {
|
|
4102
|
+
const encodedToken = tokenAddress.toLowerCase().replace("0x", "").padStart(64, "0");
|
|
4103
|
+
const data = `${PAYOUTS_SELECTORS.claimEarnings}${encodedToken}`;
|
|
4104
|
+
const tx = await signer.sendTransaction({
|
|
4105
|
+
to: this.contractAddress,
|
|
4106
|
+
data,
|
|
4107
|
+
value: "0x0"
|
|
4108
|
+
});
|
|
4109
|
+
return {
|
|
4110
|
+
hash: tx.hash,
|
|
4111
|
+
network: "ethereum",
|
|
4112
|
+
status: "pending",
|
|
4113
|
+
metadata: { token: tokenAddress }
|
|
4114
|
+
};
|
|
4115
|
+
} catch (error) {
|
|
4116
|
+
console.error("Failed to claim earnings:", error);
|
|
4117
|
+
throw new Error(`Claim failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
4118
|
+
}
|
|
3261
4119
|
}
|
|
3262
4120
|
/**
|
|
3263
4121
|
* Claim specific amount of earnings
|
|
4122
|
+
* Requires a signer with sendTransaction capability
|
|
3264
4123
|
*/
|
|
3265
|
-
async claimPartialEarnings(amount) {
|
|
4124
|
+
async claimPartialEarnings(tokenAddress, amount, signer) {
|
|
3266
4125
|
if (amount <= 0n) {
|
|
3267
4126
|
throw new Error("Amount must be greater than 0");
|
|
3268
4127
|
}
|
|
3269
|
-
|
|
3270
|
-
|
|
3271
|
-
|
|
3272
|
-
|
|
3273
|
-
|
|
4128
|
+
try {
|
|
4129
|
+
const encodedToken = tokenAddress.toLowerCase().replace("0x", "").padStart(64, "0");
|
|
4130
|
+
const encodedAmount = amount.toString(16).padStart(64, "0");
|
|
4131
|
+
const data = `${PAYOUTS_SELECTORS.claimPartialEarnings}${encodedToken}${encodedAmount}`;
|
|
4132
|
+
const tx = await signer.sendTransaction({
|
|
4133
|
+
to: this.contractAddress,
|
|
4134
|
+
data,
|
|
4135
|
+
value: "0x0"
|
|
4136
|
+
});
|
|
4137
|
+
return {
|
|
4138
|
+
hash: tx.hash,
|
|
4139
|
+
network: "ethereum",
|
|
4140
|
+
status: "pending",
|
|
4141
|
+
metadata: { token: tokenAddress, amount: amount.toString() }
|
|
4142
|
+
};
|
|
4143
|
+
} catch (error) {
|
|
4144
|
+
console.error("Failed to claim partial earnings:", error);
|
|
4145
|
+
throw new Error(`Partial claim failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
4146
|
+
}
|
|
3274
4147
|
}
|
|
3275
4148
|
/**
|
|
3276
4149
|
* Setup revenue split with collaborators
|
|
3277
4150
|
* Basis points must sum to 10000 (100%)
|
|
4151
|
+
* Requires a signer with sendTransaction capability
|
|
3278
4152
|
*/
|
|
3279
|
-
async setupRevenueSplit(splits) {
|
|
4153
|
+
async setupRevenueSplit(splits, signer) {
|
|
3280
4154
|
const totalBps = splits.reduce((sum, split) => sum + split.basisPoints, 0);
|
|
3281
4155
|
if (totalBps !== 1e4) {
|
|
3282
4156
|
throw new Error("Revenue splits must sum to 100% (10000 basis points)");
|
|
@@ -3289,40 +4163,98 @@ var ZubariPayoutsProtocol = class {
|
|
|
3289
4163
|
throw new Error("Each split must have a valid recipient address");
|
|
3290
4164
|
}
|
|
3291
4165
|
}
|
|
3292
|
-
|
|
3293
|
-
|
|
3294
|
-
|
|
3295
|
-
|
|
3296
|
-
|
|
4166
|
+
try {
|
|
4167
|
+
const offset = "0".padStart(64, "0").slice(-64);
|
|
4168
|
+
const arrayLength = splits.length.toString(16).padStart(64, "0");
|
|
4169
|
+
let encodedSplits = "";
|
|
4170
|
+
for (const split of splits) {
|
|
4171
|
+
const encodedRecipient = split.recipient.toLowerCase().replace("0x", "").padStart(64, "0");
|
|
4172
|
+
const encodedBps = split.basisPoints.toString(16).padStart(64, "0");
|
|
4173
|
+
encodedSplits += encodedRecipient + encodedBps;
|
|
4174
|
+
}
|
|
4175
|
+
const data = `${PAYOUTS_SELECTORS.setRevenueSplit}${"0000000000000000000000000000000000000000000000000000000000000020"}${arrayLength}${encodedSplits}`;
|
|
4176
|
+
const tx = await signer.sendTransaction({
|
|
4177
|
+
to: this.contractAddress,
|
|
4178
|
+
data,
|
|
4179
|
+
value: "0x0"
|
|
4180
|
+
});
|
|
4181
|
+
return {
|
|
4182
|
+
hash: tx.hash,
|
|
4183
|
+
network: "ethereum",
|
|
4184
|
+
status: "pending",
|
|
4185
|
+
metadata: { splits }
|
|
4186
|
+
};
|
|
4187
|
+
} catch (error) {
|
|
4188
|
+
console.error("Failed to setup revenue split:", error);
|
|
4189
|
+
throw new Error(`Revenue split setup failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
4190
|
+
}
|
|
3297
4191
|
}
|
|
3298
4192
|
/**
|
|
3299
|
-
* Get current revenue split configuration
|
|
4193
|
+
* Get current revenue split configuration via API
|
|
3300
4194
|
*/
|
|
3301
|
-
async getRevenueSplit() {
|
|
3302
|
-
|
|
4195
|
+
async getRevenueSplit(creatorAddress) {
|
|
4196
|
+
try {
|
|
4197
|
+
const response = await fetch(`${this.apiBaseUrl}/api/payouts/revenue-split/${creatorAddress}`, {
|
|
4198
|
+
headers: { "Content-Type": "application/json" }
|
|
4199
|
+
});
|
|
4200
|
+
if (response.ok) {
|
|
4201
|
+
const data = await response.json();
|
|
4202
|
+
if (data.success && data.splits) {
|
|
4203
|
+
return data.splits;
|
|
4204
|
+
}
|
|
4205
|
+
}
|
|
4206
|
+
return [];
|
|
4207
|
+
} catch (error) {
|
|
4208
|
+
console.error("Failed to get revenue split:", error);
|
|
4209
|
+
return [];
|
|
4210
|
+
}
|
|
3303
4211
|
}
|
|
3304
4212
|
/**
|
|
3305
4213
|
* Remove revenue split (creator gets 100%)
|
|
4214
|
+
* Requires a signer with sendTransaction capability
|
|
3306
4215
|
*/
|
|
3307
|
-
async removeRevenueSplit() {
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
4216
|
+
async removeRevenueSplit(signer) {
|
|
4217
|
+
try {
|
|
4218
|
+
const data = PAYOUTS_SELECTORS.removeRevenueSplit;
|
|
4219
|
+
const tx = await signer.sendTransaction({
|
|
4220
|
+
to: this.contractAddress,
|
|
4221
|
+
data,
|
|
4222
|
+
value: "0x0"
|
|
4223
|
+
});
|
|
4224
|
+
return {
|
|
4225
|
+
hash: tx.hash,
|
|
4226
|
+
network: "ethereum",
|
|
4227
|
+
status: "pending"
|
|
4228
|
+
};
|
|
4229
|
+
} catch (error) {
|
|
4230
|
+
console.error("Failed to remove revenue split:", error);
|
|
4231
|
+
throw new Error(`Remove revenue split failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
4232
|
+
}
|
|
3313
4233
|
}
|
|
3314
4234
|
/**
|
|
3315
|
-
* Convert earnings to stablecoin (USDT)
|
|
4235
|
+
* Convert earnings to stablecoin (USDT) via swap
|
|
4236
|
+
* This will be implemented when SwapService is complete
|
|
3316
4237
|
*/
|
|
3317
|
-
async convertToStable(token, amount) {
|
|
4238
|
+
async convertToStable(token, amount, swapService) {
|
|
3318
4239
|
if (amount <= 0n) {
|
|
3319
4240
|
throw new Error("Amount must be greater than 0");
|
|
3320
4241
|
}
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
4242
|
+
if (!swapService) {
|
|
4243
|
+
throw new Error("SwapService required for conversion. Import and pass SwapService instance.");
|
|
4244
|
+
}
|
|
4245
|
+
try {
|
|
4246
|
+
return await swapService.executeSwap({
|
|
4247
|
+
tokenIn: token,
|
|
4248
|
+
tokenOut: "0xdAC17F958D2ee523a2206206994597C13D831ec7",
|
|
4249
|
+
// USDT mainnet
|
|
4250
|
+
amountIn: amount,
|
|
4251
|
+
slippageBps: 50
|
|
4252
|
+
// 0.5% slippage
|
|
4253
|
+
});
|
|
4254
|
+
} catch (error) {
|
|
4255
|
+
console.error("Failed to convert to stable:", error);
|
|
4256
|
+
throw new Error(`Conversion failed: ${error instanceof Error ? error.message : "Unknown error"}`);
|
|
4257
|
+
}
|
|
3326
4258
|
}
|
|
3327
4259
|
/**
|
|
3328
4260
|
* Get the contract address
|