You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Solana转账故障求助:transfer方法无法创建指令

问题:Solana钱包转账失败,SystemProgram.transfer无法生成指令

问题描述

完全按照Solana官方JavaScript API文档编写钱包转账代码,但功能无法正常运行,核心问题是SystemProgram.transfer方法无法创建交易指令,尝试多种方法仍未解决,附上相关代码及报错位置。

我的代码

async function transfer() {
  const provider = await IsConnected();
  console.log(provider.publicKey.toString());
  const connection = new solanaWeb3.Connection(
    "https://api.devnet.solana.com",
    "confirmed"
  );

  var recieverWallet = new solanaWeb3.PublicKey(
    "3uePV7kJcT3w5qMLPTHVAdLc72SF2iDRwNcxDE713EMf"
  );

  // var airdropSignature = await connection.requestAirdrop(
  //   provider.publicKey,
  //   solanaWeb3.LAMPORTS_PER_SOL * 0.4
  // );

  // await connection
  //   .confirmTransaction(airdropSignature)
  //   .then(console.log("Airdropped"));
  var transaction = new solanaWeb3.Transaction();

  transaction.feePayer = await provider.publicKey;
  let blockhashObj = await connection.getRecentBlockhash();
  transaction.recentBlockhash = await blockhashObj.blockhash;
  transaction.add(
    await solanaWeb3.SystemProgram.transfer({
      fromPubkey: provider.publicKey,
      toPubkey: recieverWallet,
      lamports: 10000,
    })
  );
  if (transaction) {
    console.log("Txn created successfully");
  }

  let signed = await provider.signTransaction(transaction).serialize();

  let signature = await connection.sendRawTransaction(signed);

  console.log(signature);

  let bConfirmed = await connection.confirmTransaction(signature);

 
  console.log(bConfirmed);
}

报错位置代码

static transfer(
    params: TransferParams | TransferWithSeedParams,
  ): TransactionInstruction {
    let data;
    let keys;
    if ('basePubkey' in params) {
      const type = SYSTEM_INSTRUCTION_LAYOUTS.TransferWithSeed;
      data = encodeData(type, {
        lamports: BigInt(params.lamports),
        seed: params.seed,
        programId: toBuffer(params.programId.toBuffer()),
      });
      keys = [
        {pubkey: params.fromPubkey, isSigner: false, isWritable: true},
        {pubkey: params.basePubkey, isSigner: true, isWritable: false},
        {pubkey: params.toPubkey, isSigner: false, isWritable: true},
      ];
    } else {
      const type = SYSTEM_INSTRUCTION_LAYOUTS.Transfer;
      // ***报错位置 ->***
      data = encodeData(type, {lamports: BigInt(params.lamports)});
      keys = [
        {pubkey: params.fromPubkey, isSigner: true, isWritable: true},
        {pubkey: params.toPubkey, isSigner: false, isWritable: true},
      ];
    }

    return new TransactionInstruction({
      keys,
      programId: this.programId,
      data,
    });
  }


export function encodeData<TInputData extends IInstructionInputData>(
  type: InstructionType<TInputData>,
  fields?: any,
): Buffer {
  const allocLength =
    type.layout.span >= 0 ? type.layout.span : Layout.getAlloc(type, fields);
  const data = Buffer.alloc(allocLength);
  const layoutFields = Object.assign({instruction: type.index}, fields);
  type.layout.encode(layoutFields, data);
  return data;
}



    encode(src, b, offset = 0) {
        const firstOffset = offset;
        let lastOffset = 0;
        let lastWrote = 0;
        for (const fd of this.fields) {
            let span = fd.span;
            lastWrote = (0 < span) ? span : 0;
            if (undefined !== fd.property) {
                const fv = src[fd.property];
                if (undefined !== fv) {
                    lastWrote = fd.encode(fv, b, offset);
                    if (0 > span) {
                        /* Read the as-encoded span, which is not necessarily the
                         * same as what we wrote. */
                        span = fd.getSpan(b, offset);
                    }
                }
            }
            lastOffset = offset;
            offset += span;
        }


const bigInt =
  (length: number) =>
  (property?: string): Layout<bigint> => {
    const layout = blob(length, property);
    const {encode, decode} = encodeDecode(layout);

    const bigIntLayout = layout as Layout<unknown> as Layout<bigint>;

    bigIntLayout.decode = (buffer: Buffer, offset: number) => {
      const src = decode(buffer, offset);
      return toBigIntLE(Buffer.from(src));
    };

    bigIntLayout.encode = (bigInt: bigint, buffer: Buffer, offset: number) => {
      const src = toBufferLE(bigInt, length);
      return encode(src, buffer, offset);
    };

    return bigIntLayout;
  };



function toBufferLE(num, width) {
    {
        const hex = num.toString(16);
        const buffer = Buffer.from(hex.padStart(width * 2, '0').slice(0, width * 2), 'hex');
        buffer.reverse();
        return buffer;
    }
    // Allocation is done here, since it is slower using napi in C
    return converter.fromBigInt(num, Buffer.allocUnsafe(width), false);
}
exports.toBufferLE = toBufferLE;

修复建议

  1. 移除不必要的await:provider.publicKey、blockhashObj.blockhash、SystemProgram.transfer()都是同步操作,无需异步等待,修改后代码如下:

    transaction.feePayer = provider.publicKey;
    transaction.recentBlockhash = blockhashObj.blockhash;
    transaction.add(
      solanaWeb3.SystemProgram.transfer({
        fromPubkey: provider.publicKey,
        toPubkey: recieverWallet,
        lamports: 10000,
      })
    );
    
  2. 修正签名步骤:signTransaction返回Promise,需先await拿到签名后的交易再序列化:

    let signedTx = await provider.signTransaction(transaction);
    let signed = signedTx.serialize();
    
  3. 更新依赖版本:确保@solana/web3.js为最新稳定版,旧版本可能存在BigInt编码或指令布局的兼容性问题。

  4. 添加错误捕获:在交易流程中加入try/catch,打印具体错误信息辅助定位:

    try {
      // 交易创建、签名、发送逻辑
    } catch (err) {
      console.error("交易失败详情:", err);
    }
    

内容的提问来源于stack exchange,提问作者pidor ads243

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 08:18:34