@faremeter/payment-solana 0.20.0 → 0.21.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.
Files changed (62) hide show
  1. package/dist/src/charge/client.d.ts +10 -6
  2. package/dist/src/charge/client.d.ts.map +1 -1
  3. package/dist/src/charge/client.js +117 -102
  4. package/dist/src/charge/common.d.ts +3 -3
  5. package/dist/src/charge/server.d.ts +18 -7
  6. package/dist/src/charge/server.d.ts.map +1 -1
  7. package/dist/src/charge/server.js +22 -24
  8. package/dist/src/compat.d.ts +38 -0
  9. package/dist/src/compat.d.ts.map +1 -0
  10. package/dist/src/compat.js +86 -0
  11. package/dist/src/compat.test.d.ts +3 -0
  12. package/dist/src/compat.test.d.ts.map +1 -0
  13. package/dist/src/compat.test.js +70 -0
  14. package/dist/src/exact/client.d.ts +18 -15
  15. package/dist/src/exact/client.d.ts.map +1 -1
  16. package/dist/src/exact/client.js +124 -96
  17. package/dist/src/exact/common.d.ts +1 -1
  18. package/dist/src/exact/facilitator.d.ts +19 -12
  19. package/dist/src/exact/facilitator.d.ts.map +1 -1
  20. package/dist/src/exact/facilitator.js +19 -18
  21. package/dist/src/exact/memo.d.ts +0 -2
  22. package/dist/src/exact/memo.d.ts.map +1 -1
  23. package/dist/src/exact/memo.js +0 -9
  24. package/dist/src/exact/verify.d.ts +5 -1
  25. package/dist/src/exact/verify.d.ts.map +1 -1
  26. package/dist/src/exact/verify.js +8 -2
  27. package/dist/src/exact/verify.test.js +80 -3
  28. package/dist/src/flex/client/handler.d.ts +31 -0
  29. package/dist/src/flex/client/handler.d.ts.map +1 -0
  30. package/dist/src/flex/client/handler.js +104 -0
  31. package/dist/src/flex/client/index.d.ts +3 -0
  32. package/dist/src/flex/client/index.d.ts.map +1 -0
  33. package/dist/src/flex/client/index.js +1 -0
  34. package/dist/src/flex/common.d.ts +15 -0
  35. package/dist/src/flex/common.d.ts.map +1 -0
  36. package/dist/src/flex/common.js +7 -0
  37. package/dist/src/flex/facilitator/handler.d.ts +48 -0
  38. package/dist/src/flex/facilitator/handler.d.ts.map +1 -0
  39. package/dist/src/flex/facilitator/handler.js +705 -0
  40. package/dist/src/flex/facilitator/index.d.ts +5 -0
  41. package/dist/src/flex/facilitator/index.d.ts.map +1 -0
  42. package/dist/src/flex/facilitator/index.js +2 -0
  43. package/dist/src/flex/hono/index.d.ts +3 -0
  44. package/dist/src/flex/hono/index.d.ts.map +1 -0
  45. package/dist/src/flex/hono/index.js +1 -0
  46. package/dist/src/flex/hono/upto-handler.d.ts +20 -0
  47. package/dist/src/flex/hono/upto-handler.d.ts.map +1 -0
  48. package/dist/src/flex/hono/upto-handler.js +72 -0
  49. package/dist/src/flex/hono/upto-handler.test.d.ts +3 -0
  50. package/dist/src/flex/hono/upto-handler.test.d.ts.map +1 -0
  51. package/dist/src/flex/hono/upto-handler.test.js +381 -0
  52. package/dist/src/flex/index.d.ts +4 -0
  53. package/dist/src/flex/index.d.ts.map +1 -0
  54. package/dist/src/flex/index.js +3 -0
  55. package/dist/src/flex/logger.d.ts +2 -0
  56. package/dist/src/flex/logger.d.ts.map +1 -0
  57. package/dist/src/flex/logger.js +2 -0
  58. package/dist/src/index.d.ts +1 -0
  59. package/dist/src/index.d.ts.map +1 -1
  60. package/dist/src/index.js +1 -0
  61. package/dist/tsconfig.tsbuildinfo +1 -1
  62. package/package.json +23 -7
@@ -1,17 +1,21 @@
1
1
  import type { MPPPaymentHandler } from "@faremeter/types/mpp";
2
- import { Connection, PublicKey } from "@solana/web3.js";
3
- import type { Wallet } from "../exact/index.js";
2
+ import { type Address, type Rpc, type SolanaRpcApi } from "@solana/kit";
3
+ import { type Wallet } from "../exact/client.js";
4
4
  export type CreateMPPSolanaChargeClientArgs = {
5
5
  wallet: Wallet;
6
- mint: PublicKey;
7
- connection?: Connection;
8
- tokenProgramId?: PublicKey;
6
+ mint: Address | {
7
+ toBase58(): string;
8
+ };
9
+ rpc?: Rpc<SolanaRpcApi> | string;
10
+ tokenProgramId?: Address | {
11
+ toBase58(): string;
12
+ };
9
13
  broadcast?: boolean;
10
14
  };
