@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.
- package/dist/src/exact/client.d.ts.map +1 -1
- package/dist/src/exact/client.js +13 -5
- package/dist/src/exact/facilitator.d.ts +1 -0
- package/dist/src/exact/facilitator.d.ts.map +1 -1
- package/dist/src/exact/facilitator.js +11 -7
- package/dist/src/exact/verify.d.ts +2 -2
- package/dist/src/exact/verify.d.ts.map +1 -1
- package/dist/src/exact/verify.js +6 -6
- package/dist/src/exact/verify.test.js +35 -23
- package/dist/src/splToken.d.ts +4 -0
- package/dist/src/splToken.d.ts.map +1 -1
- package/dist/src/splToken.js +6 -3
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
|
@@ -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;
|
|
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"}
|
package/dist/src/exact/client.js
CHANGED
|
@@ -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
|
|
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);
|
|
@@ -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,
|
|
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
|
|
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
|
|
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;
|
|
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"}
|
package/dist/src/exact/verify.js
CHANGED
|
@@ -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,
|
|
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
|
|
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
|
|
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
|
|
29
|
+
tokenProgram,
|
|
29
30
|
});
|
|
30
31
|
const [receiverATA] = await findAssociatedTokenPda({
|
|
31
32
|
mint: mint.address,
|
|
32
33
|
owner: receiver.address,
|
|
33
|
-
tokenProgram
|
|
34
|
+
tokenProgram,
|
|
34
35
|
});
|
|
35
36
|
const [facilitatorATA] = await findAssociatedTokenPda({
|
|
36
37
|
mint: mint.address,
|
|
37
38
|
owner: facilitator.address,
|
|
38
|
-
tokenProgram
|
|
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();
|
package/dist/src/splToken.d.ts
CHANGED
|
@@ -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;
|
|
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"}
|
package/dist/src/splToken.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import { address } from "@solana/
|
|
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 {
|