@settlr/sdk 0.4.4 → 0.6.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/index.mjs CHANGED
@@ -1176,26 +1176,400 @@ function createWebhookHandler(options) {
1176
1176
  }
1177
1177
  };
1178
1178
  }
1179
+
1180
+ // src/privacy.ts
1181
+ import { PublicKey as PublicKey3, SystemProgram } from "@solana/web3.js";
1182
+ var INCO_LIGHTNING_PROGRAM_ID = new PublicKey3(
1183
+ "5sjEbPiqgZrYwR31ahR6Uk9wf5awoX61YGg7jExQSwaj"
1184
+ );
1185
+ var SETTLR_PROGRAM_ID = new PublicKey3(
1186
+ "339A4zncMj8fbM2zvEopYXu6TZqRieJKebDiXCKwquA5"
1187
+ );
1188
+ function findAllowancePda(handle, allowedAddress) {
1189
+ const handleBuffer = Buffer.alloc(16);
1190
+ let h = handle;
1191
+ for (let i = 0; i < 16; i++) {
1192
+ handleBuffer[i] = Number(h & BigInt(255));
1193
+ h = h >> BigInt(8);
1194
+ }
1195
+ return PublicKey3.findProgramAddressSync(
1196
+ [handleBuffer, allowedAddress.toBuffer()],
1197
+ INCO_LIGHTNING_PROGRAM_ID
1198
+ );
1199
+ }
1200
+ function findPrivateReceiptPda(paymentId) {
1201
+ return PublicKey3.findProgramAddressSync(
1202
+ [Buffer.from("private_receipt"), Buffer.from(paymentId)],
1203
+ SETTLR_PROGRAM_ID
1204
+ );
1205
+ }
1206
+ async function encryptAmount(amount) {
1207
+ const buffer = Buffer.alloc(16);
1208
+ let a = amount;
1209
+ for (let i = 0; i < 16; i++) {
1210
+ buffer[i] = Number(a & BigInt(255));
1211
+ a = a >> BigInt(8);
1212
+ }
1213
+ return new Uint8Array(buffer);
1214
+ }
1215
+ async function buildPrivateReceiptAccounts(config) {
1216
+ const [privateReceiptPda, privateReceiptBump] = findPrivateReceiptPda(config.paymentId);
1217
+ return {
1218
+ customer: config.customer,
1219
+ merchant: config.merchant,
1220
+ privateReceipt: privateReceiptPda,
1221
+ incoLightningProgram: INCO_LIGHTNING_PROGRAM_ID,
1222
+ systemProgram: SystemProgram.programId,
1223
+ bump: privateReceiptBump
1224
+ };
1225
+ }
1226
+ async function simulateAndGetHandle(connection, transaction, privateReceiptPda) {
1227
+ try {
1228
+ const simulation = await connection.simulateTransaction(
1229
+ transaction,
1230
+ void 0,
1231
+ [privateReceiptPda]
1232
+ );
1233
+ if (simulation.value.err) {
1234
+ console.error("Simulation failed:", simulation.value.err);
1235
+ return null;
1236
+ }
1237
+ if (simulation.value.accounts?.[0]?.data) {
1238
+ const data = Buffer.from(simulation.value.accounts[0].data[0], "base64");
1239
+ const paymentIdLen = data.readUInt32LE(8);
1240
+ const handleOffset = 8 + 4 + paymentIdLen + 32 + 32;
1241
+ let handle = BigInt(0);
1242
+ for (let i = 15; i >= 0; i--) {
1243
+ handle = handle * BigInt(256) + BigInt(data[handleOffset + i]);
1244
+ }
1245
+ return handle;
1246
+ }
1247
+ return null;
1248
+ } catch (error) {
1249
+ console.error("Simulation error:", error);
1250
+ return null;
1251
+ }
1252
+ }
1253
+ function buildAllowanceRemainingAccounts(handle, customer, merchant) {
1254
+ const [customerAllowancePda] = findAllowancePda(handle, customer);
1255
+ const [merchantAllowancePda] = findAllowancePda(handle, merchant);
1256
+ return [
1257
+ { pubkey: customerAllowancePda, isSigner: false, isWritable: true },
1258
+ { pubkey: merchantAllowancePda, isSigner: false, isWritable: true }
1259
+ ];
1260
+ }
1261
+ var PrivacyFeatures = {
1262
+ /** Amount is FHE-encrypted, only handle stored on-chain */
1263
+ ENCRYPTED_AMOUNTS: true,
1264
+ /** Selective disclosure - only merchant + customer can decrypt */
1265
+ ACCESS_CONTROL: true,
1266
+ /** CSV export still works (decrypts server-side for authorized merchant) */
1267
+ ACCOUNTING_COMPATIBLE: true,
1268
+ /** Inco covalidators ensure trustless decryption */
1269
+ TRUSTLESS_DECRYPTION: true
1270
+ };
1271
+ var BillingCycles = {
1272
+ /** Weekly (7 days) */
1273
+ WEEKLY: 7 * 24 * 60 * 60,
1274
+ /** Bi-weekly (14 days) */
1275
+ BIWEEKLY: 14 * 24 * 60 * 60,
1276
+ /** Monthly (30 days) */
1277
+ MONTHLY: 30 * 24 * 60 * 60,
1278
+ /** Quarterly (90 days) */
1279
+ QUARTERLY: 90 * 24 * 60 * 60,
1280
+ /** Yearly (365 days) */
1281
+ YEARLY: 365 * 24 * 60 * 60
1282
+ };
1283
+
1284
+ // src/one-click.ts
1285
+ var OneClickClient = class {
1286
+ constructor(baseUrl = "https://settlr.dev") {
1287
+ this.baseUrl = baseUrl.replace(/\/$/, "");
1288
+ }
1289
+ /**
1290
+ * Customer approves a spending limit for a merchant
1291
+ */
1292
+ async approve(options) {
1293
+ const response = await fetch(`${this.baseUrl}/api/one-click`, {
1294
+ method: "POST",
1295
+ headers: { "Content-Type": "application/json" },
1296
+ body: JSON.stringify({
1297
+ action: "approve",
1298
+ ...options
1299
+ })
1300
+ });
1301
+ const data = await response.json();
1302
+ if (!response.ok) {
1303
+ throw new Error(data.error || "Failed to create approval");
1304
+ }
1305
+ return {
1306
+ success: true,
1307
+ approval: data.approval
1308
+ };
1309
+ }
1310
+ /**
1311
+ * Check if customer has active approval for merchant
1312
+ */
1313
+ async check(customerWallet, merchantWallet) {
1314
+ const response = await fetch(`${this.baseUrl}/api/one-click`, {
1315
+ method: "POST",
1316
+ headers: { "Content-Type": "application/json" },
1317
+ body: JSON.stringify({
1318
+ action: "check",
1319
+ customerWallet,
1320
+ merchantWallet
1321
+ })
1322
+ });
1323
+ const data = await response.json();
1324
+ return {
1325
+ hasApproval: data.hasApproval || false,
1326
+ remainingLimit: data.remainingLimit,
1327
+ approval: data.approval
1328
+ };
1329
+ }
1330
+ /**
1331
+ * Merchant charges customer using their one-click approval
1332
+ * No customer interaction required if approval exists with sufficient limit
1333
+ */
1334
+ async charge(options) {
1335
+ const response = await fetch(`${this.baseUrl}/api/one-click`, {
1336
+ method: "POST",
1337
+ headers: { "Content-Type": "application/json" },
1338
+ body: JSON.stringify({
1339
+ action: "charge",
1340
+ ...options
1341
+ })
1342
+ });
1343
+ const data = await response.json();
1344
+ if (!response.ok) {
1345
+ return {
1346
+ success: false,
1347
+ error: data.error
1348
+ };
1349
+ }
1350
+ return {
1351
+ success: true,
1352
+ txSignature: data.txSignature,
1353
+ remainingLimit: data.remainingLimit
1354
+ };
1355
+ }
1356
+ /**
1357
+ * Customer revokes merchant's one-click access
1358
+ */
1359
+ async revoke(customerWallet, merchantWallet) {
1360
+ const response = await fetch(`${this.baseUrl}/api/one-click`, {
1361
+ method: "POST",
1362
+ headers: { "Content-Type": "application/json" },
1363
+ body: JSON.stringify({
1364
+ action: "revoke",
1365
+ customerWallet,
1366
+ merchantWallet
1367
+ })
1368
+ });
1369
+ return { success: response.ok };
1370
+ }
1371
+ };
1372
+ function createOneClickClient(baseUrl) {
1373
+ return new OneClickClient(baseUrl);
1374
+ }
1375
+
1376
+ // src/mobile.ts
1377
+ function generateCheckoutUrl(options, baseUrl = "https://settlr.dev") {
1378
+ const params = new URLSearchParams();
1379
+ params.set("amount", options.amount.toString());
1380
+ params.set("merchant", options.merchantWallet);
1381
+ if (options.merchantName) params.set("name", options.merchantName);
1382
+ if (options.memo) params.set("memo", options.memo);
1383
+ if (options.successUrl) params.set("success_url", options.successUrl);
1384
+ if (options.cancelUrl) params.set("cancel_url", options.cancelUrl);
1385
+ if (options.orderId) params.set("order_id", options.orderId);
1386
+ if (options.customerId) params.set("customer_id", options.customerId);
1387
+ return `${baseUrl}/checkout?${params.toString()}`;
1388
+ }
1389
+ function generateDeepLinkCheckout(options, appScheme, baseUrl = "https://settlr.dev") {
1390
+ const orderId = options.orderId || `order_${Date.now()}`;
1391
+ return generateCheckoutUrl({
1392
+ ...options,
1393
+ orderId,
1394
+ successUrl: `${appScheme}://payment-success?order=${orderId}`,
1395
+ cancelUrl: `${appScheme}://payment-cancel?order=${orderId}`
1396
+ }, baseUrl);
1397
+ }
1398
+ function parseCallbackUrl(url) {
1399
+ try {
1400
+ const parsed = new URL(url);
1401
+ const params = parsed.searchParams;
1402
+ if (parsed.host === "payment-success" || parsed.pathname.includes("success")) {
1403
+ return {
1404
+ success: true,
1405
+ signature: params.get("signature") || void 0,
1406
+ orderId: params.get("order") || params.get("order_id") || void 0
1407
+ };
1408
+ }
1409
+ if (parsed.host === "payment-cancel" || parsed.pathname.includes("cancel")) {
1410
+ return {
1411
+ success: false,
1412
+ orderId: params.get("order") || params.get("order_id") || void 0,
1413
+ error: "Payment cancelled by user"
1414
+ };
1415
+ }
1416
+ return {
1417
+ success: false,
1418
+ error: "Unknown callback URL format"
1419
+ };
1420
+ } catch {
1421
+ return {
1422
+ success: false,
1423
+ error: "Failed to parse callback URL"
1424
+ };
1425
+ }
1426
+ }
1427
+ var REST_API = {
1428
+ createSession: "/api/checkout/create",
1429
+ checkStatus: "/api/checkout/status",
1430
+ oneClick: "/api/one-click",
1431
+ webhook: "/api/webhooks"
1432
+ // For server-to-server notifications
1433
+ };
1434
+ var UNITY_EXAMPLE = `
1435
+ // SettlrPayment.cs - Drop into your Unity project
1436
+
1437
+ using UnityEngine;
1438
+ using UnityEngine.Networking;
1439
+ using System.Collections;
1440
+
1441
+ public class SettlrPayment : MonoBehaviour
1442
+ {
1443
+ public string merchantWallet = "YOUR_WALLET_ADDRESS";
1444
+ public string settlrUrl = "https://settlr.dev";
1445
+
1446
+ // Call this to start a payment
1447
+ public void StartPayment(float amount, string orderId, System.Action<bool, string> callback)
1448
+ {
1449
+ string url = $"{settlrUrl}/checkout?amount={amount}&merchant={merchantWallet}&order_id={orderId}";
1450
+
1451
+ // Add deep link callback (register mygame:// scheme in your app)
1452
+ url += $"&success_url=mygame://payment-success?order={orderId}";
1453
+ url += $"&cancel_url=mygame://payment-cancel?order={orderId}";
1454
+
1455
+ Application.OpenURL(url);
1456
+
1457
+ // Start polling for completion
1458
+ StartCoroutine(PollPaymentStatus(orderId, callback));
1459
+ }
1460
+
1461
+ IEnumerator PollPaymentStatus(string orderId, System.Action<bool, string> callback)
1462
+ {
1463
+ string statusUrl = $"{settlrUrl}/api/checkout/status?order_id={orderId}";
1464
+
1465
+ for (int i = 0; i < 60; i++) // Poll for 5 minutes
1466
+ {
1467
+ using (UnityWebRequest request = UnityWebRequest.Get(statusUrl))
1468
+ {
1469
+ yield return request.SendWebRequest();
1470
+
1471
+ if (request.result == UnityWebRequest.Result.Success)
1472
+ {
1473
+ var response = JsonUtility.FromJson<PaymentStatusResponse>(request.downloadHandler.text);
1474
+
1475
+ if (response.status == "completed")
1476
+ {
1477
+ callback(true, response.signature);
1478
+ yield break;
1479
+ }
1480
+ else if (response.status == "expired" || response.status == "cancelled")
1481
+ {
1482
+ callback(false, null);
1483
+ yield break;
1484
+ }
1485
+ }
1486
+ }
1487
+
1488
+ yield return new WaitForSeconds(5f); // Check every 5 seconds
1489
+ }
1490
+
1491
+ callback(false, "Timeout");
1492
+ }
1493
+
1494
+ [System.Serializable]
1495
+ class PaymentStatusResponse
1496
+ {
1497
+ public string status;
1498
+ public string signature;
1499
+ }
1500
+ }
1501
+ `;
1502
+ var REACT_NATIVE_EXAMPLE = `
1503
+ // SettlrPayment.tsx - React Native component
1504
+
1505
+ import { Linking, Alert } from 'react-native';
1506
+ import { useEffect } from 'react';
1507
+
1508
+ const SETTLR_URL = 'https://settlr.dev';
1509
+ const APP_SCHEME = 'mygame';
1510
+
1511
+ export function useSettlrPayment(onSuccess: (sig: string) => void) {
1512
+ useEffect(() => {
1513
+ const handleDeepLink = ({ url }: { url: string }) => {
1514
+ if (url.includes('payment-success')) {
1515
+ const sig = new URL(url).searchParams.get('signature');
1516
+ if (sig) onSuccess(sig);
1517
+ }
1518
+ };
1519
+
1520
+ Linking.addEventListener('url', handleDeepLink);
1521
+ return () => Linking.removeAllListeners('url');
1522
+ }, [onSuccess]);
1523
+
1524
+ const startPayment = async (amount: number, merchantWallet: string) => {
1525
+ const orderId = \`order_\${Date.now()}\`;
1526
+ const url = \`\${SETTLR_URL}/checkout?amount=\${amount}&merchant=\${merchantWallet}\` +
1527
+ \`&success_url=\${APP_SCHEME}://payment-success?order=\${orderId}\` +
1528
+ \`&cancel_url=\${APP_SCHEME}://payment-cancel?order=\${orderId}\`;
1529
+
1530
+ await Linking.openURL(url);
1531
+ };
1532
+
1533
+ return { startPayment };
1534
+ }
1535
+ `;
1179
1536
  export {
1180
1537
  BuyButton,
1181
1538
  CheckoutWidget,
1539
+ INCO_LIGHTNING_PROGRAM_ID,
1540
+ OneClickClient,
1182
1541
  PaymentModal,
1542
+ PrivacyFeatures,
1543
+ REACT_NATIVE_EXAMPLE,
1544
+ REST_API,
1183
1545
  SETTLR_CHECKOUT_URL,
1546
+ SETTLR_PROGRAM_ID,
1184
1547
  SUPPORTED_NETWORKS,
1185
1548
  SUPPORTED_TOKENS,
1186
1549
  Settlr,
1187
1550
  SettlrProvider,
1551
+ UNITY_EXAMPLE,
1188
1552
  USDC_MINT_DEVNET,
1189
1553
  USDC_MINT_MAINNET,
1190
1554
  USDT_MINT_DEVNET,
1191
1555
  USDT_MINT_MAINNET,
1556
+ buildAllowanceRemainingAccounts,
1557
+ buildPrivateReceiptAccounts,
1558
+ createOneClickClient,
1192
1559
  createWebhookHandler,
1560
+ encryptAmount,
1561
+ findAllowancePda,
1562
+ findPrivateReceiptPda,
1193
1563
  formatUSDC,
1564
+ generateCheckoutUrl,
1565
+ generateDeepLinkCheckout,
1194
1566
  getTokenDecimals,
1195
1567
  getTokenMint,
1568
+ parseCallbackUrl,
1196
1569
  parseUSDC,
1197
1570
  parseWebhookPayload,
1198
1571
  shortenAddress,
1572
+ simulateAndGetHandle,
1199
1573
  usePaymentLink,
1200
1574
  usePaymentModal,
1201
1575
  useSettlr,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@settlr/sdk",
3
- "version": "0.4.4",
4
- "description": "Settlr SDK - Accept Solana USDC payments in games and apps. Email checkout, gasless transactions, no wallet required. The easiest way to add crypto payments.",
3
+ "version": "0.6.1",
4
+ "description": "Settlr SDK - Accept Solana USDC payments with privacy. Email checkout, gasless transactions, FHE-encrypted receipts. Private on-chain, compliant off-chain.",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",
@@ -21,6 +21,7 @@
21
21
  "build": "tsup",
22
22
  "dev": "tsup --watch",
23
23
  "lint": "eslint src/",
24
+ "test": "npx tsx node_modules/mocha/bin/mocha.js 'src/__tests__/**/*.test.ts'",
24
25
  "prepublishOnly": "npm run build"
25
26
  },
