@futurekode/stablepay-react 0.3.1 → 0.5.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.
- package/dist/index.d.mts +51 -4
- package/dist/index.d.ts +51 -4
- package/dist/index.js +258 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +261 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
|
|
4
|
-
type StablePaySuccessPayload = {
|
|
4
|
+
type StablePaySuccessPayload$1 = {
|
|
5
5
|
signature: string;
|
|
6
6
|
amount: number;
|
|
7
7
|
to: string;
|
|
@@ -11,7 +11,7 @@ type StablePayPayArgs = {
|
|
|
11
11
|
amount: number;
|
|
12
12
|
to: string;
|
|
13
13
|
reference?: string;
|
|
14
|
-
onSuccess?: (payload: StablePaySuccessPayload) => void;
|
|
14
|
+
onSuccess?: (payload: StablePaySuccessPayload$1) => void;
|
|
15
15
|
onError?: (error: Error) => void;
|
|
16
16
|
};
|
|
17
17
|
type StablePayProviderProps = {
|
|
@@ -27,7 +27,7 @@ type StablePayProps = {
|
|
|
27
27
|
onClick?: (event: React.MouseEvent) => void;
|
|
28
28
|
disabled?: boolean;
|
|
29
29
|
}>;
|
|
30
|
-
onSuccess?: (payload: StablePaySuccessPayload) => void;
|
|
30
|
+
onSuccess?: (payload: StablePaySuccessPayload$1) => void;
|
|
31
31
|
onError?: (error: Error) => void;
|
|
32
32
|
};
|
|
33
33
|
type UseStablePayResult = {
|
|
@@ -36,6 +36,25 @@ type UseStablePayResult = {
|
|
|
36
36
|
error: Error | null;
|
|
37
37
|
signature: string | null;
|
|
38
38
|
};
|
|
39
|
+
type VerifyPaymentInput = {
|
|
40
|
+
to: string;
|
|
41
|
+
amount: string;
|
|
42
|
+
txHash: string;
|
|
43
|
+
reference?: string;
|
|
44
|
+
};
|
|
45
|
+
type VerifyPaymentResult = {
|
|
46
|
+
ok: true;
|
|
47
|
+
status: "confirmed" | "pending";
|
|
48
|
+
txHash: string;
|
|
49
|
+
to: string;
|
|
50
|
+
amount: string;
|
|
51
|
+
reference?: string;
|
|
52
|
+
confirmations: number;
|
|
53
|
+
} | {
|
|
54
|
+
ok: false;
|
|
55
|
+
reason: "TX_FAILED" | "TO_MISMATCH" | "AMOUNT_TOO_LOW" | "REFERENCE_MISMATCH" | "INVALID_TRANSACTION";
|
|
56
|
+
txHash: string;
|
|
57
|
+
};
|
|
39
58
|
|
|
40
59
|
declare function StablePayProvider({ children, endpoint, to, }: StablePayProviderProps): react_jsx_runtime.JSX.Element;
|
|
41
60
|
|
|
@@ -51,4 +70,32 @@ declare function useStablePay(): {
|
|
|
51
70
|
signature: string | null;
|
|
52
71
|
};
|
|
53
72
|
|
|
54
|
-
|
|
73
|
+
type StablePaySuccessPayload = {
|
|
74
|
+
signature: string;
|
|
75
|
+
amount: number;
|
|
76
|
+
to: string;
|
|
77
|
+
reference?: string;
|
|
78
|
+
};
|
|
79
|
+
type PaymentVerificationStatus = "idle" | "verifying" | "pending" | "confirmed" | "failed";
|
|
80
|
+
type UsePaymentVerificationOptions = {
|
|
81
|
+
maxAttempts?: number;
|
|
82
|
+
intervalMs?: number;
|
|
83
|
+
};
|
|
84
|
+
type UsePaymentVerificationResult = {
|
|
85
|
+
status: PaymentVerificationStatus;
|
|
86
|
+
result: VerifyPaymentResult | null;
|
|
87
|
+
error: Error | null;
|
|
88
|
+
verify: (payload: StablePaySuccessPayload) => Promise<VerifyPaymentResult>;
|
|
89
|
+
reset: () => void;
|
|
90
|
+
};
|
|
91
|
+
declare function usePaymentVerification(options?: UsePaymentVerificationOptions): UsePaymentVerificationResult;
|
|
92
|
+
|
|
93
|
+
declare function verifyPayment(input: VerifyPaymentInput): Promise<VerifyPaymentResult>;
|
|
94
|
+
|
|
95
|
+
type WaitForPaymentConfirmationOptions = {
|
|
96
|
+
maxAttempts?: number;
|
|
97
|
+
intervalMs?: number;
|
|
98
|
+
};
|
|
99
|
+
declare function waitForPaymentConfirmation(input: VerifyPaymentInput, options?: WaitForPaymentConfirmationOptions): Promise<VerifyPaymentResult>;
|
|
100
|
+
|
|
101
|
+
export { StablePay, type StablePayPayArgs, type StablePayProps, StablePayProvider, type StablePayProviderProps, type StablePaySuccessPayload$1 as StablePaySuccessPayload, type UseStablePayResult, type VerifyPaymentInput, usePaymentVerification, useStablePay, verifyPayment, waitForPaymentConfirmation };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
|
|
4
|
-
type StablePaySuccessPayload = {
|
|
4
|
+
type StablePaySuccessPayload$1 = {
|
|
5
5
|
signature: string;
|
|
6
6
|
amount: number;
|
|
7
7
|
to: string;
|
|
@@ -11,7 +11,7 @@ type StablePayPayArgs = {
|
|
|
11
11
|
amount: number;
|
|
12
12
|
to: string;
|
|
13
13
|
reference?: string;
|
|
14
|
-
onSuccess?: (payload: StablePaySuccessPayload) => void;
|
|
14
|
+
onSuccess?: (payload: StablePaySuccessPayload$1) => void;
|
|
15
15
|
onError?: (error: Error) => void;
|
|
16
16
|
};
|
|
17
17
|
type StablePayProviderProps = {
|
|
@@ -27,7 +27,7 @@ type StablePayProps = {
|
|
|
27
27
|
onClick?: (event: React.MouseEvent) => void;
|
|
28
28
|
disabled?: boolean;
|
|
29
29
|
}>;
|
|
30
|
-
onSuccess?: (payload: StablePaySuccessPayload) => void;
|
|
30
|
+
onSuccess?: (payload: StablePaySuccessPayload$1) => void;
|
|
31
31
|
onError?: (error: Error) => void;
|
|
32
32
|
};
|
|
33
33
|
type UseStablePayResult = {
|
|
@@ -36,6 +36,25 @@ type UseStablePayResult = {
|
|
|
36
36
|
error: Error | null;
|
|
37
37
|
signature: string | null;
|
|
38
38
|
};
|
|
39
|
+
type VerifyPaymentInput = {
|
|
40
|
+
to: string;
|
|
41
|
+
amount: string;
|
|
42
|
+
txHash: string;
|
|
43
|
+
reference?: string;
|
|
44
|
+
};
|
|
45
|
+
type VerifyPaymentResult = {
|
|
46
|
+
ok: true;
|
|
47
|
+
status: "confirmed" | "pending";
|
|
48
|
+
txHash: string;
|
|
49
|
+
to: string;
|
|
50
|
+
amount: string;
|
|
51
|
+
reference?: string;
|
|
52
|
+
confirmations: number;
|
|
53
|
+
} | {
|
|
54
|
+
ok: false;
|
|
55
|
+
reason: "TX_FAILED" | "TO_MISMATCH" | "AMOUNT_TOO_LOW" | "REFERENCE_MISMATCH" | "INVALID_TRANSACTION";
|
|
56
|
+
txHash: string;
|
|
57
|
+
};
|
|
39
58
|
|
|
40
59
|
declare function StablePayProvider({ children, endpoint, to, }: StablePayProviderProps): react_jsx_runtime.JSX.Element;
|
|
41
60
|
|
|
@@ -51,4 +70,32 @@ declare function useStablePay(): {
|
|
|
51
70
|
signature: string | null;
|
|
52
71
|
};
|
|
53
72
|
|
|
54
|
-
|
|
73
|
+
type StablePaySuccessPayload = {
|
|
74
|
+
signature: string;
|
|
75
|
+
amount: number;
|
|
76
|
+
to: string;
|
|
77
|
+
reference?: string;
|
|
78
|
+
};
|
|
79
|
+
type PaymentVerificationStatus = "idle" | "verifying" | "pending" | "confirmed" | "failed";
|
|
80
|
+
type UsePaymentVerificationOptions = {
|
|
81
|
+
maxAttempts?: number;
|
|
82
|
+
intervalMs?: number;
|
|
83
|
+
};
|
|
84
|
+
type UsePaymentVerificationResult = {
|
|
85
|
+
status: PaymentVerificationStatus;
|
|
86
|
+
result: VerifyPaymentResult | null;
|
|
87
|
+
error: Error | null;
|
|
88
|
+
verify: (payload: StablePaySuccessPayload) => Promise<VerifyPaymentResult>;
|
|
89
|
+
reset: () => void;
|
|
90
|
+
};
|
|
91
|
+
declare function usePaymentVerification(options?: UsePaymentVerificationOptions): UsePaymentVerificationResult;
|
|
92
|
+
|
|
93
|
+
declare function verifyPayment(input: VerifyPaymentInput): Promise<VerifyPaymentResult>;
|
|
94
|
+
|
|
95
|
+
type WaitForPaymentConfirmationOptions = {
|
|
96
|
+
maxAttempts?: number;
|
|
97
|
+
intervalMs?: number;
|
|
98
|
+
};
|
|
99
|
+
declare function waitForPaymentConfirmation(input: VerifyPaymentInput, options?: WaitForPaymentConfirmationOptions): Promise<VerifyPaymentResult>;
|
|
100
|
+
|
|
101
|
+
export { StablePay, type StablePayPayArgs, type StablePayProps, StablePayProvider, type StablePayProviderProps, type StablePaySuccessPayload$1 as StablePaySuccessPayload, type UseStablePayResult, type VerifyPaymentInput, usePaymentVerification, useStablePay, verifyPayment, waitForPaymentConfirmation };
|
package/dist/index.js
CHANGED
|
@@ -32,7 +32,10 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
StablePay: () => StablePay,
|
|
34
34
|
StablePayProvider: () => StablePayProvider,
|
|
35
|
-
|
|
35
|
+
usePaymentVerification: () => usePaymentVerification,
|
|
36
|
+
useStablePay: () => useStablePay,
|
|
37
|
+
verifyPayment: () => verifyPayment,
|
|
38
|
+
waitForPaymentConfirmation: () => waitForPaymentConfirmation
|
|
36
39
|
});
|
|
37
40
|
module.exports = __toCommonJS(index_exports);
|
|
38
41
|
|
|
@@ -81,7 +84,7 @@ var import_web3 = require("@solana/web3.js");
|
|
|
81
84
|
var import_spl_token = require("@solana/spl-token");
|
|
82
85
|
|
|
83
86
|
// src/solana/constants.ts
|
|
84
|
-
var
|
|
87
|
+
var SOLANA_USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
|
85
88
|
var USDC_DECIMALS = 6;
|
|
86
89
|
|
|
87
90
|
// src/solana/amount.ts
|
|
@@ -94,20 +97,38 @@ function toTokenBaseUnits(amount) {
|
|
|
94
97
|
}
|
|
95
98
|
|
|
96
99
|
// src/solana/buildUsdcTransfer.ts
|
|
100
|
+
var MEMO_PROGRAM_ID = new import_web3.PublicKey(
|
|
101
|
+
"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"
|
|
102
|
+
);
|
|
97
103
|
async function buildUsdcTransfer({
|
|
98
104
|
connection,
|
|
99
105
|
fromWallet,
|
|
100
106
|
toWallet,
|
|
101
|
-
amount
|
|
107
|
+
amount,
|
|
108
|
+
reference
|
|
102
109
|
}) {
|
|
103
|
-
const mint = new import_web3.PublicKey(
|
|
110
|
+
const mint = new import_web3.PublicKey(SOLANA_USDC_MINT);
|
|
104
111
|
const fromAta = await (0, import_spl_token.getAssociatedTokenAddress)(mint, fromWallet);
|
|
105
112
|
const toAta = await (0, import_spl_token.getAssociatedTokenAddress)(mint, toWallet);
|
|
106
113
|
const tx = new import_web3.Transaction();
|
|
114
|
+
console.log("REFERENCE IN BUILD:", reference);
|
|
115
|
+
if (reference) {
|
|
116
|
+
const memoInstruction = new import_web3.TransactionInstruction({
|
|
117
|
+
keys: [],
|
|
118
|
+
programId: MEMO_PROGRAM_ID,
|
|
119
|
+
data: Buffer.from(reference)
|
|
120
|
+
});
|
|
121
|
+
tx.add(memoInstruction);
|
|
122
|
+
}
|
|
107
123
|
const toAtaInfo = await connection.getAccountInfo(toAta);
|
|
108
124
|
if (!toAtaInfo) {
|
|
109
125
|
tx.add(
|
|
110
|
-
(0, import_spl_token.createAssociatedTokenAccountInstruction)(
|
|
126
|
+
(0, import_spl_token.createAssociatedTokenAccountInstruction)(
|
|
127
|
+
fromWallet,
|
|
128
|
+
toAta,
|
|
129
|
+
toWallet,
|
|
130
|
+
mint
|
|
131
|
+
)
|
|
111
132
|
);
|
|
112
133
|
}
|
|
113
134
|
tx.add(
|
|
@@ -140,7 +161,7 @@ function useStablePay() {
|
|
|
140
161
|
null
|
|
141
162
|
);
|
|
142
163
|
const executePayment = (0, import_react3.useCallback)(
|
|
143
|
-
async ({ amount, to }) => {
|
|
164
|
+
async ({ amount, to, reference }) => {
|
|
144
165
|
if (!publicKey) {
|
|
145
166
|
throw new Error("Wallet not connected");
|
|
146
167
|
}
|
|
@@ -154,7 +175,8 @@ function useStablePay() {
|
|
|
154
175
|
connection,
|
|
155
176
|
fromWallet: publicKey,
|
|
156
177
|
toWallet: recipient,
|
|
157
|
-
amount
|
|
178
|
+
amount,
|
|
179
|
+
reference
|
|
158
180
|
});
|
|
159
181
|
const sig = await sendTransaction(transaction, connection);
|
|
160
182
|
await connection.confirmTransaction(sig, "confirmed");
|
|
@@ -174,7 +196,7 @@ function useStablePay() {
|
|
|
174
196
|
return;
|
|
175
197
|
}
|
|
176
198
|
try {
|
|
177
|
-
const sig = await executePayment({ amount, to });
|
|
199
|
+
const sig = await executePayment({ amount, to, reference });
|
|
178
200
|
onSuccess?.({
|
|
179
201
|
signature: sig,
|
|
180
202
|
amount,
|
|
@@ -278,10 +300,237 @@ function StablePay({
|
|
|
278
300
|
disabled: Boolean(children.props.disabled) || loading
|
|
279
301
|
});
|
|
280
302
|
}
|
|
303
|
+
|
|
304
|
+
// src/hooks/usePaymentVerification.ts
|
|
305
|
+
var import_react5 = require("react");
|
|
306
|
+
|
|
307
|
+
// src/parseUsdcPaymentFromTransaction.ts
|
|
308
|
+
var import_web33 = require("@solana/web3.js");
|
|
309
|
+
function isParsedInstruction(ix) {
|
|
310
|
+
return "parsed" in ix;
|
|
311
|
+
}
|
|
312
|
+
async function parseUsdcPaymentFromTransaction(txHash) {
|
|
313
|
+
const connection = new import_web33.Connection(DEFAULT_RPC, "confirmed");
|
|
314
|
+
const tx = await connection.getParsedTransaction(txHash, {
|
|
315
|
+
maxSupportedTransactionVersion: 0,
|
|
316
|
+
commitment: "confirmed"
|
|
317
|
+
});
|
|
318
|
+
if (!tx || !tx.meta) return null;
|
|
319
|
+
if (tx.meta.err) {
|
|
320
|
+
return {
|
|
321
|
+
txHash,
|
|
322
|
+
status: "failed",
|
|
323
|
+
to: "",
|
|
324
|
+
amount: "0",
|
|
325
|
+
confirmations: 0
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
const allInstructions = [
|
|
329
|
+
...tx.transaction.message.instructions,
|
|
330
|
+
...tx.meta.innerInstructions?.flatMap((group) => group.instructions) ?? []
|
|
331
|
+
];
|
|
332
|
+
let amount = null;
|
|
333
|
+
let reference;
|
|
334
|
+
let destinationTokenAccount = null;
|
|
335
|
+
for (const ix of allInstructions) {
|
|
336
|
+
if (!isParsedInstruction(ix)) continue;
|
|
337
|
+
if (ix.program === "spl-token") {
|
|
338
|
+
const parsedType = ix.parsed?.type;
|
|
339
|
+
const info = ix.parsed?.info;
|
|
340
|
+
if ((parsedType === "transfer" || parsedType === "transferChecked") && info) {
|
|
341
|
+
const mint = info.mint;
|
|
342
|
+
const rawAmount = info.tokenAmount?.amount ?? info.amount;
|
|
343
|
+
if (mint === SOLANA_USDC_MINT && rawAmount) {
|
|
344
|
+
destinationTokenAccount = info.destination;
|
|
345
|
+
amount = (Number(rawAmount) / 1e6).toString();
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
if (ix.program === "spl-memo") {
|
|
350
|
+
if (typeof ix.parsed === "string") {
|
|
351
|
+
reference = ix.parsed;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
if (!destinationTokenAccount || !amount) {
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
const currentSlot = await connection.getSlot("confirmed");
|
|
359
|
+
const confirmations = Math.max(0, currentSlot - tx.slot);
|
|
360
|
+
console.log("parsed tx", tx);
|
|
361
|
+
console.log("allInstructions", allInstructions);
|
|
362
|
+
console.log("destinationTokenAccount", destinationTokenAccount);
|
|
363
|
+
console.log("amount", amount);
|
|
364
|
+
console.log("reference", reference);
|
|
365
|
+
return {
|
|
366
|
+
txHash,
|
|
367
|
+
status: confirmations > 0 ? "confirmed" : "pending",
|
|
368
|
+
to: destinationTokenAccount,
|
|
369
|
+
amount,
|
|
370
|
+
reference,
|
|
371
|
+
confirmations
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
// src/utils.ts
|
|
376
|
+
var import_web34 = require("@solana/web3.js");
|
|
377
|
+
var import_spl_token2 = require("@solana/spl-token");
|
|
378
|
+
function toAtomicUnits(amount) {
|
|
379
|
+
const [whole, fraction = ""] = amount.split(".");
|
|
380
|
+
const paddedFraction = (fraction + "000000").slice(0, 6);
|
|
381
|
+
return BigInt(whole) * 1000000n + BigInt(paddedFraction);
|
|
382
|
+
}
|
|
383
|
+
function amountGte(actual, expected) {
|
|
384
|
+
return toAtomicUnits(actual) >= toAtomicUnits(expected);
|
|
385
|
+
}
|
|
386
|
+
function sameAddress(a, b) {
|
|
387
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
388
|
+
}
|
|
389
|
+
function getUsdcTokenAccountForWallet(walletAddress) {
|
|
390
|
+
const wallet = new import_web34.PublicKey(walletAddress);
|
|
391
|
+
const mint = new import_web34.PublicKey(SOLANA_USDC_MINT);
|
|
392
|
+
return (0, import_spl_token2.getAssociatedTokenAddressSync)(mint, wallet, true).toBase58();
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// src/verifyPayment.ts
|
|
396
|
+
async function verifyPayment(input) {
|
|
397
|
+
const parsed = await parseUsdcPaymentFromTransaction(input.txHash);
|
|
398
|
+
if (!parsed) {
|
|
399
|
+
return {
|
|
400
|
+
ok: false,
|
|
401
|
+
reason: "INVALID_TRANSACTION",
|
|
402
|
+
txHash: input.txHash
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
if (parsed.status === "failed") {
|
|
406
|
+
return {
|
|
407
|
+
ok: false,
|
|
408
|
+
reason: "TX_FAILED",
|
|
409
|
+
txHash: input.txHash
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
const expectedTokenAccount = getUsdcTokenAccountForWallet(input.to);
|
|
413
|
+
if (!sameAddress(parsed.to, expectedTokenAccount)) {
|
|
414
|
+
return {
|
|
415
|
+
ok: false,
|
|
416
|
+
reason: "TO_MISMATCH",
|
|
417
|
+
txHash: input.txHash
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
if (!amountGte(parsed.amount, input.amount)) {
|
|
421
|
+
return {
|
|
422
|
+
ok: false,
|
|
423
|
+
reason: "AMOUNT_TOO_LOW",
|
|
424
|
+
txHash: input.txHash
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
if (input.reference && parsed.reference !== input.reference) {
|
|
428
|
+
return {
|
|
429
|
+
ok: false,
|
|
430
|
+
reason: "REFERENCE_MISMATCH",
|
|
431
|
+
txHash: input.txHash
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
return {
|
|
435
|
+
ok: true,
|
|
436
|
+
status: parsed.status === "pending" ? "pending" : "confirmed",
|
|
437
|
+
txHash: parsed.txHash,
|
|
438
|
+
to: input.to,
|
|
439
|
+
amount: parsed.amount,
|
|
440
|
+
reference: parsed.reference,
|
|
441
|
+
confirmations: parsed.confirmations
|
|
442
|
+
};
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// src/waitForPaymentConfirmation.ts
|
|
446
|
+
function sleep(ms) {
|
|
447
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
448
|
+
}
|
|
449
|
+
async function waitForPaymentConfirmation(input, options = {}) {
|
|
450
|
+
const maxAttempts = options.maxAttempts ?? 10;
|
|
451
|
+
const intervalMs = options.intervalMs ?? 1500;
|
|
452
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
453
|
+
const result = await verifyPayment(input);
|
|
454
|
+
if (result.ok && result.status === "confirmed") {
|
|
455
|
+
return result;
|
|
456
|
+
}
|
|
457
|
+
if (result.ok && result.status === "pending") {
|
|
458
|
+
await sleep(intervalMs);
|
|
459
|
+
continue;
|
|
460
|
+
}
|
|
461
|
+
if (!result.ok && result.reason === "INVALID_TRANSACTION") {
|
|
462
|
+
await sleep(intervalMs);
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
return result;
|
|
466
|
+
}
|
|
467
|
+
return {
|
|
468
|
+
ok: false,
|
|
469
|
+
reason: "INVALID_TRANSACTION",
|
|
470
|
+
txHash: input.txHash
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// src/hooks/usePaymentVerification.ts
|
|
475
|
+
function usePaymentVerification(options = {}) {
|
|
476
|
+
const [status, setStatus] = (0, import_react5.useState)("idle");
|
|
477
|
+
const [result, setResult] = (0, import_react5.useState)(null);
|
|
478
|
+
const [error, setError] = (0, import_react5.useState)(null);
|
|
479
|
+
const reset = (0, import_react5.useCallback)(() => {
|
|
480
|
+
setStatus("idle");
|
|
481
|
+
setResult(null);
|
|
482
|
+
setError(null);
|
|
483
|
+
}, []);
|
|
484
|
+
const verify = (0, import_react5.useCallback)(
|
|
485
|
+
async (payload) => {
|
|
486
|
+
setStatus("verifying");
|
|
487
|
+
setError(null);
|
|
488
|
+
try {
|
|
489
|
+
const verificationResult = await waitForPaymentConfirmation(
|
|
490
|
+
{
|
|
491
|
+
to: payload.to,
|
|
492
|
+
amount: String(payload.amount),
|
|
493
|
+
txHash: payload.signature,
|
|
494
|
+
reference: payload.reference
|
|
495
|
+
},
|
|
496
|
+
{
|
|
497
|
+
maxAttempts: options.maxAttempts,
|
|
498
|
+
intervalMs: options.intervalMs
|
|
499
|
+
}
|
|
500
|
+
);
|
|
501
|
+
setResult(verificationResult);
|
|
502
|
+
if (verificationResult.ok) {
|
|
503
|
+
setStatus(
|
|
504
|
+
verificationResult.status === "confirmed" ? "confirmed" : "pending"
|
|
505
|
+
);
|
|
506
|
+
} else {
|
|
507
|
+
setStatus("failed");
|
|
508
|
+
}
|
|
509
|
+
return verificationResult;
|
|
510
|
+
} catch (err) {
|
|
511
|
+
const nextError = err instanceof Error ? err : new Error("Payment verification failed");
|
|
512
|
+
setError(nextError);
|
|
513
|
+
setStatus("failed");
|
|
514
|
+
throw nextError;
|
|
515
|
+
}
|
|
516
|
+
},
|
|
517
|
+
[options.maxAttempts, options.intervalMs]
|
|
518
|
+
);
|
|
519
|
+
return {
|
|
520
|
+
status,
|
|
521
|
+
result,
|
|
522
|
+
error,
|
|
523
|
+
verify,
|
|
524
|
+
reset
|
|
525
|
+
};
|
|
526
|
+
}
|
|
281
527
|
// Annotate the CommonJS export names for ESM import in node:
|
|
282
528
|
0 && (module.exports = {
|
|
283
529
|
StablePay,
|
|
284
530
|
StablePayProvider,
|
|
285
|
-
|
|
531
|
+
usePaymentVerification,
|
|
532
|
+
useStablePay,
|
|
533
|
+
verifyPayment,
|
|
534
|
+
waitForPaymentConfirmation
|
|
286
535
|
});
|
|
287
536
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/provider/StablePayProvider.tsx","../src/context/StablePayContext.ts","../src/components/StablePay.tsx","../src/hooks/useStablePay.ts","../src/solana/buildUsdcTransfer.ts","../src/solana/constants.ts","../src/solana/amount.ts"],"sourcesContent":["export { StablePayProvider } from \"./provider/StablePayProvider\";\nexport { StablePay } from \"./components/StablePay\";\nexport { useStablePay } from \"./hooks/useStablePay\";\nexport type {\n StablePayProps,\n StablePayProviderProps,\n StablePaySuccessPayload,\n StablePayPayArgs,\n UseStablePayResult,\n} from \"./types\";\n","import React, { useMemo } from \"react\";\nimport {\n ConnectionProvider,\n WalletProvider,\n} from \"@solana/wallet-adapter-react\";\nimport { WalletModalProvider } from \"@solana/wallet-adapter-react-ui\";\nimport {\n PhantomWalletAdapter,\n SolflareWalletAdapter,\n} from \"@solana/wallet-adapter-wallets\";\nimport type { StablePayProviderProps } from \"../types\";\nimport StablePayContext from \"../context/StablePayContext\";\n\nimport \"@solana/wallet-adapter-react-ui/styles.css\";\n\nconst DEFAULT_RPC =\n \"https://mainnet.helius-rpc.com/?api-key=a90079ee-e2b5-438e-9b1a-2ae7ba8c1417\";\n\nexport function StablePayProvider({\n children,\n endpoint,\n to,\n}: StablePayProviderProps) {\n const resolvedEndpoint = endpoint ?? DEFAULT_RPC;\n\n const wallets = useMemo(\n () => [new PhantomWalletAdapter(), new SolflareWalletAdapter()],\n [],\n );\n\n return (\n <StablePayContext.Provider value={{ defaultTo: to }}>\n <ConnectionProvider endpoint={resolvedEndpoint}>\n <WalletProvider wallets={wallets} autoConnect>\n <WalletModalProvider>{children}</WalletModalProvider>\n </WalletProvider>\n </ConnectionProvider>\n </StablePayContext.Provider>\n );\n}\n","import { createContext, useContext } from \"react\";\n\ntype StablePayContextValue = {\n defaultTo?: string;\n};\n\nconst StablePayContext = createContext<StablePayContextValue>({});\n\nexport function useStablePayContext() {\n return useContext(StablePayContext);\n}\n\nexport default StablePayContext;\n","import React from \"react\";\nimport { useStablePay } from \"../hooks/useStablePay\";\nimport { useStablePayContext } from \"../context/StablePayContext\";\nimport type { StablePayProps } from \"../types\";\n\ntype ClickableChildProps = {\n onClick?: (event: React.MouseEvent) => void;\n disabled?: boolean;\n};\n\nfunction getResolvedTo(to?: string, defaultTo?: string): string {\n const resolved = to ?? defaultTo;\n\n if (!resolved) {\n throw new Error(\n \"StablePay: missing recipient address. Provide `to` on StablePay or StablePayProvider.\",\n );\n }\n\n return resolved;\n}\n\nexport function StablePay({\n amount,\n to,\n reference,\n children,\n onSuccess,\n onError,\n}: StablePayProps) {\n const { pay, loading } = useStablePay();\n const { defaultTo } = useStablePayContext();\n\n const resolvedTo = getResolvedTo(to, defaultTo);\n\n if (!resolvedTo) {\n throw new Error(\n \"StablePay: missing recipient address. Provide `to` on StablePay or StablePayProvider.\",\n );\n }\n\n if (!React.isValidElement<ClickableChildProps>(children)) {\n throw new Error(\"StablePay expects a single React element child.\");\n }\n\n async function handleClick(event: React.MouseEvent) {\n try {\n children.props.onClick?.(event);\n\n if (event.defaultPrevented) return;\n\n await pay({\n amount,\n to: resolvedTo,\n reference,\n onSuccess,\n onError,\n });\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error(\"Payment failed\"));\n }\n }\n\n return React.cloneElement(children, {\n onClick: handleClick,\n disabled: Boolean(children.props.disabled) || loading,\n });\n}\n","import { useCallback, useEffect, useState } from \"react\";\nimport { PublicKey } from \"@solana/web3.js\";\nimport { useConnection, useWallet } from \"@solana/wallet-adapter-react\";\nimport { useWalletModal } from \"@solana/wallet-adapter-react-ui\";\nimport { buildUsdcTransfer } from \"../solana/buildUsdcTransfer\";\nimport { StablePayPayArgs } from \"../types\";\n\ntype PendingPayment = StablePayPayArgs;\n\nexport function useStablePay() {\n const { connection } = useConnection();\n const { connected, publicKey, sendTransaction } = useWallet();\n const { setVisible } = useWalletModal();\n\n const [loading, setLoading] = useState(false);\n const [signature, setSignature] = useState<string | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const [pendingPayment, setPendingPayment] = useState<PendingPayment | null>(\n null,\n );\n\n const executePayment = useCallback(\n async ({ amount, to }: StablePayPayArgs) => {\n if (!publicKey) {\n throw new Error(\"Wallet not connected\");\n }\n\n let recipient: PublicKey;\n\n try {\n recipient = new PublicKey(to);\n } catch {\n throw new Error(\"Invalid recipient wallet address\");\n }\n\n const transaction = await buildUsdcTransfer({\n connection,\n fromWallet: publicKey,\n toWallet: recipient,\n amount,\n });\n\n const sig = await sendTransaction(transaction, connection);\n await connection.confirmTransaction(sig, \"confirmed\");\n\n setSignature(sig);\n return sig;\n },\n [publicKey, connection, sendTransaction],\n );\n\n const pay = useCallback(\n async ({ amount, to, reference, onSuccess, onError }: StablePayPayArgs) => {\n setLoading(true);\n setSignature(null);\n setError(null);\n\n // Not connected → store intent + callbacks\n if (!connected || !publicKey) {\n setPendingPayment({ amount, to, reference, onSuccess, onError });\n setVisible(true);\n return;\n }\n\n try {\n const sig = await executePayment({ amount, to });\n onSuccess?.({\n signature: sig,\n amount,\n to,\n reference,\n });\n } catch (err) {\n const normalized =\n err instanceof Error ? err : new Error(\"Payment failed\");\n setError(normalized);\n onError?.(normalized);\n } finally {\n setLoading(false);\n }\n },\n [connected, publicKey, executePayment, setVisible],\n );\n\n // Resume after wallet connects\n useEffect(() => {\n if (!connected || !publicKey || !pendingPayment) return;\n\n const payment = pendingPayment;\n\n let cancelled = false;\n\n async function resumePayment() {\n try {\n const sig = await executePayment(payment);\n\n if (!cancelled) {\n payment.onSuccess?.({\n signature: sig,\n amount: payment.amount,\n to: payment.to,\n reference: payment.reference,\n });\n setSignature(sig);\n setPendingPayment(null);\n }\n } catch (err) {\n if (!cancelled) {\n const normalized =\n err instanceof Error ? err : new Error(\"Payment failed\");\n setError(normalized);\n payment.onError?.(normalized);\n setPendingPayment(null);\n }\n } finally {\n if (!cancelled) {\n setLoading(false);\n }\n }\n }\n\n resumePayment();\n\n return () => {\n cancelled = true;\n };\n }, [connected, publicKey, pendingPayment, executePayment]);\n\n return { pay, loading, error, signature };\n}\n","import { Connection, PublicKey, Transaction } from \"@solana/web3.js\";\nimport {\n TOKEN_PROGRAM_ID,\n createAssociatedTokenAccountInstruction,\n createTransferCheckedInstruction,\n getAssociatedTokenAddress,\n} from \"@solana/spl-token\";\nimport { toTokenBaseUnits } from \"./amount\";\nimport { USDC_DECIMALS, USDC_MINT } from \"./constants\";\n\ntype BuildUsdcTransferParams = {\n connection: Connection;\n fromWallet: PublicKey;\n toWallet: PublicKey;\n amount: number;\n};\n\nexport async function buildUsdcTransfer({\n connection,\n fromWallet,\n toWallet,\n amount,\n}: BuildUsdcTransferParams) {\n const mint = new PublicKey(USDC_MINT);\n const fromAta = await getAssociatedTokenAddress(mint, fromWallet);\n const toAta = await getAssociatedTokenAddress(mint, toWallet);\n\n const tx = new Transaction();\n const toAtaInfo = await connection.getAccountInfo(toAta);\n\n if (!toAtaInfo) {\n tx.add(\n createAssociatedTokenAccountInstruction(fromWallet, toAta, toWallet, mint)\n );\n }\n\n tx.add(\n createTransferCheckedInstruction(\n fromAta,\n mint,\n toAta,\n fromWallet,\n Number(toTokenBaseUnits(amount)),\n USDC_DECIMALS,\n [],\n TOKEN_PROGRAM_ID\n )\n );\n\n const latestBlockhash = await connection.getLatestBlockhash();\n tx.feePayer = fromWallet;\n tx.recentBlockhash = latestBlockhash.blockhash;\n\n return tx;\n}\n","export const USDC_MINT = \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\";\nexport const USDC_DECIMALS = 6;\n","import { USDC_DECIMALS } from \"./constants\";\n\nexport function toTokenBaseUnits(amount: number): bigint {\n if (!Number.isFinite(amount) || amount <= 0) {\n throw new Error(\"Amount must be a positive number\");\n }\n\n const multiplier = 10 ** USDC_DECIMALS;\n return BigInt(Math.round(amount * multiplier));\n}\n"],"mappings":"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","names":["import_react","import_react","import_react","import_web3","import_wallet_adapter_react","import_wallet_adapter_react_ui","React"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/provider/StablePayProvider.tsx","../src/context/StablePayContext.ts","../src/components/StablePay.tsx","../src/hooks/useStablePay.ts","../src/solana/buildUsdcTransfer.ts","../src/solana/constants.ts","../src/solana/amount.ts","../src/hooks/usePaymentVerification.ts","../src/parseUsdcPaymentFromTransaction.ts","../src/utils.ts","../src/verifyPayment.ts","../src/waitForPaymentConfirmation.ts"],"sourcesContent":["export { StablePayProvider } from \"./provider/StablePayProvider\";\nexport { StablePay } from \"./components/StablePay\";\nexport { useStablePay } from \"./hooks/useStablePay\";\nexport { usePaymentVerification } from \"./hooks/usePaymentVerification\";\nexport { verifyPayment } from \"./verifyPayment\";\nexport { waitForPaymentConfirmation } from \"./waitForPaymentConfirmation\";\nexport type {\n StablePayProps,\n StablePayProviderProps,\n StablePaySuccessPayload,\n StablePayPayArgs,\n UseStablePayResult,\n VerifyPaymentInput,\n} from \"./types\";\n","import React, { useMemo } from \"react\";\nimport {\n ConnectionProvider,\n WalletProvider,\n} from \"@solana/wallet-adapter-react\";\nimport { WalletModalProvider } from \"@solana/wallet-adapter-react-ui\";\nimport {\n PhantomWalletAdapter,\n SolflareWalletAdapter,\n} from \"@solana/wallet-adapter-wallets\";\nimport type { StablePayProviderProps } from \"../types\";\nimport StablePayContext from \"../context/StablePayContext\";\n\nimport \"@solana/wallet-adapter-react-ui/styles.css\";\n\nexport const DEFAULT_RPC =\n \"https://mainnet.helius-rpc.com/?api-key=a90079ee-e2b5-438e-9b1a-2ae7ba8c1417\";\n\nexport function StablePayProvider({\n children,\n endpoint,\n to,\n}: StablePayProviderProps) {\n const resolvedEndpoint = endpoint ?? DEFAULT_RPC;\n\n const wallets = useMemo(\n () => [new PhantomWalletAdapter(), new SolflareWalletAdapter()],\n [],\n );\n\n return (\n <StablePayContext.Provider value={{ defaultTo: to }}>\n <ConnectionProvider endpoint={resolvedEndpoint}>\n <WalletProvider wallets={wallets} autoConnect>\n <WalletModalProvider>{children}</WalletModalProvider>\n </WalletProvider>\n </ConnectionProvider>\n </StablePayContext.Provider>\n );\n}\n","import { createContext, useContext } from \"react\";\n\ntype StablePayContextValue = {\n defaultTo?: string;\n};\n\nconst StablePayContext = createContext<StablePayContextValue>({});\n\nexport function useStablePayContext() {\n return useContext(StablePayContext);\n}\n\nexport default StablePayContext;\n","import React from \"react\";\nimport { useStablePay } from \"../hooks/useStablePay\";\nimport { useStablePayContext } from \"../context/StablePayContext\";\nimport type { StablePayProps } from \"../types\";\n\ntype ClickableChildProps = {\n onClick?: (event: React.MouseEvent) => void;\n disabled?: boolean;\n};\n\nfunction getResolvedTo(to?: string, defaultTo?: string): string {\n const resolved = to ?? defaultTo;\n\n if (!resolved) {\n throw new Error(\n \"StablePay: missing recipient address. Provide `to` on StablePay or StablePayProvider.\",\n );\n }\n\n return resolved;\n}\n\nexport function StablePay({\n amount,\n to,\n reference,\n children,\n onSuccess,\n onError,\n}: StablePayProps) {\n const { pay, loading } = useStablePay();\n const { defaultTo } = useStablePayContext();\n\n const resolvedTo = getResolvedTo(to, defaultTo);\n\n if (!resolvedTo) {\n throw new Error(\n \"StablePay: missing recipient address. Provide `to` on StablePay or StablePayProvider.\",\n );\n }\n\n if (!React.isValidElement<ClickableChildProps>(children)) {\n throw new Error(\"StablePay expects a single React element child.\");\n }\n\n async function handleClick(event: React.MouseEvent) {\n try {\n children.props.onClick?.(event);\n\n if (event.defaultPrevented) return;\n\n await pay({\n amount,\n to: resolvedTo,\n reference,\n onSuccess,\n onError,\n });\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error(\"Payment failed\"));\n }\n }\n\n return React.cloneElement(children, {\n onClick: handleClick,\n disabled: Boolean(children.props.disabled) || loading,\n });\n}\n","import { useCallback, useEffect, useState } from \"react\";\nimport { PublicKey } from \"@solana/web3.js\";\nimport { useConnection, useWallet } from \"@solana/wallet-adapter-react\";\nimport { useWalletModal } from \"@solana/wallet-adapter-react-ui\";\nimport { buildUsdcTransfer } from \"../solana/buildUsdcTransfer\";\nimport { StablePayPayArgs } from \"../types\";\n\ntype PendingPayment = StablePayPayArgs;\n\nexport function useStablePay() {\n const { connection } = useConnection();\n const { connected, publicKey, sendTransaction } = useWallet();\n const { setVisible } = useWalletModal();\n\n const [loading, setLoading] = useState(false);\n const [signature, setSignature] = useState<string | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const [pendingPayment, setPendingPayment] = useState<PendingPayment | null>(\n null,\n );\n\n const executePayment = useCallback(\n async ({ amount, to, reference }: StablePayPayArgs) => {\n if (!publicKey) {\n throw new Error(\"Wallet not connected\");\n }\n\n let recipient: PublicKey;\n\n try {\n recipient = new PublicKey(to);\n } catch {\n throw new Error(\"Invalid recipient wallet address\");\n }\n\n const transaction = await buildUsdcTransfer({\n connection,\n fromWallet: publicKey,\n toWallet: recipient,\n amount,\n reference,\n });\n\n const sig = await sendTransaction(transaction, connection);\n await connection.confirmTransaction(sig, \"confirmed\");\n\n setSignature(sig);\n return sig;\n },\n [publicKey, connection, sendTransaction],\n );\n\n const pay = useCallback(\n async ({ amount, to, reference, onSuccess, onError }: StablePayPayArgs) => {\n setLoading(true);\n setSignature(null);\n setError(null);\n\n // Not connected → store intent + callbacks\n if (!connected || !publicKey) {\n setPendingPayment({ amount, to, reference, onSuccess, onError });\n setVisible(true);\n return;\n }\n\n try {\n const sig = await executePayment({ amount, to, reference });\n onSuccess?.({\n signature: sig,\n amount,\n to,\n reference,\n });\n } catch (err) {\n const normalized =\n err instanceof Error ? err : new Error(\"Payment failed\");\n setError(normalized);\n onError?.(normalized);\n } finally {\n setLoading(false);\n }\n },\n [connected, publicKey, executePayment, setVisible],\n );\n\n // Resume after wallet connects\n useEffect(() => {\n if (!connected || !publicKey || !pendingPayment) return;\n\n const payment = pendingPayment;\n\n let cancelled = false;\n\n async function resumePayment() {\n try {\n const sig = await executePayment(payment);\n\n if (!cancelled) {\n payment.onSuccess?.({\n signature: sig,\n amount: payment.amount,\n to: payment.to,\n reference: payment.reference,\n });\n setSignature(sig);\n setPendingPayment(null);\n }\n } catch (err) {\n if (!cancelled) {\n const normalized =\n err instanceof Error ? err : new Error(\"Payment failed\");\n setError(normalized);\n payment.onError?.(normalized);\n setPendingPayment(null);\n }\n } finally {\n if (!cancelled) {\n setLoading(false);\n }\n }\n }\n\n resumePayment();\n\n return () => {\n cancelled = true;\n };\n }, [connected, publicKey, pendingPayment, executePayment]);\n\n return { pay, loading, error, signature };\n}\n","import {\n Connection,\n PublicKey,\n Transaction,\n TransactionInstruction,\n} from \"@solana/web3.js\";\nimport {\n TOKEN_PROGRAM_ID,\n createAssociatedTokenAccountInstruction,\n createTransferCheckedInstruction,\n getAssociatedTokenAddress,\n} from \"@solana/spl-token\";\nimport { toTokenBaseUnits } from \"./amount\";\nimport { USDC_DECIMALS, SOLANA_USDC_MINT } from \"./constants\";\n\nconst MEMO_PROGRAM_ID = new PublicKey(\n \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\",\n);\n\ntype BuildUsdcTransferParams = {\n connection: Connection;\n fromWallet: PublicKey;\n toWallet: PublicKey;\n amount: number;\n reference?: string;\n};\n\nexport async function buildUsdcTransfer({\n connection,\n fromWallet,\n toWallet,\n amount,\n reference,\n}: BuildUsdcTransferParams) {\n const mint = new PublicKey(SOLANA_USDC_MINT);\n const fromAta = await getAssociatedTokenAddress(mint, fromWallet);\n const toAta = await getAssociatedTokenAddress(mint, toWallet);\n\n const tx = new Transaction();\n\n console.log(\"REFERENCE IN BUILD:\", reference);\n\n if (reference) {\n const memoInstruction = new TransactionInstruction({\n keys: [],\n programId: MEMO_PROGRAM_ID,\n data: Buffer.from(reference),\n });\n\n tx.add(memoInstruction);\n }\n\n const toAtaInfo = await connection.getAccountInfo(toAta);\n\n if (!toAtaInfo) {\n tx.add(\n createAssociatedTokenAccountInstruction(\n fromWallet,\n toAta,\n toWallet,\n mint,\n ),\n );\n }\n\n tx.add(\n createTransferCheckedInstruction(\n fromAta,\n mint,\n toAta,\n fromWallet,\n Number(toTokenBaseUnits(amount)),\n USDC_DECIMALS,\n [],\n TOKEN_PROGRAM_ID,\n ),\n );\n\n const latestBlockhash = await connection.getLatestBlockhash();\n tx.feePayer = fromWallet;\n tx.recentBlockhash = latestBlockhash.blockhash;\n\n return tx;\n}\n","export const SOLANA_USDC_MINT = \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\";\nexport const USDC_DECIMALS = 6;\n","import { USDC_DECIMALS } from \"./constants\";\n\nexport function toTokenBaseUnits(amount: number): bigint {\n if (!Number.isFinite(amount) || amount <= 0) {\n throw new Error(\"Amount must be a positive number\");\n }\n\n const multiplier = 10 ** USDC_DECIMALS;\n return BigInt(Math.round(amount * multiplier));\n}\n","import { useCallback, useState } from \"react\";\nimport { VerifyPaymentResult } from \"../types\";\nimport { waitForPaymentConfirmation } from \"../waitForPaymentConfirmation\";\n\nexport type StablePaySuccessPayload = {\n signature: string;\n amount: number;\n to: string;\n reference?: string;\n};\n\nexport type PaymentVerificationStatus =\n | \"idle\"\n | \"verifying\"\n | \"pending\"\n | \"confirmed\"\n | \"failed\";\n\nexport type UsePaymentVerificationOptions = {\n maxAttempts?: number;\n intervalMs?: number;\n};\n\nexport type UsePaymentVerificationResult = {\n status: PaymentVerificationStatus;\n result: VerifyPaymentResult | null;\n error: Error | null;\n verify: (payload: StablePaySuccessPayload) => Promise<VerifyPaymentResult>;\n reset: () => void;\n};\n\nexport function usePaymentVerification(\n options: UsePaymentVerificationOptions = {},\n): UsePaymentVerificationResult {\n const [status, setStatus] = useState<PaymentVerificationStatus>(\"idle\");\n const [result, setResult] = useState<VerifyPaymentResult | null>(null);\n const [error, setError] = useState<Error | null>(null);\n\n const reset = useCallback(() => {\n setStatus(\"idle\");\n setResult(null);\n setError(null);\n }, []);\n\n const verify = useCallback(\n async (payload: StablePaySuccessPayload) => {\n setStatus(\"verifying\");\n setError(null);\n\n try {\n const verificationResult = await waitForPaymentConfirmation(\n {\n to: payload.to,\n amount: String(payload.amount),\n txHash: payload.signature,\n reference: payload.reference,\n },\n {\n maxAttempts: options.maxAttempts,\n intervalMs: options.intervalMs,\n },\n );\n\n setResult(verificationResult);\n\n if (verificationResult.ok) {\n setStatus(\n verificationResult.status === \"confirmed\" ? \"confirmed\" : \"pending\",\n );\n } else {\n setStatus(\"failed\");\n }\n\n return verificationResult;\n } catch (err) {\n const nextError =\n err instanceof Error ? err : new Error(\"Payment verification failed\");\n\n setError(nextError);\n setStatus(\"failed\");\n throw nextError;\n }\n },\n [options.maxAttempts, options.intervalMs],\n );\n\n return {\n status,\n result,\n error,\n verify,\n reset,\n };\n}\n","import {\n Connection,\n ParsedInstruction,\n PartiallyDecodedInstruction,\n PublicKey,\n} from \"@solana/web3.js\";\nimport { ParsedPayment } from \"./types\";\nimport { DEFAULT_RPC } from \"./provider/StablePayProvider\";\nimport { SOLANA_USDC_MINT } from \"./solana/constants\";\n\nfunction isParsedInstruction(\n ix: ParsedInstruction | PartiallyDecodedInstruction,\n): ix is ParsedInstruction {\n return \"parsed\" in ix;\n}\n\nexport async function parseUsdcPaymentFromTransaction(\n txHash: string,\n): Promise<ParsedPayment | null> {\n const connection = new Connection(DEFAULT_RPC, \"confirmed\");\n\n const tx = await connection.getParsedTransaction(txHash, {\n maxSupportedTransactionVersion: 0,\n commitment: \"confirmed\",\n });\n\n if (!tx || !tx.meta) return null;\n\n if (tx.meta.err) {\n return {\n txHash,\n status: \"failed\",\n to: \"\",\n amount: \"0\",\n confirmations: 0,\n };\n }\n\n const allInstructions = [\n ...tx.transaction.message.instructions,\n ...(tx.meta.innerInstructions?.flatMap((group) => group.instructions) ??\n []),\n ];\n\n let amount: string | null = null;\n let reference: string | undefined;\n let destinationTokenAccount: string | null = null;\n\n for (const ix of allInstructions) {\n if (!isParsedInstruction(ix)) continue;\n\n if (ix.program === \"spl-token\") {\n const parsedType = ix.parsed?.type;\n const info = ix.parsed?.info;\n\n if (\n (parsedType === \"transfer\" || parsedType === \"transferChecked\") &&\n info\n ) {\n const mint = info.mint;\n const rawAmount = info.tokenAmount?.amount ?? info.amount;\n\n if (mint === SOLANA_USDC_MINT && rawAmount) {\n destinationTokenAccount = info.destination;\n amount = (Number(rawAmount) / 1_000_000).toString();\n }\n }\n }\n\n if (ix.program === \"spl-memo\") {\n if (typeof ix.parsed === \"string\") {\n reference = ix.parsed;\n }\n }\n }\n\n if (!destinationTokenAccount || !amount) {\n return null;\n }\n\n const currentSlot = await connection.getSlot(\"confirmed\");\n const confirmations = Math.max(0, currentSlot - tx.slot);\n\n console.log(\"parsed tx\", tx);\n console.log(\"allInstructions\", allInstructions);\n console.log(\"destinationTokenAccount\", destinationTokenAccount);\n console.log(\"amount\", amount);\n console.log(\"reference\", reference);\n\n return {\n txHash,\n status: confirmations > 0 ? \"confirmed\" : \"pending\",\n to: destinationTokenAccount,\n amount,\n reference,\n confirmations,\n };\n}\n","import { PublicKey } from \"@solana/web3.js\";\nimport { SOLANA_USDC_MINT } from \"./solana/constants\";\nimport { getAssociatedTokenAddressSync } from \"@solana/spl-token\";\n\n/**\n * Convert human-readable USDC to atomic units (6 decimals)\n */\nexport function toAtomicUnits(amount: string): bigint {\n const [whole, fraction = \"\"] = amount.split(\".\");\n\n const paddedFraction = (fraction + \"000000\").slice(0, 6);\n\n return BigInt(whole) * 1_000_000n + BigInt(paddedFraction);\n}\n\nexport function amountGte(actual: string, expected: string): boolean {\n return toAtomicUnits(actual) >= toAtomicUnits(expected);\n}\n\nexport function sameAddress(a: string, b: string): boolean {\n return a.toLowerCase() === b.toLowerCase();\n}\n\nexport function getUsdcTokenAccountForWallet(walletAddress: string): string {\n const wallet = new PublicKey(walletAddress);\n const mint = new PublicKey(SOLANA_USDC_MINT);\n\n return getAssociatedTokenAddressSync(mint, wallet, true).toBase58();\n}\n","import { VerifyPaymentInput, VerifyPaymentResult } from \"./types\";\nimport { parseUsdcPaymentFromTransaction } from \"./parseUsdcPaymentFromTransaction\";\nimport { amountGte, getUsdcTokenAccountForWallet, sameAddress } from \"./utils\";\n\nexport async function verifyPayment(\n input: VerifyPaymentInput,\n): Promise<VerifyPaymentResult> {\n const parsed = await parseUsdcPaymentFromTransaction(input.txHash);\n\n if (!parsed) {\n return {\n ok: false,\n reason: \"INVALID_TRANSACTION\",\n txHash: input.txHash,\n };\n }\n\n if (parsed.status === \"failed\") {\n return {\n ok: false,\n reason: \"TX_FAILED\",\n txHash: input.txHash,\n };\n }\n\n const expectedTokenAccount = getUsdcTokenAccountForWallet(input.to);\n\n if (!sameAddress(parsed.to, expectedTokenAccount)) {\n return {\n ok: false,\n reason: \"TO_MISMATCH\",\n txHash: input.txHash,\n };\n }\n\n if (!amountGte(parsed.amount, input.amount)) {\n return {\n ok: false,\n reason: \"AMOUNT_TOO_LOW\",\n txHash: input.txHash,\n };\n }\n\n if (input.reference && parsed.reference !== input.reference) {\n return {\n ok: false,\n reason: \"REFERENCE_MISMATCH\",\n txHash: input.txHash,\n };\n }\n\n return {\n ok: true,\n status: parsed.status === \"pending\" ? \"pending\" : \"confirmed\",\n txHash: parsed.txHash,\n to: input.to,\n amount: parsed.amount,\n reference: parsed.reference,\n confirmations: parsed.confirmations,\n };\n}\n","import { verifyPayment } from \"./verifyPayment\";\nimport { VerifyPaymentInput, VerifyPaymentResult } from \"./types\";\n\ntype WaitForPaymentConfirmationOptions = {\n maxAttempts?: number;\n intervalMs?: number;\n};\n\nfunction sleep(ms: number) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function waitForPaymentConfirmation(\n input: VerifyPaymentInput,\n options: WaitForPaymentConfirmationOptions = {},\n): Promise<VerifyPaymentResult> {\n const maxAttempts = options.maxAttempts ?? 10;\n const intervalMs = options.intervalMs ?? 1500;\n\n for (let i = 0; i < maxAttempts; i++) {\n const result = await verifyPayment(input);\n\n if (result.ok && result.status === \"confirmed\") {\n return result;\n }\n\n if (result.ok && result.status === \"pending\") {\n await sleep(intervalMs);\n continue;\n }\n\n if (!result.ok && result.reason === \"INVALID_TRANSACTION\") {\n await sleep(intervalMs);\n continue;\n }\n\n return result;\n }\n\n return {\n ok: false,\n reason: \"INVALID_TRANSACTION\",\n txHash: input.txHash,\n };\n}\n"],"mappings":"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","names":["import_react","import_react","import_react","import_web3","import_wallet_adapter_react","import_wallet_adapter_react_ui","React","import_react","import_web3","import_web3","import_spl_token"]}
|
package/dist/index.mjs
CHANGED
|
@@ -45,7 +45,11 @@ import { useConnection, useWallet } from "@solana/wallet-adapter-react";
|
|
|
45
45
|
import { useWalletModal } from "@solana/wallet-adapter-react-ui";
|
|
46
46
|
|
|
47
47
|
// src/solana/buildUsdcTransfer.ts
|
|
48
|
-
import {
|
|
48
|
+
import {
|
|
49
|
+
PublicKey,
|
|
50
|
+
Transaction,
|
|
51
|
+
TransactionInstruction
|
|
52
|
+
} from "@solana/web3.js";
|
|
49
53
|
import {
|
|
50
54
|
TOKEN_PROGRAM_ID,
|
|
51
55
|
createAssociatedTokenAccountInstruction,
|
|
@@ -54,7 +58,7 @@ import {
|
|
|
54
58
|
} from "@solana/spl-token";
|
|
55
59
|
|
|
56
60
|
// src/solana/constants.ts
|
|
57
|
-
var
|
|
61
|
+
var SOLANA_USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
|
58
62
|
var USDC_DECIMALS = 6;
|
|
59
63
|
|
|
60
64
|
// src/solana/amount.ts
|
|
@@ -67,20 +71,38 @@ function toTokenBaseUnits(amount) {
|
|
|
67
71
|
}
|
|
68
72
|
|
|
69
73
|
// src/solana/buildUsdcTransfer.ts
|
|
74
|
+
var MEMO_PROGRAM_ID = new PublicKey(
|
|
75
|
+
"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"
|
|
76
|
+
);
|
|
70
77
|
async function buildUsdcTransfer({
|
|
71
78
|
connection,
|
|
72
79
|
fromWallet,
|
|
73
80
|
toWallet,
|
|
74
|
-
amount
|
|
81
|
+
amount,
|
|
82
|
+
reference
|
|
75
83
|
}) {
|
|
76
|
-
const mint = new PublicKey(
|
|
84
|
+
const mint = new PublicKey(SOLANA_USDC_MINT);
|
|
77
85
|
const fromAta = await getAssociatedTokenAddress(mint, fromWallet);
|
|
78
86
|
const toAta = await getAssociatedTokenAddress(mint, toWallet);
|
|
79
87
|
const tx = new Transaction();
|
|
88
|
+
console.log("REFERENCE IN BUILD:", reference);
|
|
89
|
+
if (reference) {
|
|
90
|
+
const memoInstruction = new TransactionInstruction({
|
|
91
|
+
keys: [],
|
|
92
|
+
programId: MEMO_PROGRAM_ID,
|
|
93
|
+
data: Buffer.from(reference)
|
|
94
|
+
});
|
|
95
|
+
tx.add(memoInstruction);
|
|
96
|
+
}
|
|
80
97
|
const toAtaInfo = await connection.getAccountInfo(toAta);
|
|
81
98
|
if (!toAtaInfo) {
|
|
82
99
|
tx.add(
|
|
83
|
-
createAssociatedTokenAccountInstruction(
|
|
100
|
+
createAssociatedTokenAccountInstruction(
|
|
101
|
+
fromWallet,
|
|
102
|
+
toAta,
|
|
103
|
+
toWallet,
|
|
104
|
+
mint
|
|
105
|
+
)
|
|
84
106
|
);
|
|
85
107
|
}
|
|
86
108
|
tx.add(
|
|
@@ -113,7 +135,7 @@ function useStablePay() {
|
|
|
113
135
|
null
|
|
114
136
|
);
|
|
115
137
|
const executePayment = useCallback(
|
|
116
|
-
async ({ amount, to }) => {
|
|
138
|
+
async ({ amount, to, reference }) => {
|
|
117
139
|
if (!publicKey) {
|
|
118
140
|
throw new Error("Wallet not connected");
|
|
119
141
|
}
|
|
@@ -127,7 +149,8 @@ function useStablePay() {
|
|
|
127
149
|
connection,
|
|
128
150
|
fromWallet: publicKey,
|
|
129
151
|
toWallet: recipient,
|
|
130
|
-
amount
|
|
152
|
+
amount,
|
|
153
|
+
reference
|
|
131
154
|
});
|
|
132
155
|
const sig = await sendTransaction(transaction, connection);
|
|
133
156
|
await connection.confirmTransaction(sig, "confirmed");
|
|
@@ -147,7 +170,7 @@ function useStablePay() {
|
|
|
147
170
|
return;
|
|
148
171
|
}
|
|
149
172
|
try {
|
|
150
|
-
const sig = await executePayment({ amount, to });
|
|
173
|
+
const sig = await executePayment({ amount, to, reference });
|
|
151
174
|
onSuccess?.({
|
|
152
175
|
signature: sig,
|
|
153
176
|
amount,
|
|
@@ -251,9 +274,238 @@ function StablePay({
|
|
|
251
274
|
disabled: Boolean(children.props.disabled) || loading
|
|
252
275
|
});
|
|
253
276
|
}
|
|
277
|
+
|
|
278
|
+
// src/hooks/usePaymentVerification.ts
|
|
279
|
+
import { useCallback as useCallback2, useState as useState2 } from "react";
|
|
280
|
+
|
|
281
|
+
// src/parseUsdcPaymentFromTransaction.ts
|
|
282
|
+
import {
|
|
283
|
+
Connection as Connection2
|
|
284
|
+
} from "@solana/web3.js";
|
|
285
|
+
function isParsedInstruction(ix) {
|
|
286
|
+
return "parsed" in ix;
|
|
287
|
+
}
|
|
288
|
+
async function parseUsdcPaymentFromTransaction(txHash) {
|
|
289
|
+
const connection = new Connection2(DEFAULT_RPC, "confirmed");
|
|
290
|
+
const tx = await connection.getParsedTransaction(txHash, {
|
|
291
|
+
maxSupportedTransactionVersion: 0,
|
|
292
|
+
commitment: "confirmed"
|
|
293
|
+
});
|
|
294
|
+
if (!tx || !tx.meta) return null;
|
|
295
|
+
if (tx.meta.err) {
|
|
296
|
+
return {
|
|
297
|
+
txHash,
|
|
298
|
+
status: "failed",
|
|
299
|
+
to: "",
|
|
300
|
+
amount: "0",
|
|
301
|
+
confirmations: 0
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
const allInstructions = [
|
|
305
|
+
...tx.transaction.message.instructions,
|
|
306
|
+
...tx.meta.innerInstructions?.flatMap((group) => group.instructions) ?? []
|
|
307
|
+
];
|
|
308
|
+
let amount = null;
|
|
309
|
+
let reference;
|
|
310
|
+
let destinationTokenAccount = null;
|
|
311
|
+
for (const ix of allInstructions) {
|
|
312
|
+
if (!isParsedInstruction(ix)) continue;
|
|
313
|
+
if (ix.program === "spl-token") {
|
|
314
|
+
const parsedType = ix.parsed?.type;
|
|
315
|
+
const info = ix.parsed?.info;
|
|
316
|
+
if ((parsedType === "transfer" || parsedType === "transferChecked") && info) {
|
|
317
|
+
const mint = info.mint;
|
|
318
|
+
const rawAmount = info.tokenAmount?.amount ?? info.amount;
|
|
319
|
+
if (mint === SOLANA_USDC_MINT && rawAmount) {
|
|
320
|
+
destinationTokenAccount = info.destination;
|
|
321
|
+
amount = (Number(rawAmount) / 1e6).toString();
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
if (ix.program === "spl-memo") {
|
|
326
|
+
if (typeof ix.parsed === "string") {
|
|
327
|
+
reference = ix.parsed;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
if (!destinationTokenAccount || !amount) {
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
const currentSlot = await connection.getSlot("confirmed");
|
|
335
|
+
const confirmations = Math.max(0, currentSlot - tx.slot);
|
|
336
|
+
console.log("parsed tx", tx);
|
|
337
|
+
console.log("allInstructions", allInstructions);
|
|
338
|
+
console.log("destinationTokenAccount", destinationTokenAccount);
|
|
339
|
+
console.log("amount", amount);
|
|
340
|
+
console.log("reference", reference);
|
|
341
|
+
return {
|
|
342
|
+
txHash,
|
|
343
|
+
status: confirmations > 0 ? "confirmed" : "pending",
|
|
344
|
+
to: destinationTokenAccount,
|
|
345
|
+
amount,
|
|
346
|
+
reference,
|
|
347
|
+
confirmations
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// src/utils.ts
|
|
352
|
+
import { PublicKey as PublicKey4 } from "@solana/web3.js";
|
|
353
|
+
import { getAssociatedTokenAddressSync } from "@solana/spl-token";
|
|
354
|
+
function toAtomicUnits(amount) {
|
|
355
|
+
const [whole, fraction = ""] = amount.split(".");
|
|
356
|
+
const paddedFraction = (fraction + "000000").slice(0, 6);
|
|
357
|
+
return BigInt(whole) * 1000000n + BigInt(paddedFraction);
|
|
358
|
+
}
|
|
359
|
+
function amountGte(actual, expected) {
|
|
360
|
+
return toAtomicUnits(actual) >= toAtomicUnits(expected);
|
|
361
|
+
}
|
|
362
|
+
function sameAddress(a, b) {
|
|
363
|
+
return a.toLowerCase() === b.toLowerCase();
|
|
364
|
+
}
|
|
365
|
+
function getUsdcTokenAccountForWallet(walletAddress) {
|
|
366
|
+
const wallet = new PublicKey4(walletAddress);
|
|
367
|
+
const mint = new PublicKey4(SOLANA_USDC_MINT);
|
|
368
|
+
return getAssociatedTokenAddressSync(mint, wallet, true).toBase58();
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// src/verifyPayment.ts
|
|
372
|
+
async function verifyPayment(input) {
|
|
373
|
+
const parsed = await parseUsdcPaymentFromTransaction(input.txHash);
|
|
374
|
+
if (!parsed) {
|
|
375
|
+
return {
|
|
376
|
+
ok: false,
|
|
377
|
+
reason: "INVALID_TRANSACTION",
|
|
378
|
+
txHash: input.txHash
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
if (parsed.status === "failed") {
|
|
382
|
+
return {
|
|
383
|
+
ok: false,
|
|
384
|
+
reason: "TX_FAILED",
|
|
385
|
+
txHash: input.txHash
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
const expectedTokenAccount = getUsdcTokenAccountForWallet(input.to);
|
|
389
|
+
if (!sameAddress(parsed.to, expectedTokenAccount)) {
|
|
390
|
+
return {
|
|
391
|
+
ok: false,
|
|
392
|
+
reason: "TO_MISMATCH",
|
|
393
|
+
txHash: input.txHash
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
if (!amountGte(parsed.amount, input.amount)) {
|
|
397
|
+
return {
|
|
398
|
+
ok: false,
|
|
399
|
+
reason: "AMOUNT_TOO_LOW",
|
|
400
|
+
txHash: input.txHash
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
if (input.reference && parsed.reference !== input.reference) {
|
|
404
|
+
return {
|
|
405
|
+
ok: false,
|
|
406
|
+
reason: "REFERENCE_MISMATCH",
|
|
407
|
+
txHash: input.txHash
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
return {
|
|
411
|
+
ok: true,
|
|
412
|
+
status: parsed.status === "pending" ? "pending" : "confirmed",
|
|
413
|
+
txHash: parsed.txHash,
|
|
414
|
+
to: input.to,
|
|
415
|
+
amount: parsed.amount,
|
|
416
|
+
reference: parsed.reference,
|
|
417
|
+
confirmations: parsed.confirmations
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// src/waitForPaymentConfirmation.ts
|
|
422
|
+
function sleep(ms) {
|
|
423
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
424
|
+
}
|
|
425
|
+
async function waitForPaymentConfirmation(input, options = {}) {
|
|
426
|
+
const maxAttempts = options.maxAttempts ?? 10;
|
|
427
|
+
const intervalMs = options.intervalMs ?? 1500;
|
|
428
|
+
for (let i = 0; i < maxAttempts; i++) {
|
|
429
|
+
const result = await verifyPayment(input);
|
|
430
|
+
if (result.ok && result.status === "confirmed") {
|
|
431
|
+
return result;
|
|
432
|
+
}
|
|
433
|
+
if (result.ok && result.status === "pending") {
|
|
434
|
+
await sleep(intervalMs);
|
|
435
|
+
continue;
|
|
436
|
+
}
|
|
437
|
+
if (!result.ok && result.reason === "INVALID_TRANSACTION") {
|
|
438
|
+
await sleep(intervalMs);
|
|
439
|
+
continue;
|
|
440
|
+
}
|
|
441
|
+
return result;
|
|
442
|
+
}
|
|
443
|
+
return {
|
|
444
|
+
ok: false,
|
|
445
|
+
reason: "INVALID_TRANSACTION",
|
|
446
|
+
txHash: input.txHash
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
// src/hooks/usePaymentVerification.ts
|
|
451
|
+
function usePaymentVerification(options = {}) {
|
|
452
|
+
const [status, setStatus] = useState2("idle");
|
|
453
|
+
const [result, setResult] = useState2(null);
|
|
454
|
+
const [error, setError] = useState2(null);
|
|
455
|
+
const reset = useCallback2(() => {
|
|
456
|
+
setStatus("idle");
|
|
457
|
+
setResult(null);
|
|
458
|
+
setError(null);
|
|
459
|
+
}, []);
|
|
460
|
+
const verify = useCallback2(
|
|
461
|
+
async (payload) => {
|
|
462
|
+
setStatus("verifying");
|
|
463
|
+
setError(null);
|
|
464
|
+
try {
|
|
465
|
+
const verificationResult = await waitForPaymentConfirmation(
|
|
466
|
+
{
|
|
467
|
+
to: payload.to,
|
|
468
|
+
amount: String(payload.amount),
|
|
469
|
+
txHash: payload.signature,
|
|
470
|
+
reference: payload.reference
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
maxAttempts: options.maxAttempts,
|
|
474
|
+
intervalMs: options.intervalMs
|
|
475
|
+
}
|
|
476
|
+
);
|
|
477
|
+
setResult(verificationResult);
|
|
478
|
+
if (verificationResult.ok) {
|
|
479
|
+
setStatus(
|
|
480
|
+
verificationResult.status === "confirmed" ? "confirmed" : "pending"
|
|
481
|
+
);
|
|
482
|
+
} else {
|
|
483
|
+
setStatus("failed");
|
|
484
|
+
}
|
|
485
|
+
return verificationResult;
|
|
486
|
+
} catch (err) {
|
|
487
|
+
const nextError = err instanceof Error ? err : new Error("Payment verification failed");
|
|
488
|
+
setError(nextError);
|
|
489
|
+
setStatus("failed");
|
|
490
|
+
throw nextError;
|
|
491
|
+
}
|
|
492
|
+
},
|
|
493
|
+
[options.maxAttempts, options.intervalMs]
|
|
494
|
+
);
|
|
495
|
+
return {
|
|
496
|
+
status,
|
|
497
|
+
result,
|
|
498
|
+
error,
|
|
499
|
+
verify,
|
|
500
|
+
reset
|
|
501
|
+
};
|
|
502
|
+
}
|
|
254
503
|
export {
|
|
255
504
|
StablePay,
|
|
256
505
|
StablePayProvider,
|
|
257
|
-
|
|
506
|
+
usePaymentVerification,
|
|
507
|
+
useStablePay,
|
|
508
|
+
verifyPayment,
|
|
509
|
+
waitForPaymentConfirmation
|
|
258
510
|
};
|
|
259
511
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/provider/StablePayProvider.tsx","../src/context/StablePayContext.ts","../src/components/StablePay.tsx","../src/hooks/useStablePay.ts","../src/solana/buildUsdcTransfer.ts","../src/solana/constants.ts","../src/solana/amount.ts"],"sourcesContent":["import React, { useMemo } from \"react\";\nimport {\n ConnectionProvider,\n WalletProvider,\n} from \"@solana/wallet-adapter-react\";\nimport { WalletModalProvider } from \"@solana/wallet-adapter-react-ui\";\nimport {\n PhantomWalletAdapter,\n SolflareWalletAdapter,\n} from \"@solana/wallet-adapter-wallets\";\nimport type { StablePayProviderProps } from \"../types\";\nimport StablePayContext from \"../context/StablePayContext\";\n\nimport \"@solana/wallet-adapter-react-ui/styles.css\";\n\nconst DEFAULT_RPC =\n \"https://mainnet.helius-rpc.com/?api-key=a90079ee-e2b5-438e-9b1a-2ae7ba8c1417\";\n\nexport function StablePayProvider({\n children,\n endpoint,\n to,\n}: StablePayProviderProps) {\n const resolvedEndpoint = endpoint ?? DEFAULT_RPC;\n\n const wallets = useMemo(\n () => [new PhantomWalletAdapter(), new SolflareWalletAdapter()],\n [],\n );\n\n return (\n <StablePayContext.Provider value={{ defaultTo: to }}>\n <ConnectionProvider endpoint={resolvedEndpoint}>\n <WalletProvider wallets={wallets} autoConnect>\n <WalletModalProvider>{children}</WalletModalProvider>\n </WalletProvider>\n </ConnectionProvider>\n </StablePayContext.Provider>\n );\n}\n","import { createContext, useContext } from \"react\";\n\ntype StablePayContextValue = {\n defaultTo?: string;\n};\n\nconst StablePayContext = createContext<StablePayContextValue>({});\n\nexport function useStablePayContext() {\n return useContext(StablePayContext);\n}\n\nexport default StablePayContext;\n","import React from \"react\";\nimport { useStablePay } from \"../hooks/useStablePay\";\nimport { useStablePayContext } from \"../context/StablePayContext\";\nimport type { StablePayProps } from \"../types\";\n\ntype ClickableChildProps = {\n onClick?: (event: React.MouseEvent) => void;\n disabled?: boolean;\n};\n\nfunction getResolvedTo(to?: string, defaultTo?: string): string {\n const resolved = to ?? defaultTo;\n\n if (!resolved) {\n throw new Error(\n \"StablePay: missing recipient address. Provide `to` on StablePay or StablePayProvider.\",\n );\n }\n\n return resolved;\n}\n\nexport function StablePay({\n amount,\n to,\n reference,\n children,\n onSuccess,\n onError,\n}: StablePayProps) {\n const { pay, loading } = useStablePay();\n const { defaultTo } = useStablePayContext();\n\n const resolvedTo = getResolvedTo(to, defaultTo);\n\n if (!resolvedTo) {\n throw new Error(\n \"StablePay: missing recipient address. Provide `to` on StablePay or StablePayProvider.\",\n );\n }\n\n if (!React.isValidElement<ClickableChildProps>(children)) {\n throw new Error(\"StablePay expects a single React element child.\");\n }\n\n async function handleClick(event: React.MouseEvent) {\n try {\n children.props.onClick?.(event);\n\n if (event.defaultPrevented) return;\n\n await pay({\n amount,\n to: resolvedTo,\n reference,\n onSuccess,\n onError,\n });\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error(\"Payment failed\"));\n }\n }\n\n return React.cloneElement(children, {\n onClick: handleClick,\n disabled: Boolean(children.props.disabled) || loading,\n });\n}\n","import { useCallback, useEffect, useState } from \"react\";\nimport { PublicKey } from \"@solana/web3.js\";\nimport { useConnection, useWallet } from \"@solana/wallet-adapter-react\";\nimport { useWalletModal } from \"@solana/wallet-adapter-react-ui\";\nimport { buildUsdcTransfer } from \"../solana/buildUsdcTransfer\";\nimport { StablePayPayArgs } from \"../types\";\n\ntype PendingPayment = StablePayPayArgs;\n\nexport function useStablePay() {\n const { connection } = useConnection();\n const { connected, publicKey, sendTransaction } = useWallet();\n const { setVisible } = useWalletModal();\n\n const [loading, setLoading] = useState(false);\n const [signature, setSignature] = useState<string | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const [pendingPayment, setPendingPayment] = useState<PendingPayment | null>(\n null,\n );\n\n const executePayment = useCallback(\n async ({ amount, to }: StablePayPayArgs) => {\n if (!publicKey) {\n throw new Error(\"Wallet not connected\");\n }\n\n let recipient: PublicKey;\n\n try {\n recipient = new PublicKey(to);\n } catch {\n throw new Error(\"Invalid recipient wallet address\");\n }\n\n const transaction = await buildUsdcTransfer({\n connection,\n fromWallet: publicKey,\n toWallet: recipient,\n amount,\n });\n\n const sig = await sendTransaction(transaction, connection);\n await connection.confirmTransaction(sig, \"confirmed\");\n\n setSignature(sig);\n return sig;\n },\n [publicKey, connection, sendTransaction],\n );\n\n const pay = useCallback(\n async ({ amount, to, reference, onSuccess, onError }: StablePayPayArgs) => {\n setLoading(true);\n setSignature(null);\n setError(null);\n\n // Not connected → store intent + callbacks\n if (!connected || !publicKey) {\n setPendingPayment({ amount, to, reference, onSuccess, onError });\n setVisible(true);\n return;\n }\n\n try {\n const sig = await executePayment({ amount, to });\n onSuccess?.({\n signature: sig,\n amount,\n to,\n reference,\n });\n } catch (err) {\n const normalized =\n err instanceof Error ? err : new Error(\"Payment failed\");\n setError(normalized);\n onError?.(normalized);\n } finally {\n setLoading(false);\n }\n },\n [connected, publicKey, executePayment, setVisible],\n );\n\n // Resume after wallet connects\n useEffect(() => {\n if (!connected || !publicKey || !pendingPayment) return;\n\n const payment = pendingPayment;\n\n let cancelled = false;\n\n async function resumePayment() {\n try {\n const sig = await executePayment(payment);\n\n if (!cancelled) {\n payment.onSuccess?.({\n signature: sig,\n amount: payment.amount,\n to: payment.to,\n reference: payment.reference,\n });\n setSignature(sig);\n setPendingPayment(null);\n }\n } catch (err) {\n if (!cancelled) {\n const normalized =\n err instanceof Error ? err : new Error(\"Payment failed\");\n setError(normalized);\n payment.onError?.(normalized);\n setPendingPayment(null);\n }\n } finally {\n if (!cancelled) {\n setLoading(false);\n }\n }\n }\n\n resumePayment();\n\n return () => {\n cancelled = true;\n };\n }, [connected, publicKey, pendingPayment, executePayment]);\n\n return { pay, loading, error, signature };\n}\n","import { Connection, PublicKey, Transaction } from \"@solana/web3.js\";\nimport {\n TOKEN_PROGRAM_ID,\n createAssociatedTokenAccountInstruction,\n createTransferCheckedInstruction,\n getAssociatedTokenAddress,\n} from \"@solana/spl-token\";\nimport { toTokenBaseUnits } from \"./amount\";\nimport { USDC_DECIMALS, USDC_MINT } from \"./constants\";\n\ntype BuildUsdcTransferParams = {\n connection: Connection;\n fromWallet: PublicKey;\n toWallet: PublicKey;\n amount: number;\n};\n\nexport async function buildUsdcTransfer({\n connection,\n fromWallet,\n toWallet,\n amount,\n}: BuildUsdcTransferParams) {\n const mint = new PublicKey(USDC_MINT);\n const fromAta = await getAssociatedTokenAddress(mint, fromWallet);\n const toAta = await getAssociatedTokenAddress(mint, toWallet);\n\n const tx = new Transaction();\n const toAtaInfo = await connection.getAccountInfo(toAta);\n\n if (!toAtaInfo) {\n tx.add(\n createAssociatedTokenAccountInstruction(fromWallet, toAta, toWallet, mint)\n );\n }\n\n tx.add(\n createTransferCheckedInstruction(\n fromAta,\n mint,\n toAta,\n fromWallet,\n Number(toTokenBaseUnits(amount)),\n USDC_DECIMALS,\n [],\n TOKEN_PROGRAM_ID\n )\n );\n\n const latestBlockhash = await connection.getLatestBlockhash();\n tx.feePayer = fromWallet;\n tx.recentBlockhash = latestBlockhash.blockhash;\n\n return tx;\n}\n","export const USDC_MINT = \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\";\nexport const USDC_DECIMALS = 6;\n","import { USDC_DECIMALS } from \"./constants\";\n\nexport function toTokenBaseUnits(amount: number): bigint {\n if (!Number.isFinite(amount) || amount <= 0) {\n throw new Error(\"Amount must be a positive number\");\n }\n\n const multiplier = 10 ** USDC_DECIMALS;\n return BigInt(Math.round(amount * multiplier));\n}\n"],"mappings":"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","names":["React","PublicKey","PublicKey","React"]}
|
|
1
|
+
{"version":3,"sources":["../src/provider/StablePayProvider.tsx","../src/context/StablePayContext.ts","../src/components/StablePay.tsx","../src/hooks/useStablePay.ts","../src/solana/buildUsdcTransfer.ts","../src/solana/constants.ts","../src/solana/amount.ts","../src/hooks/usePaymentVerification.ts","../src/parseUsdcPaymentFromTransaction.ts","../src/utils.ts","../src/verifyPayment.ts","../src/waitForPaymentConfirmation.ts"],"sourcesContent":["import React, { useMemo } from \"react\";\nimport {\n ConnectionProvider,\n WalletProvider,\n} from \"@solana/wallet-adapter-react\";\nimport { WalletModalProvider } from \"@solana/wallet-adapter-react-ui\";\nimport {\n PhantomWalletAdapter,\n SolflareWalletAdapter,\n} from \"@solana/wallet-adapter-wallets\";\nimport type { StablePayProviderProps } from \"../types\";\nimport StablePayContext from \"../context/StablePayContext\";\n\nimport \"@solana/wallet-adapter-react-ui/styles.css\";\n\nexport const DEFAULT_RPC =\n \"https://mainnet.helius-rpc.com/?api-key=a90079ee-e2b5-438e-9b1a-2ae7ba8c1417\";\n\nexport function StablePayProvider({\n children,\n endpoint,\n to,\n}: StablePayProviderProps) {\n const resolvedEndpoint = endpoint ?? DEFAULT_RPC;\n\n const wallets = useMemo(\n () => [new PhantomWalletAdapter(), new SolflareWalletAdapter()],\n [],\n );\n\n return (\n <StablePayContext.Provider value={{ defaultTo: to }}>\n <ConnectionProvider endpoint={resolvedEndpoint}>\n <WalletProvider wallets={wallets} autoConnect>\n <WalletModalProvider>{children}</WalletModalProvider>\n </WalletProvider>\n </ConnectionProvider>\n </StablePayContext.Provider>\n );\n}\n","import { createContext, useContext } from \"react\";\n\ntype StablePayContextValue = {\n defaultTo?: string;\n};\n\nconst StablePayContext = createContext<StablePayContextValue>({});\n\nexport function useStablePayContext() {\n return useContext(StablePayContext);\n}\n\nexport default StablePayContext;\n","import React from \"react\";\nimport { useStablePay } from \"../hooks/useStablePay\";\nimport { useStablePayContext } from \"../context/StablePayContext\";\nimport type { StablePayProps } from \"../types\";\n\ntype ClickableChildProps = {\n onClick?: (event: React.MouseEvent) => void;\n disabled?: boolean;\n};\n\nfunction getResolvedTo(to?: string, defaultTo?: string): string {\n const resolved = to ?? defaultTo;\n\n if (!resolved) {\n throw new Error(\n \"StablePay: missing recipient address. Provide `to` on StablePay or StablePayProvider.\",\n );\n }\n\n return resolved;\n}\n\nexport function StablePay({\n amount,\n to,\n reference,\n children,\n onSuccess,\n onError,\n}: StablePayProps) {\n const { pay, loading } = useStablePay();\n const { defaultTo } = useStablePayContext();\n\n const resolvedTo = getResolvedTo(to, defaultTo);\n\n if (!resolvedTo) {\n throw new Error(\n \"StablePay: missing recipient address. Provide `to` on StablePay or StablePayProvider.\",\n );\n }\n\n if (!React.isValidElement<ClickableChildProps>(children)) {\n throw new Error(\"StablePay expects a single React element child.\");\n }\n\n async function handleClick(event: React.MouseEvent) {\n try {\n children.props.onClick?.(event);\n\n if (event.defaultPrevented) return;\n\n await pay({\n amount,\n to: resolvedTo,\n reference,\n onSuccess,\n onError,\n });\n } catch (err) {\n onError?.(err instanceof Error ? err : new Error(\"Payment failed\"));\n }\n }\n\n return React.cloneElement(children, {\n onClick: handleClick,\n disabled: Boolean(children.props.disabled) || loading,\n });\n}\n","import { useCallback, useEffect, useState } from \"react\";\nimport { PublicKey } from \"@solana/web3.js\";\nimport { useConnection, useWallet } from \"@solana/wallet-adapter-react\";\nimport { useWalletModal } from \"@solana/wallet-adapter-react-ui\";\nimport { buildUsdcTransfer } from \"../solana/buildUsdcTransfer\";\nimport { StablePayPayArgs } from \"../types\";\n\ntype PendingPayment = StablePayPayArgs;\n\nexport function useStablePay() {\n const { connection } = useConnection();\n const { connected, publicKey, sendTransaction } = useWallet();\n const { setVisible } = useWalletModal();\n\n const [loading, setLoading] = useState(false);\n const [signature, setSignature] = useState<string | null>(null);\n const [error, setError] = useState<Error | null>(null);\n const [pendingPayment, setPendingPayment] = useState<PendingPayment | null>(\n null,\n );\n\n const executePayment = useCallback(\n async ({ amount, to, reference }: StablePayPayArgs) => {\n if (!publicKey) {\n throw new Error(\"Wallet not connected\");\n }\n\n let recipient: PublicKey;\n\n try {\n recipient = new PublicKey(to);\n } catch {\n throw new Error(\"Invalid recipient wallet address\");\n }\n\n const transaction = await buildUsdcTransfer({\n connection,\n fromWallet: publicKey,\n toWallet: recipient,\n amount,\n reference,\n });\n\n const sig = await sendTransaction(transaction, connection);\n await connection.confirmTransaction(sig, \"confirmed\");\n\n setSignature(sig);\n return sig;\n },\n [publicKey, connection, sendTransaction],\n );\n\n const pay = useCallback(\n async ({ amount, to, reference, onSuccess, onError }: StablePayPayArgs) => {\n setLoading(true);\n setSignature(null);\n setError(null);\n\n // Not connected → store intent + callbacks\n if (!connected || !publicKey) {\n setPendingPayment({ amount, to, reference, onSuccess, onError });\n setVisible(true);\n return;\n }\n\n try {\n const sig = await executePayment({ amount, to, reference });\n onSuccess?.({\n signature: sig,\n amount,\n to,\n reference,\n });\n } catch (err) {\n const normalized =\n err instanceof Error ? err : new Error(\"Payment failed\");\n setError(normalized);\n onError?.(normalized);\n } finally {\n setLoading(false);\n }\n },\n [connected, publicKey, executePayment, setVisible],\n );\n\n // Resume after wallet connects\n useEffect(() => {\n if (!connected || !publicKey || !pendingPayment) return;\n\n const payment = pendingPayment;\n\n let cancelled = false;\n\n async function resumePayment() {\n try {\n const sig = await executePayment(payment);\n\n if (!cancelled) {\n payment.onSuccess?.({\n signature: sig,\n amount: payment.amount,\n to: payment.to,\n reference: payment.reference,\n });\n setSignature(sig);\n setPendingPayment(null);\n }\n } catch (err) {\n if (!cancelled) {\n const normalized =\n err instanceof Error ? err : new Error(\"Payment failed\");\n setError(normalized);\n payment.onError?.(normalized);\n setPendingPayment(null);\n }\n } finally {\n if (!cancelled) {\n setLoading(false);\n }\n }\n }\n\n resumePayment();\n\n return () => {\n cancelled = true;\n };\n }, [connected, publicKey, pendingPayment, executePayment]);\n\n return { pay, loading, error, signature };\n}\n","import {\n Connection,\n PublicKey,\n Transaction,\n TransactionInstruction,\n} from \"@solana/web3.js\";\nimport {\n TOKEN_PROGRAM_ID,\n createAssociatedTokenAccountInstruction,\n createTransferCheckedInstruction,\n getAssociatedTokenAddress,\n} from \"@solana/spl-token\";\nimport { toTokenBaseUnits } from \"./amount\";\nimport { USDC_DECIMALS, SOLANA_USDC_MINT } from \"./constants\";\n\nconst MEMO_PROGRAM_ID = new PublicKey(\n \"MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr\",\n);\n\ntype BuildUsdcTransferParams = {\n connection: Connection;\n fromWallet: PublicKey;\n toWallet: PublicKey;\n amount: number;\n reference?: string;\n};\n\nexport async function buildUsdcTransfer({\n connection,\n fromWallet,\n toWallet,\n amount,\n reference,\n}: BuildUsdcTransferParams) {\n const mint = new PublicKey(SOLANA_USDC_MINT);\n const fromAta = await getAssociatedTokenAddress(mint, fromWallet);\n const toAta = await getAssociatedTokenAddress(mint, toWallet);\n\n const tx = new Transaction();\n\n console.log(\"REFERENCE IN BUILD:\", reference);\n\n if (reference) {\n const memoInstruction = new TransactionInstruction({\n keys: [],\n programId: MEMO_PROGRAM_ID,\n data: Buffer.from(reference),\n });\n\n tx.add(memoInstruction);\n }\n\n const toAtaInfo = await connection.getAccountInfo(toAta);\n\n if (!toAtaInfo) {\n tx.add(\n createAssociatedTokenAccountInstruction(\n fromWallet,\n toAta,\n toWallet,\n mint,\n ),\n );\n }\n\n tx.add(\n createTransferCheckedInstruction(\n fromAta,\n mint,\n toAta,\n fromWallet,\n Number(toTokenBaseUnits(amount)),\n USDC_DECIMALS,\n [],\n TOKEN_PROGRAM_ID,\n ),\n );\n\n const latestBlockhash = await connection.getLatestBlockhash();\n tx.feePayer = fromWallet;\n tx.recentBlockhash = latestBlockhash.blockhash;\n\n return tx;\n}\n","export const SOLANA_USDC_MINT = \"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v\";\nexport const USDC_DECIMALS = 6;\n","import { USDC_DECIMALS } from \"./constants\";\n\nexport function toTokenBaseUnits(amount: number): bigint {\n if (!Number.isFinite(amount) || amount <= 0) {\n throw new Error(\"Amount must be a positive number\");\n }\n\n const multiplier = 10 ** USDC_DECIMALS;\n return BigInt(Math.round(amount * multiplier));\n}\n","import { useCallback, useState } from \"react\";\nimport { VerifyPaymentResult } from \"../types\";\nimport { waitForPaymentConfirmation } from \"../waitForPaymentConfirmation\";\n\nexport type StablePaySuccessPayload = {\n signature: string;\n amount: number;\n to: string;\n reference?: string;\n};\n\nexport type PaymentVerificationStatus =\n | \"idle\"\n | \"verifying\"\n | \"pending\"\n | \"confirmed\"\n | \"failed\";\n\nexport type UsePaymentVerificationOptions = {\n maxAttempts?: number;\n intervalMs?: number;\n};\n\nexport type UsePaymentVerificationResult = {\n status: PaymentVerificationStatus;\n result: VerifyPaymentResult | null;\n error: Error | null;\n verify: (payload: StablePaySuccessPayload) => Promise<VerifyPaymentResult>;\n reset: () => void;\n};\n\nexport function usePaymentVerification(\n options: UsePaymentVerificationOptions = {},\n): UsePaymentVerificationResult {\n const [status, setStatus] = useState<PaymentVerificationStatus>(\"idle\");\n const [result, setResult] = useState<VerifyPaymentResult | null>(null);\n const [error, setError] = useState<Error | null>(null);\n\n const reset = useCallback(() => {\n setStatus(\"idle\");\n setResult(null);\n setError(null);\n }, []);\n\n const verify = useCallback(\n async (payload: StablePaySuccessPayload) => {\n setStatus(\"verifying\");\n setError(null);\n\n try {\n const verificationResult = await waitForPaymentConfirmation(\n {\n to: payload.to,\n amount: String(payload.amount),\n txHash: payload.signature,\n reference: payload.reference,\n },\n {\n maxAttempts: options.maxAttempts,\n intervalMs: options.intervalMs,\n },\n );\n\n setResult(verificationResult);\n\n if (verificationResult.ok) {\n setStatus(\n verificationResult.status === \"confirmed\" ? \"confirmed\" : \"pending\",\n );\n } else {\n setStatus(\"failed\");\n }\n\n return verificationResult;\n } catch (err) {\n const nextError =\n err instanceof Error ? err : new Error(\"Payment verification failed\");\n\n setError(nextError);\n setStatus(\"failed\");\n throw nextError;\n }\n },\n [options.maxAttempts, options.intervalMs],\n );\n\n return {\n status,\n result,\n error,\n verify,\n reset,\n };\n}\n","import {\n Connection,\n ParsedInstruction,\n PartiallyDecodedInstruction,\n PublicKey,\n} from \"@solana/web3.js\";\nimport { ParsedPayment } from \"./types\";\nimport { DEFAULT_RPC } from \"./provider/StablePayProvider\";\nimport { SOLANA_USDC_MINT } from \"./solana/constants\";\n\nfunction isParsedInstruction(\n ix: ParsedInstruction | PartiallyDecodedInstruction,\n): ix is ParsedInstruction {\n return \"parsed\" in ix;\n}\n\nexport async function parseUsdcPaymentFromTransaction(\n txHash: string,\n): Promise<ParsedPayment | null> {\n const connection = new Connection(DEFAULT_RPC, \"confirmed\");\n\n const tx = await connection.getParsedTransaction(txHash, {\n maxSupportedTransactionVersion: 0,\n commitment: \"confirmed\",\n });\n\n if (!tx || !tx.meta) return null;\n\n if (tx.meta.err) {\n return {\n txHash,\n status: \"failed\",\n to: \"\",\n amount: \"0\",\n confirmations: 0,\n };\n }\n\n const allInstructions = [\n ...tx.transaction.message.instructions,\n ...(tx.meta.innerInstructions?.flatMap((group) => group.instructions) ??\n []),\n ];\n\n let amount: string | null = null;\n let reference: string | undefined;\n let destinationTokenAccount: string | null = null;\n\n for (const ix of allInstructions) {\n if (!isParsedInstruction(ix)) continue;\n\n if (ix.program === \"spl-token\") {\n const parsedType = ix.parsed?.type;\n const info = ix.parsed?.info;\n\n if (\n (parsedType === \"transfer\" || parsedType === \"transferChecked\") &&\n info\n ) {\n const mint = info.mint;\n const rawAmount = info.tokenAmount?.amount ?? info.amount;\n\n if (mint === SOLANA_USDC_MINT && rawAmount) {\n destinationTokenAccount = info.destination;\n amount = (Number(rawAmount) / 1_000_000).toString();\n }\n }\n }\n\n if (ix.program === \"spl-memo\") {\n if (typeof ix.parsed === \"string\") {\n reference = ix.parsed;\n }\n }\n }\n\n if (!destinationTokenAccount || !amount) {\n return null;\n }\n\n const currentSlot = await connection.getSlot(\"confirmed\");\n const confirmations = Math.max(0, currentSlot - tx.slot);\n\n console.log(\"parsed tx\", tx);\n console.log(\"allInstructions\", allInstructions);\n console.log(\"destinationTokenAccount\", destinationTokenAccount);\n console.log(\"amount\", amount);\n console.log(\"reference\", reference);\n\n return {\n txHash,\n status: confirmations > 0 ? \"confirmed\" : \"pending\",\n to: destinationTokenAccount,\n amount,\n reference,\n confirmations,\n };\n}\n","import { PublicKey } from \"@solana/web3.js\";\nimport { SOLANA_USDC_MINT } from \"./solana/constants\";\nimport { getAssociatedTokenAddressSync } from \"@solana/spl-token\";\n\n/**\n * Convert human-readable USDC to atomic units (6 decimals)\n */\nexport function toAtomicUnits(amount: string): bigint {\n const [whole, fraction = \"\"] = amount.split(\".\");\n\n const paddedFraction = (fraction + \"000000\").slice(0, 6);\n\n return BigInt(whole) * 1_000_000n + BigInt(paddedFraction);\n}\n\nexport function amountGte(actual: string, expected: string): boolean {\n return toAtomicUnits(actual) >= toAtomicUnits(expected);\n}\n\nexport function sameAddress(a: string, b: string): boolean {\n return a.toLowerCase() === b.toLowerCase();\n}\n\nexport function getUsdcTokenAccountForWallet(walletAddress: string): string {\n const wallet = new PublicKey(walletAddress);\n const mint = new PublicKey(SOLANA_USDC_MINT);\n\n return getAssociatedTokenAddressSync(mint, wallet, true).toBase58();\n}\n","import { VerifyPaymentInput, VerifyPaymentResult } from \"./types\";\nimport { parseUsdcPaymentFromTransaction } from \"./parseUsdcPaymentFromTransaction\";\nimport { amountGte, getUsdcTokenAccountForWallet, sameAddress } from \"./utils\";\n\nexport async function verifyPayment(\n input: VerifyPaymentInput,\n): Promise<VerifyPaymentResult> {\n const parsed = await parseUsdcPaymentFromTransaction(input.txHash);\n\n if (!parsed) {\n return {\n ok: false,\n reason: \"INVALID_TRANSACTION\",\n txHash: input.txHash,\n };\n }\n\n if (parsed.status === \"failed\") {\n return {\n ok: false,\n reason: \"TX_FAILED\",\n txHash: input.txHash,\n };\n }\n\n const expectedTokenAccount = getUsdcTokenAccountForWallet(input.to);\n\n if (!sameAddress(parsed.to, expectedTokenAccount)) {\n return {\n ok: false,\n reason: \"TO_MISMATCH\",\n txHash: input.txHash,\n };\n }\n\n if (!amountGte(parsed.amount, input.amount)) {\n return {\n ok: false,\n reason: \"AMOUNT_TOO_LOW\",\n txHash: input.txHash,\n };\n }\n\n if (input.reference && parsed.reference !== input.reference) {\n return {\n ok: false,\n reason: \"REFERENCE_MISMATCH\",\n txHash: input.txHash,\n };\n }\n\n return {\n ok: true,\n status: parsed.status === \"pending\" ? \"pending\" : \"confirmed\",\n txHash: parsed.txHash,\n to: input.to,\n amount: parsed.amount,\n reference: parsed.reference,\n confirmations: parsed.confirmations,\n };\n}\n","import { verifyPayment } from \"./verifyPayment\";\nimport { VerifyPaymentInput, VerifyPaymentResult } from \"./types\";\n\ntype WaitForPaymentConfirmationOptions = {\n maxAttempts?: number;\n intervalMs?: number;\n};\n\nfunction sleep(ms: number) {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport async function waitForPaymentConfirmation(\n input: VerifyPaymentInput,\n options: WaitForPaymentConfirmationOptions = {},\n): Promise<VerifyPaymentResult> {\n const maxAttempts = options.maxAttempts ?? 10;\n const intervalMs = options.intervalMs ?? 1500;\n\n for (let i = 0; i < maxAttempts; i++) {\n const result = await verifyPayment(input);\n\n if (result.ok && result.status === \"confirmed\") {\n return result;\n }\n\n if (result.ok && result.status === \"pending\") {\n await sleep(intervalMs);\n continue;\n }\n\n if (!result.ok && result.reason === \"INVALID_TRANSACTION\") {\n await sleep(intervalMs);\n continue;\n }\n\n return result;\n }\n\n return {\n ok: false,\n reason: \"INVALID_TRANSACTION\",\n txHash: input.txHash,\n };\n}\n"],"mappings":"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","names":["React","PublicKey","PublicKey","React","useCallback","useState","Connection","Connection","PublicKey","PublicKey","useState","useCallback"]}
|