<h1 align="center"> gill </h1>
<p align="center"> 用于与 Solana 区块链交互的 javascript/typescript 客户端库 </p>
<p align="center"> <a href="https://github.com/DecalLabs/gill/actions/workflows/publish-packages.yml"><img src="https://img.shields.io/github/actions/workflow/status/DecalLabs/gill/publish-packages.yml?logo=GitHub&label=tests" /></a> <a href="https://www.npmjs.com/package/gill"><img src="https://img.shields.io/npm/v/gill?logo=npm&color=377CC0" /></a> <a href="https://www.npmjs.com/package/gill"><img src="https://img.shields.io/npm/dm/gill?color=377CC0" /></a> </p>
<p align="center"> <img width="600" alt="gill" src="https://raw.githubusercontent.com/DecalLabs/gill/refs/heads/master/docs/public/cover.png" /> </p>
概述
欢迎使用 gill,这是一个用于与 Solana 区块链交互的 JavaScript/TypeScript 客户端库。你可以使用它在 Node、web、React Native 或几乎任何其他 JavaScript 环境中构建 Solana 应用程序。
Gill 构建于 Anza 构建的 Solana 现代 javascript 库之上,称为 @solana/kit(以前称为“web3.js v2”)。通过在底层使用相同的类型和函数,gill 与 kit 兼容。请参阅 用 gill 替换 Kit。
有关使用 gill 与 web3js v2 的比较,请查看 比较示例。
安装
使用你选择的包管理器安装 gill:
npm install gillpnpm add gillyarn add gill用 gill 替换 Kit
@solana/kit 库中的所有导入都可以直接替换为 gill 以实现完全相同的功能。此外,还可以解锁仅包含在 Gill 中的附加功能,例如 createSolanaTransaction。
只需安装 gill 并替换你的导入
快速开始
在
/examples目录中查找使用gill的示例代码片段集合,包括 基本操作 和常见的 token 操作。
- 创建 Solana RPC 连接
- 进行 Solana RPC 调用
- 创建交易
- 签署交易
- 模拟交易
- 发送和确认交易
- 获取交易签名
- 获取 Solana Explorer 链接
- 计算帐户的最低租金余额
- 生成密钥对和签名者
- 生成可提取的密钥对和签名者
你还可以找到一些 NodeJS 特定的辅助程序,例如:
你可以找到用于常见任务的 交易构建器,包括:
有关故障排除和调试 Solana 交易,请参阅下面的 调试模式。
你还可以查阅 Anza 的 JavaScript 客户端 的文档,以获取更多信息和有用的资源。
生成密钥对和签名者
对于大多数“签名”操作,你需要一个 KeyPairSigner 实例,该实例可用于签署交易和消息。
要生成一个随机的 KeyPairSigner:
import { generateKeyPairSigner } from "gill"; const signer: KeyPairSigner = await generateKeyPairSigner();注意:这些签名者是不可提取的,这意味着无法从实例中获取密钥材料。 这是一种更安全的做法,强烈建议使用,而不是可提取的密钥对,除非你确实需要 出于某种原因能够保存密钥对。
生成可提取的密钥对和签名者
可提取的密钥对不太安全,除非你确实需要出于某种原因保存密钥,否则不应使用。 由于在保存这些密钥对时有一些有用的用例,因此 gill 包含一个单独的显式函数来生成 这些可提取的密钥对。
要生成一个随机的、可提取的KeyPairSigner:
import { generateExtractableKeyPairSigner } from "gill"; const signer: KeyPairSigner = await generateExtractableKeyPairSigner();警告:使用 可提取的 密钥对本质上不太安全,因为它们允许提取密钥材料。 显然。因此,应谨慎使用它们,并且仅当你有明确的原因需要 提取密钥材料(例如,如果你要将密钥保存到文件)。
创建 Solana RPC 连接
为任何 RPC URL 或标准 Solana 网络别名(即 devnet、localnet、mainnet 等)创建 Solana rpc 和 rpcSubscriptions 客户端。
import { createSolanaClient } from "gill"; const { rpc, rpcSubscriptions, sendAndConfirmTransaction } = createSolanaClient({ urlOrMoniker: "mainnet", });使用 Solana 别名将连接到公共 RPC 端点。这些端点受速率限制,不应在生产应用程序中使用。应用程序应找到自己的 RPC 提供商以及他们提供的 URL。
要为你的本地测试验证器创建一个 RPC 客户端:
import { createSolanaClient } from "gill"; const { rpc, rpcSubscriptions, sendAndConfirmTransaction } = createSolanaClient({ urlOrMoniker: "localnet", });要为自定义 RPC 提供商或服务创建一个 RPC 客户端:
import { createSolanaClient } from "gill"; const { rpc, rpcSubscriptions, sendAndConfirmTransaction } = createSolanaClient({ urlOrMoniker: "https://private-solana-rpc-provider.com", });进行 Solana RPC 调用
在你拥有 Solana rpc 连接后,你可以直接在其上进行所有 JSON RPC 方法 调用。
import { createSolanaClient } from "gill"; const { rpc } = createSolanaClient({ urlOrMoniker: "devnet" }); // 获取 slot const slot = await rpc.getSlot().send(); // 获取最新的 blockhash const { value: latestBlockhash } = await rpc.getLatestBlockhash().send();
rpc客户端要求你在 RPC 方法上调用.send(),以便实际将请求发送到你的 RPC 提供商并获取响应。
你还可以在 RPC 调用中包含自定义配置设置,例如使用 JavaScript AbortController,方法是将其传递到 send() 中:
import { createSolanaClient } from "gill"; const { rpc } = createSolanaClient({ urlOrMoniker: "devnet" }); // 创建一个新的 AbortController。 const abortController = new AbortController(); // 当用户离开当前页面时中止请求。 function onUserNavigateAway() { abortController.abort(); } // 仅当用户离开页面时,才会中止请求。 const slot = await rpc.getSlot().send({ abortSignal: abortController.signal });创建交易
快速创建 Solana 交易:
注意:
feePayer可以是Address或TransactionSigner。
import { createTransaction } from "gill"; const transaction = createTransaction({ version, feePayer, instructions, // 强烈建议设置计算预算值,以便最大限度地提高交易着陆率 // computeUnitLimit: number, // computeUnitPrice: number, });要在设置最新 blockhash 的同时创建交易:
import { createTransaction } from "gill"; const { value: latestBlockhash } = await rpc.getLatestBlockhash().send(); const transaction = createTransaction({ version, feePayer, instructions, latestBlockhash, // 强烈建议设置计算预算值,以便最大限度地提高交易着陆率 // computeUnitLimit: number, // computeUnitPrice: number, });签署交易
如果你的交易已经通过 createTransaction 设置了最新的 blockhash 生存期:
import { createTransaction, signTransactionMessageWithSigners } from "gill"; const transaction = createTransaction(...); const signedTransaction = await signTransactionMessageWithSigners(transaction);如果你的交易没有通过 createTransaction 设置最新的 blockhash 生存期,你必须在签署操作之前(或期间)设置最新的 blockhash 生存期:
import { createTransaction, createSolanaClient, signTransactionMessageWithSigners, setTransactionMessageLifetimeUsingBlockhash, } from "gill"; const { rpc } = createSolanaClient(...); const transaction = createTransaction(...); const { value: latestBlockhash } = await rpc.getLatestBlockhash().send(); const signedTransaction = await signTransactionMessageWithSigners( setTransactionMessageLifetimeUsingBlockhash(latestBlockhash, transaction), );模拟交易
要在区块链上模拟一笔交易,你可以使用从 createSolanaClient() 初始化的 simulateTransaction() 函数。
import { ... } from "gill"; const { simulateTransaction } = createSolanaClient({ urlOrMoniker: "mainnet", }); const transaction = createTransaction(...); const simulation = await simulateTransaction(transaction)提供给 simulateTransaction() 的交易可以是已签名或未签名的。
发送和确认交易
要将交易发送到区块链并确认,你可以使用从 createSolanaClient() 初始化的 sendAndConfirmTransaction 函数。
import { ... } from "gill"; const { sendAndConfirmTransaction } = createSolanaClient({ urlOrMoniker: "mainnet", }); const transaction = createTransaction(...); const signedTransaction = await signTransactionMessageWithSigners(transaction); const signature: string = getSignatureFromTransaction(signedTransaction); console.log(getExplorerLink({ transaction: signature })); // 默认提交级别为“已确认” await sendAndConfirmTransaction(signedTransaction)如果你希望更精细地控制 sendAndConfirmTransaction 功能的配置,你可以包含配置设置:
await sendAndConfirmTransaction(signedTransaction, { commitment: "confirmed", skipPreflight: true, maxRetries: 10n, ... });获取已签名交易的签名
在你拥有由 feePayer 签名的交易(部分签名或完全签名)后,你可以按如下方式获取交易签名:
import { getSignatureFromTransaction } from "gill"; const signature: string = getSignatureFromTransaction(signedTransaction); console.log(signature); // 示例输出:4nzNU7YxPtPsVzeg16oaZvLz4jMPtbAzavDfEFmemHNv93iYXKKYAaqBJzFCwEVxiULqTYYrbjPwQnA1d9ZCTELg注意:在交易由费用支付者签名后,它将具有交易签名(也称为交易 ID)。 这是因为 Solana 交易 ID 是交易
signatures数组中的第一个项目。因此,客户端 应用程序有可能在甚至发送到网络进行确认之前就知道签名。
获取交易、帐户或区块的 Solana Explorer 链接
为任何集群上的交易、帐户或区块制作 Solana Explorer 链接。
如果在
getExplorerLink函数中未提供cluster,则默认为mainnet。
获取交易的 Solana Explorer 链接
要获取交易签名(也称为交易 ID)的 Explorer 链接:
import { getExplorerLink } from "gill"; const link: string = getExplorerLink({ transaction: "4nzNU7YxPtPsVzeg16oaZvLz4jMPtbAzavDfEFmemHNv93iYXKKYAaqBJzFCwEVxiULqTYYrbjPwQnA1d9ZCTELg", });如果你有部分签名或完全签名的交易,你甚至可以在将交易发送到网络之前获取 Explorer 链接:
import { getExplorerLink, getSignatureFromTransaction signTransactionMessageWithSigners, } from "gill"; const signedTransaction = await signTransactionMessageWithSigners(...); const link: string = getExplorerLink({ transaction: getSignatureFromTransaction(signedTransaction), });获取帐户的 Solana Explorer 链接
要获取 Solana 的 devnet 上帐户的 Explorer 链接:
import { getExplorerLink } from "gill"; const link: string = getExplorerLink({ cluster: "devnet", account: "nick6zJc6HpW3kfBm4xS2dmbuVRyb5F3AnUvj5ymzR5", });要获取本地测试验证器上帐户的 Explorer 链接:
import { getExplorerLink } from "gill"; const link: string = getExplorerLink({ cluster: "localnet", account: "11111111111111111111111111111111", });获取区块的 Solana Explorer 链接
要获取区块的 Explorer 链接:
import { getExplorerLink } from "gill"; const link: string = getExplorerLink({ cluster: "mainnet", block: "242233124", });计算帐户的最低租金
要计算帐户的最低租金余额(也称为数据存储押金):
import { getMinimumBalanceForRentExemption } from "gill"; // 当未提供 `space` 参数时:默认为 `0` const rent: bigint = getMinimumBalanceForRentExemption(); // 预期值:890_880n // 与相同 // getMinimumBalanceForRentExemption(0); // 与相同,但这需要网络调用 // const rent = await rpc.getMinimumBalanceForRentExemption(0n).send();import { getMinimumBalanceForRentExemption } from "gill"; const rent: bigint = getMinimumBalanceForRentExemption(50 /* 50 字节 */); // 预期值:1_238_880n // 与相同,但这需要网络调用 // const rent = await rpc.getMinimumBalanceForRentExemption(50n).send();注意:目前,帐户的最低租金金额是基于 Solana 运行时中的静态值计算的。 虽然你可以在你的 连接上使用
getMinimumBalanceForRentExemptionRPC 调用来获取此值,但这将导致网络调用并受到 延迟的影响。
Node 特定的导入
gill 包具有特定的导入,用于 NodeJS 服务器后端和/或有权访问 Node 特定 API 的无服务器环境(例如通过 node:fs 访问文件系统)。
import { ... } from "gill/node"从文件加载密钥对
import { loadKeypairSignerFromFile } from "gill/node"; // 默认文件路径:~/.config/solana/id.json const signer = await loadKeypairSignerFromFile(); console.log("address:", signer.address);从文件系统钱包 json 文件加载 KeyPairSigner,例如从 Solana CLI 输出的文件(即数字的 JSON 数组)。
默认情况下,加载的密钥对文件是 Solana CLI 的默认密钥对:~/.config/solana/id.json
要从特定文件路径加载签名者:
import { loadKeypairSignerFromFile } from "gill/node"; const signer = await loadKeypairSignerFromFile("/path/to/your/keypair.json"); console.log("address:", signer.address);将密钥对保存到文件
有关保存到 env 文件,请参阅
saveKeypairSignerToEnvFile。
将可提取的KeyPairSigner 保存到本地 json 文件(例如 keypair.json)。
import { ... } from "gill/node"; const extractableSigner = generateExtractableKeyPairSigner(); await saveKeypairSignerToFile(extractableSigner, filePath);有关如何从本地文件系统加载密钥对,请参阅 loadKeypairSignerFromFile。
从环境变量加载密钥对
从环境变量进程中存储的字节加载 KeyPairSigner(例如 process.env[variableName])
import { loadKeypairSignerFromEnvironment } from "gill/node"; // 从存储在 `process.env[variableName]` 的字节加载签名者 const signer = await loadKeypairSignerFromEnvironment(variableName); console.log("address:", signer.address);将密钥对保存到环境变量文件
将可提取的KeyPairSigner 保存到本地环境变量文件(例如 .env)。
import { ... } from "gill/node"; const extractableSigner = generateExtractableKeyPairSigner(); // 默认值:envPath = `.env`(在你当前的工作目录中) await saveKeypairSignerToEnvFile(extractableSigner, variableName, envPath);有关如何从环境变量加载密钥对,请参阅 loadKeypairSignerFromEnvironment。
从 base58 环境变量加载密钥对
从环境变量进程中存储的字节加载 KeyPairSigner(例如 process.env[variableName])
import { loadKeypairSignerFromEnvironmentBase58 } from "gill/node"; // 从存储在 `process.env[variableName]` 的base58密钥对加载签名者 const signer = await loadKeypairSignerFromEnvironmentBase58(variableName); console.log("address:", signer.address);交易构建器
为了简化常见交易的创建,gill 包括各种“交易构建器”,以帮助轻松组装 这些任务的随时可以签名的交易,这些交易通常一次与多个程序交互。
由于每个交易构建器都限定于单个任务,因此它们可以轻松抽象出各种样板代码, 同时还有助于创建优化的交易,包括:
- 设置/建议默认的计算单元限制(当然很容易覆盖),以优化交易并提高 着陆率
- 在需要时自动派生所需的地址
- 通常建议安全默认设置和回退设置
所有自动填充的信息也可以手动覆盖,以确保你始终可以实现 你期望的功能。
由于这些交易构建器可能不适合所有人,因此 gill 为每个 用于构建相应交易的组件公开了一个相关的“指令构建器”功能。开发人员也可以完全放弃这些构建器 抽象并手动构建相同的功能。
使用元数据创建 token
构建一个可以使用元数据创建 token 的交易,可以使用 原始 token 或 token 扩展(token22) 程序。
- 使用原始 token 程序(
TOKEN_PROGRAM_ADDRESS,默认)创建的 token 将使用 Metaplex 的 Token Metadata 程序进行链上元数据 - 使用 token 扩展程序(
TOKEN_2022_PROGRAM_ADDRESS)创建的 token 将使用元数据指针 扩展
相关指令构建器:getCreateTokenInstructions
import { buildCreateTokenTransaction } from "gill/programs/token"; const createTokenTx = await buildCreateTokenTransaction({ feePayer: signer, latestBlockhash, mint, // mintAuthority, // default=与 `feePayer` 相同 metadata: { isMutable: true, // 如果 `updateAuthority` 将来可以更改此元数据 name: "Only Possible On Solana", symbol: "OPOS", uri: "https://raw.githubusercontent.com/solana-developers/opos-asset/main/assets/Climate/metadata.json", }, // updateAuthority, // default=与 `feePayer` 相同 decimals: 2, // default=9, tokenProgram, // default=TOKEN_PROGRAM_ADDRESS, 也支持 token22 // 设置默认 cu 限制以进行优化,但可以在此处覆盖 // computeUnitLimit?: number, // 从你最喜欢的优先级费用 api 获取 // computeUnitPrice?: number, // 未设置默认值 });将 token 铸造到目标钱包
构建一个将新 token 铸造到 destination 钱包地址(提高 token 的整体供应量)的交易。
- 确保你设置了
mint本身使用的正确的tokenProgram - 如果
destination所有者没有为mint创建关联的 token 帐户 (ata),则将自动为他们创建 - 在此交易中设置
amount时,请确保考虑到mint的decimals
相关指令构建器:getMintTokensInstructions
import { buildMintTokensTransaction } from "gill/programs/token"; const mintTokensTx = await buildMintTokensTransaction({ feePayer: signer, latestBlockhash, mint, mintAuthority: signer, amount: 1000, // 注意:请务必考虑 mint 的 `decimals` 值 // 如果 decimals=2 => 这将铸造 10.00 个 token // 如果 decimals=4 => 这将铸造 0.100 个 token destination, // 为 `mint` 使用正确的 token 程序 tokenProgram, // default=TOKEN_PROGRAM_ADDRESS // 设置默认 cu 限制以进行优化,但可以在此处覆盖 // computeUnitLimit?: number, // 从你最喜欢的优先级费用 api 获取 // computeUnitPrice?: number, // 未设置默认值 });将 token 转移到目标钱包
构建一个将 token 从 source(即从 sourceAta 到 destinationAta)转移到 destination 钱包地址的交易。
- 确保你设置了
mint本身使用的正确的tokenProgram - 如果
destination所有者没有为mint创建关联的 token 帐户 (ata),则将自动为他们创建 - 在此交易中设置
amount时,请确保考虑到mint的decimals
相关指令构建器:getTransferTokensInstructions
import { buildTransferTokensTransaction } from "gill/programs/token"; const transferTokensTx = await buildTransferTokensTransaction({ feePayer: signer, latestBlockhash, mint, authority: signer, // sourceAta, // default=从 `authority` 派生。 /** * 如果 `sourceAta` 不是从 `authority` 派生的(例如对于多重签名钱包), * 使用 `getAssociatedTokenAccountAddress()` 手动派生 */ amount: 900, // 注意:请务必考虑 mint 的 `decimals` 值 // 如果 decimals=2 => 这将转移 9.00 个 token // 如果 decimals=4 => 这将转移 0.090 个 token destination: address(...), // 为 `mint` 使用正确的 token 程序 tokenProgram, // default=TOKEN_PROGRAM_ADDRESS // 设置默认 cu 限制以进行优化,但可以在此处覆盖 // computeUnitLimit?: number, // 从你最喜欢的优先级费用 api 获取 // computeUnitPrice?: number, // 未设置默认值 });调试模式
在 gill 中,你可以启用“调试模式”以自动记录其他信息,这些信息将有助于 对你的交易进行故障排除。
默认情况下,调试模式处于禁用状态,以最大限度地减少应用程序的其他日志。但凭借其灵活的调试 控制器,你可以从代码运行的最常见位置启用它。包括你的代码本身、NodeJS 后端、无服务器函数,甚至 Web 浏览器控制台本身。
gill 中存在的一些现有调试日志示例:
- 在你发送交易时记录它们的 Solana Explorer 链接
- 记录 base64 交易字符串以通过以下方式进行故障排除
mucho inspect或 Solana Explorer 的 交易检查器
如何启用调试模式
要启用调试模式,请将以下任何一项设置为 true 或 1:
process.env.GILL_DEBUGglobal.__GILL_DEBUG__window.__GILL_DEBUG__(即在 Web 浏览器的控制台中)- 或手动设置任何调试日志级别(请参阅下文)
要在你的应用程序中设置所需的日志输出级别,请设置以下其中一项的值(默认值: info):
process.env.GILL_DEBUG_LEVELglobal.__GILL_DEBUG_LEVEL__window.__GILL_DEBUG_LEVEL__(即在 Web 浏览器的控制台中)
支持的日志级别(按优先级顺序):
debug(最低)info(默认)warnerror
自定义调试日志
Gill 还导出了它在内部使用的相同调试函数,使你可以实现与 你的 Solana 交易,并使用与 gill 相同的控制器。
isDebugEnabled()- 检查是否启用了调试模式debug()- 如果达到设置的日志级别,则打印调试消息
import { debug, isDebugEnabled } from "gill"; if (isDebugEnabled()) { // 你的自定义逻辑 } // 如果启用了“info”或更高级别的日志级别,则记录此消息 debug("custom message"); // 如果启用了“debug”或更高级别的日志级别,则记录此消息 debug("custom message", "debug"); // 如果启用了“warn”或更高级别的日志级别,则记录此消息 debug("custom message", "warn"); // 如果启用了“warn”或更高级别的日志级别,则记录此消息 debug("custom message", "warn");程序客户端
使用 gill,你还可以导入一些最常用的程序客户端。这些客户端也 完全可进行 tree-shaking,因此如果你不在项目中导入它们,它们将在构建时被 JavaScript 打包程序(即 Webpack)删除。
要导入任何这些程序客户端:
import { ... } from "gill/programs"; import { ... } from "gill/programs/token";注意:某些客户端重新导出的客户端程序客户端具有命名冲突。因此,它们可能会在
gill/programs的子路径下重新导出。例如,gill/programs/token。
gill 中包含的程序客户端是:
- 系统程序 - 从
@solana-program/system重新导出 - 计算预算程序 - 从
@solana-program/compute-budget重新导出 - 备注程序 - 从
@solana-program/memo重新导出 - Token 程序和 Token 扩展程序(也称为 Token22)- 从
@solana-program/token-2022重新导出,它是与原始 Token 程序的完全向后兼容的 客户端 - 地址查找表程序 - 从
@solana-program/address-lookup-table重新导出 - 来自 Metaplex 的 Token 元数据程序(仅 v3 功能)- 通过 Codama 的 IDL 生成 (来源)
如果在 gill/programs 或其子路径中未导出其中一个现有客户端,你当然可以 手动将它们的兼容客户端添加到你的存储库。
注意:由于 Token 扩展程序客户端与原始 Token 程序客户端完全兼容,因此
gill仅发布@solana-program/token-2022客户端和TOKEN_PROGRAM_ADDRESS,以便从 库中删除所有冗余代码。要使用原始 Token 程序,只需将
TOKEN_PROGRAM_ADDRESS作为任何 指令的程序地址传递即可
其他兼容的程序客户端
从 solana-program GitHub 组织(以前称为 Solana 程序库 (SPL)),你可以找到各种其他特定程序的客户端库。安装它们各自的 包以与 gill 结合使用:
- Stake 程序 -
@solana-program/stake - Vote 程序 -
@solana-program/vote
从 IDL 生成程序客户端
如果你想使用此库轻松地与任何自定义程序交互,你可以使用 Codama 来使用其 IDL 生成兼容的 JavaScript/TypeScript 客户端。你可以将生成的客户端存储在你的存储库中,也可以将其作为 NPM 包发布,以便其他人轻松使用。
- 原文链接: github.com/DecalLabs/gil...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~