26
27
  "keywords": [
@@ -46,7 +47,17 @@
46
47
  "typescript",
47
48
  "email-checkout",
48
49
  "no-wallet",
49
- "privy"
50
+ "privy",
51
+ "inco-lightning",
52
+ "fhe",
53
+ "homomorphic-encryption",
54
+ "private-receipts",
55
+ "privacy-cash",
56
+ "zk-payments",
57
+ "range-security",
58
+ "compliance",
59
+ "sanctions-screening",
60
+ "one-click-payments"
50
61
  ],
51
62
  "author": "Settlr <hello@settlr.dev> (https://settlr.dev)",
52
63
  "license": "MIT",
@@ -68,10 +79,16 @@
68
79
  "@solana/web3.js": "^1.98.0"
69
80
  },
70
81
  "devDependencies": {
82
+ "@types/chai": "^5.2.3",
83
+ "@types/mocha": "^10.0.10",
71
84
  "@types/node": "^20.0.0",
72
85
  "@types/react": "^19.2.7",
86
+ "chai": "^6.2.2",
87
+ "mocha": "^11.7.5",
73
88
  "react": "^19.2.3",
89
+ "ts-node": "^10.9.2",
74
90
  "tsup": "^8.0.0",
91
+ "tsx": "^4.21.0",
75
92
  "typescript": "^5.0.0"
76
93
  },
77
94
  "peerDependencies": {