Gill 简介:现代 Solana JavaScript 客户端库

  • Shivam
  • 发布于 7小时前
  • 阅读 99

Gill 是一个新的 JavaScript 客户端库,用于与 Solana 区块链交互。

介绍

介绍 Gill:用于与 Solana 区块链交互的全新 JavaScript 客户端库。它基于 Anza 构建的现代 Solana JavaScript 库。它利用了 Web3 JS 第二版的速度和优雅性,并提供了一个轻量级且高度抽象的解决方案。它轻量、快速,并具有可摇树优化的架构。你可以使用它在 Node、Web、React Native 或几乎任何其他 JavaScript 环境中构建 Solana d-app。

为什么 Gill 有用?

由于 Solana Web3.js v2 在性能方面非常出色,具有可摇树优化的架构,但在你所做的每件事中,由于其更长的函数名称和超模块化的子包,感觉很冗长,因此 Gill 与 v2 完全兼容,并通过改进的开发者体验 (DevEx) 提供了更容易的采用曲线。

Gill 为 Web3.js v2、流行的 SPL 程序(如 System、Compute Budget、Memo、Token、Token22)以及生态系统程序(如 Metaplex 的 Token Metadata)提供了一个单一入口点。

Gill 提供 Transaction Builders(交易构建器),可以轻松地为常见的 Solana 任务组装随时可签名的交易,例如创建带有元数据的 Token、铸造 Token 和转移 Token。这些任务通常涉及一次与多个程序交互。

Gill 可用于在 Node、Web、React Native 或任何其他 JavaScript 环境中构建 Solana d-app。

Gill 提供了一个 debug mode(调试模式),你可以启用它来自动记录有助于解决交易问题的其他信息。你可以从代码运行的最常见位置启用它,包括在代码中、Node.js 后端、无服务器函数中,甚至直接在 Web 浏览器控制台中。

我可以用 Gill 做什么?

Gill 提供与 Solana Web3.js v2 (Solana Kit) 相同的功能,但具有改进的命名和简化的常见 Solana 任务方法。

通过使用 Gill,你可以完成以下操作:

密钥对/钱包 -:

  • 生成随机密钥对 - 使用 generateKeyPairSigner 生成一个不可提取的密钥对,用于签署交易。不可提取的 意味着私钥无法从实例中检索,从而为密钥对提供增强的安全性。

  • 生成随机可提取密钥对 - 使用 generateExtractableKeyPairSigner 生成可提取的密钥对。这些不太安全,因为它们允许提取密钥材料。

  • 从文件加载钱包 - 使用 loadKeypairSignerFromFile 从文件系统钱包 JSON 文件加载密钥对签名者。默认情况下,此函数加载 Solana CLI 使用的文件中存储的钱包密钥对:~/.config/solana/id.json。它还会解析使用 ~ 字符表示用户主目录的相对路径。

  • 从环境变量加载密钥对 - 使用 loadKeypairSignerFromEnvironment 从环境变量中存储的字节加载 keypairSigner,与标准 Solana 工具一致。

客户端连接和 Rpc 调用 -:

  • 创建 Solana RPC 连接 - 使用 createSolanaClient 创建一个 Solana 客户端,其中包含你喜欢的 RPC 端点 URL 或标准 Solana 网络别名(例如,devnetlocalnetmainnet 等)。

  • 要进行 RPC 调用,RPC 客户端需要你在 RPC 方法上调用 .send(),以将请求发送到你的 RPC 提供程序并接收响应。

交易

  • 创建交易 - 使用 createTransaction 方法轻松创建具有所有标准参数的交易。

  • 签名和发送交易 - 在你拥有可签名的交易后,你可以使用 signTransactionMessageWithSigners 对其进行签名,使用 getSignatureFromTransaction 检索签名(甚至在将其发送到网络之前),并使用 sendAndConfirmTransaction 发送交易。

  • 获取 Solana Explorer 链接 - 使用 getExplorerLink 方法为交易、帐户或区块生成 Solana Explorer 链接。

  • 交易构建器 - 为了简化常见的 Solana 任务(如创建 Token、铸造 Token 和转移 SPL Token),Gill 引入了 Transaction Builders(交易构建器),以帮助轻松地为这些任务组装随时可签名的交易。

