Ver Fonte

fix: 支持 Token-2022 余额查询和账户创建

通过查询 mint 账户 owner 判断 token program 类型,用正确的 programId 派生 ATA 地址,修复 Token-2022 代币余额返回 0 的问题

Co-authored-by: Cursor <cursoragent@cursor.com>
zhangchunrui há 1 mês atrás
pai
commit
d7fd81f5f0
1 ficheiros alterados com 32 adições e 6 exclusões
  1. 32 6
      src/services/jupiter.js

+ 32 - 6
src/services/jupiter.js

@@ -1,6 +1,6 @@
 import axios from 'axios';
 import { Connection, PublicKey, Keypair, VersionedTransaction, Transaction } from '@solana/web3.js';
-import { getAssociatedTokenAddress, createAssociatedTokenAccountInstruction } from '@solana/spl-token';
+import { getAssociatedTokenAddress, createAssociatedTokenAccountInstruction, TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID } from '@solana/spl-token';
 import bs58 from 'bs58';
 import { CONFIG } from '../config/index.js';
 import { logger, sleep } from '../utils/index.js';
@@ -36,6 +36,24 @@ export class JupiterSwapper {
     return headers;
   }
 
+  /**
+   * 查询 mint 账户的 owner 判断是标准 SPL Token 还是 Token-2022
+   */
+  async getTokenProgramId(mintAddress) {
+    try {
+      const mintAccountInfo = await this.connection.getAccountInfo(new PublicKey(mintAddress));
+      if (mintAccountInfo) {
+        const owner = mintAccountInfo.owner.toString();
+        if (owner === TOKEN_2022_PROGRAM_ID.toString()) {
+          return TOKEN_2022_PROGRAM_ID;
+        }
+      }
+      return TOKEN_PROGRAM_ID;
+    } catch (e) {
+      return TOKEN_PROGRAM_ID;
+    }
+  }
+
   async getTokenBalance(mintAddress) {
     try {
       if (mintAddress === 'So11111111111111111111111111111111111111112') {
@@ -43,9 +61,12 @@ export class JupiterSwapper {
         return balance / 1e9;
       }
 
+      const programId = await this.getTokenProgramId(mintAddress);
       const tokenAccount = await getAssociatedTokenAddress(
         new PublicKey(mintAddress),
-        this.keypair.publicKey
+        this.keypair.publicKey,
+        false,
+        programId
       );
 
       try {
@@ -289,22 +310,27 @@ export class JupiterSwapper {
 
   async ensureTokenAccount(mintAddress) {
     try {
+      const mintPubkey = new PublicKey(mintAddress);
+      const programId = await this.getTokenProgramId(mintAddress);
       const tokenAccount = await getAssociatedTokenAddress(
-        new PublicKey(mintAddress),
-        this.keypair.publicKey
+        mintPubkey,
+        this.keypair.publicKey,
+        false,
+        programId
       );
 
       try {
         await this.connection.getAccountInfo(tokenAccount);
         return tokenAccount;
       } catch (e) {
-        logger.info(`Creating token account for ${mintAddress}...`);
+        logger.info(`Creating token account for ${mintAddress} (program: ${programId.toString().slice(0, 8)}...)...`);
         const transaction = new Transaction().add(
           createAssociatedTokenAccountInstruction(
             this.keypair.publicKey,
             tokenAccount,
             this.keypair.publicKey,
-            new PublicKey(mintAddress)
+            mintPubkey,
+            programId
           )
         );