使用 solana-web3.js 转账原生代币和其他代币

4,859 阅读1分钟

Solana区块链,对接合约操作和转账

一、 转账操作 使用 solana-web3.js 转账sol币

1.引入库

代码如下(示例):

import bs58 from 'bs58'
import np from '@/utils/number-precision'
import * as BufferLayout from 'buffer-layout'
import { TokenListProvider } from '@solana/spl-token-registry'
import {
  Program, AnchorProvider,
  BN
} from '@project-serum/anchor'
import {
  Connection,
  PublicKey,
  SystemProgram,
  SYSVAR_CLOCK_PUBKEY,
  SYSVAR_RENT_PUBKEY,
  Transaction,
  sendAndConfirmTransaction,
  TransactionInstruction
  // LAMPORTS_PER_SOL
} from '@solana/web3.js'
import {
  Token, ASSOCIATED_TOKEN_PROGRAM_ID,
  TOKEN_PROGRAM_ID
} from '@solana/spl-token'

2.创建钱包连接connection

代码如下(示例):

    const netWork ="https://api.devnet.solana.com" //开发网
    const netWork ="https://api.testnet.solana.com"//测试网
    const netWork = "http://solscan.rpcpool.com" //主网
    this.connection = new Connection(netWork , 'recent')

3.查询账户信息并且进行sol转账操作

代码如下(示例):

    async toAccounts () {
      try {
        const rp = await this.connection.getAccountInfo(new PublicKey(钱包地址))
        // 转账
        const fromPubkey = new PublicKey(转出的钱包地址)
        const toPubkey = new PublicKey(转入钱包地址)
        const tx = new Transaction() // 建一个交易单
        // 设置交易单数据
        tx.add(
          SystemProgram.transfer({
            fromPubkey: fromPubkey,
            toPubkey: toPubkey,
            lamports: this.form.lamports * Math.pow(10, 9) // lamports  是看代币单位要*多少个0
          })
        )
        // 查找最近的区块
        tx.recentBlockhash = (
          await this.connection.getLatestBlockhash('max')
        ).blockhash
        tx.feePayer = fromPubkey// 付款人
        // 调用slope钱包获取签名
        const slope = new window.Slope()
        const { msg, data } = await slope.signTransaction(
          bs58.encode(tx.serializeMessage())
        )
        if (msg === 'ok') {
          // 给交易设置slope钱包签名
          tx.addSignature(pubkey, bs58.decode(data.signature))
          const txid = await this.connection.sendRawTransaction(
            tx.serialize(),
            bs58.decode(data.signature),
            {
              skipPreflight: false,
              preflightCommitment: 'recent'
            }
          )

          console.log(txid)// 交易成功返回签名地址可在https://solscan.io/查询记录
          let err = await this.confirmTx(txid)
          err && (err = await this.confirmTx(txid))
          if (err) {
            this.$message.error('Transaction failed, please try again!')
            this.loading = false
            return
          }
        }
      } catch (e) {
        console.log(e)
      }
    },
    // 交易确认
    async confirmTx (txid) {
      try {
        const cfmRp = await this.connection.confirmTransaction(txid, 'recent')
        if (cfmRp.value.err !== null) {
          return cfmRp.value.err
        }
      } catch (error) {
        console.log(error)
      }
    },

4.其他代币转账操作

 export const toAccountss = async () => {
  try {
    //  const rp = await this.connection.getAccountInfo(new PublicKey(钱包地址))
    // balances代币数据 mintAddress
    const decimals = 10000000
    const mint = new PublicKey('aaaaaa')
    const fromPubkey = new PublicKey('aaaaaa')// 转出的钱包地址
    const toPubkey = new PublicKey('aaaaaa')// 转入钱包地址
    // 获取代币地址
    const destinationAssociatedTokenAddress = await Token.getAssociatedTokenAddress(
      ASSOCIATED_TOKEN_PROGRAM_ID, // 导包
      TOKEN_PROGRAM_ID, // 导包
      mint, // 代币mint地址
      fromPubkey, // 账户地址
      true
    )
    // 查询代币,没有就创建代币  Token.createAssociatedTokenAccountInstruction
    const destination = await connection.getAccountInfo(destinationAssociatedTokenAddress)
    // console.log(destination, 'destination', destinationAssociatedTokenAddress)
    const tx = new Transaction() // 建一个交易单

    if (!destination) {
      // 给转入地址创建一个代币token
      const associatedTokenAccountIx = tx.add(
        Token.createAssociatedTokenAccountInstruction(
          destinationAssociatedTokenAddress,
          new PublicKey(fromPubkey), // 付款账户地址
          new PublicKey(toPubkey), // 转入地址
          new PublicKey(mint)// 代币地址
        )
      )
      tx.add(associatedTokenAccountIx) // 插入创建代币指令
      console.log(tx, '创建token账户 ')
    }
    // 创建交易单采用底层逻辑
    const splTransferIx = await createTransferInstruction({
      programId: TOKEN_PROGRAM_ID,
      source: new PublicKey('aaaaaa'), // 代币账户地址
      destination: destinationAssociatedTokenAddress, // 查询的代币账户地址
      owner: new PublicKey(fromPubkey), // 所属人new PublicKey(puk)发送方的钱包地址
      amount: new BN(1 * decimals)
    })
    tx.add(splTransferIx)
    // 查找最近的区块
    tx.recentBlockhash = (
      await this.connection.getLatestBlockhash('max')
    ).blockhash
    tx.feePayer = fromPubkey// 付款人
    // 调用slope钱包获取签名
    const slope = new window.Slope()
    const { msg, data } = await slope.signTransaction(
      bs58.encode(tx.serializeMessage())
    )
    if (msg === 'ok') {
      // 给交易设置slope钱包签名
      tx.addSignature(fromPubkey, bs58.decode(data.signature))
      const txid = await this.connection.sendRawTransaction(
        tx.serialize(),
        bs58.decode(data.signature),
        {
          skipPreflight: false,
          preflightCommitment: 'recent'
        }
      )

      console.log(txid)// 交易成功返回签名地址可在查询记录
      let err = await this.confirmTx(txid)
      err && (err = await this.confirmTx(txid))
      if (err) {
        this.$message.error('Transaction failed, please try again!')
        this.loading = false
        return
      }
    }
  } catch (e) {
    console.log(e)
  }
}

5.创建token代币交易方法

// 创建token交易
export const createTransferInstruction = async ({
  programId,
  source,
  destination,
  owner,
  amount
}) => {
  const multiSigners = []
  const dataLayout = BufferLayout.struct([
    BufferLayout.u8('instruction'),
    BufferLayout.blob(8, 'amount')
  ])

  const data = Buffer.alloc(dataLayout.span)
  dataLayout.encode(
    {
      instruction: 3, // Transfer instruction
      amount: new U64(amount).toBuffer()
    },
    data
  )
  console.log(multiSigners, 'multiSigners1')
  const keys = [
    { pubkey: source, isSigner: false, isWritable: true },
    { pubkey: destination, isSigner: false, isWritable: true }
  ]

  if (multiSigners.length === 0) {
    keys.push({
      pubkey: owner,
      isSigner: true,
      isWritable: false
    })
    console.log(multiSigners, 'multiSigners2', keys)
  } else {
    console.log(multiSigners, 'multiSigners3')
    keys.push({ pubkey: owner, isSigner: false, isWritable: false })
    multiSigners.forEach(signer =>
      keys.push({
        pubkey: signer.publicKey,
        isSigner: true,
        isWritable: false
      })
    )
  }

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