11
15
  export declare function createMPPSolanaChargeClient(args: CreateMPPSolanaChargeClientArgs): MPPPaymentHandler;
12
16
  export type CreateMPPSolanaNativeChargeClientArgs = {
13
17
  wallet: Wallet;
14
- connection?: Connection;
18
+ rpc?: Rpc<SolanaRpcApi> | string;
15
19
  broadcast?: boolean;
16
20
  };
17
21
  export declare function createMPPSolanaNativeChargeClient(args: CreateMPPSolanaNativeChargeClientArgs): MPPPaymentHandler;
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/charge/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EAIlB,MAAM,sBAAsB,CAAC;AAS9B,OAAO,EAEL,UAAU,EACV,SAAS,EAIV,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAqCvC,MAAM,MAAM,+BAA+B,GAAG;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,SAAS,CAAC;IAChB,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,cAAc,CAAC,EAAE,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,+BAA+B,GACpC,iBAAiB,CAoInB;AAED,MAAM,MAAM,qCAAqC,GAAG;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,wBAAgB,iCAAiC,CAC/C,IAAI,EAAE,qCAAqC,GAC1C,iBAAiB,CAmGnB"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/charge/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EAIlB,MAAM,sBAAsB,CAAC;AAc9B,OAAO,EAIL,KAAK,OAAO,EAGZ,KAAK,GAAG,EAER,KAAK,YAAY,EAElB,MAAM,aAAa,CAAC;AACrB,OAAO,EAEL,KAAK,MAAM,EAEZ,MAAM,iBAAiB,CAAC;AAmFzB,MAAM,MAAM,+BAA+B,GAAG;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,OAAO,GAAG;QAAE,QAAQ,IAAI,MAAM,CAAA;KAAE,CAAC;IACvC,GAAG,CAAC,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,MAAM,CAAC;IACjC,cAAc,CAAC,EAAE,OAAO,GAAG;QAAE,QAAQ,IAAI,MAAM,CAAA;KAAE,CAAC;IAClD,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,+BAA+B,GACpC,iBAAiB,CAwHnB;AAED,MAAM,MAAM,qCAAqC,GAAG;IAClD,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,MAAM,CAAC;IACjC,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,wBAAgB,iCAAiC,CAC/C,IAAI,EAAE,qCAAqC,GAC1C,iBAAiB,CAoFnB"}
@@ -1,32 +1,79 @@
1
1
  import { decodeBase64URL } from "@faremeter/types/mpp";
2
2
  import { isValidationError } from "@faremeter/types";
3
- import { createTransferCheckedInstruction, getAssociatedTokenAddressSync, getMint, TOKEN_PROGRAM_ID, } from "@solana/spl-token";
4
- import { ComputeBudgetProgram, Connection, PublicKey, SystemProgram, TransactionMessage, VersionedTransaction, } from "@solana/web3.js";
3
+ import { fetchMint, findAssociatedTokenPda, getTransferCheckedInstruction, TOKEN_PROGRAM_ADDRESS, } from "@solana-program/token";
4
+ import { getSetComputeUnitLimitInstruction, getSetComputeUnitPriceInstruction, } from "@solana-program/compute-budget";
5
+ import { getTransferSolInstruction } from "@solana-program/system";
6
+ import { address, createNoopSigner, getBase64EncodedWireTransaction, } from "@solana/kit";
7
+ import { buildAndSignClientTransaction, } from "../exact/client.js";
5
8
  import { mppChargeRequest } from "./common.js";
