@faremeter/payment-solana 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/exact/client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,cAAc,EAEf,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAYjE,OAAO,EAEL,UAAU,EACV,SAAS,EACT,sBAAsB,EAEtB,oBAAoB,EAErB,MAAM,iBAAiB,CAAC;AAKzB,MAAM,MAAM,MAAM,GAAG;IACnB,OAAO,EAAE,MAAM,GAAG,kBAAkB,CAAC;IACrC,SAAS,EAAE,SAAS,CAAC;IACrB,gBAAgB,CAAC,EAAE,CACjB,YAAY,EAAE,sBAAsB,EAAE,EACtC,eAAe,EAAE,MAAM,KACpB,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnC,wBAAwB,CAAC,EAAE,CACzB,EAAE,EAAE,oBAAoB,KACrB,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnC,iBAAiB,CAAC,EAAE,CAClB,EAAE,EAAE,oBAAoB,KACrB,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnC,eAAe,CAAC,EAAE,CAAC,EAAE,EAAE,oBAAoB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACjE,CAAC;AAEF,UAAU,oCAAoC;IAC5C,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,wBAAwB,CAAC,EAAE,SAAS,CAAC;CACtC;AAiFD,UAAU,2BAA2B;IACnC,KAAK,CAAC,EAAE,oCAAoC,CAAC;IAC7C,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,EAAE;QACT,wBAAwB,CAAC,EAAE,OAAO,CAAC;KACpC,CAAC;CACH;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,SAAS,EACf,UAAU,CAAC,EAAE,UAAU,EACvB,OAAO,CAAC,EAAE,2BAA2B,GACpC,cAAc,CA2LhB"}
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/exact/client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAEV,cAAc,EAEf,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAajE,OAAO,EAEL,UAAU,EACV,SAAS,EACT,sBAAsB,EAEtB,oBAAoB,EAErB,MAAM,iBAAiB,CAAC;AAKzB,MAAM,MAAM,MAAM,GAAG;IACnB,OAAO,EAAE,MAAM,GAAG,kBAAkB,CAAC;IACrC,SAAS,EAAE,SAAS,CAAC;IACrB,gBAAgB,CAAC,EAAE,CACjB,YAAY,EAAE,sBAAsB,EAAE,EACtC,eAAe,EAAE,MAAM,KACpB,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnC,wBAAwB,CAAC,EAAE,CACzB,EAAE,EAAE,oBAAoB,KACrB,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnC,iBAAiB,CAAC,EAAE,CAClB,EAAE,EAAE,oBAAoB,KACrB,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACnC,eAAe,CAAC,EAAE,CAAC,EAAE,EAAE,oBAAoB,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACjE,CAAC;AAEF,UAAU,oCAAoC;IAC5C,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,wBAAwB,CAAC,EAAE,SAAS,CAAC;CACtC;AAsFD,UAAU,2BAA2B;IACnC,KAAK,CAAC,EAAE,oCAAoC,CAAC;IAC7C,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,EAAE;QACT,wBAAwB,CAAC,EAAE,OAAO,CAAC;KACpC,CAAC;CACH;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,SAAS,EACf,UAAU,CAAC,EAAE,UAAU,EACvB,OAAO,CAAC,EAAE,2BAA2B,GACpC,cAAc,CAuMhB"}
@@ -1,5 +1,5 @@
1
1
  import { isValidationError, throwValidationError } from "@faremeter/types";
2
- import { createAssociatedTokenAccountIdempotentInstruction, createTransferCheckedInstruction, getAssociatedTokenAddressSync, getMint, } from "@solana/spl-token";
2
+ import { createAssociatedTokenAccountIdempotentInstruction, createTransferCheckedInstruction, getAssociatedTokenAddressSync, getMint, TOKEN_PROGRAM_ID, } from "@solana/spl-token";
3
3
  import { getBase64EncodedWireTransaction, } from "@solana/transactions";
4
4
  import { ComputeBudgetProgram, Connection, PublicKey, TransactionInstruction, TransactionMessage, VersionedTransaction, Keypair, } from "@solana/web3.js";
5
5
  import { PaymentRequirementsExtra } from "./facilitator.js";
@@ -53,6 +53,9 @@ async function extractMetadata(args) {
53
53
  wallet.sendTransaction) {
54
54
  paymentMode = PaymentMode.SettlementAccount;
55
55
  }
56
+ const tokenProgramId = extra.tokenProgram
57
+ ? new PublicKey(extra.tokenProgram)
58
+ : (options?.token?.programId ?? TOKEN_PROGRAM_ID);
56
59
  return {
57
60
  recentBlockhash,
58
61
  decimals,
@@ -60,6 +63,7 @@ async function extractMetadata(args) {
60
63
  amount,
61
64
  payerKey,
62
65
  paymentMode,
66
+ tokenProgramId,
63
67
  };
64
68
  }
65
69
  /**
@@ -75,7 +79,7 @@ async function extractMetadata(args) {
75
79
  * @returns A PaymentHandler function for use with the x402 client
76
80
  */