调试模式

  • 调试 Solana 交易 - Gill 引入了调试模式,这将使排除 Solana 交易问题变得更容易。默认情况下,调试模式处于禁用状态,以最大限度地减少应用程序的其他日志。但是,通过其灵活的调试控制器,你可以从代码将运行的最常见位置启用它。

示例比较

至此,我们已经了解了 Gill 是什么,为什么它对开发者有帮助,以及它可以完成的常见任务。现在,让我们看一个使用 Gill 和 Web3.js v2 创建 Token 的示例:

使用 Gill 创建“OPOS”Token -:

import {
  createSolanaClient,
  signTransactionMessageWithSigners,
  getSignatureFromTransaction,
  getExplorerLink,
  createKeyPairSignerFromBytes,
  getBase58Codec,
  generateKeyPairSigner
} from "gill";
import { buildCreateTokenTransaction, TOKEN_2022_PROGRAM_ADDRES } from "gill/programs/token";

const { rpc, sendAndConfirmTransaction } = createSolanaClient({
  urlOrMoniker: "devnet",
});

// get the latest blockhash
// 获取最新的区块哈希
const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();

const keypairBase58feePayer = "your_secret_key";
const keypairBytesfeePayer = getBase58Codec().encode(keypairBase58feePayer);
const feepayersigner = await createKeyPairSignerFromBytes(keypairBytesfeePayer);

async function createTokenFunc() {

  const mint = await generateKeyPairSigner();

  // create tokens
  // 创建 Token
  const createTokenTx = await buildCreateTokenTransaction({
    feePayer: feepayersigner,
    latestBlockhash,
    mint: mint,  // Use mintKey here
    metadata: {
      isMutable: true, // if the `updateAuthority` can change this metadata in the future
      // 如果 `updateAuthority` 将来可以更改此元数据
      name: "Only Possible On Solana",
      symbol: "OPOS",
      uri: "https://raw.githubusercontent.com/solana-developers/opos-asset/main/assets/Climate/metadata.json",
    },
    decimals: 2,
    tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
  });

  const signedTransaction = await signTransactionMessageWithSigners(createTokenTx);
  const signature: string = getSignatureFromTransaction(signedTransaction);
  console.log(getExplorerLink({ transaction: signature }));

  // default commitment level of `confirmed`
  // 默认的 `确认` 承诺级别
  await sendAndConfirmTransaction(signedTransaction);
}

createTokenFunc().catch(console.error);

使用 Gill 创建“OPOS”Token:

import {
    airdropFactory,
    appendTransactionMessageInstructions,
    createSolanaRpc,
    createSolanaRpcSubscriptions,
    createTransactionMessage,
    generateKeyPairSigner,
    getSignatureFromTransaction,
    lamports,
    pipe,
    sendAndConfirmTransactionFactory,
    setTransactionMessageFeePayerSigner,
    setTransactionMessageLifetimeUsingBlockhash,
    signTransactionMessageWithSigners,
    some,
  } from "@solana/web3.js";
  import { getCreateAccountInstruction } from "@solana-program/system";
  import {
    getInitializeMintInstruction,
    getMintSize,
    TOKEN_2022_PROGRAM_ADDRESS,
    extension,
    getInitializeMetadataPointerInstruction,
    getInitializeTokenMetadataInstruction,
    tokenMetadataField,
    getUpdateTokenMetadataFieldInstruction,
  } from "@solana-program/token-2022";

  const rpc = createSolanaRpc("http://127.0.0.1:8899");
  const rpcSubscriptions = createSolanaRpcSubscriptions("ws://127.0.0.1:8900");

  const feePayer = await generateKeyPairSigner();
  console.log(feePayer.address);
  const mint = await generateKeyPairSigner();

  await airdropFactory({ rpc, rpcSubscriptions })({
    recipientAddress: feePayer.address,
    lamports: lamports(1_000_000_000n),
    commitment: "confirmed",
  });

  const balance = await rpc.getBalance(feePayer.address).send();
  console.log("balance:", balance.value);

  const metadataPointerExtension = extension("MetadataPointer", {
    authority: some(feePayer.address),
    metadataAddress: some(mint.address),
  });

  const tokenMetadataExtension = extension("TokenMetadata", {
    updateAuthority: some(feePayer.address),
    mint: mint.address,
    name: "Only Possible On Solana",
    symbol: "OPOS",
    uri: "https://raw.githubusercontent.com/solana-developers/opos-asset/main/assets/Climate/metadata.json",
    additionalMetadata: new Map<string, string>([["description", "Only Possible On Solana"]]),
  });

  const spaceWithoutMetadata = BigInt(getMintSize([metadataPointerExtension]));

  const spaceWithMetadata = BigInt(getMintSize([metadataPointerExtension, tokenMetadataExtension]));

  const rent = await rpc.getMinimumBalanceForRentExemption(spaceWithMetadata).send();

  const createAccountInstruction = getCreateAccountInstruction({
    payer: feePayer,
    newAccount: mint,
    lamports: rent,
    space: spaceWithoutMetadata,
    programAddress: TOKEN_2022_PROGRAM_ADDRESS,
  });

  const initializeMetadataPointerInstruction = getInitializeMetadataPointerInstruction({
    mint: mint.address,
    authority: feePayer.address,
    metadataAddress: mint.address,
  });

  const initializeMintInstruction = getInitializeMintInstruction({
    mint: mint.address,
    decimals: 2,
    mintAuthority: feePayer.address,
  });

  const initializeTokenMetadataInstruction = getInitializeTokenMetadataInstruction({
    metadata: mint.address,
    updateAuthority: feePayer.address,
    mint: mint.address,
    mintAuthority: feePayer,
    name: tokenMetadataExtension.name,
    symbol: tokenMetadataExtension.symbol,
    uri: tokenMetadataExtension.uri,
  });

  const updateTokenMetadataInstruction = getUpdateTokenMetadataFieldInstruction({
    metadata: mint.address,
    updateAuthority: feePayer,
    field: tokenMetadataField("Key", ["description"]),
    value: "Only Possible On Solana",
  });

  const instructions = [\
    createAccountInstruction,\
    initializeMetadataPointerInstruction,\
    initializeMintInstruction,\
    initializeTokenMetadataInstruction,\
    updateTokenMetadataInstruction,\
  ];

  const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();

  const transactionMessage = pipe(
    createTransactionMessage({ version: 0 }),
    (message) => setTransactionMessageFeePayerSigner(feePayer, message),
    (message) => setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, message),
    (message) => appendTransactionMessageInstructions(instructions, message),
  );

  const signedTransaction = await signTransactionMessageWithSigners(transactionMessage);

  const transactionSignature = getSignatureFromTransaction(signedTransaction);

  await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(signedTransaction, {
    commitment: "confirmed",
    skipPreflight: true,
  });

  console.log("Transaction Signature:", `https://explorer.solana.com/tx/${transactionSignature}?cluster=custom`);

正如你所看到的,由于其交易构建器和比 Web3.js v2 更高级别的抽象,使用 Gill 创建 Token 非常容易。使用一个交易构建器和一些代码行,我们创建了一个 SPL Token。

现在我们了解了 Gill 是什么、为什么它很重要以及它如何增强 Web3.js v2 的开发者体验,现在是编写一个简单的 SPL Token 铸造和转移示例的时候了。开始吧!