6
- async function broadcastAndConfirm(tx, wallet, connection, challenge, md, recentBlockhash) {
9
+ import { toAddress, toRpc } from "../compat.js";
10
+ async function broadcastAndConfirm(tx, wallet, rpc, challenge, md, lifetimeConstraint) {
7
11
  if (md?.feePayer) {
8
12
  throw new Error("push mode is not allowed with fee sponsorship");
9
13
  }
10
- const { lastValidBlockHeight } = await connection.getLatestBlockhash({
11
- commitment: "confirmed",
12
- });
13
14
  let signature;
14
15
  if (wallet.sendTransaction) {
15
16
  signature = await wallet.sendTransaction(tx);
16
17
  }
17
18
  else {
18
- signature = await connection.sendRawTransaction(tx.serialize());
19
+ const wire = getBase64EncodedWireTransaction(tx);
20
+ signature = await rpc.sendTransaction(wire, { encoding: "base64" }).send();
21
+ }
22
+ // Poll until the signature is confirmed or the blockhash expires.
23
+ const maxPolls = 60;
24
+ let confirmed = false;
25
+ for (let i = 0; i < maxPolls; i++) {
26
+ const status = await rpc
27
+ .getSignatureStatuses([signature])
28
+ .send();
29
+ if (status.value[0]?.err) {
30
+ throw new Error(`transaction failed: ${JSON.stringify(status.value[0].err)}`);
31
+ }
32
+ if (status.value[0]?.confirmationStatus === "confirmed" ||
33
+ status.value[0]?.confirmationStatus === "finalized") {
34
+ confirmed = true;
35
+ break;
36
+ }
37
+ const currentHeight = await rpc.getBlockHeight().send();
38
+ if (lifetimeConstraint.lastValidBlockHeight > 0n &&
39
+ currentHeight > lifetimeConstraint.lastValidBlockHeight) {
40
+ throw new Error("blockhash expired before confirmation");
41
+ }
42
+ await new Promise((resolve) => setTimeout(resolve, 1000));
43
+ }
44
+ if (!confirmed) {
45
+ throw new Error("transaction confirmation timed out");
19
46
  }
20
- await connection.confirmTransaction({ signature, blockhash: recentBlockhash, lastValidBlockHeight }, "confirmed");
21
47
  return {
22
48
  challenge,
23
49
  payload: { type: "signature", signature },
24
50
  };
25
51
  }
52
+ async function fetchLifetimeConstraint(rpc, supplied) {
53
+ if (supplied) {
54
+ return {
55
+ blockhash: supplied,
56
+ lastValidBlockHeight: 0n,
57
+ };
58
+ }
59
+ if (!rpc) {
60
+ throw new Error("no blockhash available");
61
+ }
62
+ const { value } = await rpc.getLatestBlockhash().send();
63
+ return {
64
+ blockhash: value.blockhash,
65
+ lastValidBlockHeight: value.lastValidBlockHeight,
66
+ };
67
+ }
26
68
  export function createMPPSolanaChargeClient(args) {
27
- const { wallet, mint, connection, broadcast = false } = args;
28
- if (broadcast && !connection) {
29
- throw new Error("connection is required when broadcast is true");
69
+ const mint = toAddress(args.mint);
70
+ const defaultTokenProgram = args.tokenProgramId
71
+ ? toAddress(args.tokenProgramId)
72
+ : undefined;
73
+ const rpc = args.rpc ? toRpc(args.rpc) : undefined;
74
+ const { wallet, broadcast = false } = args;
75
+ if (broadcast && !rpc) {
76
+ throw new Error("rpc is required when broadcast is true");
30
77
  }
31
78
  return async (challenge) => {
32
79
  if (challenge.method !== "solana")
@@ -50,69 +97,60 @@ export function createMPPSolanaChargeClient(args) {
50
97
  exec: async () => {
51
98
  const md = request.methodDetails;
52
99
  const amount = BigInt(request.amount);
53
- const recipientKey = new PublicKey(request.recipient);
54
- const feePayerKey = md?.feePayer === true ? md.feePayerKey : undefined;
55
- let recentBlockhash;
56
- if (md?.recentBlockhash) {
57
- recentBlockhash = md.recentBlockhash;
58
- }
59
- else if (connection) {
60
- recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
61
- }
62
- else {
63
- throw new Error("no blockhash available");
64
- }
100
+ const recipientKey = address(request.recipient);
101
+ const feePayerKey = md?.feePayer === true && md.feePayerKey
102
+ ? address(md.feePayerKey)
103
+ : undefined;
104
+ const lifetimeConstraint = await fetchLifetimeConstraint(rpc, md?.recentBlockhash);
65
105
  let decimals;
66
106
  if (md?.decimals !== undefined) {
67
107
  decimals = md.decimals;
68
108
  }
69
- else if (connection) {
70
- const mintInfo = await getMint(connection, mint);
71
- decimals = mintInfo.decimals;
109
+ else if (rpc) {
110
+ const mintInfo = await fetchMint(rpc, mint);
111
+ decimals = mintInfo.data.decimals;
72
112
  }
73
113
  else {
74
114
  throw new Error("no decimals available");
75
115
  }
76
116
  const tokenProgramId = md?.tokenProgram
77
- ? new PublicKey(md.tokenProgram)
78
- : (args.tokenProgramId ?? TOKEN_PROGRAM_ID);
79
- const sourceAccount = getAssociatedTokenAddressSync(mint, wallet.publicKey, false, tokenProgramId);
80
- const receiverAccount = getAssociatedTokenAddressSync(mint, recipientKey, false, tokenProgramId);
117
+ ? address(md.tokenProgram)
118
+ : (defaultTokenProgram ?? TOKEN_PROGRAM_ADDRESS);
119
+ const [sourceAccount] = await findAssociatedTokenPda({
120
+ mint,
121
+ owner: wallet.publicKey,
122
+ tokenProgram: tokenProgramId,
123
+ });
124
+ const [receiverAccount] = await findAssociatedTokenPda({
125
+ mint,
126
+ owner: recipientKey,
127
+ tokenProgram: tokenProgramId,
128
+ });
129
+ const walletSigner = createNoopSigner(wallet.publicKey);
81
130
  const instructions = [
82
- ComputeBudgetProgram.setComputeUnitLimit({ units: 200_000 }),
83
- ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 }),
84
- createTransferCheckedInstruction(sourceAccount, mint, receiverAccount, wallet.publicKey, amount, decimals, undefined, tokenProgramId),
131
+ getSetComputeUnitLimitInstruction({ units: 200_000 }),
132
+ getSetComputeUnitPriceInstruction({ microLamports: 1n }),
133
+ getTransferCheckedInstruction({
134
+ source: sourceAccount,
135
+ mint,
136
+ destination: receiverAccount,
137
+ authority: walletSigner,
138
+ amount,
139
+ decimals,
140
+ }, { programAddress: tokenProgramId }),
85
141
  ];
86
- const payerKey = feePayerKey
87
- ? new PublicKey(feePayerKey)
88
- : wallet.publicKey;
89
- let tx;
90
- if (wallet.buildTransaction) {
91
- tx = await wallet.buildTransaction(instructions, recentBlockhash);
92
- }
93
- else {
94
- const message = new TransactionMessage({
95
- instructions,
96
- payerKey,
97
- recentBlockhash,
98
- }).compileToV0Message();
99
- tx = new VersionedTransaction(message);
100
- }
101
- if (wallet.partiallySignTransaction) {
102
- tx = await wallet.partiallySignTransaction(tx);
103
- }
142
+ const payerKey = feePayerKey ?? wallet.publicKey;
143
+ const tx = await buildAndSignClientTransaction(wallet, instructions, payerKey, lifetimeConstraint);
104
144
  if (broadcast) {
105
- if (!connection)
106
- throw new Error("connection is required");
107
- return broadcastAndConfirm(tx, wallet, connection, challenge, md, recentBlockhash);
145
+ if (!rpc)
146
+ throw new Error("rpc is required");
147
+ return broadcastAndConfirm(tx, wallet, rpc, challenge, md, lifetimeConstraint);
108
148
  }
109
- const wireBytes = tx.serialize();
110
- const base64Transaction = btoa(String.fromCharCode.apply(null, [...wireBytes]));
111
149
  return {
112
150
  challenge,
113
151
  payload: {
114
152
  type: "transaction",
115
- transaction: base64Transaction,
153
+ transaction: getBase64EncodedWireTransaction(tx),
116
154
  },
117
155
  };
118
156
  },
@@ -120,9 +158,10 @@ export function createMPPSolanaChargeClient(args) {
120
158
  };
121
159
  }
122
160
  export function createMPPSolanaNativeChargeClient(args) {
123
- const { wallet, connection, broadcast = false } = args;
124
- if (broadcast && !connection) {
125
- throw new Error("connection is required when broadcast is true");
161
+ const rpc = args.rpc ? toRpc(args.rpc) : undefined;
162
+ const { wallet, broadcast = false } = args;
163
+ if (broadcast && !rpc) {
164
+ throw new Error("rpc is required when broadcast is true");
126
165
  }
127
166
  return async (challenge) => {
128
167
  if (challenge.method !== "solana")
@@ -146,57 +185,33 @@ export function createMPPSolanaNativeChargeClient(args) {
146
185
  exec: async () => {
147
186
  const md = request.methodDetails;
148
187
  const amount = BigInt(request.amount);
149
- const recipientKey = new PublicKey(request.recipient);
150
- const feePayerKey = md?.feePayer === true ? md.feePayerKey : undefined;
151
- let recentBlockhash;
152
- if (md?.recentBlockhash) {
153
- recentBlockhash = md.recentBlockhash;
154
- }
155
- else if (connection) {
156
- recentBlockhash = (await connection.getLatestBlockhash()).blockhash;
157
- }
158
- else {
159
- throw new Error("no blockhash available");
160
- }
188
+ const recipientKey = address(request.recipient);
189
+ const feePayerKey = md?.feePayer === true && md.feePayerKey
190
+ ? address(md.feePayerKey)
191
+ : undefined;
192
+ const lifetimeConstraint = await fetchLifetimeConstraint(rpc, md?.recentBlockhash);
193
+ const walletSigner = createNoopSigner(wallet.publicKey);
161
194
  const instructions = [
162
- ComputeBudgetProgram.setComputeUnitLimit({ units: 200_000 }),
163
- ComputeBudgetProgram.setComputeUnitPrice({ microLamports: 1 }),
164
- SystemProgram.transfer({
165
- fromPubkey: wallet.publicKey,
166
- toPubkey: recipientKey,
167
- lamports: amount,
195
+ getSetComputeUnitLimitInstruction({ units: 200_000 }),
196
+ getSetComputeUnitPriceInstruction({ microLamports: 1n }),
197
+ getTransferSolInstruction({
198
+ source: walletSigner,
199
+ destination: recipientKey,
200
+ amount,
168
201
  }),
169
202
  ];
170
- const payerKey = feePayerKey
171
- ? new PublicKey(feePayerKey)
172
- : wallet.publicKey;
173
- let tx;
174
- if (wallet.buildTransaction) {
175
- tx = await wallet.buildTransaction(instructions, recentBlockhash);
176
- }
177
- else {
178
- const message = new TransactionMessage({
179
- instructions,
180
- payerKey,
181
- recentBlockhash,
182
- }).compileToV0Message();
183
- tx = new VersionedTransaction(message);
184
- }
185
- if (wallet.partiallySignTransaction) {
186
- tx = await wallet.partiallySignTransaction(tx);
187
- }
203
+ const payerKey = feePayerKey ?? wallet.publicKey;
204
+ const tx = await buildAndSignClientTransaction(wallet, instructions, payerKey, lifetimeConstraint);
188
205
  if (broadcast) {
189
- if (!connection)
190
- throw new Error("connection is required");
191
- return broadcastAndConfirm(tx, wallet, connection, challenge, md, recentBlockhash);
206
+ if (!rpc)
207
+ throw new Error("rpc is required");
208
+ return broadcastAndConfirm(tx, wallet, rpc, challenge, md, lifetimeConstraint);
192
209
  }
193
- const wireBytes = tx.serialize();
194
- const base64Transaction = btoa(String.fromCharCode.apply(null, [...wireBytes]));
195
210
  return {
196
211
  challenge,
197
212
  payload: {
198
213
  type: "transaction",
199
- transaction: base64Transaction,
214
+ transaction: getBase64EncodedWireTransaction(tx),
200
215
  },
201
216
  };
202
217
  },
@@ -1,4 +1,4 @@
1
- export declare const solanaChargeMethodDetails: import("arktype/internal/methods/object.ts").ObjectType<{
1
+ export declare const solanaChargeMethodDetails: import("arktype/internal/variants/object.ts").ObjectType<{
2
2
  network?: string;
3
3
  decimals?: number;
4
4
  tokenProgram?: string;
@@ -12,7 +12,7 @@ export declare const solanaChargeMethodDetails: import("arktype/internal/methods
12
12
  }[];
13
13
  }, {}>;
14
14
  export type solanaChargeMethodDetails = typeof solanaChargeMethodDetails.infer;
15
- export declare const mppChargeRequest: import("arktype/internal/methods/object.ts").ObjectType<{
15
+ export declare const mppChargeRequest: import("arktype/internal/variants/object.ts").ObjectType<{
16
16
  amount: string;
17
17
  currency: string;
18
18
  recipient: string;
@@ -33,7 +33,7 @@ export declare const mppChargeRequest: import("arktype/internal/methods/object.t
33
33
  };
34
34
  }, {}>;
35
35
  export type mppChargeRequest = typeof mppChargeRequest.infer;
36
- export declare const chargeCredentialPayload: import("arktype/internal/methods/object.ts").ObjectType<{
36
+ export declare const chargeCredentialPayload: import("arktype/internal/variants/object.ts").ObjectType<{
37
37
  type: "transaction";
38
38
  transaction: string;
39
39
  } | {
@@ -1,13 +1,19 @@
1
1
  import type { MPPMethodHandler } from "@faremeter/types/mpp";
2
2
  import { type SolanaCAIP2Network } from "@faremeter/info/solana";
3
- import { type Rpc, type SolanaRpcApi } from "@solana/kit";
4
- import { Keypair, PublicKey } from "@solana/web3.js";
3
+ import { type Address, type KeyPairSigner, type Rpc, type SolanaRpcApi } from "@solana/kit";
5
4
  import type { ReplayStore } from "./replay.js";
6
5
  export type CreateMPPSolanaChargeHandlerArgs = {
7
6
  network: string | SolanaCAIP2Network;
8
- rpc: Rpc<SolanaRpcApi>;
9
- feePayerKeypair?: Keypair;
10
- mint: PublicKey;
7
+ rpc: Rpc<SolanaRpcApi> | string;
8
+ feePayerSigner?: KeyPairSigner | {
9
+ secretKey: Uint8Array;
10
+ publicKey: {
11
+ toBase58(): string;
12
+ };
13
+ };
14
+ mint: Address | {
15
+ toBase58(): string;
16
+ };
11
17
  replayStore: ReplayStore;
12
18
  realm: string;
13
19
  secretKey: Uint8Array;
@@ -18,8 +24,13 @@ export type CreateMPPSolanaChargeHandlerArgs = {
18
24
  export declare function createMPPSolanaChargeHandler(args: CreateMPPSolanaChargeHandlerArgs): Promise<MPPMethodHandler>;
19
25
  export type CreateMPPSolanaNativeChargeHandlerArgs = {
20
26
  network: string | SolanaCAIP2Network;
21
- rpc: Rpc<SolanaRpcApi>;
22
- feePayerKeypair?: Keypair;
27
+ rpc: Rpc<SolanaRpcApi> | string;
28
+ feePayerSigner?: KeyPairSigner | {
29
+ secretKey: Uint8Array;
30
+ publicKey: {
31
+ toBase58(): string;
32
+ };
33
+ };
23
34
  replayStore: ReplayStore;
24
35
  realm: string;
25
36
  secretKey: Uint8Array;
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/charge/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAKjB,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAKL,KAAK,GAAG,EAER,KAAK,YAAY,EAElB,MAAM,aAAa,CAAC;AAMrB,OAAO,EAAE,OAAO,EAAoB,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAIvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAiD5C,MAAM,MAAM,gCAAgC,GAAG;IAC7C,OAAO,EAAE,MAAM,GAAG,kBAAkB,CAAC;IACrC,GAAG,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,IAAI,EAAE,SAAS,CAAC;IAChB,WAAW,EAAE,WAAW,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,UAAU,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAsGF,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,gCAAgC,GACrC,OAAO,CAAC,gBAAgB,CAAC,CAoN3B;AAID,MAAM,MAAM,sCAAsC,GAAG;IACnD,OAAO,EAAE,MAAM,GAAG,kBAAkB,CAAC;IACrC,GAAG,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,WAAW,EAAE,WAAW,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,UAAU,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,wBAAsB,kCAAkC,CACtD,IAAI,EAAE,sCAAsC,GAC3C,OAAO,CAAC,gBAAgB,CAAC,CA6M3B"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/charge/server.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAKjB,MAAM,sBAAsB,CAAC;AAQ9B,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAIL,KAAK,OAAO,EACZ,KAAK,aAAa,EAClB,KAAK,GAAG,EAER,KAAK,YAAY,EAElB,MAAM,aAAa,CAAC;AAWrB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAkD5C,MAAM,MAAM,gCAAgC,GAAG;IAC7C,OAAO,EAAE,MAAM,GAAG,kBAAkB,CAAC;IACrC,GAAG,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,MAAM,CAAC;IAChC,cAAc,CAAC,EACX,aAAa,GACb;QAAE,SAAS,EAAE,UAAU,CAAC;QAAC,SAAS,EAAE;YAAE,QAAQ,IAAI,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;IACjE,IAAI,EAAE,OAAO,GAAG;QAAE,QAAQ,IAAI,MAAM,CAAA;KAAE,CAAC;IACvC,WAAW,EAAE,WAAW,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,UAAU,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAsGF,wBAAsB,4BAA4B,CAChD,IAAI,EAAE,gCAAgC,GACrC,OAAO,CAAC,gBAAgB,CAAC,CA+M3B;AAID,MAAM,MAAM,sCAAsC,GAAG;IACnD,OAAO,EAAE,MAAM,GAAG,kBAAkB,CAAC;IACrC,GAAG,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,MAAM,CAAC;IAChC,cAAc,CAAC,EACX,aAAa,GACb;QAAE,SAAS,EAAE,UAAU,CAAC;QAAC,SAAS,EAAE;YAAE,QAAQ,IAAI,MAAM,CAAA;SAAE,CAAA;KAAE,CAAC;IACjE,WAAW,EAAE,WAAW,CAAC;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,UAAU,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAEF,wBAAsB,kCAAkC,CACtD,IAAI,EAAE,sCAAsC,GAC3C,OAAO,CAAC,gBAAgB,CAAC,CAwM3B"}
@@ -2,12 +2,13 @@ import { encodeBase64URL, canonicalizeSortedJSON, decodeBase64URL, } from "@fare
2
2
  import { isValidationError } from "@faremeter/types";
3
3
  import { lookupX402Network, caip2ToCluster, } from "@faremeter/info/solana";
4
4
  import { fetchMint } from "@solana-program/token";
5
- import { address, decompileTransactionMessage, getBase64Encoder, getCompiledTransactionMessageDecoder, } from "@solana/kit";
5
+ import { decompileTransactionMessage, getBase64Encoder, getCompiledTransactionMessageDecoder, } from "@solana/kit";
6
6
  import { getBase64EncodedWireTransaction, getTransactionDecoder, partiallySignTransaction, } from "@solana/transactions";
7
- import { Keypair, LAMPORTS_PER_SOL, PublicKey } from "@solana/web3.js";
7
+ const LAMPORTS_PER_SOL = 1_000_000_000;
8
8
  import { mppChargeRequest, chargeCredentialPayload } from "./common.js";
9
9
  import { verifyChargeTransaction, verifyNativeChargeTransaction, } from "./verify.js";
10
10
  import { logger } from "./logger.js";
11
+ import { toAddress, toKeyPairSigner, toRpc } from "../compat.js";
11
12
  async function generateChallengeID(secret, params) {
12
13
  const slots = [
13
14
  params.realm,
@@ -106,26 +107,25 @@ const decodeWireTransaction = (base64Transaction) => {
106
107
  };
107
108
  };
108
109
  export async function createMPPSolanaChargeHandler(args) {
109
- const { network, rpc, feePayerKeypair, mint, replayStore, realm, secretKey, maxRetries = 30, retryDelayMs = 1000, maxPriorityFee = 100_000, } = args;
110
+ const { network, replayStore, realm, secretKey, maxRetries = 30, retryDelayMs = 1000, maxPriorityFee = 100_000, } = args;
111
+ const rpc = toRpc(args.rpc);
112
+ const mint = toAddress(args.mint);
113
+ const feePayerSigner = args.feePayerSigner
114
+ ? await toKeyPairSigner(args.feePayerSigner)
115
+ : undefined;
110
116
  const solanaNetwork = lookupX402Network(network);
111
- const mintAddress = mint.toBase58();
112
- const hasFeePayerKeypair = feePayerKeypair !== undefined;
113
- const feePayerAddress = feePayerKeypair?.publicKey.toBase58();
114
- const mintInfo = await fetchMint(rpc, address(mintAddress));
117
+ const mintAddress = mint;
118
+ const hasFeePayer = feePayerSigner !== undefined;
119
+ const feePayerAddress = feePayerSigner?.address;
120
+ const mintInfo = await fetchMint(rpc, mint);
115
121
  const tokenProgram = mintInfo.programAddress;
116
- const feePayerSigner = hasFeePayerKeypair
117
- ? await (async () => {
118
- const { createKeyPairSignerFromBytes } = await import("@solana/kit");
119
- return createKeyPairSignerFromBytes(feePayerKeypair.secretKey);
120
- })()
121
- : null;
122
122
  const getChallenge = async (intent, pricing, _resourceURL, opts) => {
123
123
  const methodDetails = {
124
124
  network: caip2ToCluster(solanaNetwork.caip2) ?? solanaNetwork.caip2,
125
125
  decimals: mintInfo.data.decimals,
126
126
  tokenProgram: tokenProgram,
127
127
  };
128
- if (hasFeePayerKeypair && feePayerAddress) {
128
+ if (hasFeePayer && feePayerAddress) {
129
129
  const latestBlockhash = await rpc.getLatestBlockhash().send();
130
130
  methodDetails.feePayer = true;
131
131
  methodDetails.feePayerKey = feePayerAddress;
@@ -253,22 +253,20 @@ export async function createMPPSolanaChargeHandler(args) {
253
253
  }
254
254
  const SOL_DECIMALS = Math.log10(LAMPORTS_PER_SOL);
255
255
  export async function createMPPSolanaNativeChargeHandler(args) {
256
- const { network, rpc, feePayerKeypair, replayStore, realm, secretKey, maxRetries = 30, retryDelayMs = 1000, maxPriorityFee = 100_000, } = args;
256
+ const { network, replayStore, realm, secretKey, maxRetries = 30, retryDelayMs = 1000, maxPriorityFee = 100_000, } = args;
257
+ const rpc = toRpc(args.rpc);
258
+ const feePayerSigner = args.feePayerSigner
259
+ ? await toKeyPairSigner(args.feePayerSigner)
260
+ : undefined;
257
261
  const solanaNetwork = lookupX402Network(network);
258
- const hasFeePayerKeypair = feePayerKeypair !== undefined;
259
- const feePayerAddress = feePayerKeypair?.publicKey.toBase58();
260
- const feePayerSigner = hasFeePayerKeypair
261
- ? await (async () => {
262
- const { createKeyPairSignerFromBytes } = await import("@solana/kit");
263
- return createKeyPairSignerFromBytes(feePayerKeypair.secretKey);
264
- })()
265
- : null;
262
+ const hasFeePayer = feePayerSigner !== undefined;
263
+ const feePayerAddress = feePayerSigner?.address;
266
264
  const getChallenge = async (intent, pricing, _resourceURL, opts) => {
267
265
  const methodDetails = {
268
266
  network: caip2ToCluster(solanaNetwork.caip2) ?? solanaNetwork.caip2,
269
267
  decimals: SOL_DECIMALS,
270
268
  };
271
- if (hasFeePayerKeypair && feePayerAddress) {
269
+ if (hasFeePayer && feePayerAddress) {
272
270
  const latestBlockhash = await rpc.getLatestBlockhash().send();
273
271
  methodDetails.feePayer = true;
274
272
  methodDetails.feePayerKey = feePayerAddress;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Backwards-compatibility helpers for callers still using
3
+ * @solana/web3.js v1 types (PublicKey, Keypair).
4
+ *
5
+ * These use duck-typing so payment-solana never imports v1 at
6
+ * runtime. The v1 package stays out of our dependency tree while
7
+ * callers who still have it can pass v1 objects directly.
8
+ *
9
+ * Every helper logs a one-shot deprecation warning the first time
10
+ * the v1 code-path is taken.
11
+ */
12
+ import { type Address, type KeyPairSigner, type Rpc, type SolanaRpcApi } from "@solana/kit";
13
+ /** Duck-type for @solana/web3.js v1 PublicKey. */
14
+ interface PublicKeyLike {
15
+ toBase58(): string;
16
+ }
17
+ /** Duck-type for @solana/web3.js v1 Keypair. */
18
+ interface KeypairLike {
19
+ secretKey: Uint8Array;
20
+ publicKey: PublicKeyLike;
21
+ }
22
+ /**
23
+ * Accepts an {@link Address} string or a v1 `PublicKey` and returns
24
+ * a kit `Address`.
25
+ */
26
+ export declare function toAddress(input: Address | PublicKeyLike): Address;
27
+ /**
28
+ * Accepts a kit `KeyPairSigner`, a 64-byte secret key, or a v1
29
+ * `Keypair` and returns a `KeyPairSigner`.
30
+ */
31
+ export declare function toKeyPairSigner(input: KeyPairSigner | Uint8Array | KeypairLike): Promise<KeyPairSigner>;
32
+ /**
33
+ * Accepts an `Rpc<SolanaRpcApi>` or a URL string and returns
34
+ * an `Rpc<SolanaRpcApi>`.
35
+ */
36
+ export declare function toRpc(input: Rpc<SolanaRpcApi> | string): Rpc<SolanaRpcApi>;
37
+ export {};
38
+ //# sourceMappingURL=compat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compat.d.ts","sourceRoot":"","sources":["../../src/compat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,EAIL,KAAK,OAAO,EACZ,KAAK,aAAa,EAClB,KAAK,GAAG,EACR,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AAQrB,kDAAkD;AAClD,UAAU,aAAa;IACrB,QAAQ,IAAI,MAAM,CAAC;CACpB;AAED,gDAAgD;AAChD,UAAU,WAAW;IACnB,SAAS,EAAE,UAAU,CAAC;IACtB,SAAS,EAAE,aAAa,CAAC;CAC1B;AAmBD;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,GAAG,OAAO,CAiBjE;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,aAAa,GAAG,UAAU,GAAG,WAAW,GAC9C,OAAO,CAAC,aAAa,CAAC,CA+BxB;AAED;;;GAGG;AACH,wBAAgB,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,YAAY,CAAC,GAAG,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC,CAK1E"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Backwards-compatibility helpers for callers still using
3
+ * @solana/web3.js v1 types (PublicKey, Keypair).
4
+ *
5
+ * These use duck-typing so payment-solana never imports v1 at
6
+ * runtime. The v1 package stays out of our dependency tree while
7
+ * callers who still have it can pass v1 objects directly.
8
+ *
9
+ * Every helper logs a one-shot deprecation warning the first time
10
+ * the v1 code-path is taken.
11
+ */
12
+ import { address, createKeyPairSignerFromBytes, createSolanaRpc, } from "@solana/kit";
13
+ import { getLogger } from "@faremeter/logs";
14
+ const logger = await getLogger(["faremeter", "payment-solana", "compat"]);
15
+ let warnedPublicKey = false;
16
+ let warnedKeypair = false;
17
+ function isPublicKeyLike(v) {
18
+ return (typeof v === "object" &&
19
+ v !== null &&
20
+ typeof v.toBase58 === "function");
21
+ }
22
+ function isKeypairLike(v) {
23
+ return (typeof v === "object" &&
24
+ v !== null &&
25
+ v.secretKey instanceof Uint8Array &&
26
+ isPublicKeyLike(v.publicKey));
27
+ }
28
+ /**
29
+ * Accepts an {@link Address} string or a v1 `PublicKey` and returns
30
+ * a kit `Address`.
31
+ */
32
+ export function toAddress(input) {
33
+ if (typeof input === "string") {
34
+ return address(input);
35
+ }
36
+ if (isPublicKeyLike(input)) {
37
+ if (!warnedPublicKey) {
38
+ logger.warning("Passing a @solana/web3.js PublicKey is deprecated — " +
39
+ "use a plain address string or @solana/kit address() " +
40
+ "instead. v1 compatibility will be removed in a " +
41
+ "future release.");
42
+ warnedPublicKey = true;
43
+ }
44
+ return address(input.toBase58());
45
+ }
46
+ throw new TypeError("expected an Address string or PublicKey");
47
+ }
48
+ /**
49
+ * Accepts a kit `KeyPairSigner`, a 64-byte secret key, or a v1
50
+ * `Keypair` and returns a `KeyPairSigner`.
51
+ */
52
+ export async function toKeyPairSigner(input) {
53
+ // Already a KeyPairSigner (has signMessages method)
54
+ if (typeof input === "object" &&
55
+ input !== null &&
56
+ "address" in input &&
57
+ "signMessages" in input) {
58
+ return input;
59
+ }
60
+ // Raw secret key bytes
61
+ if (input instanceof Uint8Array) {
62
+ return createKeyPairSignerFromBytes(input);
63
+ }
64
+ // v1 Keypair duck-type
65
+ if (isKeypairLike(input)) {
66
+ if (!warnedKeypair) {
67
+ logger.warning("Passing a @solana/web3.js Keypair is deprecated — " +
68
+ "use a Uint8Array secret key or @solana/kit " +
69
+ "KeyPairSigner instead. v1 compatibility will be " +
70
+ "removed in a future release.");
71
+ warnedKeypair = true;
72
+ }
73
+ return createKeyPairSignerFromBytes(input.secretKey);
74
+ }
75
+ throw new TypeError("expected a Uint8Array, KeyPairSigner, or Keypair");
76
+ }
77
+ /**
78
+ * Accepts an `Rpc<SolanaRpcApi>` or a URL string and returns
79
+ * an `Rpc<SolanaRpcApi>`.
80
+ */
81
+ export function toRpc(input) {
82
+ if (typeof input === "string") {
83
+ return createSolanaRpc(input);
84
+ }
85
+ return input;
86
+ }
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env pnpm tsx
2
+ export {};
3
+ //# sourceMappingURL=compat.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compat.test.d.ts","sourceRoot":"","sources":["../../src/compat.test.ts"],"names":[],"mappings":""}