@zubari/sdk 0.1.29 → 0.2.0

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.
@@ -1,4 +1,5 @@
1
1
  // src/config/contracts.ts
2
+ var ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
2
3
  var PLATFORM_CONFIG = {
3
4
  // Platform fee in basis points (300 = 3%)
4
5
  tipFeeBps: 300,
@@ -16,37 +17,116 @@ var NFT_VOUCHER_TYPES = {
16
17
  { name: "uri", type: "string" },
17
18
  { name: "creator", type: "address" },
18
19
  { name: "royaltyBps", type: "uint256" },
19
- { name: "deadline", type: "uint256" }
20
+ { name: "deadline", type: "uint256" },
21
+ // Pricing fields
22
+ { name: "price", type: "uint256" },
23
+ { name: "currency", type: "address" },
24
+ { name: "nonce", type: "uint256" },
25
+ // Watermarking fields
26
+ { name: "contentHash", type: "bytes32" },
27
+ { name: "userId", type: "bytes32" },
28
+ { name: "watermarkTimestamp", type: "uint256" },
29
+ { name: "sessionId", type: "bytes32" }
20
30
  ]
21
31
  };
32
+ var CURRENCY_ADDRESSES = {
33
+ testnet: {
34
+ ETH: ZERO_ADDRESS,
35
+ USDT: "0xaA8E23Fb1079EA71e0a56F48a2aA51851D8433D0"
36
+ // USDT on Sepolia
37
+ },
38
+ mainnet: {
39
+ ETH: ZERO_ADDRESS,
40
+ USDT: "0xdAC17F958D2ee523a2206206994597C13D831ec7"
41
+ // USDT on Ethereum
42
+ }
43
+ };
22
44
 
23
45
  // src/protocols/NFTProtocol.ts
