Web3 新手系列:现在升级 @solana/web3.js 2.x 开启函数式编程
Solana Web3.js 是一个功能非常丰富的 JavaScript 库,在今年11月正式发布了 2.x 版本。相比 1.x,新版本变化比较大,这篇文章尝试对其主要变化做一些概括。
目前由于 2.x 版本刚发布,使用量并不高,很多使用量很高的库也没有切换。不过我们可以先了解一下,为以后的迁移做好准备。
版本对比
不得不承认,旧版本使用起来其实更加简单。首先,旧版实际上只有一个包:@solana/web3.js 所有内容都在它里面。并且它基于类,封装了大量常用的操作。例如 Connection 类,它带有几十种方法,基本将开发者所想要的功能涵盖了。而且 Solana cookbook 中提供了大量的示例代码,开发者总能从这里找到自己需要的东西。
但是,这也造成了另一些问题:虽然开发者实际上使用到的功能,往往只占其中的很小一部分,但是最终整个代码库都会被下载到用户的设备上。由于整个库的代码量很大,这可能会持续一小段时间。
反观 2.x 版本,官方团队将原有的代码库拆分为了几个很小的模块组成,例如 @solana/accounts、@solana/codecs、@solana/rpc、@solana/signers、@solana/transactions 等。并且放弃了基于类的实现,更多的采用单个函数,这在 JavaScript 代码构建时的优化很有帮助,dapp 没有使用到的代码将会被删除,实际上不会被下载到用户设备上。据官方文档的统计,使用新版的 dapp 基本都能得到 30% 的尺寸优化,如果只用到了很小一部分功能,那么能得到更高的优化比例(https://solana-labs.github.io/solana-web3.js/#statistics)。
这就对 Solana 团队的文档水平带来了考验,如何让开发者迅速找到需要的功能,将是一个重要的事项。不过目前看来,至少包名具有不错的语义性,从名字上就能大概知道它们可以被用来做什么。这应该能从一定程度上减少开发者迁移的难度。
当然,由于其刚发布不久,所以很多项目还没有进行迁移。Solana Cookbook 上,2.x 版本的示例也比较少。并且由于新版本倾向于使用运行时内置功能(例如生成密钥对),文档中却缺失对这里的描述,导致有些地方让开发者有些无所适从。
2.x 还有一个很重要的特点:零依赖。这一点可能对很多用户来说并不重要,但是从今年 12 月初发生在 @solana/web3.js 1.95.5 和 1.95.6 版本上的供应链攻击来看,更多的外部输入和依赖会急速增加安全事件发生的可能。而随着 2.x 版本的发布,Web3.js 的开发团队决定应该更多的使用本机的功能,而取消外部依赖和 Polyfills 的引入。以后可能会有变化,但至少目前来说,2.x 版本消除了所有外部依赖。
重要变更点
连接
如上文所介绍的,1.x 有大量方法通过 Connection 来提供。不过其最主要的功能,还是用于通过配置 rpc 请求地址,创建一个请求发送器。然后通过它来发送各种请求。
在 2.x 中,则是通过更加函数式的方式来实现:
const rpc = createSolanaRpc(HTTPS);
const rpcSubscriptions = createSolanaRpcSubscriptions(WSS);
const sendAndConfirmTransaction = sendAndConfirmTransactionFactory({
rpc,
rpcSubscriptions,
});
以上代码中,当我们调用sendAndConfirmTransaction
来发送交易时,会自动发起 https 请求,并且建立一个 wss 连接,订阅交易状态,在交易被确认后返回交易hash。
密钥对
公钥和私钥相关的地方也有很大变化。在 1.x 版本最常用的 Keypair 和 PublicKey 两个类不存在了,被成一些函数替代。
例如可以使用await generateKeyPair()
生成密钥对,在之前则是直接通过Keypair.generate()
生成一个密钥对。
你可能注意到新的 generateKeyPair 返回了 Promise,而不是想之前那样,可以直接返回需要的密钥对。这是由于新的实现尽可能的利用了 JavaScript 的 Web Crypto API,使用了原生的 Ed25519 实现。Web Crypto API 的很多方法都是异步的。不过这一点变化倒是并非不能接受,在2024年即将结束的今天,JavaScript 开发者们早已将 Promise 看作非常熟悉的朋友了。
发送交易
1.x 的用户应该很熟悉 Transaction
和VersionedTransaction
两个类,最开始了解 Solana 时,它们之间的关系也曾让我非常疑惑。
在 2.x 版本中,同样不再有这两个类。
旧版本中提供的 System Program 相关方法也不再继续存在,所以SystemProgram
类上的静态方法都需要从另外的地方引入。
例如transfer
指令,需要调用@solana-program/system
中的getTransferSolInstruction
函数。
由于不再提供 class,Web3.js 提供了函数式编程的能力中常用的 pipe 形式。下面通过pipe
函数来实现原本 1.x 的转账功能:
const LAMPORTS_PER_SOL = BigInt(1_000_000_000);
const rpc = createSolanaRpc(`https://api.zan.top/node/v1/solana/devnet/${YOUR_ZAN_API_KEY}`);
const rpcSubscriptions = createSolanaRpcSubscriptions(`wss://api.zan.top/node/v1/solana/devnet/${YOUR_ZAN_API_KEY}`);
const sendAndConfirmTransaction = sendAndConfirmTransactionFactory({
rpc,
rpcSubscriptions,
});
const onTransfer = async () => {
const keypair = await createKeyPairFromPrivateKeyBytes(YOUR_PRIV_KEY_BYTES);
const signer = await createSignerFromKeyPair(theKeypair);
const toAddress = address("4Nu34Lrv9Wv4fX1zA7xTNy8Z4bTKcB9oL8ZMbZV9CNUz");
const { value: blockhashValue } = await rpc.getLatestBlockhash().send();
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayer(signer.address, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(blockhashValue, tx),
(tx) =>
appendTransactionMessageInstruction(
getTransferSolInstruction({
source: signer,
destination: toAddress,
amount: lamports(LAMPORTS_PER_SOL / BigInt(10)),
}),
tx
)
);
const signedTx = await signTransactionMessageWithSigners(
transactionMessage
);
const signature = getSignatureFromTransaction(signedTx);
console.log('transaction signature:', signature);
await sendAndConfirmTransaction(signedTx, { commitment: "confirmed" });
};
能够发现交易不再通过 Connection 来发起,而是通过我们定义的 RPC Provider,生成一个特有的函数,然后调用该函数来发起交易。相对 1.x 版本来说,代码量有些增加,不过优点是可定制性更强了。
交易通过 HTTPS RPC 发起,然后通过订阅 WSS RPC 来确认交易结果。可以感受到新的方式非常依赖 WSS,相信以后 WSS 的应用将会越加广泛,这也确实对 RPC 供应商的服务稳定性提出了更高的要求。如果你正在寻找一个可靠的 WSS 节点供应商,ZAN Node 是一个不错的选择。作为 Solana 在亚太地区的领先服务商,我们致力于提供稳定、高效的连接性能。除了 Ethereum 和 Solana 等热门链外,我们还支持超过 20 条主流链的 RPC 服务,以满足不同场景的需求。
React
有趣的是,@solana/web3.js 项目中还包含了一个名为 @solana/react 的库,提供了一些 React Hook,内置了诸如 signIn 等功能。
总结
@solana/web3.js 2.x 版本的发布,充分体现了 Solana 团队对于不断发展和改进的承诺。为开发人员提供一个高效、灵活、可定制的与 Solana 网络进行交互的方式,并有助于推动该平台的采用和发展。
關於 ZAN
ZAN 是螞蟻數科旗下 Web3 科技品牌,致力於 Web3 應用優化--降低成本、增強安全和提升效能,圍繞 Web3 應用全生命週期,提供可靠、穩定安全、客製化的產品和服務。依托 AntChain OpenLabs 的 TrustBase 開源開放技術體系,ZAN 擁有 Web3 領域獨特的優勢和創新能力,為 Web3 社群的區塊鏈應用開發、企業和開發者的 Web3 應用提供了全面的技術產品和服務,其中包括節點服務(ZAN Node Service)、zk 加速(ZAN PowerZebra)、身分驗證eKYC(ZAN Identity)以及智慧合約稽核(ZAN Smart Contract Review)等。