@settlr/sdk 0.6.0 → 0.6.2
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/README.md +66 -1
- package/dist/index.d.mts +118 -2
- package/dist/index.d.ts +118 -2
- package/dist/index.js +214 -2
- package/dist/index.mjs +224 -12
- package/package.json +19 -2
package/README.md
CHANGED
|
@@ -97,6 +97,71 @@ const accounts = await buildPrivateReceiptAccounts({
|
|
|
97
97
|
|
|
98
98
|
> **Private on-chain. Compliant off-chain.** Your competitors can't see your revenue, but your accountant can.
|
|
99
99
|
|
|
100
|
+
## 🛡️ Wallet Security (Range)
|
|
101
|
+
|
|
102
|
+
Settlr integrates Range Security to screen wallets before processing payments:
|
|
103
|
+
|
|
104
|
+
```typescript
|
|
105
|
+
import { screenWallet, isWalletBlocked, RiskLevel } from "@settlr/sdk";
|
|
106
|
+
|
|
107
|
+
// Screen a wallet for sanctions, fraud, mixers, etc.
|
|
108
|
+
const result = await screenWallet("SomeWalletAddress...");
|
|
109
|
+
|
|
110
|
+
if (result.riskLevel === RiskLevel.SEVERE || result.isSanctioned) {
|
|
111
|
+
console.log("Wallet is blocked:", result.categories);
|
|
112
|
+
// Don't process payment
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Quick check
|
|
116
|
+
const blocked = await isWalletBlocked("SuspiciousWallet...");
|
|
117
|
+
if (blocked) {
|
|
118
|
+
return { error: "Payment blocked for compliance" };
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**What Range screens for:**
|
|
123
|
+
|
|
124
|
+
- 🚫 **Sanctions** - OFAC, EU sanctions lists
|
|
125
|
+
- 🕵️ **Fraud** - Known scam wallets
|
|
126
|
+
- 🌀 **Mixers** - Tornado Cash, etc.
|
|
127
|
+
- 🌑 **Darknet** - Illicit marketplace activity
|
|
128
|
+
- 💀 **Ransomware** - Known attack wallets
|
|
129
|
+
- 🎰 **Gambling** - Unlicensed gambling (configurable)
|
|
130
|
+
|
|
131
|
+
## 💸 Private Payouts (Privacy Cash)
|
|
132
|
+
|
|
133
|
+
Enable ZK-shielded payments for privacy-conscious merchants:
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
import {
|
|
137
|
+
createPrivacyCashClient,
|
|
138
|
+
shieldPayment,
|
|
139
|
+
privateTransfer,
|
|
140
|
+
} from "@settlr/sdk";
|
|
141
|
+
|
|
142
|
+
// Initialize Privacy Cash
|
|
143
|
+
const privacy = createPrivacyCashClient({
|
|
144
|
+
connection,
|
|
145
|
+
wallet,
|
|
146
|
+
network: "mainnet-beta",
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Shield funds (move to private pool)
|
|
150
|
+
const shieldTx = await shieldPayment(privacy, 100); // $100 USDC
|
|
151
|
+
console.log("Shielded:", shieldTx);
|
|
152
|
+
|
|
153
|
+
// Private transfer (ZK-shielded, amount hidden)
|
|
154
|
+
const transferTx = await privateTransfer(privacy, "RecipientWallet...", 50);
|
|
155
|
+
console.log("Private transfer:", transferTx);
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Privacy Cash features:**
|
|
159
|
+
|
|
160
|
+
- 🔐 ZK-shielded transactions
|
|
161
|
+
- 👁️ Amount hidden from on-chain observers
|
|
162
|
+
- ⚡ Fast finality on Solana
|
|
163
|
+
- 💰 Supports USDC and SOL
|
|
164
|
+
|
|
100
165
|
## Installation
|
|
101
166
|
|
|
102
167
|
```bash
|
|
@@ -499,7 +564,7 @@ app.post(
|
|
|
499
564
|
await fulfillOrder(event.payment.orderId);
|
|
500
565
|
},
|
|
501
566
|
},
|
|
502
|
-
})
|
|
567
|
+
}),
|
|
503
568
|
);
|
|
504
569
|
```
|
|
505
570
|
|
package/dist/index.d.mts
CHANGED
|
@@ -270,8 +270,10 @@ declare class Settlr {
|
|
|
270
270
|
constructor(config: SettlrConfig);
|
|
271
271
|
/**
|
|
272
272
|
* Validate API key with Settlr backend
|
|
273
|
+
* This is called automatically by SettlrProvider, but can also be called manually.
|
|
274
|
+
* Fetches merchant wallet address if not provided in config.
|
|
273
275
|
*/
|
|
274
|
-
|
|
276
|
+
validateApiKey(): Promise<void>;
|
|
275
277
|
/**
|
|
276
278
|
* Get the current tier
|
|
277
279
|
*/
|
|
@@ -455,6 +457,10 @@ interface SettlrContextValue {
|
|
|
455
457
|
settlr: Settlr | null;
|
|
456
458
|
/** Whether user is authenticated */
|
|
457
459
|
authenticated: boolean;
|
|
460
|
+
/** Whether the SDK is ready (API key validated) */
|
|
461
|
+
ready: boolean;
|
|
462
|
+
/** Error if initialization failed */
|
|
463
|
+
error: Error | null;
|
|
458
464
|
/** Create a payment link (redirect flow) */
|
|
459
465
|
createPayment: (options: CreatePaymentOptions) => Promise<Payment>;
|
|
460
466
|
/** Generate checkout URL for redirect */
|
|
@@ -1143,4 +1149,114 @@ declare class OneClickClient {
|
|
|
1143
1149
|
*/
|
|
1144
1150
|
declare function createOneClickClient(baseUrl?: string): OneClickClient;
|
|
1145
1151
|
|
|
1146
|
-
|
|
1152
|
+
/**
|
|
1153
|
+
* Mobile Game Integration Utilities
|
|
1154
|
+
*
|
|
1155
|
+
* Simple helpers for integrating Settlr payments in mobile games.
|
|
1156
|
+
* Works with Unity, Unreal, native iOS/Android, React Native, etc.
|
|
1157
|
+
*
|
|
1158
|
+
* The simplest integration is URL-based - just open the checkout URL
|
|
1159
|
+
* and listen for the callback.
|
|
1160
|
+
*/
|
|
1161
|
+
interface MobileCheckoutOptions {
|
|
1162
|
+
/** Amount in USDC */
|
|
1163
|
+
amount: number;
|
|
1164
|
+
/** Merchant wallet address */
|
|
1165
|
+
merchantWallet: string;
|
|
1166
|
+
/** Optional: Merchant display name */
|
|
1167
|
+
merchantName?: string;
|
|
1168
|
+
/** Optional: Payment description */
|
|
1169
|
+
memo?: string;
|
|
1170
|
+
/** URL to redirect after success */
|
|
1171
|
+
successUrl?: string;
|
|
1172
|
+
/** URL to redirect on cancel */
|
|
1173
|
+
cancelUrl?: string;
|
|
1174
|
+
/** Optional: Your order/transaction ID */
|
|
1175
|
+
orderId?: string;
|
|
1176
|
+
/** Optional: Customer ID for one-click */
|
|
1177
|
+
customerId?: string;
|
|
1178
|
+
}
|
|
1179
|
+
interface MobileCheckoutResult {
|
|
1180
|
+
success: boolean;
|
|
1181
|
+
signature?: string;
|
|
1182
|
+
orderId?: string;
|
|
1183
|
+
error?: string;
|
|
1184
|
+
}
|
|
1185
|
+
/**
|
|
1186
|
+
* Generate a checkout URL for mobile games
|
|
1187
|
+
*
|
|
1188
|
+
* Usage in Unity (C#):
|
|
1189
|
+
* ```csharp
|
|
1190
|
+
* string url = $"https://settlr.dev/checkout?amount={amount}&merchant={wallet}";
|
|
1191
|
+
* Application.OpenURL(url);
|
|
1192
|
+
* ```
|
|
1193
|
+
*
|
|
1194
|
+
* Usage in Swift:
|
|
1195
|
+
* ```swift
|
|
1196
|
+
* let url = "https://settlr.dev/checkout?amount=\(amount)&merchant=\(wallet)"
|
|
1197
|
+
* UIApplication.shared.open(URL(string: url)!)
|
|
1198
|
+
* ```
|
|
1199
|
+
*/
|
|
1200
|
+
declare function generateCheckoutUrl(options: MobileCheckoutOptions, baseUrl?: string): string;
|
|
1201
|
+
/**
|
|
1202
|
+
* Generate a deep link for mobile app integration
|
|
1203
|
+
*
|
|
1204
|
+
* For apps that register a custom URL scheme (e.g., mygame://)
|
|
1205
|
+
* the success/cancel URLs can redirect back to the app.
|
|
1206
|
+
*
|
|
1207
|
+
* Example:
|
|
1208
|
+
* - successUrl: "mygame://payment-success?order=123"
|
|
1209
|
+
* - cancelUrl: "mygame://payment-cancel?order=123"
|
|
1210
|
+
*/
|
|
1211
|
+
declare function generateDeepLinkCheckout(options: MobileCheckoutOptions, appScheme: string, baseUrl?: string): string;
|
|
1212
|
+
/**
|
|
1213
|
+
* Parse the callback URL when user returns to app
|
|
1214
|
+
*
|
|
1215
|
+
* Usage in Swift:
|
|
1216
|
+
* ```swift
|
|
1217
|
+
* func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
|
|
1218
|
+
* if url.scheme == "mygame" && url.host == "payment-success" {
|
|
1219
|
+
* let signature = URLComponents(url: url, resolvingAgainstBaseURL: true)?
|
|
1220
|
+
* .queryItems?.first(where: { $0.name == "signature" })?.value
|
|
1221
|
+
* // Handle success
|
|
1222
|
+
* }
|
|
1223
|
+
* }
|
|
1224
|
+
* ```
|
|
1225
|
+
*/
|
|
1226
|
+
declare function parseCallbackUrl(url: string): MobileCheckoutResult;
|
|
1227
|
+
/**
|
|
1228
|
+
* REST API endpoint info for server-side integration
|
|
1229
|
+
*
|
|
1230
|
+
* Mobile games can use these APIs directly without the SDK:
|
|
1231
|
+
*
|
|
1232
|
+
* 1. Create checkout session:
|
|
1233
|
+
* POST /api/checkout/create
|
|
1234
|
+
* { amount, merchantWallet, memo }
|
|
1235
|
+
* → { sessionId, checkoutUrl }
|
|
1236
|
+
*
|
|
1237
|
+
* 2. Check payment status:
|
|
1238
|
+
* GET /api/checkout/status?session={sessionId}
|
|
1239
|
+
* → { status: 'pending' | 'completed' | 'expired', signature? }
|
|
1240
|
+
*
|
|
1241
|
+
* 3. One-click payment (for returning players):
|
|
1242
|
+
* POST /api/one-click
|
|
1243
|
+
* { action: 'charge', customerWallet, merchantWallet, amount }
|
|
1244
|
+
* → { success, signature }
|
|
1245
|
+
*/
|
|
1246
|
+
declare const REST_API: {
|
|
1247
|
+
createSession: string;
|
|
1248
|
+
checkStatus: string;
|
|
1249
|
+
oneClick: string;
|
|
1250
|
+
webhook: string;
|
|
1251
|
+
};
|
|
1252
|
+
/**
|
|
1253
|
+
* Example Unity C# integration code
|
|
1254
|
+
* (For documentation purposes)
|
|
1255
|
+
*/
|
|
1256
|
+
declare const UNITY_EXAMPLE = "\n// SettlrPayment.cs - Drop into your Unity project\n\nusing UnityEngine;\nusing UnityEngine.Networking;\nusing System.Collections;\n\npublic class SettlrPayment : MonoBehaviour\n{\n public string merchantWallet = \"YOUR_WALLET_ADDRESS\";\n public string settlrUrl = \"https://settlr.dev\";\n \n // Call this to start a payment\n public void StartPayment(float amount, string orderId, System.Action<bool, string> callback)\n {\n string url = $\"{settlrUrl}/checkout?amount={amount}&merchant={merchantWallet}&order_id={orderId}\";\n \n // Add deep link callback (register mygame:// scheme in your app)\n url += $\"&success_url=mygame://payment-success?order={orderId}\";\n url += $\"&cancel_url=mygame://payment-cancel?order={orderId}\";\n \n Application.OpenURL(url);\n \n // Start polling for completion\n StartCoroutine(PollPaymentStatus(orderId, callback));\n }\n \n IEnumerator PollPaymentStatus(string orderId, System.Action<bool, string> callback)\n {\n string statusUrl = $\"{settlrUrl}/api/checkout/status?order_id={orderId}\";\n \n for (int i = 0; i < 60; i++) // Poll for 5 minutes\n {\n using (UnityWebRequest request = UnityWebRequest.Get(statusUrl))\n {\n yield return request.SendWebRequest();\n \n if (request.result == UnityWebRequest.Result.Success)\n {\n var response = JsonUtility.FromJson<PaymentStatusResponse>(request.downloadHandler.text);\n \n if (response.status == \"completed\")\n {\n callback(true, response.signature);\n yield break;\n }\n else if (response.status == \"expired\" || response.status == \"cancelled\")\n {\n callback(false, null);\n yield break;\n }\n }\n }\n \n yield return new WaitForSeconds(5f); // Check every 5 seconds\n }\n \n callback(false, \"Timeout\");\n }\n \n [System.Serializable]\n class PaymentStatusResponse\n {\n public string status;\n public string signature;\n }\n}\n";
|
|
1257
|
+
/**
|
|
1258
|
+
* Example React Native integration
|
|
1259
|
+
*/
|
|
1260
|
+
declare const REACT_NATIVE_EXAMPLE = "\n// SettlrPayment.tsx - React Native component\n\nimport { Linking, Alert } from 'react-native';\nimport { useEffect } from 'react';\n\nconst SETTLR_URL = 'https://settlr.dev';\nconst APP_SCHEME = 'mygame';\n\nexport function useSettlrPayment(onSuccess: (sig: string) => void) {\n useEffect(() => {\n const handleDeepLink = ({ url }: { url: string }) => {\n if (url.includes('payment-success')) {\n const sig = new URL(url).searchParams.get('signature');\n if (sig) onSuccess(sig);\n }\n };\n \n Linking.addEventListener('url', handleDeepLink);\n return () => Linking.removeAllListeners('url');\n }, [onSuccess]);\n \n const startPayment = async (amount: number, merchantWallet: string) => {\n const orderId = `order_${Date.now()}`;\n const url = `${SETTLR_URL}/checkout?amount=${amount}&merchant=${merchantWallet}` +\n `&success_url=${APP_SCHEME}://payment-success?order=${orderId}` +\n `&cancel_url=${APP_SCHEME}://payment-cancel?order=${orderId}`;\n \n await Linking.openURL(url);\n };\n \n return { startPayment };\n}\n";
|
|
1261
|
+
|
|
1262
|
+
export { type ApproveOneClickOptions, BuyButton, type BuyButtonProps, type ChargeOneClickOptions, CheckoutWidget, type CheckoutWidgetProps, type CreatePaymentOptions, type CreateSubscriptionOptions, INCO_LIGHTNING_PROGRAM_ID, type IssuePrivateReceiptResult, type MerchantConfig, type MobileCheckoutOptions, type MobileCheckoutResult, OneClickClient, type OneClickResult, type Payment, PaymentModal, type PaymentModalProps, type PaymentResult, type PaymentStatus, PrivacyFeatures, type PrivateReceiptConfig, REACT_NATIVE_EXAMPLE, REST_API, SETTLR_CHECKOUT_URL, SETTLR_PROGRAM_ID, SUPPORTED_NETWORKS, SUPPORTED_TOKENS, Settlr, type SettlrConfig, SettlrProvider, type SpendingApproval, type Subscription, type SubscriptionInterval, type SubscriptionPlan, type SubscriptionStatus, type SupportedToken, type TransactionOptions, UNITY_EXAMPLE, USDC_MINT_DEVNET, USDC_MINT_MAINNET, USDT_MINT_DEVNET, USDT_MINT_MAINNET, type WebhookEventType, type WebhookHandler, type WebhookHandlers, type WebhookPayload, buildAllowanceRemainingAccounts, buildPrivateReceiptAccounts, createOneClickClient, createWebhookHandler, encryptAmount, findAllowancePda, findPrivateReceiptPda, formatUSDC, generateCheckoutUrl, generateDeepLinkCheckout, getTokenDecimals, getTokenMint, parseCallbackUrl, parseUSDC, parseWebhookPayload, shortenAddress, simulateAndGetHandle, usePaymentLink, usePaymentModal, useSettlr, verifyWebhookSignature };
|
package/dist/index.d.ts
CHANGED
|
@@ -270,8 +270,10 @@ declare class Settlr {
|
|
|
270
270
|
constructor(config: SettlrConfig);
|
|
271
271
|
/**
|
|
272
272
|
* Validate API key with Settlr backend
|
|
273
|
+
* This is called automatically by SettlrProvider, but can also be called manually.
|
|
274
|
+
* Fetches merchant wallet address if not provided in config.
|
|
273
275
|
*/
|
|
274
|
-
|
|
276
|
+
validateApiKey(): Promise<void>;
|
|
275
277
|
/**
|
|
276
278
|
* Get the current tier
|
|
277
279
|
*/
|
|
@@ -455,6 +457,10 @@ interface SettlrContextValue {
|
|
|
455
457
|
settlr: Settlr | null;
|
|
456
458
|
/** Whether user is authenticated */
|
|
457
459
|
authenticated: boolean;
|
|
460
|
+
/** Whether the SDK is ready (API key validated) */
|
|
461
|
+
ready: boolean;
|
|
462
|
+
/** Error if initialization failed */
|
|
463
|
+
error: Error | null;
|
|
458
464
|
/** Create a payment link (redirect flow) */
|
|
459
465
|
createPayment: (options: CreatePaymentOptions) => Promise<Payment>;
|
|
460
466
|
/** Generate checkout URL for redirect */
|
|
@@ -1143,4 +1149,114 @@ declare class OneClickClient {
|
|
|
1143
1149
|
*/
|
|
1144
1150
|
declare function createOneClickClient(baseUrl?: string): OneClickClient;
|
|
1145
1151
|
|
|
1146
|
-
|
|
1152
|
+
/**
|
|
1153
|
+
* Mobile Game Integration Utilities
|
|
1154
|
+
*
|
|
1155
|
+
* Simple helpers for integrating Settlr payments in mobile games.
|
|
1156
|
+
* Works with Unity, Unreal, native iOS/Android, React Native, etc.
|
|
1157
|
+
*
|
|
1158
|
+
* The simplest integration is URL-based - just open the checkout URL
|
|
1159
|
+
* and listen for the callback.
|
|
1160
|
+
*/
|
|
1161
|
+
interface MobileCheckoutOptions {
|
|
1162
|
+
/** Amount in USDC */
|
|
1163
|
+
amount: number;
|
|
1164
|
+
/** Merchant wallet address */
|
|
1165
|
+
merchantWallet: string;
|
|
1166
|
+
/** Optional: Merchant display name */
|
|
1167
|
+
merchantName?: string;
|
|
1168
|
+
/** Optional: Payment description */
|
|
1169
|
+
memo?: string;
|
|
1170
|
+
/** URL to redirect after success */
|
|
1171
|
+
successUrl?: string;
|
|
1172
|
+
/** URL to redirect on cancel */
|
|
1173
|
+
cancelUrl?: string;
|
|
1174
|
+
/** Optional: Your order/transaction ID */
|
|
1175
|
+
orderId?: string;
|
|
1176
|
+
/** Optional: Customer ID for one-click */
|
|
1177
|
+
customerId?: string;
|
|
1178
|
+
}
|
|
1179
|
+
interface MobileCheckoutResult {
|
|
1180
|
+
success: boolean;
|
|
1181
|
+
signature?: string;
|
|
1182
|
+
orderId?: string;
|
|
1183
|
+
error?: string;
|
|
1184
|
+
}
|
|
1185
|
+
/**
|
|
1186
|
+
* Generate a checkout URL for mobile games
|
|
1187
|
+
*
|
|
1188
|
+
* Usage in Unity (C#):
|
|
1189
|
+
* ```csharp
|
|
1190
|
+
* string url = $"https://settlr.dev/checkout?amount={amount}&merchant={wallet}";
|
|
1191
|
+
* Application.OpenURL(url);
|
|
1192
|
+
* ```
|
|
1193
|
+
*
|
|
1194
|
+
* Usage in Swift:
|
|
1195
|
+
* ```swift
|
|
1196
|
+
* let url = "https://settlr.dev/checkout?amount=\(amount)&merchant=\(wallet)"
|
|
1197
|
+
* UIApplication.shared.open(URL(string: url)!)
|
|
1198
|
+
* ```
|
|
1199
|
+
*/
|
|
1200
|
+
declare function generateCheckoutUrl(options: MobileCheckoutOptions, baseUrl?: string): string;
|
|
1201
|
+
/**
|
|
1202
|
+
* Generate a deep link for mobile app integration
|
|
1203
|
+
*
|
|
1204
|
+
* For apps that register a custom URL scheme (e.g., mygame://)
|
|
1205
|
+
* the success/cancel URLs can redirect back to the app.
|
|
1206
|
+
*
|
|
1207
|
+
* Example:
|
|
1208
|
+
* - successUrl: "mygame://payment-success?order=123"
|
|
1209
|
+
* - cancelUrl: "mygame://payment-cancel?order=123"
|
|
1210
|
+
*/
|
|
1211
|
+
declare function generateDeepLinkCheckout(options: MobileCheckoutOptions, appScheme: string, baseUrl?: string): string;
|
|
1212
|
+
/**
|
|
1213
|
+
* Parse the callback URL when user returns to app
|
|
1214
|
+
*
|
|
1215
|
+
* Usage in Swift:
|
|
1216
|
+
* ```swift
|
|
1217
|
+
* func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
|
|
1218
|
+
* if url.scheme == "mygame" && url.host == "payment-success" {
|
|
1219
|
+
* let signature = URLComponents(url: url, resolvingAgainstBaseURL: true)?
|
|
1220
|
+
* .queryItems?.first(where: { $0.name == "signature" })?.value
|
|
1221
|
+
* // Handle success
|
|
1222
|
+
* }
|
|
1223
|
+
* }
|
|
1224
|
+
* ```
|
|
1225
|
+
*/
|
|
1226
|
+
declare function parseCallbackUrl(url: string): MobileCheckoutResult;
|
|
1227
|
+
/**
|
|
1228
|
+
* REST API endpoint info for server-side integration
|
|
1229
|
+
*
|
|
1230
|
+
* Mobile games can use these APIs directly without the SDK:
|
|
1231
|
+
*
|
|
1232
|
+
* 1. Create checkout session:
|
|
1233
|
+
* POST /api/checkout/create
|
|
1234
|
+
* { amount, merchantWallet, memo }
|
|
1235
|
+
* → { sessionId, checkoutUrl }
|
|
1236
|
+
*
|
|
1237
|
+
* 2. Check payment status:
|
|
1238
|
+
* GET /api/checkout/status?session={sessionId}
|
|
1239
|
+
* → { status: 'pending' | 'completed' | 'expired', signature? }
|
|
1240
|
+
*
|
|
1241
|
+
* 3. One-click payment (for returning players):
|
|
1242
|
+
* POST /api/one-click
|
|
1243
|
+
* { action: 'charge', customerWallet, merchantWallet, amount }
|
|
1244
|
+
* → { success, signature }
|
|
1245
|
+
*/
|
|
1246
|
+
declare const REST_API: {
|
|
1247
|
+
createSession: string;
|
|
1248
|
+
checkStatus: string;
|
|
1249
|
+
oneClick: string;
|
|
1250
|
+
webhook: string;
|
|
1251
|
+
};
|
|
1252
|
+
/**
|
|
1253
|
+
* Example Unity C# integration code
|
|
1254
|
+
* (For documentation purposes)
|
|
1255
|
+
*/
|
|
1256
|
+
declare const UNITY_EXAMPLE = "\n// SettlrPayment.cs - Drop into your Unity project\n\nusing UnityEngine;\nusing UnityEngine.Networking;\nusing System.Collections;\n\npublic class SettlrPayment : MonoBehaviour\n{\n public string merchantWallet = \"YOUR_WALLET_ADDRESS\";\n public string settlrUrl = \"https://settlr.dev\";\n \n // Call this to start a payment\n public void StartPayment(float amount, string orderId, System.Action<bool, string> callback)\n {\n string url = $\"{settlrUrl}/checkout?amount={amount}&merchant={merchantWallet}&order_id={orderId}\";\n \n // Add deep link callback (register mygame:// scheme in your app)\n url += $\"&success_url=mygame://payment-success?order={orderId}\";\n url += $\"&cancel_url=mygame://payment-cancel?order={orderId}\";\n \n Application.OpenURL(url);\n \n // Start polling for completion\n StartCoroutine(PollPaymentStatus(orderId, callback));\n }\n \n IEnumerator PollPaymentStatus(string orderId, System.Action<bool, string> callback)\n {\n string statusUrl = $\"{settlrUrl}/api/checkout/status?order_id={orderId}\";\n \n for (int i = 0; i < 60; i++) // Poll for 5 minutes\n {\n using (UnityWebRequest request = UnityWebRequest.Get(statusUrl))\n {\n yield return request.SendWebRequest();\n \n if (request.result == UnityWebRequest.Result.Success)\n {\n var response = JsonUtility.FromJson<PaymentStatusResponse>(request.downloadHandler.text);\n \n if (response.status == \"completed\")\n {\n callback(true, response.signature);\n yield break;\n }\n else if (response.status == \"expired\" || response.status == \"cancelled\")\n {\n callback(false, null);\n yield break;\n }\n }\n }\n \n yield return new WaitForSeconds(5f); // Check every 5 seconds\n }\n \n callback(false, \"Timeout\");\n }\n \n [System.Serializable]\n class PaymentStatusResponse\n {\n public string status;\n public string signature;\n }\n}\n";
|
|
1257
|
+
/**
|
|
1258
|
+
* Example React Native integration
|
|
1259
|
+
*/
|
|
1260
|
+
declare const REACT_NATIVE_EXAMPLE = "\n// SettlrPayment.tsx - React Native component\n\nimport { Linking, Alert } from 'react-native';\nimport { useEffect } from 'react';\n\nconst SETTLR_URL = 'https://settlr.dev';\nconst APP_SCHEME = 'mygame';\n\nexport function useSettlrPayment(onSuccess: (sig: string) => void) {\n useEffect(() => {\n const handleDeepLink = ({ url }: { url: string }) => {\n if (url.includes('payment-success')) {\n const sig = new URL(url).searchParams.get('signature');\n if (sig) onSuccess(sig);\n }\n };\n \n Linking.addEventListener('url', handleDeepLink);\n return () => Linking.removeAllListeners('url');\n }, [onSuccess]);\n \n const startPayment = async (amount: number, merchantWallet: string) => {\n const orderId = `order_${Date.now()}`;\n const url = `${SETTLR_URL}/checkout?amount=${amount}&merchant=${merchantWallet}` +\n `&success_url=${APP_SCHEME}://payment-success?order=${orderId}` +\n `&cancel_url=${APP_SCHEME}://payment-cancel?order=${orderId}`;\n \n await Linking.openURL(url);\n };\n \n return { startPayment };\n}\n";
|
|
1261
|
+
|
|
1262
|
+
export { type ApproveOneClickOptions, BuyButton, type BuyButtonProps, type ChargeOneClickOptions, CheckoutWidget, type CheckoutWidgetProps, type CreatePaymentOptions, type CreateSubscriptionOptions, INCO_LIGHTNING_PROGRAM_ID, type IssuePrivateReceiptResult, type MerchantConfig, type MobileCheckoutOptions, type MobileCheckoutResult, OneClickClient, type OneClickResult, type Payment, PaymentModal, type PaymentModalProps, type PaymentResult, type PaymentStatus, PrivacyFeatures, type PrivateReceiptConfig, REACT_NATIVE_EXAMPLE, REST_API, SETTLR_CHECKOUT_URL, SETTLR_PROGRAM_ID, SUPPORTED_NETWORKS, SUPPORTED_TOKENS, Settlr, type SettlrConfig, SettlrProvider, type SpendingApproval, type Subscription, type SubscriptionInterval, type SubscriptionPlan, type SubscriptionStatus, type SupportedToken, type TransactionOptions, UNITY_EXAMPLE, USDC_MINT_DEVNET, USDC_MINT_MAINNET, USDT_MINT_DEVNET, USDT_MINT_MAINNET, type WebhookEventType, type WebhookHandler, type WebhookHandlers, type WebhookPayload, buildAllowanceRemainingAccounts, buildPrivateReceiptAccounts, createOneClickClient, createWebhookHandler, encryptAmount, findAllowancePda, findPrivateReceiptPda, formatUSDC, generateCheckoutUrl, generateDeepLinkCheckout, getTokenDecimals, getTokenMint, parseCallbackUrl, parseUSDC, parseWebhookPayload, shortenAddress, simulateAndGetHandle, usePaymentLink, usePaymentModal, useSettlr, verifyWebhookSignature };
|
package/dist/index.js
CHANGED
|
@@ -36,12 +36,15 @@ __export(index_exports, {
|
|
|
36
36
|
OneClickClient: () => OneClickClient,
|
|
37
37
|
PaymentModal: () => PaymentModal,
|
|
38
38
|
PrivacyFeatures: () => PrivacyFeatures,
|
|
39
|
+
REACT_NATIVE_EXAMPLE: () => REACT_NATIVE_EXAMPLE,
|
|
40
|
+
REST_API: () => REST_API,
|
|
39
41
|
SETTLR_CHECKOUT_URL: () => SETTLR_CHECKOUT_URL,
|
|
40
42
|
SETTLR_PROGRAM_ID: () => SETTLR_PROGRAM_ID,
|
|
41
43
|
SUPPORTED_NETWORKS: () => SUPPORTED_NETWORKS,
|
|
42
44
|
SUPPORTED_TOKENS: () => SUPPORTED_TOKENS,
|
|
43
45
|
Settlr: () => Settlr,
|
|
44
46
|
SettlrProvider: () => SettlrProvider,
|
|
47
|
+
UNITY_EXAMPLE: () => UNITY_EXAMPLE,
|
|
45
48
|
USDC_MINT_DEVNET: () => USDC_MINT_DEVNET,
|
|
46
49
|
USDC_MINT_MAINNET: () => USDC_MINT_MAINNET,
|
|
47
50
|
USDT_MINT_DEVNET: () => USDT_MINT_DEVNET,
|
|
@@ -54,8 +57,11 @@ __export(index_exports, {
|
|
|
54
57
|
findAllowancePda: () => findAllowancePda,
|
|
55
58
|
findPrivateReceiptPda: () => findPrivateReceiptPda,
|
|
56
59
|
formatUSDC: () => formatUSDC,
|
|
60
|
+
generateCheckoutUrl: () => generateCheckoutUrl,
|
|
61
|
+
generateDeepLinkCheckout: () => generateDeepLinkCheckout,
|
|
57
62
|
getTokenDecimals: () => getTokenDecimals,
|
|
58
63
|
getTokenMint: () => getTokenMint,
|
|
64
|
+
parseCallbackUrl: () => parseCallbackUrl,
|
|
59
65
|
parseUSDC: () => parseUSDC,
|
|
60
66
|
parseWebhookPayload: () => parseWebhookPayload,
|
|
61
67
|
shortenAddress: () => shortenAddress,
|
|
@@ -197,6 +203,8 @@ var Settlr = class {
|
|
|
197
203
|
}
|
|
198
204
|
/**
|
|
199
205
|
* Validate API key with Settlr backend
|
|
206
|
+
* This is called automatically by SettlrProvider, but can also be called manually.
|
|
207
|
+
* Fetches merchant wallet address if not provided in config.
|
|
200
208
|
*/
|
|
201
209
|
async validateApiKey() {
|
|
202
210
|
if (this.validated) return;
|
|
@@ -224,6 +232,7 @@ var Settlr = class {
|
|
|
224
232
|
this.tier = data.tier;
|
|
225
233
|
if (data.merchantWallet && !this.merchantWallet) {
|
|
226
234
|
this.merchantWallet = new import_web32.PublicKey(data.merchantWallet);
|
|
235
|
+
this.merchantWalletFromValidation = data.merchantWallet;
|
|
227
236
|
this.config.merchant.walletAddress = data.merchantWallet;
|
|
228
237
|
}
|
|
229
238
|
if (data.merchantName && !this.config.merchant.name) {
|
|
@@ -595,27 +604,54 @@ function SettlrProvider({
|
|
|
595
604
|
config,
|
|
596
605
|
authenticated = false
|
|
597
606
|
}) {
|
|
607
|
+
const [ready, setReady] = (0, import_react.useState)(false);
|
|
608
|
+
const [error, setError] = (0, import_react.useState)(null);
|
|
598
609
|
const settlr = (0, import_react.useMemo)(() => {
|
|
599
610
|
return new Settlr({
|
|
600
611
|
...config,
|
|
601
612
|
rpcEndpoint: config.rpcEndpoint ?? "https://api.devnet.solana.com"
|
|
602
613
|
});
|
|
603
614
|
}, [config]);
|
|
615
|
+
(0, import_react.useEffect)(() => {
|
|
616
|
+
let cancelled = false;
|
|
617
|
+
settlr.validateApiKey().then(() => {
|
|
618
|
+
if (!cancelled) {
|
|
619
|
+
setReady(true);
|
|
620
|
+
setError(null);
|
|
621
|
+
}
|
|
622
|
+
}).catch((err) => {
|
|
623
|
+
if (!cancelled) {
|
|
624
|
+
console.error("[Settlr] API key validation failed:", err);
|
|
625
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
626
|
+
if (config.apiKey?.startsWith("sk_test_")) {
|
|
627
|
+
setReady(true);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
});
|
|
631
|
+
return () => {
|
|
632
|
+
cancelled = true;
|
|
633
|
+
};
|
|
634
|
+
}, [settlr, config.apiKey]);
|
|
604
635
|
const value = (0, import_react.useMemo)(
|
|
605
636
|
() => ({
|
|
606
637
|
settlr,
|
|
607
638
|
authenticated,
|
|
639
|
+
ready,
|
|
640
|
+
error,
|
|
608
641
|
createPayment: (options) => {
|
|
609
642
|
return settlr.createPayment(options);
|
|
610
643
|
},
|
|
611
644
|
getCheckoutUrl: (options) => {
|
|
645
|
+
if (!ready) {
|
|
646
|
+
console.warn("[Settlr] SDK not ready yet. Ensure API key is valid.");
|
|
647
|
+
}
|
|
612
648
|
return settlr.getCheckoutUrl(options);
|
|
613
649
|
},
|
|
614
650
|
getBalance: () => {
|
|
615
651
|
return settlr.getMerchantBalance();
|
|
616
652
|
}
|
|
617
653
|
}),
|
|
618
|
-
[settlr, authenticated]
|
|
654
|
+
[settlr, authenticated, ready, error]
|
|
619
655
|
);
|
|
620
656
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SettlrContext.Provider, { value, children });
|
|
621
657
|
}
|
|
@@ -695,11 +731,18 @@ function BuyButton({
|
|
|
695
731
|
variant = "primary",
|
|
696
732
|
size = "md"
|
|
697
733
|
}) {
|
|
698
|
-
const { getCheckoutUrl, createPayment } = useSettlr();
|
|
734
|
+
const { getCheckoutUrl, createPayment, ready, error: sdkError } = useSettlr();
|
|
699
735
|
const [loading, setLoading] = (0, import_react2.useState)(false);
|
|
700
736
|
const [status, setStatus] = (0, import_react2.useState)("idle");
|
|
701
737
|
const handleClick = (0, import_react2.useCallback)(async () => {
|
|
702
738
|
if (disabled || loading) return;
|
|
739
|
+
if (!ready) {
|
|
740
|
+
const notReadyError = new Error(
|
|
741
|
+
sdkError?.message || "Settlr SDK not ready. Please check your API key configuration."
|
|
742
|
+
);
|
|
743
|
+
onError?.(notReadyError);
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
703
746
|
setLoading(true);
|
|
704
747
|
setStatus("processing");
|
|
705
748
|
onProcessing?.();
|
|
@@ -723,6 +766,8 @@ function BuyButton({
|
|
|
723
766
|
orderId,
|
|
724
767
|
disabled,
|
|
725
768
|
loading,
|
|
769
|
+
ready,
|
|
770
|
+
sdkError,
|
|
726
771
|
successUrl,
|
|
727
772
|
cancelUrl,
|
|
728
773
|
getCheckoutUrl,
|
|
@@ -1426,6 +1471,167 @@ var OneClickClient = class {
|
|
|
1426
1471
|
function createOneClickClient(baseUrl) {
|
|
1427
1472
|
return new OneClickClient(baseUrl);
|
|
1428
1473
|
}
|
|
1474
|
+
|
|
1475
|
+
// src/mobile.ts
|
|
1476
|
+
function generateCheckoutUrl(options, baseUrl = "https://settlr.dev") {
|
|
1477
|
+
const params = new URLSearchParams();
|
|
1478
|
+
params.set("amount", options.amount.toString());
|
|
1479
|
+
params.set("merchant", options.merchantWallet);
|
|
1480
|
+
if (options.merchantName) params.set("name", options.merchantName);
|
|
1481
|
+
if (options.memo) params.set("memo", options.memo);
|
|
1482
|
+
if (options.successUrl) params.set("success_url", options.successUrl);
|
|
1483
|
+
if (options.cancelUrl) params.set("cancel_url", options.cancelUrl);
|
|
1484
|
+
if (options.orderId) params.set("order_id", options.orderId);
|
|
1485
|
+
if (options.customerId) params.set("customer_id", options.customerId);
|
|
1486
|
+
return `${baseUrl}/checkout?${params.toString()}`;
|
|
1487
|
+
}
|
|
1488
|
+
function generateDeepLinkCheckout(options, appScheme, baseUrl = "https://settlr.dev") {
|
|
1489
|
+
const orderId = options.orderId || `order_${Date.now()}`;
|
|
1490
|
+
return generateCheckoutUrl({
|
|
1491
|
+
...options,
|
|
1492
|
+
orderId,
|
|
1493
|
+
successUrl: `${appScheme}://payment-success?order=${orderId}`,
|
|
1494
|
+
cancelUrl: `${appScheme}://payment-cancel?order=${orderId}`
|
|
1495
|
+
}, baseUrl);
|
|
1496
|
+
}
|
|
1497
|
+
function parseCallbackUrl(url) {
|
|
1498
|
+
try {
|
|
1499
|
+
const parsed = new URL(url);
|
|
1500
|
+
const params = parsed.searchParams;
|
|
1501
|
+
if (parsed.host === "payment-success" || parsed.pathname.includes("success")) {
|
|
1502
|
+
return {
|
|
1503
|
+
success: true,
|
|
1504
|
+
signature: params.get("signature") || void 0,
|
|
1505
|
+
orderId: params.get("order") || params.get("order_id") || void 0
|
|
1506
|
+
};
|
|
1507
|
+
}
|
|
1508
|
+
if (parsed.host === "payment-cancel" || parsed.pathname.includes("cancel")) {
|
|
1509
|
+
return {
|
|
1510
|
+
success: false,
|
|
1511
|
+
orderId: params.get("order") || params.get("order_id") || void 0,
|
|
1512
|
+
error: "Payment cancelled by user"
|
|
1513
|
+
};
|
|
1514
|
+
}
|
|
1515
|
+
return {
|
|
1516
|
+
success: false,
|
|
1517
|
+
error: "Unknown callback URL format"
|
|
1518
|
+
};
|
|
1519
|
+
} catch {
|
|
1520
|
+
return {
|
|
1521
|
+
success: false,
|
|
1522
|
+
error: "Failed to parse callback URL"
|
|
1523
|
+
};
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
var REST_API = {
|
|
1527
|
+
createSession: "/api/checkout/create",
|
|
1528
|
+
checkStatus: "/api/checkout/status",
|
|
1529
|
+
oneClick: "/api/one-click",
|
|
1530
|
+
webhook: "/api/webhooks"
|
|
1531
|
+
// For server-to-server notifications
|
|
1532
|
+
};
|
|
1533
|
+
var UNITY_EXAMPLE = `
|
|
1534
|
+
// SettlrPayment.cs - Drop into your Unity project
|
|
1535
|
+
|
|
1536
|
+
using UnityEngine;
|
|
1537
|
+
using UnityEngine.Networking;
|
|
1538
|
+
using System.Collections;
|
|
1539
|
+
|
|
1540
|
+
public class SettlrPayment : MonoBehaviour
|
|
1541
|
+
{
|
|
1542
|
+
public string merchantWallet = "YOUR_WALLET_ADDRESS";
|
|
1543
|
+
public string settlrUrl = "https://settlr.dev";
|
|
1544
|
+
|
|
1545
|
+
// Call this to start a payment
|
|
1546
|
+
public void StartPayment(float amount, string orderId, System.Action<bool, string> callback)
|
|
1547
|
+
{
|
|
1548
|
+
string url = $"{settlrUrl}/checkout?amount={amount}&merchant={merchantWallet}&order_id={orderId}";
|
|
1549
|
+
|
|
1550
|
+
// Add deep link callback (register mygame:// scheme in your app)
|
|
1551
|
+
url += $"&success_url=mygame://payment-success?order={orderId}";
|
|
1552
|
+
url += $"&cancel_url=mygame://payment-cancel?order={orderId}";
|
|
1553
|
+
|
|
1554
|
+
Application.OpenURL(url);
|
|
1555
|
+
|
|
1556
|
+
// Start polling for completion
|
|
1557
|
+
StartCoroutine(PollPaymentStatus(orderId, callback));
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
IEnumerator PollPaymentStatus(string orderId, System.Action<bool, string> callback)
|
|
1561
|
+
{
|
|
1562
|
+
string statusUrl = $"{settlrUrl}/api/checkout/status?order_id={orderId}";
|
|
1563
|
+
|
|
1564
|
+
for (int i = 0; i < 60; i++) // Poll for 5 minutes
|
|
1565
|
+
{
|
|
1566
|
+
using (UnityWebRequest request = UnityWebRequest.Get(statusUrl))
|
|
1567
|
+
{
|
|
1568
|
+
yield return request.SendWebRequest();
|
|
1569
|
+
|
|
1570
|
+
if (request.result == UnityWebRequest.Result.Success)
|
|
1571
|
+
{
|
|
1572
|
+
var response = JsonUtility.FromJson<PaymentStatusResponse>(request.downloadHandler.text);
|
|
1573
|
+
|
|
1574
|
+
if (response.status == "completed")
|
|
1575
|
+
{
|
|
1576
|
+
callback(true, response.signature);
|
|
1577
|
+
yield break;
|
|
1578
|
+
}
|
|
1579
|
+
else if (response.status == "expired" || response.status == "cancelled")
|
|
1580
|
+
{
|
|
1581
|
+
callback(false, null);
|
|
1582
|
+
yield break;
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
yield return new WaitForSeconds(5f); // Check every 5 seconds
|
|
1588
|
+
}
|
|
1589
|
+
|
|
1590
|
+
callback(false, "Timeout");
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
[System.Serializable]
|
|
1594
|
+
class PaymentStatusResponse
|
|
1595
|
+
{
|
|
1596
|
+
public string status;
|
|
1597
|
+
public string signature;
|
|
1598
|
+
}
|
|
1599
|
+
}
|
|
1600
|
+
`;
|
|
1601
|
+
var REACT_NATIVE_EXAMPLE = `
|
|
1602
|
+
// SettlrPayment.tsx - React Native component
|
|
1603
|
+
|
|
1604
|
+
import { Linking, Alert } from 'react-native';
|
|
1605
|
+
import { useEffect } from 'react';
|
|
1606
|
+
|
|
1607
|
+
const SETTLR_URL = 'https://settlr.dev';
|
|
1608
|
+
const APP_SCHEME = 'mygame';
|
|
1609
|
+
|
|
1610
|
+
export function useSettlrPayment(onSuccess: (sig: string) => void) {
|
|
1611
|
+
useEffect(() => {
|
|
1612
|
+
const handleDeepLink = ({ url }: { url: string }) => {
|
|
1613
|
+
if (url.includes('payment-success')) {
|
|
1614
|
+
const sig = new URL(url).searchParams.get('signature');
|
|
1615
|
+
if (sig) onSuccess(sig);
|
|
1616
|
+
}
|
|
1617
|
+
};
|
|
1618
|
+
|
|
1619
|
+
Linking.addEventListener('url', handleDeepLink);
|
|
1620
|
+
return () => Linking.removeAllListeners('url');
|
|
1621
|
+
}, [onSuccess]);
|
|
1622
|
+
|
|
1623
|
+
const startPayment = async (amount: number, merchantWallet: string) => {
|
|
1624
|
+
const orderId = \`order_\${Date.now()}\`;
|
|
1625
|
+
const url = \`\${SETTLR_URL}/checkout?amount=\${amount}&merchant=\${merchantWallet}\` +
|
|
1626
|
+
\`&success_url=\${APP_SCHEME}://payment-success?order=\${orderId}\` +
|
|
1627
|
+
\`&cancel_url=\${APP_SCHEME}://payment-cancel?order=\${orderId}\`;
|
|
1628
|
+
|
|
1629
|
+
await Linking.openURL(url);
|
|
1630
|
+
};
|
|
1631
|
+
|
|
1632
|
+
return { startPayment };
|
|
1633
|
+
}
|
|
1634
|
+
`;
|
|
1429
1635
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1430
1636
|
0 && (module.exports = {
|
|
1431
1637
|
BuyButton,
|
|
@@ -1434,12 +1640,15 @@ function createOneClickClient(baseUrl) {
|
|
|
1434
1640
|
OneClickClient,
|
|
1435
1641
|
PaymentModal,
|
|
1436
1642
|
PrivacyFeatures,
|
|
1643
|
+
REACT_NATIVE_EXAMPLE,
|
|
1644
|
+
REST_API,
|
|
1437
1645
|
SETTLR_CHECKOUT_URL,
|
|
1438
1646
|
SETTLR_PROGRAM_ID,
|
|
1439
1647
|
SUPPORTED_NETWORKS,
|
|
1440
1648
|
SUPPORTED_TOKENS,
|
|
1441
1649
|
Settlr,
|
|
1442
1650
|
SettlrProvider,
|
|
1651
|
+
UNITY_EXAMPLE,
|
|
1443
1652
|
USDC_MINT_DEVNET,
|
|
1444
1653
|
USDC_MINT_MAINNET,
|
|
1445
1654
|
USDT_MINT_DEVNET,
|
|
@@ -1452,8 +1661,11 @@ function createOneClickClient(baseUrl) {
|
|
|
1452
1661
|
findAllowancePda,
|
|
1453
1662
|
findPrivateReceiptPda,
|
|
1454
1663
|
formatUSDC,
|
|
1664
|
+
generateCheckoutUrl,
|
|
1665
|
+
generateDeepLinkCheckout,
|
|
1455
1666
|
getTokenDecimals,
|
|
1456
1667
|
getTokenMint,
|
|
1668
|
+
parseCallbackUrl,
|
|
1457
1669
|
parseUSDC,
|
|
1458
1670
|
parseWebhookPayload,
|
|
1459
1671
|
shortenAddress,
|
package/dist/index.mjs
CHANGED
|
@@ -139,6 +139,8 @@ var Settlr = class {
|
|
|
139
139
|
}
|
|
140
140
|
/**
|
|
141
141
|
* Validate API key with Settlr backend
|
|
142
|
+
* This is called automatically by SettlrProvider, but can also be called manually.
|
|
143
|
+
* Fetches merchant wallet address if not provided in config.
|
|
142
144
|
*/
|
|
143
145
|
async validateApiKey() {
|
|
144
146
|
if (this.validated) return;
|
|
@@ -166,6 +168,7 @@ var Settlr = class {
|
|
|
166
168
|
this.tier = data.tier;
|
|
167
169
|
if (data.merchantWallet && !this.merchantWallet) {
|
|
168
170
|
this.merchantWallet = new PublicKey2(data.merchantWallet);
|
|
171
|
+
this.merchantWalletFromValidation = data.merchantWallet;
|
|
169
172
|
this.config.merchant.walletAddress = data.merchantWallet;
|
|
170
173
|
}
|
|
171
174
|
if (data.merchantName && !this.config.merchant.name) {
|
|
@@ -529,7 +532,13 @@ var Settlr = class {
|
|
|
529
532
|
};
|
|
530
533
|
|
|
531
534
|
// src/react.tsx
|
|
532
|
-
import {
|
|
535
|
+
import {
|
|
536
|
+
createContext,
|
|
537
|
+
useContext,
|
|
538
|
+
useMemo,
|
|
539
|
+
useEffect,
|
|
540
|
+
useState
|
|
541
|
+
} from "react";
|
|
533
542
|
import { jsx } from "react/jsx-runtime";
|
|
534
543
|
var SettlrContext = createContext(null);
|
|
535
544
|
function SettlrProvider({
|
|
@@ -537,27 +546,54 @@ function SettlrProvider({
|
|
|
537
546
|
config,
|
|
538
547
|
authenticated = false
|
|
539
548
|
}) {
|
|
549
|
+
const [ready, setReady] = useState(false);
|
|
550
|
+
const [error, setError] = useState(null);
|
|
540
551
|
const settlr = useMemo(() => {
|
|
541
552
|
return new Settlr({
|
|
542
553
|
...config,
|
|
543
554
|
rpcEndpoint: config.rpcEndpoint ?? "https://api.devnet.solana.com"
|
|
544
555
|
});
|
|
545
556
|
}, [config]);
|
|
557
|
+
useEffect(() => {
|
|
558
|
+
let cancelled = false;
|
|
559
|
+
settlr.validateApiKey().then(() => {
|
|
560
|
+
if (!cancelled) {
|
|
561
|
+
setReady(true);
|
|
562
|
+
setError(null);
|
|
563
|
+
}
|
|
564
|
+
}).catch((err) => {
|
|
565
|
+
if (!cancelled) {
|
|
566
|
+
console.error("[Settlr] API key validation failed:", err);
|
|
567
|
+
setError(err instanceof Error ? err : new Error(String(err)));
|
|
568
|
+
if (config.apiKey?.startsWith("sk_test_")) {
|
|
569
|
+
setReady(true);
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
return () => {
|
|
574
|
+
cancelled = true;
|
|
575
|
+
};
|
|
576
|
+
}, [settlr, config.apiKey]);
|
|
546
577
|
const value = useMemo(
|
|
547
578
|
() => ({
|
|
548
579
|
settlr,
|
|
549
580
|
authenticated,
|
|
581
|
+
ready,
|
|
582
|
+
error,
|
|
550
583
|
createPayment: (options) => {
|
|
551
584
|
return settlr.createPayment(options);
|
|
552
585
|
},
|
|
553
586
|
getCheckoutUrl: (options) => {
|
|
587
|
+
if (!ready) {
|
|
588
|
+
console.warn("[Settlr] SDK not ready yet. Ensure API key is valid.");
|
|
589
|
+
}
|
|
554
590
|
return settlr.getCheckoutUrl(options);
|
|
555
591
|
},
|
|
556
592
|
getBalance: () => {
|
|
557
593
|
return settlr.getMerchantBalance();
|
|
558
594
|
}
|
|
559
595
|
}),
|
|
560
|
-
[settlr, authenticated]
|
|
596
|
+
[settlr, authenticated, ready, error]
|
|
561
597
|
);
|
|
562
598
|
return /* @__PURE__ */ jsx(SettlrContext.Provider, { value, children });
|
|
563
599
|
}
|
|
@@ -571,9 +607,9 @@ function useSettlr() {
|
|
|
571
607
|
|
|
572
608
|
// src/components.tsx
|
|
573
609
|
import {
|
|
574
|
-
useState,
|
|
610
|
+
useState as useState2,
|
|
575
611
|
useCallback,
|
|
576
|
-
useEffect
|
|
612
|
+
useEffect as useEffect2
|
|
577
613
|
} from "react";
|
|
578
614
|
import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
579
615
|
var defaultStyles = {
|
|
@@ -641,11 +677,18 @@ function BuyButton({
|
|
|
641
677
|
variant = "primary",
|
|
642
678
|
size = "md"
|
|
643
679
|
}) {
|
|
644
|
-
const { getCheckoutUrl, createPayment } = useSettlr();
|
|
645
|
-
const [loading, setLoading] =
|
|
646
|
-
const [status, setStatus] =
|
|
680
|
+
const { getCheckoutUrl, createPayment, ready, error: sdkError } = useSettlr();
|
|
681
|
+
const [loading, setLoading] = useState2(false);
|
|
682
|
+
const [status, setStatus] = useState2("idle");
|
|
647
683
|
const handleClick = useCallback(async () => {
|
|
648
684
|
if (disabled || loading) return;
|
|
685
|
+
if (!ready) {
|
|
686
|
+
const notReadyError = new Error(
|
|
687
|
+
sdkError?.message || "Settlr SDK not ready. Please check your API key configuration."
|
|
688
|
+
);
|
|
689
|
+
onError?.(notReadyError);
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
649
692
|
setLoading(true);
|
|
650
693
|
setStatus("processing");
|
|
651
694
|
onProcessing?.();
|
|
@@ -669,6 +712,8 @@ function BuyButton({
|
|
|
669
712
|
orderId,
|
|
670
713
|
disabled,
|
|
671
714
|
loading,
|
|
715
|
+
ready,
|
|
716
|
+
sdkError,
|
|
672
717
|
successUrl,
|
|
673
718
|
cancelUrl,
|
|
674
719
|
getCheckoutUrl,
|
|
@@ -820,7 +865,7 @@ function CheckoutWidget({
|
|
|
820
865
|
showBranding = true
|
|
821
866
|
}) {
|
|
822
867
|
const { getCheckoutUrl } = useSettlr();
|
|
823
|
-
const [status, setStatus] =
|
|
868
|
+
const [status, setStatus] = useState2("idle");
|
|
824
869
|
const containerStyle = {
|
|
825
870
|
...widgetStyles.container,
|
|
826
871
|
...theme === "dark" ? widgetStyles.containerDark : widgetStyles.containerLight,
|
|
@@ -1003,7 +1048,7 @@ function PaymentModal({
|
|
|
1003
1048
|
onError,
|
|
1004
1049
|
checkoutUrl = "https://settlr.dev/checkout"
|
|
1005
1050
|
}) {
|
|
1006
|
-
const [loading, setLoading] =
|
|
1051
|
+
const [loading, setLoading] = useState2(true);
|
|
1007
1052
|
const params = new URLSearchParams({
|
|
1008
1053
|
amount: amount.toString(),
|
|
1009
1054
|
merchant: merchantName,
|
|
@@ -1013,7 +1058,7 @@ function PaymentModal({
|
|
|
1013
1058
|
if (memo) params.set("memo", memo);
|
|
1014
1059
|
if (orderId) params.set("orderId", orderId);
|
|
1015
1060
|
const iframeSrc = `${checkoutUrl}?${params.toString()}`;
|
|
1016
|
-
|
|
1061
|
+
useEffect2(() => {
|
|
1017
1062
|
const handleMessage = (event) => {
|
|
1018
1063
|
if (!event.origin.includes("settlr.dev") && !event.origin.includes("localhost")) {
|
|
1019
1064
|
return;
|
|
@@ -1037,7 +1082,7 @@ function PaymentModal({
|
|
|
1037
1082
|
window.addEventListener("message", handleMessage);
|
|
1038
1083
|
return () => window.removeEventListener("message", handleMessage);
|
|
1039
1084
|
}, [amount, onSuccess, onError, onClose]);
|
|
1040
|
-
|
|
1085
|
+
useEffect2(() => {
|
|
1041
1086
|
const handleEscape = (e) => {
|
|
1042
1087
|
if (e.key === "Escape") onClose?.();
|
|
1043
1088
|
};
|
|
@@ -1074,7 +1119,7 @@ function PaymentModal({
|
|
|
1074
1119
|
] }) });
|
|
1075
1120
|
}
|
|
1076
1121
|
function usePaymentModal(config) {
|
|
1077
|
-
const [modalState, setModalState] =
|
|
1122
|
+
const [modalState, setModalState] = useState2({
|
|
1078
1123
|
isOpen: false,
|
|
1079
1124
|
amount: 0
|
|
1080
1125
|
});
|
|
@@ -1372,6 +1417,167 @@ var OneClickClient = class {
|
|
|
1372
1417
|
function createOneClickClient(baseUrl) {
|
|
1373
1418
|
return new OneClickClient(baseUrl);
|
|
1374
1419
|
}
|
|
1420
|
+
|
|
1421
|
+
// src/mobile.ts
|
|
1422
|
+
function generateCheckoutUrl(options, baseUrl = "https://settlr.dev") {
|
|
1423
|
+
const params = new URLSearchParams();
|
|
1424
|
+
params.set("amount", options.amount.toString());
|
|
1425
|
+
params.set("merchant", options.merchantWallet);
|
|
1426
|
+
if (options.merchantName) params.set("name", options.merchantName);
|
|
1427
|
+
if (options.memo) params.set("memo", options.memo);
|
|
1428
|
+
if (options.successUrl) params.set("success_url", options.successUrl);
|
|
1429
|
+
if (options.cancelUrl) params.set("cancel_url", options.cancelUrl);
|
|
1430
|
+
if (options.orderId) params.set("order_id", options.orderId);
|
|
1431
|
+
if (options.customerId) params.set("customer_id", options.customerId);
|
|
1432
|
+
return `${baseUrl}/checkout?${params.toString()}`;
|
|
1433
|
+
}
|
|
1434
|
+
function generateDeepLinkCheckout(options, appScheme, baseUrl = "https://settlr.dev") {
|
|
1435
|
+
const orderId = options.orderId || `order_${Date.now()}`;
|
|
1436
|
+
return generateCheckoutUrl({
|
|
1437
|
+
...options,
|
|
1438
|
+
orderId,
|
|
1439
|
+
successUrl: `${appScheme}://payment-success?order=${orderId}`,
|
|
1440
|
+
cancelUrl: `${appScheme}://payment-cancel?order=${orderId}`
|
|
1441
|
+
}, baseUrl);
|
|
1442
|
+
}
|
|
1443
|
+
function parseCallbackUrl(url) {
|
|
1444
|
+
try {
|
|
1445
|
+
const parsed = new URL(url);
|
|
1446
|
+
const params = parsed.searchParams;
|
|
1447
|
+
if (parsed.host === "payment-success" || parsed.pathname.includes("success")) {
|
|
1448
|
+
return {
|
|
1449
|
+
success: true,
|
|
1450
|
+
signature: params.get("signature") || void 0,
|
|
1451
|
+
orderId: params.get("order") || params.get("order_id") || void 0
|
|
1452
|
+
};
|
|
1453
|
+
}
|
|
1454
|
+
if (parsed.host === "payment-cancel" || parsed.pathname.includes("cancel")) {
|
|
1455
|
+
return {
|
|
1456
|
+
success: false,
|
|
1457
|
+
orderId: params.get("order") || params.get("order_id") || void 0,
|
|
1458
|
+
error: "Payment cancelled by user"
|
|
1459
|
+
};
|
|
1460
|
+
}
|
|
1461
|
+
return {
|
|
1462
|
+
success: false,
|
|
1463
|
+
error: "Unknown callback URL format"
|
|
1464
|
+
};
|
|
1465
|
+
} catch {
|
|
1466
|
+
return {
|
|
1467
|
+
success: false,
|
|
1468
|
+
error: "Failed to parse callback URL"
|
|
1469
|
+
};
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
var REST_API = {
|
|
1473
|
+
createSession: "/api/checkout/create",
|
|
1474
|
+
checkStatus: "/api/checkout/status",
|
|
1475
|
+
oneClick: "/api/one-click",
|
|
1476
|
+
webhook: "/api/webhooks"
|
|
1477
|
+
// For server-to-server notifications
|
|
1478
|
+
};
|
|
1479
|
+
var UNITY_EXAMPLE = `
|
|
1480
|
+
// SettlrPayment.cs - Drop into your Unity project
|
|
1481
|
+
|
|
1482
|
+
using UnityEngine;
|
|
1483
|
+
using UnityEngine.Networking;
|
|
1484
|
+
using System.Collections;
|
|
1485
|
+
|
|
1486
|
+
public class SettlrPayment : MonoBehaviour
|
|
1487
|
+
{
|
|
1488
|
+
public string merchantWallet = "YOUR_WALLET_ADDRESS";
|
|
1489
|
+
public string settlrUrl = "https://settlr.dev";
|
|
1490
|
+
|
|
1491
|
+
// Call this to start a payment
|
|
1492
|
+
public void StartPayment(float amount, string orderId, System.Action<bool, string> callback)
|
|
1493
|
+
{
|
|
1494
|
+
string url = $"{settlrUrl}/checkout?amount={amount}&merchant={merchantWallet}&order_id={orderId}";
|
|
1495
|
+
|
|
1496
|
+
// Add deep link callback (register mygame:// scheme in your app)
|
|
1497
|
+
url += $"&success_url=mygame://payment-success?order={orderId}";
|
|
1498
|
+
url += $"&cancel_url=mygame://payment-cancel?order={orderId}";
|
|
1499
|
+
|
|
1500
|
+
Application.OpenURL(url);
|
|
1501
|
+
|
|
1502
|
+
// Start polling for completion
|
|
1503
|
+
StartCoroutine(PollPaymentStatus(orderId, callback));
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
IEnumerator PollPaymentStatus(string orderId, System.Action<bool, string> callback)
|
|
1507
|
+
{
|
|
1508
|
+
string statusUrl = $"{settlrUrl}/api/checkout/status?order_id={orderId}";
|
|
1509
|
+
|
|
1510
|
+
for (int i = 0; i < 60; i++) // Poll for 5 minutes
|
|
1511
|
+
{
|
|
1512
|
+
using (UnityWebRequest request = UnityWebRequest.Get(statusUrl))
|
|
1513
|
+
{
|
|
1514
|
+
yield return request.SendWebRequest();
|
|
1515
|
+
|
|
1516
|
+
if (request.result == UnityWebRequest.Result.Success)
|
|
1517
|
+
{
|
|
1518
|
+
var response = JsonUtility.FromJson<PaymentStatusResponse>(request.downloadHandler.text);
|
|
1519
|
+
|
|
1520
|
+
if (response.status == "completed")
|
|
1521
|
+
{
|
|
1522
|
+
callback(true, response.signature);
|
|
1523
|
+
yield break;
|
|
1524
|
+
}
|
|
1525
|
+
else if (response.status == "expired" || response.status == "cancelled")
|
|
1526
|
+
{
|
|
1527
|
+
callback(false, null);
|
|
1528
|
+
yield break;
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
yield return new WaitForSeconds(5f); // Check every 5 seconds
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
callback(false, "Timeout");
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
[System.Serializable]
|
|
1540
|
+
class PaymentStatusResponse
|
|
1541
|
+
{
|
|
1542
|
+
public string status;
|
|
1543
|
+
public string signature;
|
|
1544
|
+
}
|
|
1545
|
+
}
|
|
1546
|
+
`;
|
|
1547
|
+
var REACT_NATIVE_EXAMPLE = `
|
|
1548
|
+
// SettlrPayment.tsx - React Native component
|
|
1549
|
+
|
|
1550
|
+
import { Linking, Alert } from 'react-native';
|
|
1551
|
+
import { useEffect } from 'react';
|
|
1552
|
+
|
|
1553
|
+
const SETTLR_URL = 'https://settlr.dev';
|
|
1554
|
+
const APP_SCHEME = 'mygame';
|
|
1555
|
+
|
|
1556
|
+
export function useSettlrPayment(onSuccess: (sig: string) => void) {
|
|
1557
|
+
useEffect(() => {
|
|
1558
|
+
const handleDeepLink = ({ url }: { url: string }) => {
|
|
1559
|
+
if (url.includes('payment-success')) {
|
|
1560
|
+
const sig = new URL(url).searchParams.get('signature');
|
|
1561
|
+
if (sig) onSuccess(sig);
|
|
1562
|
+
}
|
|
1563
|
+
};
|
|
1564
|
+
|
|
1565
|
+
Linking.addEventListener('url', handleDeepLink);
|
|
1566
|
+
return () => Linking.removeAllListeners('url');
|
|
1567
|
+
}, [onSuccess]);
|
|
1568
|
+
|
|
1569
|
+
const startPayment = async (amount: number, merchantWallet: string) => {
|
|
1570
|
+
const orderId = \`order_\${Date.now()}\`;
|
|
1571
|
+
const url = \`\${SETTLR_URL}/checkout?amount=\${amount}&merchant=\${merchantWallet}\` +
|
|
1572
|
+
\`&success_url=\${APP_SCHEME}://payment-success?order=\${orderId}\` +
|
|
1573
|
+
\`&cancel_url=\${APP_SCHEME}://payment-cancel?order=\${orderId}\`;
|
|
1574
|
+
|
|
1575
|
+
await Linking.openURL(url);
|
|
1576
|
+
};
|
|
1577
|
+
|
|
1578
|
+
return { startPayment };
|
|
1579
|
+
}
|
|
1580
|
+
`;
|
|
1375
1581
|
export {
|
|
1376
1582
|
BuyButton,
|
|
1377
1583
|
CheckoutWidget,
|
|
@@ -1379,12 +1585,15 @@ export {
|
|
|
1379
1585
|
OneClickClient,
|
|
1380
1586
|
PaymentModal,
|
|
1381
1587
|
PrivacyFeatures,
|
|
1588
|
+
REACT_NATIVE_EXAMPLE,
|
|
1589
|
+
REST_API,
|
|
1382
1590
|
SETTLR_CHECKOUT_URL,
|
|
1383
1591
|
SETTLR_PROGRAM_ID,
|
|
1384
1592
|
SUPPORTED_NETWORKS,
|
|
1385
1593
|
SUPPORTED_TOKENS,
|
|
1386
1594
|
Settlr,
|
|
1387
1595
|
SettlrProvider,
|
|
1596
|
+
UNITY_EXAMPLE,
|
|
1388
1597
|
USDC_MINT_DEVNET,
|
|
1389
1598
|
USDC_MINT_MAINNET,
|
|
1390
1599
|
USDT_MINT_DEVNET,
|
|
@@ -1397,8 +1606,11 @@ export {
|
|
|
1397
1606
|
findAllowancePda,
|
|
1398
1607
|
findPrivateReceiptPda,
|
|
1399
1608
|
formatUSDC,
|
|
1609
|
+
generateCheckoutUrl,
|
|
1610
|
+
generateDeepLinkCheckout,
|
|
1400
1611
|
getTokenDecimals,
|
|
1401
1612
|
getTokenMint,
|
|
1613
|
+
parseCallbackUrl,
|
|
1402
1614
|
parseUSDC,
|
|
1403
1615
|
parseWebhookPayload,
|
|
1404
1616
|
shortenAddress,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@settlr/sdk",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
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",
|
|
@@ -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": {
|