24
46
  var ZubariNFTProtocol = class {
25
47
  contractAddress;
26
48
  _marketplaceAddress;
27
49
  chainId;
28
- constructor(contractAddress, marketplaceAddress, chainId) {
50
+ network;
51
+ nonceCounter = 0;
52
+ constructor(contractAddress, marketplaceAddress, chainId, network = "testnet") {
29
53
  this.contractAddress = contractAddress;
30
54
  this._marketplaceAddress = marketplaceAddress;
31
55
  this.chainId = chainId;
56
+ this.network = network;
57
+ }
58
+ /**
59
+ * Convert human-readable price to wei
60
+ * @param price - Price in human-readable format (e.g., "1.5")
61
+ * @param currency - ETH (18 decimals) or USDT (6 decimals)
62
+ */
63
+ priceToWei(price, currency) {
64
+ const decimals = currency === "ETH" ? 18 : 6;
65
+ const [whole, fraction = ""] = price.split(".");
66
+ const paddedFraction = fraction.padEnd(decimals, "0").slice(0, decimals);
67
+ const wei = whole + paddedFraction;
68
+ return wei.replace(/^0+/, "") || "0";
69
+ }
70
+ /**
71
+ * Get currency address for the configured network
72
+ */
73
+ getCurrencyAddress(currency) {
74
+ return CURRENCY_ADDRESSES[this.network][currency];
75
+ }
76
+ /**
77
+ * Generate a unique nonce
78
+ */
79
+ generateNonce() {
80
+ return Date.now() * 1e3 + this.nonceCounter++;
81
+ }
82
+ /**
83
+ * Pad string to bytes32 format
84
+ */
85
+ toBytes32(value) {
86
+ if (value.startsWith("0x")) {
87
+ return value.padEnd(66, "0");
88
+ }
89
+ const hex = Buffer.from(value).toString("hex");
90
+ return "0x" + hex.padEnd(64, "0");
32
91
  }
33
92
  /**
34
93
  * Create a lazy mint voucher for off-chain NFT creation
35
94
  * The voucher can be redeemed on-chain when purchased
95
+ *
96
+ * @param params - Voucher creation parameters
97
+ * @param signer - Object with signTypedData method (ethers.js wallet or viem client)
36
98
  */
37
- async createLazyMintVoucher(metadata, creatorAddress, signer) {
99
+ async createLazyMintVoucher(params, signer) {
100
+ const { metadata, creatorAddress, price, currency, nonce, watermarking } = params;
38
101
  if (metadata.royaltyBps > PLATFORM_CONFIG.maxRoyaltyBps) {
39
102
  throw new Error(`Royalty cannot exceed ${PLATFORM_CONFIG.maxRoyaltyBps / 100}%`);
40
103
  }
104
+ if (!price || parseFloat(price) <= 0) {
105
+ throw new Error("Price must be greater than 0");
106
+ }
41
107
  const tokenId = this.generateTokenId();
42
108
  const deadline = Math.floor(Date.now() / 1e3) + PLATFORM_CONFIG.voucherValiditySecs;
109
+ const priceInWei = this.priceToWei(price, currency);
110
+ const currencyAddress = this.getCurrencyAddress(currency);
111
+ const voucherNonce = nonce ?? this.generateNonce();
112
+ const watermarkTimestamp = watermarking ? Math.floor(Date.now() / 1e3) : 0;
113
+ const contentHash = watermarking ? this.toBytes32(watermarking.contentHash) : ZERO_ADDRESS.replace("0x", "0x" + "0".repeat(64)).slice(0, 66);
114
+ const userId = watermarking ? this.toBytes32(watermarking.userId) : ZERO_ADDRESS.replace("0x", "0x" + "0".repeat(64)).slice(0, 66);
115
+ const sessionId = watermarking ? this.toBytes32(watermarking.sessionId) : ZERO_ADDRESS.replace("0x", "0x" + "0".repeat(64)).slice(0, 66);
43
116
  const voucherData = {
44
117
  tokenId,
45
118
  uri: metadata.image,
46
119
  // Will be IPFS URI
47
120
  creator: creatorAddress,
48
121
  royaltyBps: metadata.royaltyBps,
49
- deadline
122
+ deadline,
123
+ price: priceInWei,
124
+ currency: currencyAddress,
125
+ nonce: voucherNonce,
126
+ contentHash,
127
+ userId,
128
+ watermarkTimestamp,
129
+ sessionId
50
130
  };
51
131
  const domain = {
52
132
  ...NFT_VOUCHER_DOMAIN,
@@ -55,10 +135,36 @@ var ZubariNFTProtocol = class {
55
135
  };
56
136
  const signature = await signer.signTypedData(domain, NFT_VOUCHER_TYPES, voucherData);
57
137
  return {
58
- ...voucherData,
59
- signature
138
+ tokenId,
139
+ uri: metadata.image,
140
+ creator: creatorAddress,
141
+ royaltyBps: metadata.royaltyBps,
142
+ deadline,
143
+ signature,
144
+ price: priceInWei,
145
+ currency: currencyAddress,
146
+ nonce: voucherNonce,
147
+ contentHash: watermarking ? contentHash : void 0,
148
+ userId: watermarking ? userId : void 0,
149
+ watermarkTimestamp: watermarking ? watermarkTimestamp : void 0,
150
+ sessionId: watermarking ? sessionId : void 0
60
151
  };
61
152
  }
153
+ /**
154
+ * @deprecated Use createLazyMintVoucher(params, signer) instead
155
+ * Legacy method for backward compatibility
156
+ */
157
+ async createLazyMintVoucherLegacy(metadata, creatorAddress, signer) {
158
+ return this.createLazyMintVoucher(
159
+ {
160
+ metadata,
161
+ creatorAddress,
162
+ price: "0.01",
163
+ currency: "ETH"
164
+ },
165
+ signer
166
+ );
167
+ }
62
168
  /**
63
169
  * Redeem a lazy mint voucher to mint the NFT on-chain
64
170
  */
@@ -1006,187 +1112,2021 @@ var ZubariMarketProtocol = class {
1006
1112
  }
1007
1113
  };
1008
1114
 
1009
- // src/protocols/TipsProtocol.ts
1010
- var ZubariTipsProtocol = class {
1011
- contractAddress;
1012
- chainId;
1013
- gaslessEnabled;
1014
- constructor(contractAddress, chainId, gaslessEnabled = false) {
1015
- this.contractAddress = contractAddress;
1016
- this.chainId = chainId;
1017
- this.gaslessEnabled = gaslessEnabled;
1018
- }
1019
- /**
1020
- * Send a tip to a creator
1021
- */
1022
- async sendTip(tip) {
1023
- const { recipient, amount, token, message } = tip;
1024
- const platformFee = amount * BigInt(PLATFORM_CONFIG.tipFeeBps) / BigInt(1e4);
1025
- const creatorAmount = amount - platformFee;
1026
- if (amount <= 0n) {
1027
- throw new Error("Tip amount must be greater than 0");
1028
- }
1029
- const txResult = {
1030
- hash: ""};
1031
- return {
1032
- txHash: txResult.hash,
1033
- tipId: "",
1034
- // Will be returned from contract event
1035
- recipient,
1036
- amount: creatorAmount,
1037
- platformFee,
1038
- timestamp: Math.floor(Date.now() / 1e3)
1039
- };
1040
- }
1041
- /**
1042
- * Send tips to multiple creators in a single transaction
1043
- */
1044
- async sendBatchTips(tips) {
1045
- if (tips.length === 0) {
1046
- throw new Error("At least one tip is required");
1047
- }
1048
- tips.reduce((sum, tip) => sum + tip.amount, BigInt(0));
1049
- return tips.map((tip) => ({
1050
- txHash: "",
1051
- tipId: "",
1052
- recipient: tip.recipient,
1053
- amount: tip.amount - tip.amount * BigInt(PLATFORM_CONFIG.tipFeeBps) / BigInt(1e4),
1054
- platformFee: tip.amount * BigInt(PLATFORM_CONFIG.tipFeeBps) / BigInt(1e4),
1055
- timestamp: Math.floor(Date.now() / 1e3)
1056
- }));
1057
- }
1058
- /**
1059
- * Get tips received by an address
1060
- */
1061
- async getTipsReceived(address) {
1062
- return [];
1063
- }
1064
- /**
1065
- * Get tips sent by an address
1066
- */
1067
- async getTipsSent(address) {
1068
- return [];
1069
- }
1070
- /**
1071
- * Get tip statistics for a creator
1072
- */
1073
- async getCreatorTipStats(creator) {
1074
- return {
1075
- totalReceived: BigInt(0),
1076
- tipCount: 0,
1077
- uniqueTippers: 0
1078
- };
1079
- }
1080
- /**
1081
- * Get platform fee in basis points
1082
- */
1083
- getPlatformFeeBps() {
1084
- return PLATFORM_CONFIG.tipFeeBps;
1085
- }
1086
- };
1087
-
1088
- // src/protocols/SubscriptionProtocol.ts
1089
- var ZubariSubscriptionProtocol = class {
1090
- contractAddress;
1091
- chainId;
1092
- constructor(contractAddress, chainId) {
1093
- this.contractAddress = contractAddress;
1094
- this.chainId = chainId;
1095
- }
1096
- /**
1097
- * Create a new subscription plan
1098
- */
1099
- async createPlan(plan) {
1100
- if (!plan.name || plan.name.length === 0) {
1101
- throw new Error("Plan name is required");
1102
- }
1103
- if (plan.price <= 0n) {
1104
- throw new Error("Plan price must be greater than 0");
1105
- }
1106
- if (plan.duration <= 0) {
1107
- throw new Error("Plan duration must be greater than 0");
1108
- }
1109
- const planId = this.generatePlanId(plan.name);
1110
- return planId;
1111
- }
1112
- /**
1113
- * Update an existing subscription plan
1114
- */
1115
- async updatePlan(planId, updates) {
1116
- return {
1117
- hash: "",
1118
- network: "ethereum",
1119
- status: "pending"
1120
- };
1121
- }
1122
- /**
1123
- * Subscribe to a creator's plan
1124
- */
1125
- async subscribe(creator, planId, months = 1) {
1126
- if (months <= 0) {
1127
- throw new Error("Subscription duration must be at least 1 month");
1128
- }
1129
- const now = Math.floor(Date.now() / 1e3);
1130
- const durationSeconds = months * 30 * 24 * 60 * 60;
1131
- return {
1132
- subscriptionId: "",
1133
- planId,
1134
- creator,
1135
- subscriber: "",
1136
- // Current user address
1137
- startTime: now,
1138
- endTime: now + durationSeconds,
1139
- autoRenew: false,
1140
- status: "active"
1141
- };
1142
- }
1143
- /**
1144
- * Cancel an active subscription
1145
- */
1146
- async cancel(subscriptionId) {
1147
- return {
1148
- hash: "",
1149
- network: "ethereum",
1150
- status: "pending"
1151
- };
1152
- }
1153
- /**
1154
- * Check if an address is subscribed to a creator
1155
- */
1156
- async isSubscribed(creator, subscriber) {
1157
- return false;
1158
- }
1159
- /**
1160
- * Get active subscriptions for a subscriber
1161
- */
1162
- async getActiveSubscriptions(subscriber) {
1163
- return [];
1164
- }
1165
- /**
1166
- * Get all subscribers for a creator
1167
- */
1168
- async getSubscribers(creator) {
1169
- return [];
1170
- }
1171
- /**
1172
- * Get a specific plan by ID
1173
- */
1174
- async getPlan(planId) {
1175
- return null;
1176
- }
1177
- /**
1178
- * Get all plans for a creator
1179
- */
1180
- async getCreatorPlans(creator) {
1181
- return [];
1182
- }
1183
- /**
1184
- * Generate a unique plan ID
1185
- */
1186
- generatePlanId(name) {
1187
- const bytes = new Uint8Array(16);
1188
- crypto.getRandomValues(bytes);
1189
- return "0x" + Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
1115
+ // src/abi/ZubariTips.json
1116
+ var ZubariTips_default = [
1117
+ {
1118
+ inputs: [
1119
+ {
1120
+ internalType: "address",
1121
+ name: "_treasury",
1122
+ type: "address"
1123
+ },
1124
+ {
1125
+ internalType: "uint256",
1126
+ name: "_platformFeeBps",
1127
+ type: "uint256"
1128
+ }
1129
+ ],
1130
+ stateMutability: "nonpayable",
1131
+ type: "constructor"
1132
+ },
1133
+ {
1134
+ inputs: [],
1135
+ name: "EnforcedPause",
1136
+ type: "error"
1137
+ },
1138
+ {
1139
+ inputs: [],
1140
+ name: "ExpectedPause",
1141
+ type: "error"
1142
+ },
1143
+ {
1144
+ inputs: [],
1145
+ name: "InvalidAddress",
1146
+ type: "error"
1147
+ },
1148
+ {
1149
+ inputs: [],
1150
+ name: "InvalidAmount",
1151
+ type: "error"
1152
+ },
1153
+ {
1154
+ inputs: [],
1155
+ name: "InvalidFee",
1156
+ type: "error"
1157
+ },
1158
+ {
1159
+ inputs: [],
1160
+ name: "InvalidRecipient",
1161
+ type: "error"
1162
+ },
1163
+ {
1164
+ inputs: [
1165
+ {
1166
+ internalType: "address",
1167
+ name: "owner",
1168
+ type: "address"
1169
+ }
1170
+ ],
1171
+ name: "OwnableInvalidOwner",
1172
+ type: "error"
1173
+ },
1174
+ {
1175
+ inputs: [
1176
+ {
1177
+ internalType: "address",
1178
+ name: "account",
1179
+ type: "address"
1180
+ }
1181
+ ],
1182
+ name: "OwnableUnauthorizedAccount",
1183
+ type: "error"
1184
+ },
1185
+ {
1186
+ inputs: [],
1187
+ name: "ReentrancyGuardReentrantCall",
1188
+ type: "error"
1189
+ },
1190
+ {
1191
+ inputs: [
1192
+ {
1193
+ internalType: "address",
1194
+ name: "token",
1195
+ type: "address"
1196
+ }
1197
+ ],
1198
+ name: "SafeERC20FailedOperation",
1199
+ type: "error"
1200
+ },
1201
+ {
1202
+ inputs: [],
1203
+ name: "TransferFailed",
1204
+ type: "error"
1205
+ },
1206
+ {
1207
+ anonymous: false,
1208
+ inputs: [
1209
+ {
1210
+ indexed: false,
1211
+ internalType: "uint256[]",
1212
+ name: "tipIds",
1213
+ type: "uint256[]"
1214
+ },
1215
+ {
1216
+ indexed: true,
1217
+ internalType: "address",
1218
+ name: "sender",
1219
+ type: "address"
1220
+ }
1221
+ ],
1222
+ name: "BatchTipSent",
1223
+ type: "event"
1224
+ },
1225
+ {
1226
+ anonymous: false,
1227
+ inputs: [
1228
+ {
1229
+ indexed: true,
1230
+ internalType: "address",
1231
+ name: "previousOwner",
1232
+ type: "address"
1233
+ },
1234
+ {
1235
+ indexed: true,
1236
+ internalType: "address",
1237
+ name: "newOwner",
1238
+ type: "address"
1239
+ }
1240
+ ],
1241
+ name: "OwnershipTransferred",
1242
+ type: "event"
1243
+ },
1244
+ {
1245
+ anonymous: false,
1246
+ inputs: [
1247
+ {
1248
+ indexed: false,
1249
+ internalType: "address",
1250
+ name: "account",
1251
+ type: "address"
1252
+ }
1253
+ ],
1254
+ name: "Paused",
1255
+ type: "event"
1256
+ },
1257
+ {
1258
+ anonymous: false,
1259
+ inputs: [
1260
+ {
1261
+ indexed: false,
1262
+ internalType: "uint256",
1263
+ name: "oldFee",
1264
+ type: "uint256"
1265
+ },
1266
+ {
1267
+ indexed: false,
1268
+ internalType: "uint256",
1269
+ name: "newFee",
1270
+ type: "uint256"
1271
+ }
1272
+ ],
1273
+ name: "PlatformFeeUpdated",
1274
+ type: "event"
1275
+ },
1276
+ {
1277
+ anonymous: false,
1278
+ inputs: [
1279
+ {
1280
+ indexed: true,
1281
+ internalType: "uint256",
1282
+ name: "tipId",
1283
+ type: "uint256"
1284
+ },
1285
+ {
1286
+ indexed: true,
1287
+ internalType: "address",
1288
+ name: "sender",
1289
+ type: "address"
1290
+ },
1291
+ {
1292
+ indexed: true,
1293
+ internalType: "address",
1294
+ name: "recipient",
1295
+ type: "address"
1296
+ },
1297
+ {
1298
+ indexed: false,
1299
+ internalType: "address",
1300
+ name: "token",
1301
+ type: "address"
1302
+ },
1303
+ {
1304
+ indexed: false,
1305
+ internalType: "uint256",
1306
+ name: "amount",
1307
+ type: "uint256"
1308
+ },
1309
+ {
1310
+ indexed: false,
1311
+ internalType: "uint256",
1312
+ name: "platformFee",
1313
+ type: "uint256"
1314
+ },
1315
+ {
1316
+ indexed: false,
1317
+ internalType: "string",
1318
+ name: "message",
1319
+ type: "string"
1320
+ }
1321
+ ],
1322
+ name: "TipSent",
1323
+ type: "event"
1324
+ },
1325
+ {
1326
+ anonymous: false,
1327
+ inputs: [
1328
+ {
1329
+ indexed: false,
1330
+ internalType: "address",
1331
+ name: "oldTreasury",
1332
+ type: "address"
1333
+ },
1334
+ {
1335
+ indexed: false,
1336
+ internalType: "address",
1337
+ name: "newTreasury",
1338
+ type: "address"
1339
+ }
1340
+ ],
1341
+ name: "TreasuryUpdated",
1342
+ type: "event"
1343
+ },
1344
+ {
1345
+ anonymous: false,
1346
+ inputs: [
1347
+ {
1348
+ indexed: false,
1349
+ internalType: "address",
1350
+ name: "account",
1351
+ type: "address"
1352
+ }
1353
+ ],
1354
+ name: "Unpaused",
1355
+ type: "event"
1356
+ },
1357
+ {
1358
+ inputs: [
1359
+ {
1360
+ internalType: "uint256",
1361
+ name: "tipId",
1362
+ type: "uint256"
1363
+ }
1364
+ ],
1365
+ name: "getTip",
1366
+ outputs: [
1367
+ {
1368
+ components: [
1369
+ {
1370
+ internalType: "uint256",
1371
+ name: "tipId",
1372
+ type: "uint256"
1373
+ },
1374
+ {
1375
+ internalType: "address",
1376
+ name: "sender",
1377
+ type: "address"
1378
+ },
1379
+ {
1380
+ internalType: "address",
1381
+ name: "recipient",
1382
+ type: "address"
1383
+ },
1384
+ {
1385
+ internalType: "address",
1386
+ name: "token",
1387
+ type: "address"
1388
+ },
1389
+ {
1390
+ internalType: "uint256",
1391
+ name: "amount",
1392
+ type: "uint256"
1393
+ },
1394
+ {
1395
+ internalType: "uint256",
1396
+ name: "platformFee",
1397
+ type: "uint256"
1398
+ },
1399
+ {
1400
+ internalType: "string",
1401
+ name: "message",
1402
+ type: "string"
1403
+ },
1404
+ {
1405
+ internalType: "uint256",
1406
+ name: "timestamp",
1407
+ type: "uint256"
1408
+ }
1409
+ ],
1410
+ internalType: "struct ZubariTips.Tip",
1411
+ name: "",
1412
+ type: "tuple"
1413
+ }
1414
+ ],
1415
+ stateMutability: "view",
1416
+ type: "function"
1417
+ },
1418
+ {
1419
+ inputs: [],
1420
+ name: "owner",
1421
+ outputs: [
1422
+ {
1423
+ internalType: "address",
1424
+ name: "",
1425
+ type: "address"
1426
+ }
1427
+ ],
1428
+ stateMutability: "view",
1429
+ type: "function"
1430
+ },
1431
+ {
1432
+ inputs: [],
1433
+ name: "pause",
1434
+ outputs: [],
1435
+ stateMutability: "nonpayable",
1436
+ type: "function"
1437
+ },
1438
+ {
1439
+ inputs: [],
1440
+ name: "paused",
1441
+ outputs: [
1442
+ {
1443
+ internalType: "bool",
1444
+ name: "",
1445
+ type: "bool"
1446
+ }
1447
+ ],
1448
+ stateMutability: "view",
1449
+ type: "function"
1450
+ },
1451
+ {
1452
+ inputs: [],
1453
+ name: "platformFeeBps",
1454
+ outputs: [
1455
+ {
1456
+ internalType: "uint256",
1457
+ name: "",
1458
+ type: "uint256"
1459
+ }
1460
+ ],
1461
+ stateMutability: "view",
1462
+ type: "function"
1463
+ },
1464
+ {
1465
+ inputs: [],
1466
+ name: "renounceOwnership",
1467
+ outputs: [],
1468
+ stateMutability: "nonpayable",
1469
+ type: "function"
1470
+ },
1471
+ {
1472
+ inputs: [
1473
+ {
1474
+ internalType: "address[]",
1475
+ name: "recipients",
1476
+ type: "address[]"
1477
+ },
1478
+ {
1479
+ internalType: "uint256[]",
1480
+ name: "amounts",
1481
+ type: "uint256[]"
1482
+ },
1483
+ {
1484
+ internalType: "string[]",
1485
+ name: "messages",
1486
+ type: "string[]"
1487
+ }
1488
+ ],
1489
+ name: "sendBatchTips",
1490
+ outputs: [],
1491
+ stateMutability: "payable",
1492
+ type: "function"
1493
+ },
1494
+ {
1495
+ inputs: [
1496
+ {
1497
+ internalType: "uint256",
1498
+ name: "_feeBps",
1499
+ type: "uint256"
1500
+ }
1501
+ ],
1502
+ name: "setPlatformFee",
1503
+ outputs: [],
1504
+ stateMutability: "nonpayable",
1505
+ type: "function"
1506
+ },
1507
+ {
1508
+ inputs: [
1509
+ {
1510
+ internalType: "address",
1511
+ name: "_treasury",
1512
+ type: "address"
1513
+ }
1514
+ ],
1515
+ name: "setTreasury",
1516
+ outputs: [],
1517
+ stateMutability: "nonpayable",
1518
+ type: "function"
1519
+ },
1520
+ {
1521
+ inputs: [],
1522
+ name: "tipCounter",
1523
+ outputs: [
1524
+ {
1525
+ internalType: "uint256",
1526
+ name: "",
1527
+ type: "uint256"
1528
+ }
1529
+ ],
1530
+ stateMutability: "view",
1531
+ type: "function"
1532
+ },
1533
+ {
1534
+ inputs: [
1535
+ {
1536
+ internalType: "address",
1537
+ name: "recipient",
1538
+ type: "address"
1539
+ },
1540
+ {
1541
+ internalType: "string",
1542
+ name: "message",
1543
+ type: "string"
1544
+ }
1545
+ ],
1546
+ name: "tipETH",
1547
+ outputs: [],
1548
+ stateMutability: "payable",
1549
+ type: "function"
1550
+ },
1551
+ {
1552
+ inputs: [
1553
+ {
1554
+ internalType: "address",
1555
+ name: "recipient",
1556
+ type: "address"
1557
+ },
1558
+ {
1559
+ internalType: "address",
1560
+ name: "token",
1561
+ type: "address"
1562
+ },
1563
+ {
1564
+ internalType: "uint256",
1565
+ name: "amount",
1566
+ type: "uint256"
1567
+ },
1568
+ {
1569
+ internalType: "string",
1570
+ name: "message",
1571
+ type: "string"
1572
+ }
1573
+ ],
1574
+ name: "tipToken",
1575
+ outputs: [],
1576
+ stateMutability: "nonpayable",
1577
+ type: "function"
1578
+ },
1579
+ {
1580
+ inputs: [
1581
+ {
1582
+ internalType: "uint256",
1583
+ name: "",
1584
+ type: "uint256"
1585
+ }
1586
+ ],
1587
+ name: "tips",
1588
+ outputs: [
1589
+ {
1590
+ internalType: "uint256",
1591
+ name: "tipId",
1592
+ type: "uint256"
1593
+ },
1594
+ {
1595
+ internalType: "address",
1596
+ name: "sender",
1597
+ type: "address"
1598
+ },
1599
+ {
1600
+ internalType: "address",
1601
+ name: "recipient",
1602
+ type: "address"
1603
+ },
1604
+ {
1605
+ internalType: "address",
1606
+ name: "token",
1607
+ type: "address"
1608
+ },
1609
+ {
1610
+ internalType: "uint256",
1611
+ name: "amount",
1612
+ type: "uint256"
1613
+ },
1614
+ {
1615
+ internalType: "uint256",
1616
+ name: "platformFee",
1617
+ type: "uint256"
1618
+ },
1619
+ {
1620
+ internalType: "string",
1621
+ name: "message",
1622
+ type: "string"
1623
+ },
1624
+ {
1625
+ internalType: "uint256",
1626
+ name: "timestamp",
1627
+ type: "uint256"
1628
+ }
1629
+ ],
1630
+ stateMutability: "view",
1631
+ type: "function"
1632
+ },
1633
+ {
1634
+ inputs: [
1635
+ {
1636
+ internalType: "address",
1637
+ name: "",
1638
+ type: "address"
1639
+ }
1640
+ ],
1641
+ name: "totalTipsReceived",
1642
+ outputs: [
1643
+ {
1644
+ internalType: "uint256",
1645
+ name: "",
1646
+ type: "uint256"
1647
+ }
1648
+ ],
1649
+ stateMutability: "view",
1650
+ type: "function"
1651
+ },
1652
+ {
1653
+ inputs: [
1654
+ {
1655
+ internalType: "address",
1656
+ name: "newOwner",
1657
+ type: "address"
1658
+ }
1659
+ ],
1660
+ name: "transferOwnership",
1661
+ outputs: [],
1662
+ stateMutability: "nonpayable",
1663
+ type: "function"
1664
+ },
1665
+ {
1666
+ inputs: [],
1667
+ name: "treasury",
1668
+ outputs: [
1669
+ {
1670
+ internalType: "address",
1671
+ name: "",
1672
+ type: "address"
1673
+ }
1674
+ ],
1675
+ stateMutability: "view",
1676
+ type: "function"
1677
+ },
1678
+ {
1679
+ inputs: [],
1680
+ name: "unpause",
1681
+ outputs: [],
1682
+ stateMutability: "nonpayable",
1683
+ type: "function"
1684
+ }
1685
+ ];
1686
+
1687
+ // src/protocols/TipsProtocol.ts
1688
+ var ZubariTipsProtocol = class {
1689
+ contractAddress;
1690
+ chainId;
1691
+ abi = ZubariTips_default;
1692
+ constructor(contractAddress, chainId) {
1693
+ this.contractAddress = contractAddress;
1694
+ this.chainId = chainId;
1695
+ }
1696
+ /**
1697
+ * Get the contract ABI
1698
+ */
1699
+ getAbi() {
1700
+ return this.abi;
1701
+ }
1702
+ /**
1703
+ * Get the contract address
1704
+ */
1705
+ getAddress() {
1706
+ return this.contractAddress;
1707
+ }
1708
+ /**
1709
+ * Send ETH tip to a creator
1710
+ * @param recipient The recipient address
1711
+ * @param message Optional tip message
1712
+ * @param signer Wallet signer with sendTransaction method
1713
+ * @param value ETH amount to tip (in wei)
1714
+ */
1715
+ async tipETH(recipient, message, signer, value) {
1716
+ if (!recipient || recipient === "0x0000000000000000000000000000000000000000") {
1717
+ throw new Error("Invalid recipient address");
1718
+ }
1719
+ if (value <= 0n) {
1720
+ throw new Error("Tip amount must be greater than 0");
1721
+ }
1722
+ const iface = new (await import('ethers')).Interface(this.abi);
1723
+ const data = iface.encodeFunctionData("tipETH", [recipient, message || ""]);
1724
+ const result = await signer.sendTransaction({
1725
+ to: this.contractAddress,
1726
+ value,
1727
+ data
1728
+ });
1729
+ return {
1730
+ hash: result.hash,
1731
+ network: "ethereum",
1732
+ status: "pending"
1733
+ };
1734
+ }
1735
+ /**
1736
+ * Send ERC-20 token tip to a creator
1737
+ * @param recipient The recipient address
1738
+ * @param token The ERC-20 token address
1739
+ * @param amount The amount of tokens to tip
1740
+ * @param message Optional tip message
1741
+ * @param signer Wallet signer
1742
+ */
1743
+ async tipToken(recipient, token, amount, message, signer) {
1744
+ if (!recipient || recipient === "0x0000000000000000000000000000000000000000") {
1745
+ throw new Error("Invalid recipient address");
1746
+ }
1747
+ if (!token || token === "0x0000000000000000000000000000000000000000") {
1748
+ throw new Error("Use tipETH for native ETH tips");
1749
+ }
1750
+ if (amount <= 0n) {
1751
+ throw new Error("Tip amount must be greater than 0");
1752
+ }
1753
+ const iface = new (await import('ethers')).Interface(this.abi);
1754
+ const data = iface.encodeFunctionData("tipToken", [recipient, token, amount, message || ""]);
1755
+ const result = await signer.sendTransaction({
1756
+ to: this.contractAddress,
1757
+ value: 0n,
1758
+ data
1759
+ });
1760
+ return {
1761
+ hash: result.hash,
1762
+ network: "ethereum",
1763
+ status: "pending"
1764
+ };
1765
+ }
1766
+ /**
1767
+ * Send batch tips to multiple creators in a single transaction
1768
+ * @param recipients Array of recipient addresses
1769
+ * @param amounts Array of tip amounts (in wei)
1770
+ * @param messages Array of tip messages
1771
+ * @param signer Wallet signer
1772
+ * @param value Total ETH to send
1773
+ */
1774
+ async sendBatchTips(recipients, amounts, messages, signer, value) {
1775
+ if (recipients.length === 0) {
1776
+ throw new Error("At least one recipient is required");
1777
+ }
1778
+ if (recipients.length !== amounts.length || recipients.length !== messages.length) {
1779
+ throw new Error("Recipients, amounts, and messages arrays must have the same length");
1780
+ }
1781
+ for (const recipient of recipients) {
1782
+ if (!recipient || recipient === "0x0000000000000000000000000000000000000000") {
1783
+ throw new Error("Invalid recipient address in batch");
1784
+ }
1785
+ }
1786
+ const totalAmount = amounts.reduce((sum, amount) => sum + amount, 0n);
1787
+ if (totalAmount <= 0n) {
1788
+ throw new Error("Total tip amount must be greater than 0");
1789
+ }
1790
+ const iface = new (await import('ethers')).Interface(this.abi);
1791
+ const data = iface.encodeFunctionData("sendBatchTips", [recipients, amounts, messages]);
1792
+ const result = await signer.sendTransaction({
1793
+ to: this.contractAddress,
1794
+ value,
1795
+ data
1796
+ });
1797
+ return {
1798
+ hash: result.hash,
1799
+ network: "ethereum",
1800
+ status: "pending"
1801
+ };
1802
+ }
1803
+ /**
1804
+ * Get tip details by ID
1805
+ * @param tipId The tip ID
1806
+ * @param provider JSON-RPC provider
1807
+ */
1808
+ async getTip(tipId, provider) {
1809
+ const iface = new (await import('ethers')).Interface(this.abi);
1810
+ const data = iface.encodeFunctionData("getTip", [tipId]);
1811
+ try {
1812
+ const result = await provider.call({
1813
+ to: this.contractAddress,
1814
+ data
1815
+ });
1816
+ const decoded = iface.decodeFunctionResult("getTip", result);
1817
+ const tip = decoded[0];
1818
+ if (BigInt(tip.tipId) === 0n) {
1819
+ return null;
1820
+ }
1821
+ return {
1822
+ tipId: tip.tipId.toString(),
1823
+ sender: tip.sender,
1824
+ recipient: tip.recipient,
1825
+ token: tip.token,
1826
+ amount: BigInt(tip.amount),
1827
+ platformFee: BigInt(tip.platformFee),
1828
+ message: tip.message,
1829
+ timestamp: Number(tip.timestamp)
1830
+ };
1831
+ } catch {
1832
+ return null;
1833
+ }
1834
+ }
1835
+ /**
1836
+ * Get total tips received by an address
1837
+ * @param address The address to query
1838
+ * @param provider JSON-RPC provider
1839
+ */
1840
+ async getTotalTipsReceived(address, provider) {
1841
+ const iface = new (await import('ethers')).Interface(this.abi);
1842
+ const data = iface.encodeFunctionData("totalTipsReceived", [address]);
1843
+ try {
1844
+ const result = await provider.call({
1845
+ to: this.contractAddress,
1846
+ data
1847
+ });
1848
+ const decoded = iface.decodeFunctionResult("totalTipsReceived", result);
1849
+ return BigInt(decoded[0]);
1850
+ } catch {
1851
+ return 0n;
1852
+ }
1853
+ }
1854
+ /**
1855
+ * Get platform fee in basis points
1856
+ * @param provider JSON-RPC provider
1857
+ */
1858
+ async getPlatformFeeBps(provider) {
1859
+ const iface = new (await import('ethers')).Interface(this.abi);
1860
+ const data = iface.encodeFunctionData("platformFeeBps", []);
1861
+ try {
1862
+ const result = await provider.call({
1863
+ to: this.contractAddress,
1864
+ data
1865
+ });
1866
+ const decoded = iface.decodeFunctionResult("platformFeeBps", result);
1867
+ return Number(decoded[0]);
1868
+ } catch {
1869
+ return 300;
1870
+ }
1871
+ }
1872
+ /**
1873
+ * Get current tip counter
1874
+ * @param provider JSON-RPC provider
1875
+ */
1876
+ async getTipCounter(provider) {
1877
+ const iface = new (await import('ethers')).Interface(this.abi);
1878
+ const data = iface.encodeFunctionData("tipCounter", []);
1879
+ try {
1880
+ const result = await provider.call({
1881
+ to: this.contractAddress,
1882
+ data
1883
+ });
1884
+ const decoded = iface.decodeFunctionResult("tipCounter", result);
1885
+ return BigInt(decoded[0]);
1886
+ } catch {
1887
+ return 0n;
1888
+ }
1889
+ }
1890
+ /**
1891
+ * Get treasury address
1892
+ * @param provider JSON-RPC provider
1893
+ */
1894
+ async getTreasury(provider) {
1895
+ const iface = new (await import('ethers')).Interface(this.abi);
1896
+ const data = iface.encodeFunctionData("treasury", []);
1897
+ try {
1898
+ const result = await provider.call({
1899
+ to: this.contractAddress,
1900
+ data
1901
+ });
1902
+ const decoded = iface.decodeFunctionResult("treasury", result);
1903
+ return decoded[0];
1904
+ } catch {
1905
+ return "0x0000000000000000000000000000000000000000";
1906
+ }
1907
+ }
1908
+ /**
1909
+ * Calculate platform fee for a given amount
1910
+ * @param amount The tip amount
1911
+ * @param feeBps Fee in basis points (default: 300 = 3%)
1912
+ */
1913
+ calculateFee(amount, feeBps = 300) {
1914
+ const fee = amount * BigInt(feeBps) / 10000n;
1915
+ return {
1916
+ fee,
1917
+ creatorAmount: amount - fee
1918
+ };
1919
+ }
1920
+ };
1921
+
1922
+ // src/abi/ZubariSubscription.json
1923
+ var ZubariSubscription_default = [
1924
+ {
1925
+ inputs: [
1926
+ {
1927
+ internalType: "address",
1928
+ name: "_treasury",
1929
+ type: "address"
1930
+ },
1931
+ {
1932
+ internalType: "uint256",
1933
+ name: "_platformFeeBps",
1934
+ type: "uint256"
1935
+ }
1936
+ ],
1937
+ stateMutability: "nonpayable",
1938
+ type: "constructor"
1939
+ },
1940
+ {
1941
+ inputs: [],
1942
+ name: "AlreadySubscribed",
1943
+ type: "error"
1944
+ },
1945
+ {
1946
+ inputs: [],
1947
+ name: "EnforcedPause",
1948
+ type: "error"
1949
+ },
1950
+ {
1951
+ inputs: [],
1952
+ name: "ExpectedPause",
1953
+ type: "error"
1954
+ },
1955
+ {
1956
+ inputs: [],
1957
+ name: "InvalidAddress",
1958
+ type: "error"
1959
+ },
1960
+ {
1961
+ inputs: [],
1962
+ name: "InvalidAmount",
1963
+ type: "error"
1964
+ },
1965
+ {
1966
+ inputs: [],
1967
+ name: "InvalidDuration",
1968
+ type: "error"
1969
+ },
1970
+ {
1971
+ inputs: [],
1972
+ name: "InvalidFee",
1973
+ type: "error"
1974
+ },
1975
+ {
1976
+ inputs: [],
1977
+ name: "NotSubscriber",
1978
+ type: "error"
1979
+ },
1980
+ {
1981
+ inputs: [
1982
+ {
1983
+ internalType: "address",
1984
+ name: "owner",
1985
+ type: "address"
1986
+ }
1987
+ ],
1988
+ name: "OwnableInvalidOwner",
1989
+ type: "error"
1990
+ },
1991
+ {
1992
+ inputs: [
1993
+ {
1994
+ internalType: "address",
1995
+ name: "account",
1996
+ type: "address"
1997
+ }
1998
+ ],
1999
+ name: "OwnableUnauthorizedAccount",
2000
+ type: "error"
2001
+ },
2002
+ {
2003
+ inputs: [],
2004
+ name: "PlanFull",
2005
+ type: "error"
2006
+ },
2007
+ {
2008
+ inputs: [],
2009
+ name: "PlanNotActive",
2010
+ type: "error"
2011
+ },
2012
+ {
2013
+ inputs: [],
2014
+ name: "PlanNotFound",
2015
+ type: "error"
2016
+ },
2017
+ {
2018
+ inputs: [],
2019
+ name: "ReentrancyGuardReentrantCall",
2020
+ type: "error"
2021
+ },
2022
+ {
2023
+ inputs: [
2024
+ {
2025
+ internalType: "address",
2026
+ name: "token",
2027
+ type: "address"
2028
+ }
2029
+ ],
2030
+ name: "SafeERC20FailedOperation",
2031
+ type: "error"
2032
+ },
2033
+ {
2034
+ anonymous: false,
2035
+ inputs: [
2036
+ {
2037
+ indexed: true,
2038
+ internalType: "address",
2039
+ name: "previousOwner",
2040
+ type: "address"
2041
+ },
2042
+ {
2043
+ indexed: true,
2044
+ internalType: "address",
2045
+ name: "newOwner",
2046
+ type: "address"
2047
+ }
2048
+ ],
2049
+ name: "OwnershipTransferred",
2050
+ type: "event"
2051
+ },
2052
+ {
2053
+ anonymous: false,
2054
+ inputs: [
2055
+ {
2056
+ indexed: false,
2057
+ internalType: "address",
2058
+ name: "account",
2059
+ type: "address"
2060
+ }
2061
+ ],
2062
+ name: "Paused",
2063
+ type: "event"
2064
+ },
2065
+ {
2066
+ anonymous: false,
2067
+ inputs: [
2068
+ {
2069
+ indexed: true,
2070
+ internalType: "bytes32",
2071
+ name: "planId",
2072
+ type: "bytes32"
2073
+ },
2074
+ {
2075
+ indexed: true,
2076
+ internalType: "address",
2077
+ name: "creator",
2078
+ type: "address"
2079
+ },
2080
+ {
2081
+ indexed: false,
2082
+ internalType: "string",
2083
+ name: "name",
2084
+ type: "string"
2085
+ },
2086
+ {
2087
+ indexed: false,
2088
+ internalType: "uint256",
2089
+ name: "price",
2090
+ type: "uint256"
2091
+ }
2092
+ ],
2093
+ name: "PlanCreated",
2094
+ type: "event"
2095
+ },
2096
+ {
2097
+ anonymous: false,
2098
+ inputs: [
2099
+ {
2100
+ indexed: true,
2101
+ internalType: "bytes32",
2102
+ name: "planId",
2103
+ type: "bytes32"
2104
+ }
2105
+ ],
2106
+ name: "PlanDeactivated",
2107
+ type: "event"
2108
+ },
2109
+ {
2110
+ anonymous: false,
2111
+ inputs: [
2112
+ {
2113
+ indexed: true,
2114
+ internalType: "bytes32",
2115
+ name: "planId",
2116
+ type: "bytes32"
2117
+ }
2118
+ ],
2119
+ name: "PlanUpdated",
2120
+ type: "event"
2121
+ },
2122
+ {
2123
+ anonymous: false,
2124
+ inputs: [
2125
+ {
2126
+ indexed: true,
2127
+ internalType: "bytes32",
2128
+ name: "subscriptionId",
2129
+ type: "bytes32"
2130
+ },
2131
+ {
2132
+ indexed: true,
2133
+ internalType: "bytes32",
2134
+ name: "planId",
2135
+ type: "bytes32"
2136
+ },
2137
+ {
2138
+ indexed: true,
2139
+ internalType: "address",
2140
+ name: "subscriber",
2141
+ type: "address"
2142
+ },
2143
+ {
2144
+ indexed: false,
2145
+ internalType: "address",
2146
+ name: "creator",
2147
+ type: "address"
2148
+ },
2149
+ {
2150
+ indexed: false,
2151
+ internalType: "uint256",
2152
+ name: "endTime",
2153
+ type: "uint256"
2154
+ }
2155
+ ],
2156
+ name: "Subscribed",
2157
+ type: "event"
2158
+ },
2159
+ {
2160
+ anonymous: false,
2161
+ inputs: [
2162
+ {
2163
+ indexed: true,
2164
+ internalType: "bytes32",
2165
+ name: "subscriptionId",
2166
+ type: "bytes32"
2167
+ }
2168
+ ],
2169
+ name: "SubscriptionCancelled",
2170
+ type: "event"
2171
+ },
2172
+ {
2173
+ anonymous: false,
2174
+ inputs: [
2175
+ {
2176
+ indexed: true,
2177
+ internalType: "bytes32",
2178
+ name: "subscriptionId",
2179
+ type: "bytes32"
2180
+ },
2181
+ {
2182
+ indexed: false,
2183
+ internalType: "uint256",
2184
+ name: "newEndTime",
2185
+ type: "uint256"
2186
+ }
2187
+ ],
2188
+ name: "SubscriptionRenewed",
2189
+ type: "event"
2190
+ },
2191
+ {
2192
+ anonymous: false,
2193
+ inputs: [
2194
+ {
2195
+ indexed: false,
2196
+ internalType: "address",
2197
+ name: "account",
2198
+ type: "address"
2199
+ }
2200
+ ],
2201
+ name: "Unpaused",
2202
+ type: "event"
2203
+ },
2204
+ {
2205
+ inputs: [
2206
+ {
2207
+ internalType: "address",
2208
+ name: "",
2209
+ type: "address"
2210
+ },
2211
+ {
2212
+ internalType: "address",
2213
+ name: "",
2214
+ type: "address"
2215
+ }
2216
+ ],
2217
+ name: "activeSubscription",
2218
+ outputs: [
2219
+ {
2220
+ internalType: "bytes32",
2221
+ name: "",
2222
+ type: "bytes32"
2223
+ }
2224
+ ],
2225
+ stateMutability: "view",
2226
+ type: "function"
2227
+ },
2228
+ {
2229
+ inputs: [
2230
+ {
2231
+ internalType: "bytes32",
2232
+ name: "subscriptionId",
2233
+ type: "bytes32"
2234
+ }
2235
+ ],
2236
+ name: "cancel",
2237
+ outputs: [],
2238
+ stateMutability: "nonpayable",
2239
+ type: "function"
2240
+ },
2241
+ {
2242
+ inputs: [
2243
+ {
2244
+ internalType: "string",
2245
+ name: "name",
2246
+ type: "string"
2247
+ },
2248
+ {
2249
+ internalType: "string",
2250
+ name: "description",
2251
+ type: "string"
2252
+ },
2253
+ {
2254
+ internalType: "uint256",
2255
+ name: "price",
2256
+ type: "uint256"
2257
+ },
2258
+ {
2259
+ internalType: "address",
2260
+ name: "paymentToken",
2261
+ type: "address"
2262
+ },
2263
+ {
2264
+ internalType: "uint256",
2265
+ name: "durationDays",
2266
+ type: "uint256"
2267
+ },
2268
+ {
2269
+ internalType: "uint256",
2270
+ name: "maxSubscribers",
2271
+ type: "uint256"
2272
+ }
2273
+ ],
2274
+ name: "createPlan",
2275
+ outputs: [
2276
+ {
2277
+ internalType: "bytes32",
2278
+ name: "",
2279
+ type: "bytes32"
2280
+ }
2281
+ ],
2282
+ stateMutability: "nonpayable",
2283
+ type: "function"
2284
+ },
2285
+ {
2286
+ inputs: [
2287
+ {
2288
+ internalType: "address",
2289
+ name: "",
2290
+ type: "address"
2291
+ },
2292
+ {
2293
+ internalType: "uint256",
2294
+ name: "",
2295
+ type: "uint256"
2296
+ }
2297
+ ],
2298
+ name: "creatorPlans",
2299
+ outputs: [
2300
+ {
2301
+ internalType: "bytes32",
2302
+ name: "",
2303
+ type: "bytes32"
2304
+ }
2305
+ ],
2306
+ stateMutability: "view",
2307
+ type: "function"
2308
+ },
2309
+ {
2310
+ inputs: [
2311
+ {
2312
+ internalType: "bytes32",
2313
+ name: "planId",
2314
+ type: "bytes32"
2315
+ }
2316
+ ],
2317
+ name: "deactivatePlan",
2318
+ outputs: [],
2319
+ stateMutability: "nonpayable",
2320
+ type: "function"
2321
+ },
2322
+ {
2323
+ inputs: [
2324
+ {
2325
+ internalType: "address",
2326
+ name: "creator",
2327
+ type: "address"
2328
+ }
2329
+ ],
2330
+ name: "getCreatorPlans",
2331
+ outputs: [
2332
+ {
2333
+ internalType: "bytes32[]",
2334
+ name: "",
2335
+ type: "bytes32[]"
2336
+ }
2337
+ ],
2338
+ stateMutability: "view",
2339
+ type: "function"
2340
+ },
2341
+ {
2342
+ inputs: [
2343
+ {
2344
+ internalType: "bytes32",
2345
+ name: "planId",
2346
+ type: "bytes32"
2347
+ }
2348
+ ],
2349
+ name: "getPlan",
2350
+ outputs: [
2351
+ {
2352
+ components: [
2353
+ {
2354
+ internalType: "bytes32",
2355
+ name: "planId",
2356
+ type: "bytes32"
2357
+ },
2358
+ {
2359
+ internalType: "address",
2360
+ name: "creator",
2361
+ type: "address"
2362
+ },
2363
+ {
2364
+ internalType: "string",
2365
+ name: "name",
2366
+ type: "string"
2367
+ },
2368
+ {
2369
+ internalType: "string",
2370
+ name: "description",
2371
+ type: "string"
2372
+ },
2373
+ {
2374
+ internalType: "uint256",
2375
+ name: "price",
2376
+ type: "uint256"
2377
+ },
2378
+ {
2379
+ internalType: "address",
2380
+ name: "paymentToken",
2381
+ type: "address"
2382
+ },
2383
+ {
2384
+ internalType: "uint256",
2385
+ name: "durationDays",
2386
+ type: "uint256"
2387
+ },
2388
+ {
2389
+ internalType: "uint256",
2390
+ name: "maxSubscribers",
2391
+ type: "uint256"
2392
+ },
2393
+ {
2394
+ internalType: "uint256",
2395
+ name: "subscriberCount",
2396
+ type: "uint256"
2397
+ },
2398
+ {
2399
+ internalType: "bool",
2400
+ name: "isActive",
2401
+ type: "bool"
2402
+ }
2403
+ ],
2404
+ internalType: "struct ZubariSubscription.SubscriptionPlan",
2405
+ name: "",
2406
+ type: "tuple"
2407
+ }
2408
+ ],
2409
+ stateMutability: "view",
2410
+ type: "function"
2411
+ },
2412
+ {
2413
+ inputs: [
2414
+ {
2415
+ internalType: "bytes32",
2416
+ name: "subscriptionId",
2417
+ type: "bytes32"
2418
+ }
2419
+ ],
2420
+ name: "getSubscription",
2421
+ outputs: [
2422
+ {
2423
+ components: [
2424
+ {
2425
+ internalType: "bytes32",
2426
+ name: "subscriptionId",
2427
+ type: "bytes32"
2428
+ },
2429
+ {
2430
+ internalType: "bytes32",
2431
+ name: "planId",
2432
+ type: "bytes32"
2433
+ },
2434
+ {
2435
+ internalType: "address",
2436
+ name: "creator",
2437
+ type: "address"
2438
+ },
2439
+ {
2440
+ internalType: "address",
2441
+ name: "subscriber",
2442
+ type: "address"
2443
+ },
2444
+ {
2445
+ internalType: "uint256",
2446
+ name: "startTime",
2447
+ type: "uint256"
2448
+ },
2449
+ {
2450
+ internalType: "uint256",
2451
+ name: "endTime",
2452
+ type: "uint256"
2453
+ },
2454
+ {
2455
+ internalType: "bool",
2456
+ name: "autoRenew",
2457
+ type: "bool"
2458
+ },
2459
+ {
2460
+ internalType: "enum ZubariSubscription.SubscriptionStatus",
2461
+ name: "status",
2462
+ type: "uint8"
2463
+ }
2464
+ ],
2465
+ internalType: "struct ZubariSubscription.Subscription",
2466
+ name: "",
2467
+ type: "tuple"
2468
+ }
2469
+ ],
2470
+ stateMutability: "view",
2471
+ type: "function"
2472
+ },
2473
+ {
2474
+ inputs: [
2475
+ {
2476
+ internalType: "address",
2477
+ name: "subscriber",
2478
+ type: "address"
2479
+ },
2480
+ {
2481
+ internalType: "address",
2482
+ name: "creator",
2483
+ type: "address"
2484
+ }
2485
+ ],
2486
+ name: "isSubscribed",
2487
+ outputs: [
2488
+ {
2489
+ internalType: "bool",
2490
+ name: "",
2491
+ type: "bool"
2492
+ }
2493
+ ],
2494
+ stateMutability: "view",
2495
+ type: "function"
2496
+ },
2497
+ {
2498
+ inputs: [],
2499
+ name: "owner",
2500
+ outputs: [
2501
+ {
2502
+ internalType: "address",
2503
+ name: "",
2504
+ type: "address"
2505
+ }
2506
+ ],
2507
+ stateMutability: "view",
2508
+ type: "function"
2509
+ },
2510
+ {
2511
+ inputs: [],
2512
+ name: "pause",
2513
+ outputs: [],
2514
+ stateMutability: "nonpayable",
2515
+ type: "function"
2516
+ },
2517
+ {
2518
+ inputs: [],
2519
+ name: "paused",
2520
+ outputs: [
2521
+ {
2522
+ internalType: "bool",
2523
+ name: "",
2524
+ type: "bool"
2525
+ }
2526
+ ],
2527
+ stateMutability: "view",
2528
+ type: "function"
2529
+ },
2530
+ {
2531
+ inputs: [
2532
+ {
2533
+ internalType: "bytes32",
2534
+ name: "",
2535
+ type: "bytes32"
2536
+ }
2537
+ ],
2538
+ name: "plans",
2539
+ outputs: [
2540
+ {
2541
+ internalType: "bytes32",
2542
+ name: "planId",
2543
+ type: "bytes32"
2544
+ },
2545
+ {
2546
+ internalType: "address",
2547
+ name: "creator",
2548
+ type: "address"
2549
+ },
2550
+ {
2551
+ internalType: "string",
2552
+ name: "name",
2553
+ type: "string"
2554
+ },
2555
+ {
2556
+ internalType: "string",
2557
+ name: "description",
2558
+ type: "string"
2559
+ },
2560
+ {
2561
+ internalType: "uint256",
2562
+ name: "price",
2563
+ type: "uint256"
2564
+ },
2565
+ {
2566
+ internalType: "address",
2567
+ name: "paymentToken",
2568
+ type: "address"
2569
+ },
2570
+ {
2571
+ internalType: "uint256",
2572
+ name: "durationDays",
2573
+ type: "uint256"
2574
+ },
2575
+ {
2576
+ internalType: "uint256",
2577
+ name: "maxSubscribers",
2578
+ type: "uint256"
2579
+ },
2580
+ {
2581
+ internalType: "uint256",
2582
+ name: "subscriberCount",
2583
+ type: "uint256"
2584
+ },
2585
+ {
2586
+ internalType: "bool",
2587
+ name: "isActive",
2588
+ type: "bool"
2589
+ }
2590
+ ],
2591
+ stateMutability: "view",
2592
+ type: "function"
2593
+ },
2594
+ {
2595
+ inputs: [],
2596
+ name: "platformFeeBps",
2597
+ outputs: [
2598
+ {
2599
+ internalType: "uint256",
2600
+ name: "",
2601
+ type: "uint256"
2602
+ }
2603
+ ],
2604
+ stateMutability: "view",
2605
+ type: "function"
2606
+ },
2607
+ {
2608
+ inputs: [],
2609
+ name: "renounceOwnership",
2610
+ outputs: [],
2611
+ stateMutability: "nonpayable",
2612
+ type: "function"
2613
+ },
2614
+ {
2615
+ inputs: [
2616
+ {
2617
+ internalType: "bytes32",
2618
+ name: "subscriptionId",
2619
+ type: "bytes32"
2620
+ },
2621
+ {
2622
+ internalType: "bool",
2623
+ name: "autoRenew",
2624
+ type: "bool"
2625
+ }
2626
+ ],
2627
+ name: "setAutoRenew",
2628
+ outputs: [],
2629
+ stateMutability: "nonpayable",
2630
+ type: "function"
2631
+ },
2632
+ {
2633
+ inputs: [
2634
+ {
2635
+ internalType: "uint256",
2636
+ name: "_feeBps",
2637
+ type: "uint256"
2638
+ }
2639
+ ],
2640
+ name: "setPlatformFee",
2641
+ outputs: [],
2642
+ stateMutability: "nonpayable",
2643
+ type: "function"
2644
+ },
2645
+ {
2646
+ inputs: [
2647
+ {
2648
+ internalType: "address",
2649
+ name: "_treasury",
2650
+ type: "address"
2651
+ }
2652
+ ],
2653
+ name: "setTreasury",
2654
+ outputs: [],
2655
+ stateMutability: "nonpayable",
2656
+ type: "function"
2657
+ },
2658
+ {
2659
+ inputs: [
2660
+ {
2661
+ internalType: "bytes32",
2662
+ name: "planId",
2663
+ type: "bytes32"
2664
+ },
2665
+ {
2666
+ internalType: "uint256",
2667
+ name: "months",
2668
+ type: "uint256"
2669
+ }
2670
+ ],
2671
+ name: "subscribe",
2672
+ outputs: [
2673
+ {
2674
+ internalType: "bytes32",
2675
+ name: "",
2676
+ type: "bytes32"
2677
+ }
2678
+ ],
2679
+ stateMutability: "payable",
2680
+ type: "function"
2681
+ },
2682
+ {
2683
+ inputs: [
2684
+ {
2685
+ internalType: "address",
2686
+ name: "",
2687
+ type: "address"
2688
+ },
2689
+ {
2690
+ internalType: "uint256",
2691
+ name: "",
2692
+ type: "uint256"
2693
+ }
2694
+ ],
2695
+ name: "subscriberSubscriptions",
2696
+ outputs: [
2697
+ {
2698
+ internalType: "bytes32",
2699
+ name: "",
2700
+ type: "bytes32"
2701
+ }
2702
+ ],
2703
+ stateMutability: "view",
2704
+ type: "function"
2705
+ },
2706
+ {
2707
+ inputs: [
2708
+ {
2709
+ internalType: "bytes32",
2710
+ name: "",
2711
+ type: "bytes32"
2712
+ }
2713
+ ],
2714
+ name: "subscriptions",
2715
+ outputs: [
2716
+ {
2717
+ internalType: "bytes32",
2718
+ name: "subscriptionId",
2719
+ type: "bytes32"
2720
+ },
2721
+ {
2722
+ internalType: "bytes32",
2723
+ name: "planId",
2724
+ type: "bytes32"
2725
+ },
2726
+ {
2727
+ internalType: "address",
2728
+ name: "creator",
2729
+ type: "address"
2730
+ },
2731
+ {
2732
+ internalType: "address",
2733
+ name: "subscriber",
2734
+ type: "address"
2735
+ },
2736
+ {
2737
+ internalType: "uint256",
2738
+ name: "startTime",
2739
+ type: "uint256"
2740
+ },
2741
+ {
2742
+ internalType: "uint256",
2743
+ name: "endTime",
2744
+ type: "uint256"
2745
+ },
2746
+ {
2747
+ internalType: "bool",
2748
+ name: "autoRenew",
2749
+ type: "bool"
2750
+ },
2751
+ {
2752
+ internalType: "enum ZubariSubscription.SubscriptionStatus",
2753
+ name: "status",
2754
+ type: "uint8"
2755
+ }
2756
+ ],
2757
+ stateMutability: "view",
2758
+ type: "function"
2759
+ },
2760
+ {
2761
+ inputs: [
2762
+ {
2763
+ internalType: "address",
2764
+ name: "newOwner",
2765
+ type: "address"
2766
+ }
2767
+ ],
2768
+ name: "transferOwnership",
2769
+ outputs: [],
2770
+ stateMutability: "nonpayable",
2771
+ type: "function"
2772
+ },
2773
+ {
2774
+ inputs: [],
2775
+ name: "treasury",
2776
+ outputs: [
2777
+ {
2778
+ internalType: "address",
2779
+ name: "",
2780
+ type: "address"
2781
+ }
2782
+ ],
2783
+ stateMutability: "view",
2784
+ type: "function"
2785
+ },
2786
+ {
2787
+ inputs: [],
2788
+ name: "unpause",
2789
+ outputs: [],
2790
+ stateMutability: "nonpayable",
2791
+ type: "function"
2792
+ }
2793
+ ];
2794
+
2795
+ // src/protocols/SubscriptionProtocol.ts
2796
+ var ZubariSubscriptionProtocol = class {
2797
+ contractAddress;
2798
+ chainId;
2799
+ abi = ZubariSubscription_default;
2800
+ constructor(contractAddress, chainId) {
2801
+ this.contractAddress = contractAddress;
2802
+ this.chainId = chainId;
2803
+ }
2804
+ /**
2805
+ * Get the contract ABI
2806
+ */
2807
+ getAbi() {
2808
+ return this.abi;
2809
+ }
2810
+ /**
2811
+ * Get the contract address
2812
+ */
2813
+ getAddress() {
2814
+ return this.contractAddress;
2815
+ }
2816
+ /**
2817
+ * Create a new subscription plan
2818
+ * @param plan The plan details
2819
+ * @param signer Wallet signer with sendTransaction method
2820
+ */
2821
+ async createPlan(plan, signer) {
2822
+ if (!plan.name || plan.name.length === 0) {
2823
+ throw new Error("Plan name is required");
2824
+ }
2825
+ if (plan.price <= 0n) {
2826
+ throw new Error("Plan price must be greater than 0");
2827
+ }
2828
+ if (plan.duration <= 0) {
2829
+ throw new Error("Plan duration must be greater than 0");
2830
+ }
2831
+ const iface = new (await import('ethers')).Interface(this.abi);
2832
+ const durationDays = Math.ceil(plan.duration / (24 * 60 * 60));
2833
+ const data = iface.encodeFunctionData("createPlan", [
2834
+ plan.name,
2835
+ plan.description || "",
2836
+ plan.price,
2837
+ plan.paymentToken || "0x0000000000000000000000000000000000000000",
2838
+ // ETH by default
2839
+ durationDays,
2840
+ plan.maxSubscribers || 0
2841
+ // 0 = unlimited
2842
+ ]);
2843
+ const result = await signer.sendTransaction({
2844
+ to: this.contractAddress,
2845
+ value: 0n,
2846
+ data
2847
+ });
2848
+ return result.hash;
2849
+ }
2850
+ /**
2851
+ * Deactivate a subscription plan (only creator can do this)
2852
+ * @param planId The plan ID to deactivate
2853
+ * @param signer Wallet signer
2854
+ */
2855
+ async deactivatePlan(planId, signer) {
2856
+ const iface = new (await import('ethers')).Interface(this.abi);
2857
+ const data = iface.encodeFunctionData("deactivatePlan", [planId]);
2858
+ const result = await signer.sendTransaction({
2859
+ to: this.contractAddress,
2860
+ value: 0n,
2861
+ data
2862
+ });
2863
+ return {
2864
+ hash: result.hash,
2865
+ network: "ethereum",
2866
+ status: "pending"
2867
+ };
2868
+ }
2869
+ /**
2870
+ * Subscribe to a creator's plan
2871
+ * @param planId The plan ID to subscribe to
2872
+ * @param months Number of months to subscribe
2873
+ * @param signer Wallet signer
2874
+ * @param value ETH value to send (if paying with ETH)
2875
+ */
2876
+ async subscribe(planId, months, signer, value) {
2877
+ if (months <= 0) {
2878
+ throw new Error("Subscription duration must be at least 1 month");
2879
+ }
2880
+ const iface = new (await import('ethers')).Interface(this.abi);
2881
+ const data = iface.encodeFunctionData("subscribe", [planId, months]);
2882
+ const result = await signer.sendTransaction({
2883
+ to: this.contractAddress,
2884
+ value: value || 0n,
2885
+ data
2886
+ });
2887
+ return {
2888
+ hash: result.hash,
2889
+ network: "ethereum",
2890
+ status: "pending"
2891
+ };
2892
+ }
2893
+ /**
2894
+ * Cancel an active subscription
2895
+ * @param subscriptionId The subscription ID to cancel
2896
+ * @param signer Wallet signer
2897
+ */
2898
+ async cancel(subscriptionId, signer) {
2899
+ const iface = new (await import('ethers')).Interface(this.abi);
2900
+ const data = iface.encodeFunctionData("cancel", [subscriptionId]);
2901
+ const result = await signer.sendTransaction({
2902
+ to: this.contractAddress,
2903
+ value: 0n,
2904
+ data
2905
+ });
2906
+ return {
2907
+ hash: result.hash,
2908
+ network: "ethereum",
2909
+ status: "pending"
2910
+ };
2911
+ }
2912
+ /**
2913
+ * Set auto-renew for a subscription
2914
+ * @param subscriptionId The subscription ID
2915
+ * @param autoRenew Whether to enable auto-renew
2916
+ * @param signer Wallet signer
2917
+ */
2918
+ async setAutoRenew(subscriptionId, autoRenew, signer) {
2919
+ const iface = new (await import('ethers')).Interface(this.abi);
2920
+ const data = iface.encodeFunctionData("setAutoRenew", [subscriptionId, autoRenew]);
2921
+ const result = await signer.sendTransaction({
2922
+ to: this.contractAddress,
2923
+ value: 0n,
2924
+ data
2925
+ });
2926
+ return {
2927
+ hash: result.hash,
2928
+ network: "ethereum",
2929
+ status: "pending"
2930
+ };
2931
+ }
2932
+ /**
2933
+ * Check if an address is subscribed to a creator
2934
+ * @param subscriber The subscriber address
2935
+ * @param creator The creator address
2936
+ * @param provider JSON-RPC provider
2937
+ */
2938
+ async isSubscribed(subscriber, creator, provider) {
2939
+ const iface = new (await import('ethers')).Interface(this.abi);
2940
+ const data = iface.encodeFunctionData("isSubscribed", [subscriber, creator]);
2941
+ try {
2942
+ const result = await provider.call({
2943
+ to: this.contractAddress,
2944
+ data
2945
+ });
2946
+ const decoded = iface.decodeFunctionResult("isSubscribed", result);
2947
+ return decoded[0];
2948
+ } catch {
2949
+ return false;
2950
+ }
2951
+ }
2952
+ /**
2953
+ * Get the active subscription ID between subscriber and creator
2954
+ * @param subscriber The subscriber address
2955
+ * @param creator The creator address
2956
+ * @param provider JSON-RPC provider
2957
+ */
2958
+ async getActiveSubscriptionId(subscriber, creator, provider) {
2959
+ const iface = new (await import('ethers')).Interface(this.abi);
2960
+ const data = iface.encodeFunctionData("activeSubscription", [subscriber, creator]);
2961
+ try {
2962
+ const result = await provider.call({
2963
+ to: this.contractAddress,
2964
+ data
2965
+ });
2966
+ const decoded = iface.decodeFunctionResult("activeSubscription", result);
2967
+ const subscriptionId = decoded[0];
2968
+ if (subscriptionId === "0x0000000000000000000000000000000000000000000000000000000000000000") {
2969
+ return null;
2970
+ }
2971
+ return subscriptionId;
2972
+ } catch {
2973
+ return null;
2974
+ }
2975
+ }
2976
+ /**
2977
+ * Get subscription details by ID
2978
+ * @param subscriptionId The subscription ID
2979
+ * @param provider JSON-RPC provider
2980
+ */
2981
+ async getSubscription(subscriptionId, provider) {
2982
+ const iface = new (await import('ethers')).Interface(this.abi);
2983
+ const data = iface.encodeFunctionData("getSubscription", [subscriptionId]);
2984
+ try {
2985
+ const result = await provider.call({
2986
+ to: this.contractAddress,
2987
+ data
2988
+ });
2989
+ const decoded = iface.decodeFunctionResult("getSubscription", result);
2990
+ const sub = decoded[0];
2991
+ if (sub.subscriptionId === "0x0000000000000000000000000000000000000000000000000000000000000000") {
2992
+ return null;
2993
+ }
2994
+ let status;
2995
+ switch (Number(sub.status)) {
2996
+ case 0 /* Active */:
2997
+ status = "active";
2998
+ break;
2999
+ case 1 /* Cancelled */:
3000
+ status = "cancelled";
3001
+ break;
3002
+ case 2 /* Expired */:
3003
+ status = "expired";
3004
+ break;
3005
+ default:
3006
+ status = "active";
3007
+ }
3008
+ return {
3009
+ subscriptionId: sub.subscriptionId,
3010
+ planId: sub.planId,
3011
+ creator: sub.creator,
3012
+ subscriber: sub.subscriber,
3013
+ startTime: Number(sub.startTime),
3014
+ endTime: Number(sub.endTime),
3015
+ autoRenew: sub.autoRenew,
3016
+ status
3017
+ };
3018
+ } catch {
3019
+ return null;
3020
+ }
3021
+ }
3022
+ /**
3023
+ * Get a specific plan by ID
3024
+ * @param planId The plan ID
3025
+ * @param provider JSON-RPC provider
3026
+ */
3027
+ async getPlan(planId, provider) {
3028
+ const iface = new (await import('ethers')).Interface(this.abi);
3029
+ const data = iface.encodeFunctionData("getPlan", [planId]);
3030
+ try {
3031
+ const result = await provider.call({
3032
+ to: this.contractAddress,
3033
+ data
3034
+ });
3035
+ const decoded = iface.decodeFunctionResult("getPlan", result);
3036
+ const plan = decoded[0];
3037
+ if (plan.planId === "0x0000000000000000000000000000000000000000000000000000000000000000") {
3038
+ return null;
3039
+ }
3040
+ const durationSeconds = Number(plan.durationDays) * 24 * 60 * 60;
3041
+ return {
3042
+ planId: plan.planId,
3043
+ name: plan.name,
3044
+ description: plan.description,
3045
+ price: plan.price,
3046
+ paymentToken: plan.paymentToken,
3047
+ duration: durationSeconds,
3048
+ perks: [],
3049
+ // Not stored on-chain
3050
+ maxSubscribers: Number(plan.maxSubscribers),
3051
+ nftBadge: false
3052
+ // Not stored on-chain in this contract version
3053
+ };
3054
+ } catch {
3055
+ return null;
3056
+ }
3057
+ }
3058
+ /**
3059
+ * Get all plan IDs for a creator
3060
+ * @param creator The creator address
3061
+ * @param provider JSON-RPC provider
3062
+ */
3063
+ async getCreatorPlanIds(creator, provider) {
3064
+ const iface = new (await import('ethers')).Interface(this.abi);
3065
+ const data = iface.encodeFunctionData("getCreatorPlans", [creator]);
3066
+ try {
3067
+ const result = await provider.call({
3068
+ to: this.contractAddress,
3069
+ data
3070
+ });
3071
+ const decoded = iface.decodeFunctionResult("getCreatorPlans", result);
3072
+ return decoded[0];
3073
+ } catch {
3074
+ return [];
3075
+ }
3076
+ }
3077
+ /**
3078
+ * Get all plans for a creator with full details
3079
+ * @param creator The creator address
3080
+ * @param provider JSON-RPC provider
3081
+ */
3082
+ async getCreatorPlans(creator, provider) {
3083
+ const planIds = await this.getCreatorPlanIds(creator, provider);
3084
+ const plans = [];
3085
+ for (const planId of planIds) {
3086
+ const plan = await this.getPlan(planId, provider);
3087
+ if (plan && plan.planId) {
3088
+ plans.push(plan);
3089
+ }
3090
+ }
3091
+ return plans;
3092
+ }
3093
+ /**
3094
+ * Get platform fee in basis points
3095
+ * @param provider JSON-RPC provider
3096
+ */
3097
+ async getPlatformFeeBps(provider) {
3098
+ const iface = new (await import('ethers')).Interface(this.abi);
3099
+ const data = iface.encodeFunctionData("platformFeeBps", []);
3100
+ try {
3101
+ const result = await provider.call({
3102
+ to: this.contractAddress,
3103
+ data
3104
+ });
3105
+ const decoded = iface.decodeFunctionResult("platformFeeBps", result);
3106
+ return Number(decoded[0]);
3107
+ } catch {
3108
+ return 300;
3109
+ }
3110
+ }
3111
+ /**
3112
+ * Calculate the total cost for a subscription
3113
+ * @param planPrice The plan price per period
3114
+ * @param months Number of months
3115
+ */
3116
+ calculateSubscriptionCost(planPrice, months) {
3117
+ return planPrice * BigInt(months);
3118
+ }
3119
+ /**
3120
+ * Calculate platform fee for a given amount
3121
+ * @param amount The amount
3122
+ * @param feeBps Fee in basis points
3123
+ */
3124
+ calculateFee(amount, feeBps = 300) {
3125
+ const fee = amount * BigInt(feeBps) / 10000n;
3126
+ return {
3127
+ fee,
3128
+ creatorAmount: amount - fee
3129
+ };
1190
3130
  }
1191
3131
  };
1192
3132