77
81
  export function createPaymentHandler(wallet, mint, connection, options) {
78
- const getAssociatedTokenAddressSyncRest = generateGetAssociatedTokenAddressSyncRest(options?.token ?? {});
82
+ const tokenConfig = options?.token ?? {};
79
83
  let hasWarnedAboutDeprecation = false;
80
84
  const signTransaction = async (tx) => {
81
85
  if (wallet.partiallySignTransaction) {
@@ -95,13 +99,17 @@ export function createPaymentHandler(wallet, mint, connection, options) {
95
99
  const compatibleRequirements = accepts.filter(isMatchingRequirement);
96
100
  const res = compatibleRequirements.map((requirements) => {
97
101
  const exec = async () => {
98
- const { recentBlockhash, decimals, payTo, amount, payerKey, paymentMode, } = await extractMetadata({
102
+ const { recentBlockhash, decimals, payTo, amount, payerKey, paymentMode, tokenProgramId, } = await extractMetadata({
99
103
  connection,
100
104
  mint,
101
105
  requirements,
102
106
  wallet,
103
107
  options,
104
108
  });
109
+ const getAssociatedTokenAddressSyncRest = generateGetAssociatedTokenAddressSyncRest({
110
+ ...tokenConfig,
111
+ programId: tokenProgramId,
112
+ });
105
113
  const instructions = [
106
114
  ComputeBudgetProgram.setComputeUnitLimit({
107
115
  units: 50_000,
@@ -114,7 +122,7 @@ export function createPaymentHandler(wallet, mint, connection, options) {
114
122
  switch (paymentMode) {
115
123
  case PaymentMode.ToSpec: {
116
124
  const receiverAccount = getAssociatedTokenAddressSync(mint, payTo, ...getAssociatedTokenAddressSyncRest);
117
- instructions.push(createTransferCheckedInstruction(sourceAccount, mint, receiverAccount, wallet.publicKey, amount, decimals));
125
+ instructions.push(createTransferCheckedInstruction(sourceAccount, mint, receiverAccount, wallet.publicKey, amount, decimals, undefined, tokenProgramId));
118
126
  let tx;
119
127
  if (wallet.buildTransaction) {
120
128
  tx = await wallet.buildTransaction(instructions, recentBlockhash);
@@ -140,7 +148,7 @@ export function createPaymentHandler(wallet, mint, connection, options) {
140
148
  case PaymentMode.SettlementAccount: {
141
149
  const settleKeypair = Keypair.generate();
142
150
  const settleATA = getAssociatedTokenAddressSync(mint, settleKeypair.publicKey, ...getAssociatedTokenAddressSyncRest);
143
- instructions.push(createAssociatedTokenAccountIdempotentInstruction(wallet.publicKey, settleATA, settleKeypair.publicKey, mint), createTransferCheckedInstruction(sourceAccount, mint, settleATA, wallet.publicKey, amount, decimals));
151
+ instructions.push(createAssociatedTokenAccountIdempotentInstruction(wallet.publicKey, settleATA, settleKeypair.publicKey, mint, tokenProgramId, tokenConfig.associatedTokenProgramId), createTransferCheckedInstruction(sourceAccount, mint, settleATA, wallet.publicKey, amount, decimals, undefined, tokenProgramId));
144
152
  let tx;
145
153
  if (wallet.buildTransaction) {
146
154
  tx = await wallet.buildTransaction(instructions, recentBlockhash);
@@ -32,6 +32,7 @@ export declare const PaymentRequirementsExtra: import("arktype/internal/methods/
32
32
  feePayer: string;
33
33
  decimals?: number;
34
34
  recentBlockhash?: string;
35
+ tokenProgram?: string;
35
36
  features?: {
36
37
  xSettlementAccountSupported?: boolean;
37
38
  };
@@ -1 +1 @@
1
- {"version":3,"file":"facilitator.d.ts","sourceRoot":"","sources":["../../../src/exact/facilitator.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EAExB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAML,KAAK,kBAAkB,EACxB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAYL,KAAK,GAAG,EACR,KAAK,YAAY,EAElB,MAAM,aAAa,CAAC;AAOrB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGrD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAalC,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,GAAG,kBAAkB,CAAC;IACrC,GAAG,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;IACzB,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC;IAChD,YAAY,EAAE,uBAAuB,CAAC;IACtC,OAAO,EAAE,kBAAkB,CAAC;IAC5B,MAAM,EAAE,OAAO,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,gBAAgB,CAAC,QAAQ,IAAI,YAAY,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC;AAE/E,MAAM,MAAM,iBAAiB,CAAC,QAAQ,IAAI,CACxC,IAAI,EAAE,gBAAgB,CAAC,QAAQ,CAAC,KAC7B,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEvC,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,EAAE,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;IACpD,WAAW,CAAC,EAAE,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;CACrD;AAED,eAAO,MAAM,gCAAgC;;MAE3C,CAAC;AAEH,MAAM,MAAM,gCAAgC,GAC1C,OAAO,gCAAgC,CAAC,KAAK,CAAC;AAEhD,eAAO,MAAM,wBAAwB;;;;;;;MAKnC,CAAC;AAEH,UAAU,kBAAkB;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IAGtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE;QACT,wBAAwB,CAAC,EAAE,OAAO,CAAC;QACnC,oBAAoB,CAAC,EAAE,OAAO,CAAC;KAChC,CAAC;IACF,KAAK,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACrC;AASD,eAAO,MAAM,yBAAyB;;;;;MAEpC,CAAC;AACH,MAAM,MAAM,yBAAyB,GAAG,OAAO,yBAAyB,CAAC,KAAK,CAAC;AAE/E,eAAO,MAAM,+BAA+B;;;;MAM1C,CAAC;AACH,MAAM,MAAM,+BAA+B,GACzC,OAAO,+BAA+B,CAAC,KAAK,CAAC;AAE/C,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,gBAAgB,UAY3D;AAiDD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,wBAAwB,GACnC,SAAS,MAAM,GAAG,kBAAkB,EACpC,KAAK,GAAG,CAAC,YAAY,CAAC,EACtB,iBAAiB,OAAO,EACxB,MAAM,SAAS,EACf,SAAS,kBAAkB,KAC1B,OAAO,CAAC,kBAAkB,CAub5B,CAAC"}
1
+ {"version":3,"file":"facilitator.d.ts","sourceRoot":"","sources":["../../../src/exact/facilitator.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,uBAAuB,EAC5B,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EACvB,KAAK,kBAAkB,EAExB,MAAM,yBAAyB,CAAC;AAEjC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AACvE,OAAO,EAML,KAAK,kBAAkB,EACxB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EACL,SAAS,EAIV,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAYL,KAAK,GAAG,EACR,KAAK,YAAY,EAElB,MAAM,aAAa,CAAC;AAOrB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAGrD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAKlC,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,GAAG,kBAAkB,CAAC;IACrC,GAAG,EAAE,GAAG,CAAC,YAAY,CAAC,CAAC;IACvB,eAAe,EAAE,OAAO,CAAC;IACzB,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC,UAAU,CAAC,OAAO,SAAS,CAAC,CAAC,CAAC;IAChD,YAAY,EAAE,uBAAuB,CAAC;IACtC,OAAO,EAAE,kBAAkB,CAAC;IAC5B,MAAM,EAAE,OAAO,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,gBAAgB,CAAC,QAAQ,IAAI,YAAY,GAAG;IAAE,QAAQ,EAAE,QAAQ,CAAA;CAAE,CAAC;AAE/E,MAAM,MAAM,iBAAiB,CAAC,QAAQ,IAAI,CACxC,IAAI,EAAE,gBAAgB,CAAC,QAAQ,CAAC,KAC7B,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEvC,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,EAAE,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;IACpD,WAAW,CAAC,EAAE,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;CACrD;AAED,eAAO,MAAM,gCAAgC;;MAE3C,CAAC;AAEH,MAAM,MAAM,gCAAgC,GAC1C,OAAO,gCAAgC,CAAC,KAAK,CAAC;AAEhD,eAAO,MAAM,wBAAwB;;;;;;;;MAMnC,CAAC;AAEH,UAAU,kBAAkB;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IAGtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,EAAE;QACT,wBAAwB,CAAC,EAAE,OAAO,CAAC;QACnC,oBAAoB,CAAC,EAAE,OAAO,CAAC;KAChC,CAAC;IACF,KAAK,CAAC,EAAE,SAAS,gBAAgB,EAAE,CAAC;CACrC;AASD,eAAO,MAAM,yBAAyB;;;;;MAEpC,CAAC;AACH,MAAM,MAAM,yBAAyB,GAAG,OAAO,yBAAyB,CAAC,KAAK,CAAC;AAE/E,eAAO,MAAM,+BAA+B;;;;MAM1C,CAAC;AACH,MAAM,MAAM,+BAA+B,GACzC,OAAO,+BAA+B,CAAC,KAAK,CAAC;AAE/C,wBAAgB,wBAAwB,CAAC,CAAC,EAAE,gBAAgB,UAY3D;AAiDD;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,wBAAwB,GACnC,SAAS,MAAM,GAAG,kBAAkB,EACpC,KAAK,GAAG,CAAC,YAAY,CAAC,EACtB,iBAAiB,OAAO,EACxB,MAAM,SAAS,EACf,SAAS,kBAAkB,KAC1B,OAAO,CAAC,kBAAkB,CAmc5B,CAAC"}
@@ -1,7 +1,7 @@
1
1
  import {} from "@faremeter/types/x402v2";
2
2
  import { isValidationError } from "@faremeter/types";
3
3
  import { clusterToCAIP2, isKnownCluster, caip2ToCluster, isSolanaCAIP2Network, } from "@faremeter/info/solana";
4
- import { fetchMint } from "@solana-program/token";
4
+ import { fetchMint, findAssociatedTokenPda, getTransferCheckedInstruction, getCloseAccountInstruction, } from "@solana-program/token";
5
5
  import { address, createKeyPairSignerFromBytes, decompileTransactionMessage, getBase64Encoder, getCompiledTransactionMessageDecoder, createTransactionMessage, setTransactionMessageFeePayerSigner, setTransactionMessageLifetimeUsingBlockhash, appendTransactionMessageInstructions, signTransactionMessageWithSigners, pipe, } from "@solana/kit";
6
6
  import { getBase64EncodedWireTransaction, getSignatureFromTransaction, getTransactionDecoder, partiallySignTransaction, } from "@solana/transactions";
7
7
  import { Keypair, PublicKey } from "@solana/web3.js";
@@ -9,7 +9,6 @@ import { type } from "arktype";
9
9
  import { isValidTransaction } from "./verify.js";
10
10
  import { logger } from "./logger.js";
11
11
  import { x402Scheme, generateMatcher } from "./common.js";
12
- import { TOKEN_PROGRAM_ADDRESS, findAssociatedTokenPda, getTransferCheckedInstruction, getCloseAccountInstruction, } from "@solana-program/token";
13
12
  import { getAddMemoInstruction } from "@solana-program/memo";
14
13
  import { TransactionStore } from "./cache.js";
15
14
  export const PaymentRequirementsExtraFeatures = type({
@@ -19,6 +18,7 @@ export const PaymentRequirementsExtra = type({
19
18
  feePayer: "string",
20
19
  decimals: "number?",
21
20
  recentBlockhash: "string?",
21
+ "tokenProgram?": "string",
22
22
  features: PaymentRequirementsExtraFeatures.optional(),
23
23
  });
24
24
  const TransactionString = type("string").pipe.try((tx) => {
@@ -93,6 +93,7 @@ export const createFacilitatorHandler = async (network, rpc, feePayerKeypair, mi
93
93
  const { isMatchingRequirement } = generateMatcher(network, mint.toBase58());
94
94
  const { maxRetries = 30, retryDelayMs = 1000, maxPriorityFee = 100_000, maxTransactionAge = 150, } = config ?? {};
95
95
  const mintInfo = await fetchMint(rpc, address(mint.toBase58()));
96
+ const tokenProgram = mintInfo.programAddress;
96
97
  const hookArgs = {
97
98
  network,
98
99
  rpc,
@@ -120,7 +121,7 @@ export const createFacilitatorHandler = async (network, rpc, feePayerKeypair, mi
120
121
  const [settleATA] = await findAssociatedTokenPda({
121
122
  mint: address(mint.toBase58()),
122
123
  owner: settleOwner,
123
- tokenProgram: TOKEN_PROGRAM_ADDRESS,
124
+ tokenProgram,
124
125
  });
125
126
  const { value: accountBalance } = await rpc
126
127
  .getTokenAccountBalance(settleATA, { commitment: "confirmed" })
@@ -138,11 +139,12 @@ export const createFacilitatorHandler = async (network, rpc, feePayerKeypair, mi
138
139
  const [payToATA] = await findAssociatedTokenPda({
139
140
  mint: address(mint.toBase58()),
140
141
  owner: address(requirements.payTo),
141
- tokenProgram: TOKEN_PROGRAM_ADDRESS,
142
+ tokenProgram,
142
143
  });
143
144
  const closeDestination = paymentPayload.settlementRentDestination
144
145
  ? address(paymentPayload.settlementRentDestination)
145
146
  : feePayerSigner.address;
147
+ const programAddress = tokenProgram;
146
148
  const instructions = [
147
149
  getAddMemoInstruction({ memo: crypto.randomUUID() }),
148
150
  getTransferCheckedInstruction({
@@ -152,12 +154,12 @@ export const createFacilitatorHandler = async (network, rpc, feePayerKeypair, mi
152
154
  authority: settleSigner,
153
155
  amount: BigInt(requirements.amount),
154
156
  decimals: mintInfo.data.decimals,
155
- }),
157
+ }, { programAddress }),
156
158
  getCloseAccountInstruction({
157
159
  account: settleATA,
158
160
  destination: closeDestination,
159
161
  owner: settleSigner,
160
- }),
162
+ }, { programAddress }),
161
163
  ];
162
164
  const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
163
165
  // Build the transaction message
@@ -192,7 +194,7 @@ export const createFacilitatorHandler = async (network, rpc, feePayerKeypair, mi
192
194
  }
193
195
  let validResult;
194
196
  try {
195
- validResult = await isValidTransaction(transactionMessage, requirements, feePayerKeypair.publicKey.toBase58(), maxPriorityFee);
197
+ validResult = await isValidTransaction(transactionMessage, requirements, feePayerKeypair.publicKey.toBase58(), tokenProgram, maxPriorityFee);
196
198
  if (!validResult) {
197
199
  logger.error("Invalid transaction");
198
200
  return errorResponse("Invalid transaction");
@@ -264,6 +266,7 @@ export const createFacilitatorHandler = async (network, rpc, feePayerKeypair, mi
264
266
  network: clusterToCAIP2(resolveCluster()).caip2,
265
267
  extra: {
266
268
  feePayer: feePayerKeypair.publicKey.toString(),
269
+ tokenProgram,
267
270
  features,
268
271
  },
269
272
  }),
@@ -280,6 +283,7 @@ export const createFacilitatorHandler = async (network, rpc, feePayerKeypair, mi
280
283
  feePayer: feePayerKeypair.publicKey.toString(),
281
284
  decimals: mintInfo.data.decimals,
282
285
  recentBlockhash,
286
+ tokenProgram,
283
287
  features,
284
288
  },
285
289
  };
@@ -1,6 +1,6 @@
1
1
  import type { x402PaymentRequirements } from "@faremeter/types/x402v2";
2
- import { type CompilableTransactionMessage } from "@solana/kit";
3
- export declare function isValidTransaction(transactionMessage: CompilableTransactionMessage, paymentRequirements: x402PaymentRequirements, facilitatorAddress: string, maxPriorityFee?: number): Promise<{
2
+ import { type Address, type CompilableTransactionMessage } from "@solana/kit";
3
+ export declare function isValidTransaction(transactionMessage: CompilableTransactionMessage, paymentRequirements: x402PaymentRequirements, facilitatorAddress: string, tokenProgram: Address, maxPriorityFee?: number): Promise<{
4
4
  payer: string;
5
5
  } | false>;
6
6
  //# sourceMappingURL=verify.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../../src/exact/verify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAWvE,OAAO,EAEL,KAAK,4BAA4B,EAElC,MAAM,aAAa,CAAC;AAuGrB,wBAAsB,kBAAkB,CACtC,kBAAkB,EAAE,4BAA4B,EAChD,mBAAmB,EAAE,uBAAuB,EAC5C,kBAAkB,EAAE,MAAM,EAC1B,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,KAAK,CAAC,CAkEpC"}
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../../src/exact/verify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAUvE,OAAO,EAEL,KAAK,OAAO,EACZ,KAAK,4BAA4B,EAElC,MAAM,aAAa,CAAC;AAwGrB,wBAAsB,kBAAkB,CACtC,kBAAkB,EAAE,4BAA4B,EAChD,mBAAmB,EAAE,uBAAuB,EAC5C,kBAAkB,EAAE,MAAM,EAC1B,YAAY,EAAE,OAAO,EACrB,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,KAAK,CAAC,CAmEpC"}
@@ -1,6 +1,6 @@
1
1
  import { isValidationError } from "@faremeter/types";
2
2
  import { parseSetComputeUnitLimitInstruction, parseSetComputeUnitPriceInstruction, } from "@solana-program/compute-budget";
3
- import { findAssociatedTokenPda, parseTransferCheckedInstruction, TOKEN_PROGRAM_ADDRESS, } from "@solana-program/token";
3
+ import { findAssociatedTokenPda, parseTransferCheckedInstruction, } from "@solana-program/token";
4
4
  import { address, } from "@solana/kit";
5
5
  import { PaymentRequirementsExtra } from "./facilitator.js";
6
6
  import { logger } from "./logger.js";
@@ -41,7 +41,7 @@ function verifyComputeUnitPriceInstruction(instruction) {
41
41
  function calculatePriorityFee(units, microLamports) {
42
42
  return (units * Number(microLamports)) / 1_000_000;
43
43
  }
44
- async function verifyTransferInstruction(instruction, paymentRequirements, destination, facilitatorAddress) {
44
+ async function verifyTransferInstruction(instruction, paymentRequirements, destination, facilitatorAddress, tokenProgram) {
45
45
  if (!instruction.data || !instruction.accounts) {
46
46
  return false;
47
47
  }
@@ -63,7 +63,7 @@ async function verifyTransferInstruction(instruction, paymentRequirements, desti
63
63
  const [facilitatorATA] = await findAssociatedTokenPda({
64
64
  mint: address(paymentRequirements.asset),
65
65
  owner: address(facilitatorAddress),
66
- tokenProgram: TOKEN_PROGRAM_ADDRESS,
66
+ tokenProgram,
67
67
  });
68
68
  if (transfer.accounts.source.address === facilitatorATA) {
69
69
  logger.error("Dropping transfer where the source is the facilitator");
@@ -76,7 +76,7 @@ async function verifyTransferInstruction(instruction, paymentRequirements, desti
76
76
  }
77
77
  return false;
78
78
  }
79
- export async function isValidTransaction(transactionMessage, paymentRequirements, facilitatorAddress, maxPriorityFee) {
79
+ export async function isValidTransaction(transactionMessage, paymentRequirements, facilitatorAddress, tokenProgram, maxPriorityFee) {
80
80
  const extra = PaymentRequirementsExtra(paymentRequirements.extra);
81
81
  if (isValidationError(extra)) {
82
82
  throw new Error("feePayer is required");
@@ -87,7 +87,7 @@ export async function isValidTransaction(transactionMessage, paymentRequirements
87
87
  const [destination] = await findAssociatedTokenPda({
88
88
  mint: address(paymentRequirements.asset),
89
89
  owner: address(paymentRequirements.payTo),
90
- tokenProgram: TOKEN_PROGRAM_ADDRESS,
90
+ tokenProgram,
91
91
  });
92
92
  const instructions = transactionMessage.instructions;
93
93
  if (instructions.length < 3 || instructions.length > 5) {
@@ -115,7 +115,7 @@ export async function isValidTransaction(transactionMessage, paymentRequirements
115
115
  logger.error("Dropping transaction with non-Lighthouse trailing instructions");
116
116
  return false;
117
117
  }
118
- const payer = await verifyTransferInstruction(ix2, paymentRequirements, destination, facilitatorAddress);
118
+ const payer = await verifyTransferInstruction(ix2, paymentRequirements, destination, facilitatorAddress, tokenProgram);
119
119
  if (!payer)
120
120
  return false;
121
121
  return { payer };
@@ -3,6 +3,7 @@ import t from "tap";
3
3
  import { isValidTransaction } from "./verify.js";
4
4
  import { getSetComputeUnitLimitInstruction, getSetComputeUnitPriceInstruction, } from "@solana-program/compute-budget";
5
5
  import { findAssociatedTokenPda, getTransferCheckedInstruction, TOKEN_PROGRAM_ADDRESS, } from "@solana-program/token";
6
+ import { TOKEN_2022_PROGRAM_ADDRESS } from "../splToken.js";
6
7
  import { address, appendTransactionMessageInstructions, createTransactionMessage, generateKeyPairSigner, pipe, setTransactionMessageFeePayer, setTransactionMessageLifetimeUsingBlockhash, } from "@solana/kit";
7
8
  function createRequirements(overrides) {
8
9
  return {
@@ -17,7 +18,7 @@ const FAKE_BLOCKHASH = "EETubP46DHLkT9hAFKy4x2BoFUqUFvKjiiNVY3CaYRi3";
17
18
  function buildTxMessage(instructions, feePayer) {
18
19
  return pipe(createTransactionMessage({ version: 0 }), (msg) => setTransactionMessageFeePayer(feePayer.address, msg), (msg) => setTransactionMessageLifetimeUsingBlockhash({ blockhash: FAKE_BLOCKHASH, lastValidBlockHeight: 1000n }, msg), (msg) => appendTransactionMessageInstructions(instructions, msg));
19
20
  }
20
- async function createFixtures() {
21
+ async function createFixtures({ tokenProgram = TOKEN_PROGRAM_ADDRESS, } = {}) {
21
22
  const facilitator = await generateKeyPairSigner();
22
23
  const sender = await generateKeyPairSigner();
23
24
  const receiver = await generateKeyPairSigner();
@@ -25,17 +26,17 @@ async function createFixtures() {
25
26
  const [senderATA] = await findAssociatedTokenPda({
26
27
  mint: mint.address,
27
28
  owner: sender.address,
28
- tokenProgram: TOKEN_PROGRAM_ADDRESS,
29
+ tokenProgram,
29
30
  });
30
31
  const [receiverATA] = await findAssociatedTokenPda({
31
32
  mint: mint.address,
32
33
  owner: receiver.address,
33
- tokenProgram: TOKEN_PROGRAM_ADDRESS,
34
+ tokenProgram,
34
35
  });
35
36
  const [facilitatorATA] = await findAssociatedTokenPda({
36
37
  mint: mint.address,
37
38
  owner: facilitator.address,
38
- tokenProgram: TOKEN_PROGRAM_ADDRESS,
39
+ tokenProgram,
39
40
  });
40
41
  const amount = 1000000n;
41
42
  const decimals = 6;
@@ -60,8 +61,9 @@ async function createFixtures() {
60
61
  authority: sender.address,
61
62
  amount,
62
63
  decimals,
63
- });
64
+ }, { programAddress: tokenProgram });
64
65
  return {
66
+ tokenProgram,
65
67
  facilitator,
66
68
  sender,
67
69
  receiver,
@@ -87,7 +89,7 @@ await t.test("isValidTransaction", async (t) => {
87
89
  await t.test("accepts valid 3-instruction transaction", async (t) => {
88
90
  const f = await createFixtures();
89
91
  const txMsg = buildTxMessage([f.computeLimitIx, f.computePriceIx, f.transferIx], f.facilitator);
90
- const result = await isValidTransaction(txMsg, f.requirements, f.facilitator.address);
92
+ const result = await isValidTransaction(txMsg, f.requirements, f.facilitator.address, f.tokenProgram);
91
93
  t.ok(result);
92
94
  t.equal(result && result.payer, f.sender.address);
93
95
  t.end();
@@ -95,7 +97,7 @@ await t.test("isValidTransaction", async (t) => {
95
97
  await t.test("accepts valid 4-instruction transaction with one lighthouse ix", async (t) => {
96
98
  const f = await createFixtures();
97
99
  const txMsg = buildTxMessage([f.computeLimitIx, f.computePriceIx, f.transferIx, makeLighthouseIx()], f.facilitator);
98
- const result = await isValidTransaction(txMsg, f.requirements, f.facilitator.address);
100
+ const result = await isValidTransaction(txMsg, f.requirements, f.facilitator.address, f.tokenProgram);
99
101
  t.ok(result);
100
102
  t.equal(result && result.payer, f.sender.address);
101
103
  t.end();
@@ -109,7 +111,7 @@ await t.test("isValidTransaction", async (t) => {
109
111
  makeLighthouseIx([1]),
110
112
  makeLighthouseIx([2]),
111
113
  ], f.facilitator);
112
- const result = await isValidTransaction(txMsg, f.requirements, f.facilitator.address);
114
+ const result = await isValidTransaction(txMsg, f.requirements, f.facilitator.address, f.tokenProgram);
113
115
  t.ok(result);
114
116
  t.equal(result && result.payer, f.sender.address);
115
117
  t.end();
@@ -117,21 +119,21 @@ await t.test("isValidTransaction", async (t) => {
117
119
  await t.test("rejects transaction with fewer than 3 instructions", async (t) => {
118
120
  const f = await createFixtures();
119
121
  const txMsg = buildTxMessage([f.computeLimitIx, f.computePriceIx], f.facilitator);
120
- t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address), false);
122
+ t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address, f.tokenProgram), false);
121
123
  t.end();
122
124
  });
123
125
  await t.test("rejects transaction with more than 5 instructions", async (t) => {
124
126
  const f = await createFixtures();
125
127
  const extras = Array.from({ length: 3 }, (_, i) => makeLighthouseIx([i]));
126
128
  const txMsg = buildTxMessage([f.computeLimitIx, f.computePriceIx, f.transferIx, ...extras], f.facilitator);
127
- t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address), false);
129
+ t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address, f.tokenProgram), false);
128
130
  t.end();
129
131
  });
130
132
  await t.test("rejects transaction with wrong fee payer", async (t) => {
131
133
  const f = await createFixtures();
132
134
  const wrongPayer = await generateKeyPairSigner();
133
135
  const txMsg = buildTxMessage([f.computeLimitIx, f.computePriceIx, f.transferIx], wrongPayer);
134
- t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address), false);
136
+ t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address, f.tokenProgram), false);
135
137
  t.end();
136
138
  });
137
139
  await t.test("throws when extra is missing feePayer", async (t) => {
@@ -141,19 +143,19 @@ await t.test("isValidTransaction", async (t) => {
141
143
  extra: {},
142
144
  };
143
145
  const txMsg = buildTxMessage([f.computeLimitIx, f.computePriceIx, f.transferIx], f.facilitator);
144
- await t.rejects(isValidTransaction(txMsg, badRequirements, f.facilitator.address));
146
+ await t.rejects(isValidTransaction(txMsg, badRequirements, f.facilitator.address, f.tokenProgram));
145
147
  t.end();
146
148
  });
147
149
  await t.test("rejects transaction with swapped compute budget instructions", async (t) => {
148
150
  const f = await createFixtures();
149
151
  const txMsg = buildTxMessage([f.computePriceIx, f.computeLimitIx, f.transferIx], f.facilitator);
150
- t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address), false);
152
+ t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address, f.tokenProgram), false);
151
153
  t.end();
152
154
  });
153
155
  await t.test("accepts transaction within priority fee limit", async (t) => {
154
156
  const f = await createFixtures();
155
157
  const txMsg = buildTxMessage([f.computeLimitIx, f.computePriceIx, f.transferIx], f.facilitator);
156
- const result = await isValidTransaction(txMsg, f.requirements, f.facilitator.address, 100_000);
158
+ const result = await isValidTransaction(txMsg, f.requirements, f.facilitator.address, f.tokenProgram, 100_000);
157
159
  t.ok(result);
158
160
  t.equal(result && result.payer, f.sender.address);
159
161
  t.end();
@@ -167,7 +169,7 @@ await t.test("isValidTransaction", async (t) => {
167
169
  microLamports: 10000000n,
168
170
  });
169
171
  const txMsg = buildTxMessage([highLimitIx, highPriceIx, f.transferIx], f.facilitator);
170
- t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address, 100), false);
172
+ t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address, f.tokenProgram, 100), false);
171
173
  t.end();
172
174
  });
173
175
  await t.test("rejects transaction exceeding priority fee limit with lighthouse ixs", async (t) => {
@@ -179,7 +181,7 @@ await t.test("isValidTransaction", async (t) => {
179
181
  microLamports: 10000000n,
180
182
  });
181
183
  const txMsg = buildTxMessage([highLimitIx, highPriceIx, f.transferIx, makeLighthouseIx()], f.facilitator);
182
- t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address, 100), false);
184
+ t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address, f.tokenProgram, 100), false);
183
185
  t.end();
184
186
  });
185
187
  await t.test("rejects trailing non-lighthouse instruction", async (t) => {
@@ -190,7 +192,7 @@ await t.test("isValidTransaction", async (t) => {
190
192
  data: new Uint8Array([0]),
191
193
  };
192
194
  const txMsg = buildTxMessage([f.computeLimitIx, f.computePriceIx, f.transferIx, fakeIx], f.facilitator);
193
- t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address), false);
195
+ t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address, f.tokenProgram), false);
194
196
  t.end();
195
197
  });
196
198
  await t.test("rejects mixed lighthouse and non-lighthouse trailing instructions", async (t) => {
@@ -207,7 +209,7 @@ await t.test("isValidTransaction", async (t) => {
207
209
  makeLighthouseIx(),
208
210
  fakeIx,
209
211
  ], f.facilitator);
210
- t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address), false);
212
+ t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address, f.tokenProgram), false);
211
213
  t.end();
212
214
  });
213
215
  await t.test("rejects transaction with wrong transfer amount", async (t) => {
@@ -221,7 +223,7 @@ await t.test("isValidTransaction", async (t) => {
221
223
  decimals: f.decimals,
222
224
  });
223
225
  const txMsg = buildTxMessage([f.computeLimitIx, f.computePriceIx, wrongAmountIx], f.facilitator);
224
- t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address), false);
226
+ t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address, f.tokenProgram), false);
225
227
  t.end();
226
228
  });
227
229
  await t.test("rejects transaction with wrong mint", async (t) => {
@@ -246,7 +248,7 @@ await t.test("isValidTransaction", async (t) => {
246
248
  decimals: f.decimals,
247
249
  });
248
250
  const txMsg = buildTxMessage([f.computeLimitIx, f.computePriceIx, wrongMintIx], f.facilitator);
249
- t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address), false);
251
+ t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address, f.tokenProgram), false);
250
252
  t.end();
251
253
  });
252
254
  await t.test("rejects transaction with wrong destination", async (t) => {
@@ -266,7 +268,7 @@ await t.test("isValidTransaction", async (t) => {
266
268
  decimals: f.decimals,
267
269
  });
268
270
  const txMsg = buildTxMessage([f.computeLimitIx, f.computePriceIx, wrongDestIx], f.facilitator);
269
- t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address), false);
271
+ t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address, f.tokenProgram), false);
270
272
  t.end();
271
273
  });
272
274
  await t.test("rejects transaction where facilitator is transfer authority", async (t) => {
@@ -280,7 +282,7 @@ await t.test("isValidTransaction", async (t) => {
280
282
  decimals: f.decimals,
281
283
  });
282
284
  const txMsg = buildTxMessage([f.computeLimitIx, f.computePriceIx, badIx], f.facilitator);
283
- t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address), false);
285
+ t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address, f.tokenProgram), false);
284
286
  t.end();
285
287
  });
286
288
  await t.test("rejects transaction where source is facilitator ATA", async (t) => {
@@ -294,7 +296,17 @@ await t.test("isValidTransaction", async (t) => {
294
296
  decimals: f.decimals,
295
297
  });
296
298
  const txMsg = buildTxMessage([f.computeLimitIx, f.computePriceIx, badIx], f.facilitator);
297
- t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address), false);
299
+ t.equal(await isValidTransaction(txMsg, f.requirements, f.facilitator.address, f.tokenProgram), false);
300
+ t.end();
301
+ });
302
+ await t.test("accepts valid transaction with Token-2022 program", async (t) => {
303
+ const f = await createFixtures({
304
+ tokenProgram: TOKEN_2022_PROGRAM_ADDRESS,
305
+ });
306
+ const txMsg = buildTxMessage([f.computeLimitIx, f.computePriceIx, f.transferIx], f.facilitator);
307
+ const result = await isValidTransaction(txMsg, f.requirements, f.facilitator.address, f.tokenProgram);
308
+ t.ok(result);
309
+ t.equal(result && result.payer, f.sender.address);
298
310
  t.end();
299
311
  });
300
312
  t.end();
@@ -1,6 +1,8 @@
1
1
  import type { Rpc } from "@solana/rpc";
2
2
  import type { GetTokenAccountBalanceApi } from "@solana/rpc-api";
3
+ import { type Address } from "@solana/kit";
3
4
  import { Base58Address } from "@faremeter/types/solana";
5
+ export declare const TOKEN_2022_PROGRAM_ADDRESS: Address<"TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb">;
4
6
  /**
5
7
  * Arguments for retrieving an SPL token balance.
6
8
  */
@@ -11,6 +13,8 @@ export interface GetTokenBalanceArgs {
11
13
  account: Base58Address;
12
14
  /** Solana RPC client with token balance API support */
13
15
  rpcClient: Rpc<GetTokenAccountBalanceApi>;
16
+ /** The token program address (defaults to TOKEN_PROGRAM_ADDRESS) */
17
+ tokenProgram?: Address;
14
18
  }
15
19
  /**
16
20
  * Checks if an error indicates a token account was not found.
@@ -1 +1 @@
1
- {"version":3,"file":"splToken.d.ts","sourceRoot":"","sources":["../../src/splToken.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAEjE,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAMxD;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,iCAAiC;IACjC,KAAK,EAAE,aAAa,CAAC;IACrB,kDAAkD;IAClD,OAAO,EAAE,aAAa,CAAC;IACvB,uDAAuD;IACvD,SAAS,EAAE,GAAG,CAAC,yBAAyB,CAAC,CAAC;CAC3C;AAED;;;;;;;;;GASG;AAEH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,OAAO,WAkBhD;AAED;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,mBAAmB;;;UA4B9D"}
1
+ {"version":3,"file":"splToken.d.ts","sourceRoot":"","sources":["../../src/splToken.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AACjE,OAAO,EAAW,KAAK,OAAO,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAQxD,eAAO,MAAM,0BAA0B,wDAEtC,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,iCAAiC;IACjC,KAAK,EAAE,aAAa,CAAC;IACrB,kDAAkD;IAClD,OAAO,EAAE,aAAa,CAAC;IACvB,uDAAuD;IACvD,SAAS,EAAE,GAAG,CAAC,yBAAyB,CAAC,CAAC;IAC1C,oEAAoE;IACpE,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;;;GASG;AAEH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,OAAO,WAkBhD;AAED;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,mBAAmB;;;UA4B9D"}
@@ -1,6 +1,9 @@
1
- import { address } from "@solana/addresses";
1
+ import { address } from "@solana/kit";
2
2
  import { Base58Address } from "@faremeter/types/solana";
3
3
  import { findAssociatedTokenPda, TOKEN_PROGRAM_ADDRESS, } from "@solana-program/token";
4
+ // XXX - @solana-program/token doesn't export this, and @solana-program/token-2022
5
+ // is 4MB for one constant. Define it here as a kit-native Address.
6
+ export const TOKEN_2022_PROGRAM_ADDRESS = address("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb");
4
7
  /**
5
8
  * Checks if an error indicates a token account was not found.
6
9
  *
@@ -37,13 +40,13 @@ export function isAccountNotFoundError(e) {
37
40
  * @returns The balance amount and decimals, or null if the account does not exist
38
41
  */
39
42
  export async function getTokenBalance(args) {
40
- const { asset, account, rpcClient } = args;
43
+ const { asset, account, rpcClient, tokenProgram } = args;
41
44
  const owner = address(account);
42
45
  const mint = address(asset);
43
46
  const [ata] = await findAssociatedTokenPda({
44
47
  mint,
45
48
  owner,
46
- tokenProgram: TOKEN_PROGRAM_ADDRESS,
49
+ tokenProgram: tokenProgram ?? TOKEN_PROGRAM_ADDRESS,
47
50
  });
48
51
  let balanceInfo;
49
52
  try {