使用 Gill 快速铸造和转移 SPL Token

众所周知,有很多方法可以铸造或创建 SPL Token。我们可以使用带有 Solana Web3.js 和 Solana 开发者助手的 JavaScript/TypeScript 来处理 SPL Token,或者用 Rust/Anchor 创建一个 Solana 程序来铸造 SPL Token。在本指南中,我们将使用 Gill 库来铸造 SPL Token。我们还将利用最快的方法,即利用 Gill 的预构建交易构建器方法来进行各种交易。

你需要什么

  • Solana Web3.js v2 的经验
  • 安装了最新的 Node.js 版本
  • 安装了 TypeScript 和 ts-node

本指南中使用的依赖项

对于本项目,package.json 文件中的依赖项将如下所示:

"dependencies": {
    "esrun": "^3.2.26",
    "gill": "^0.6.0"
  },
  "devDependencies": {
    "@types/node": "^22.13.10",
    "ts-node": "^10.9.2",
    "typescript": "^5.8.2"
  }

让我们设置一个新项目:

mkdir spl-token && cd spl-token

将你的项目初始化为 Node.js 项目:

npm init -y

安装所需的依赖项:

pnpm install gill esrun && pnpm install --save-dev @types/node typescript ts-node

在你的项目目录中创建一个名为 spl-token.ts 的新文件:

echo > spl-token.ts

太棒了!现在,让我们开始编码。

导入依赖项

在你的 spl-token.ts 文件中,让我们首先导入必要的依赖项:

import {
    address,
    KeyPairSigner,
    getBase58Codec,
    getExplorerLink,
    createSolanaClient,
    generateKeyPairSigner,
    getSignatureFromTransaction,
    createKeyPairSignerFromBytes,
    signTransactionMessageWithSigners,
    setTransactionMessageLifetimeUsingBlockhash,
  } from "gill";

  import {
    buildCreateTokenTransaction,
    buildMintTokensTransaction,
    buildTransferTokensTransaction
  } from "gill/programs/token";

我们正在从 Gill 库导入关键函数,以创建、铸造和转移 SPL Token。

创建一个 RPC 连接以与区块链交互

  // create Rpc connection
  // 创建 Rpc 连接
  const { rpc, sendAndConfirmTransaction } = createSolanaClient({
    urlOrMoniker: "devnet",
  });

  // get slot
  // 获取插槽
  const slot = await rpc.getSlot().send();

  // get the latest blockhash
  // 获取最新的区块哈希
  const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();

我们使用 Gill 的 createSolanaClient 方法来建立与 Devnet 的 RPC 连接。要调用任何 RPC 方法,我们需要在 RPC 方法上使用 .send() 将请求发送到 RPC 提供程序并接收响应。

生成密钥对

 const keypairBase58alice = "your_wallet_secret_key";
 const keypairBytesalice = getBase58Codec().encode(keypairBase58alice);
 const aliceKeyPair = await createKeyPairSignerFromBytes(keypairBytesalice);

 // KeyPairs and addresses
 // 密钥对和地址
 const alice = aliceKeyPair.address;

 const bob = address("4d4zsfq4gtJixDGvisSdFjsY78uH7BypkwmkXL1D8RfT");

 const mint = await generateKeyPairSigner();

在这里,我们生成 Alice、Bob 和 Mint 的地址。对于 Alice,我们使用一个密钥对来生成她的地址。在本指南中,Alice 将在她自己的钱包中创建和铸造 Token,然后将铸造的 Token 发送到 Bob 的钱包。

创建主函数

接下来,让我们创建我们的 main(主) 函数,它将包含我们脚本的逻辑:

async function main(){

// Create token transaction
// 创建 Token 交易

// Mint token transaction
// 铸造 Token 交易

// Transfer tokens transaction
// 转移 Token 交易

}

main().catch(console.error);

创建或铸造 spl token

让我们将以下代码添加到主函数作为第一步:

const createTokenTx = await buildCreateTokenTransaction({
      feePayer: aliceKeyPair,
      latestBlockhash,
      mint: mint,  // Use mintKey here
      // 在此处使用 mintKey
      metadata: {
        isMutable: true, // if the `updateAuthority` can change this metadata in the future
        // 如果 `updateAuthority` 将来可以更改此元数据
        name: "Only Possible On Solana",
        symbol: "OPOS",
        uri: "https://raw.githubusercontent.com/solana-developers/opos-asset/main/assets/Climate/metadata.json",
      },
      decimals: 2,
    });

const signedTransaction = await signTransactionMessageWithSigners(createTokenTx);
const signature: string = getSignatureFromTransaction(signedTransaction);
console.log(getExplorerLink({ transaction: signatureformint }));

// default commitment level of `confirmed`
// 默认的 `确认` 承诺级别
await sendAndConfirmTransaction(signedTransaction);

在这里,我们使用 Gill 的 buildCreateTokenTransaction tx 构建器来创建一个 SPL Token,指定 aliceKeypair 作为 feePayer,并为 Token 提供元数据。

接下来,我们使用 signTransactionMessageWithSigners 对交易进行签名,然后再将其发送到网络,类似于 Web3.js。然后,我们使用 getSignatureFromTransaction 获取签名,最后使用 sendAndConfirmTransaction 将交易发送到网络。

恭喜!我们的 OPOS Token 已经创建。请查看 Solana Explorer 链接以获取详细信息。

将创建的 Token 铸造到 Alice 的钱包

让我们将以下代码添加到主函数作为第二步:

const mintTokensTx = await buildMintTokensTransaction({
      feePayer: aliceKeyPair,
      latestBlockhash,
      mint,
      mintAuthority: aliceKeyPair,
      amount: 1000, // note: be sure to consider the mint's `decimals` value
      // 注意:请务必考虑 mint 的 `decimals` 值
      // if decimals=2 => this will mint 10.00 tokens
      // 如果 decimals=2 => 这将铸造 10.00 个 Token
      // if decimals=4 => this will mint 0.100 tokens
      // 如果 decimals=4 => 这将铸造 0.100 个 Token
      destination: alice,
      // use the correct token program for the `mint`
      // 使用正确的 Token 程序来处理 `mint`
      // tokenProgram, // default=TOKEN_PROGRAM_ADDRESS
      // 默认值=TOKEN_PROGRAM_ADDRESS
      // default cu limit set to be optimized, but can be overriden here
      // 默认的 cu 限制设置为优化,但可以在此处覆盖
      // computeUnitLimit?: number,
      // obtain from your favorite priority fee api
      // 从你最喜欢的优先费用 api 获取
      // computeUnitPrice?: number, // no default set
      // 没有设置默认值
    });

    const signedTransactionformint = await signTransactionMessageWithSigners(mintTokensTx);
    const signatureformint: string = getSignatureFromTransaction(signedTransactionformint);
    console.log(getExplorerLink({ transaction: signatureformint }));
    // default commitment level of `confirmed`
    // 默认的 `确认` 承诺级别
    await sendAndConfirmTransaction(signedTransactionformint);

在这里,我们使用 Gill 的 buildMintTokensTransaction tx 构建器将 Token 铸造到 Alice 的地址,对交易进行签名,获取签名,并将交易发送到网络。

你无需担心关联的 Token 账户,因为在交易构建器中,如果目标所有者没有 mint 的关联 Token 账户 (ATA),则会自动为其创建一个。

恭喜!你已将 10 个 OPOS SPL Token 铸造到 Alice 的 Token 账户中。

将 spl token 转移到 Bob 的钱包

让我们将以下代码添加到主函数作为第三步:

const transferTokensTx = await buildTransferTokensTransaction({
      feePayer: aliceKeyPair,
      latestBlockhash,
      mint,
      authority: aliceKeyPair,
      // sourceAta, // default=derived from the `authority`.
      // 默认值=从 `authority` 派生。
      /*
       * if the `sourceAta` is not derived from the `authority` (like for multi-sig wallets),
       * 如果 `sourceAta` 不是从 `authority` 派生的(例如对于多重签名钱包),
       * manually derive with `getAssociatedTokenAccountAddress()`
       * 使用 `getAssociatedTokenAccountAddress()` 手动派生
      */
      amount: 900, // note: be sure to consider the mint's `decimals` value
      // 注意:请务必考虑 mint 的 `decimals` 值
      // if decimals=2 => this will transfer 9.00 tokens
      // 如果 decimals=2 => 这将转移 9.00 个 Token
      // if decimals=4 => this will transfer 0.090 tokens
      // 如果 decimals=4 => 这将转移 0.090 个 Token
      destination: bob,
      // use the correct token program for the `mint`
      // 使用正确的 Token 程序来处理 `mint`
      //  tokenProgram, // default=TOKEN_PROGRAM_ADDRESS
      // 默认值=TOKEN_PROGRAM_ADDRESS
      // default cu limit set to be optimized, but can be overriden here
      // 默认的 cu 限制设置为优化,但可以在此处覆盖
      // computeUnitLimit?: number,
      // obtain from your favorite priority fee api
      // 从你最喜欢的优先费用 api 获取
      // computeUnitPrice?: number, // no default set
      // 没有设置默认值
    });

    const signedTransactionfortransfer = await signTransactionMessageWithSigners(transferTokensTx);
    const signaturefortransfer: string = getSignatureFromTransaction(signedTransactionfortransfer);
    console.log(getExplorerLink({ transaction: signaturefortransfer }));

    // default commitment level of `confirmed`
    // 默认的 `确认` 承诺级别
    await sendAndConfirmTransaction(signedTransactionfortransfer);

我们使用 buildTransferTokensTransaction 方法将 SPL Token 从 Alice 转移到 Bob,然后签名、获取签名并将其发送到网络。关联的 Token 账户 (ATA) 也会为此 mint 自动为 Bob 的钱包创建。

恭喜!你已将 9 个 OPOS Token 从 Alice 的 Token 账户转移到 Bob 的 Token 账户。

运行你的代码

在你的终端中,键入:

npx esrun ./index.ts

成功执行后,你应该会看到每个操作的三个 Solana Explorer 链接的输出:创建、铸造和转移“OPOS”Token。

https://explorer.solana.com/tx/58KC1GPc1f8aCUox6Pst7YheYRCqrQY9Np2gP6LfqDP5ogQjP5Hy76opzmJ8EKW2PyMdoGh71MYGWHL6oYHLAvdD
https://explorer.solana.com/tx/4DXAFBfsAVCgZ3X3rwEZ72EN81JVWj2zpzsYERCu5xitf1aztuytn9og3cyNbNeR3t5KnaJgneNckFy6MGAoWLGr
https://explorer.solana.com/tx/4PkHW9dSbQicKcempBoD3VCe2xQhJidJ6gptXPNvq4LVRBzJYAQrN5AGcaVfu88NabrczkgV8FrF4x1sVxKB7xSH

让我们总结一下

Gill 是一个新的 JavaScript 客户端库,用于与 Solana 区块链交互。在这篇文章中,我们讨论了 Gill 是什么、为什么它对 Solana 开发者很重要,以及它如何帮助改善开发者体验。我们还探讨了它的关键特性,提供了将其与 Web3.js v2 进行比较的示例,并演示了如何使用 Gill 创建和铸造 SPL Token。

总的来说,你会发现 Gill 在使用 Web3.js v2 时提供了出色的开发者体验。

更多资源

  • 原文链接: dev.to/shivamsspirit/int...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 1
收藏 1
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
Shivam
Shivam
江湖只有他的大名,没有他的介绍。