
使用 Elusiv 和 Light 实现 Solana 隐私:关于 SOL 隐私你需要知道的一切
前置条件
- 已安装 Node.js(用于安装所需依赖项、运行脚本和私密发送 $SOL)
- 基本了解 TypeScript
- 基本了解 @solana/web3.js
本文介绍什么?
隐私是现代区块链技术的核心。公共账本系统、交易、账户余额,甚至程序源代码通常都对所有人公开。这种前所未有的透明度被视为区块链技术的标志,但对许多应用和日常用途而言,隐私可能是一项至关重要的要求。
Elusiv 和 Light Protocol 都利用 zk-SNARKS,为 Solana 上的私密交易、私密程序和去中心化合规解决方案提供前沿的隐私方案。本文将深入探讨隐私的重要性,分析 Solana 等区块链为何需要隐私功能,并分步讲解如何使用 Elusiv 的 TypeScript SDK 和 Light 的 zk.js 模块私密发送 SOL。
隐私很重要
隐私是一项基本人权,对自主权和维护人的尊严至关重要。隐私是自由开放社会的必要基础,因为它支撑着言论自由和结社自由等其他权利的行使。它为人们创造了一个与政治生活相分离的空间,确保每个人都能思考、发言、表达观点或采取行动,而不必持续受到第三方监控。近年来,Edward Snowden 的公开披露、WikiLeaks 曝光的信息以及 Facebook-Cambridge Analytica 数据丑闻等公共争议,引发了关于隐私重要性及其边界的激烈讨论。
每个人都应关注隐私
乍看之下,主张建立在去中心化技术之上、并将透明度奉为基本原则之一的公共账本应具备隐私功能,似乎有些自相矛盾。无论你是坚定的密码朋克,还是普通用户,每个人都应关注隐私。你可能会想,既然自己没有在网上做任何有害或违法的事,又何必在意别人看到自己在区块链上的活动?不妨思考以下场景:
这里有两个角色:Alice,一位重视隐私、希望购物不受审视的普通用户;以及一名恶意行为者,以下缩写为 MA。恶意行为者可能是压迫性的政府、控制欲强的雇主或网络犯罪分子。假设 Alice 生活在一个政府持续监视每位公民的国家,或者她所在的公司制定了严格政策,禁止某些合法消费(例如政治捐款、购买特定主题的书籍)。一天,Alice 使用 Solana 这类传统区块链进行购买,并认为这是一种安全且私密的付款方式。接下来发生的事件如下:
- Alice 的交易被记录在公共账本上。她的交易包含自己的公钥、接收方的公钥和发送金额
- MA 为了监控或控制 Alice 的行为,开始使用她的公钥追踪她的交易
- MA 发现了 Alice 的购买行为,并依据其规则认定该行为“不可接受”
- MA 对 Alice 采取行动。根据具体情况,后果可能包括法律诉讼、监禁、职场处分、公开羞辱或勒索
这个思想实验揭示了区块链缺乏隐私可能会如何影响普通用户的残酷现实。随着链上侦探和恶意数据采集技术的兴起,追踪普通用户的交易已变得相当容易,并可能在现实世界中造成严重后果。在日益数字化的世界里,如果没有隐私,我们将面临个人主权被侵蚀、所有决定受到监控以及生存的方方面面被商品化的风险。如果不实施支持隐私的技术,区块链只会加速这一进程。这正是 Elusiv 和 Light Protocol 发挥作用的地方。
什么是 Elusiv?
Elusiv 将自己描述为“一种基于区块链的零知识隐私协议”,它“让用户和应用能够使用通用加密”。Elusiv 通过将零知识密码学和多方计算应用于用户和网络,力求在不牺牲安全性、可靠性和去中心化的前提下实现隐私。通用加密这一目标让 Elusiv 能够提供工具,帮助用户掌控自己的数据。现在,用户可以选择哪些内容在区块链上共享,哪些不共享。
Elusiv 如何工作?
Elusiv 的工作方式是让用户将资金发送到由 Elusiv 程序管理的共享资金池,从而为私密余额充值。用户可以从资金池发送和接收 SOL 等代币,也可以提取资金。需要注意的是,在这种共享资金池模式下,人们仍能观察到存入 Elusiv 的资金和从 Elusiv 发出的付款。不过,随着用户和交易增多,时间越长,将存款和付款关联到特定账户就越困难。相比从数百万用户中找出进行多次小额存款和付款的某位用户,关联唯一一名存入 10 SOL 又取出 10 SOL 的用户要容易得多。人越多,匿名性越强。
资金池中的资金不包含任何存款人的信息,但可以使用零知识证明,将秘密值与用户的资金关联起来,从而为未使用资金生成权限证明。Elusiv 使用的零知识证明称为 zk-SNARKS(零知识简洁非交互式知识论证)。这里不深入探讨 zk-SNARK 证明的复杂原理,你可以将其理解为一种经过数学证明的方法:你无需告诉朋友秘密密码是什么,就能证明自己知道密码。在此过程中,你的朋友无需询问任何其他信息,就能快速确认你说的是真话。因此,Elusiv 可以追踪你的未使用资金,而不必向整个 Solana 网络公开你在资金池中有多少钱。如果你想进一步了解零知识证明,强烈建议观看 Porter 的零知识证明课程。
什么是 Light Protocol?
Light Protocol 将自己描述为“Solana 上的下一代 zkLayer”,可以直接在 Solana 上执行私密程序。Light 通过三个核心概念在 Solana 上实现隐私:
- 私密状态
- UTXO 模型
- 在链上验证私密状态转换
Light Protocol 如何工作?
Light Protocol 可以加密链上状态。在这里,用户“拥有”该状态,并享有专属解密权。与 Elusiv 的资金池方案不同,Light Protocol 将 UTXO(未花费交易输出)模型引入 Solana。UTXO 与一个隐私密钥对绑定,可以保存两种余额:一种是 SOL(因为它是 Light Protocol 中的手续费代币),另一种是其他 SPL 代币。在这种方案下,每笔交易都会生成新的 UTXO,并将其追加到线性列表中,从而避免原地更新;状态会被隐藏,不会泄露哪个状态正由谁更新。
Solana 上的程序逻辑几乎总是具有某些独特约束的托管机制。Light Protocol 对这一设计进行了创新:在客户端将程序逻辑编码到零知识电路(zk-SNARKS)中,并在客户端完成计算和生成证明。该证明会在链上共享,由专门为该电路构建的验证程序检查其有效性。验证成功后,自定义验证程序会调用另一个原生验证器,完成各种安全检查,并将新的承诺添加到 Light 的 Merkle 树程序中。
虽然不在本文讨论范围内,但 Light 允许你从头创建自己的自定义私密 Solana 程序(PSP)。建议你先读完本文并查看其文档,然后再尝试自行创建。其文档包含创建自定义 PSP 的教程,可在这里查看。
这些都很酷,但如何将它们直接用于 Solana 编程?
使用 Elusiv 私密发送 SOL
完整代码
import * as ed from "@noble/ed25519";
import { sha512 } from "@noble/hashes/sha512";
ed.etc.sha512Sync = (...m) => sha512(ed.etc.concatBytes(...m));
import {
Connection,
PublicKey,
Keypair,
ConfirmedSignatureInfo,
Cluster,
LAMPORTS_PER_SOL,
clusterApiUrl,
} from "@solana/web3.js";
import { Elusiv, TokenType, SEED_MESSAGE } from "@elusiv/sdk";
const CLUSTER: Cluster = "devnet";
const RPC = "https://rpc-devnet.helius.xyz";
const main = async () => {
const connection: Connection = new Connection(RPC);
const keyPair: Keypair = generateKeypair();
const recipientPublicKey: PublicKey = new PublicKey(generateKeypair().publicKey);
await airdropSol(keyPair);
const seed: Uint8Array = ed.sign(Buffer.from(SEED_MESSAGE, "utf-8"), keyPair.secretKey.slice(0, 32));
const elusiv: Elusiv = await Elusiv.getElusivInstance(seed, keyPair.publicKey, connection, CLUSTER);
const balance: bigint = await elusiv.getLatestPrivateBalance("LAMPORTS");
try {
if (balance > BigInt(0)) {
const signature = await send(elusiv, recipientPublicKey, 1 * LAMPORTS_PER_SOL, "LAMPORTS");
console.log(`Sent with signature ${signature.signature}`);
} else {
console.log("Private balance is empty. Topping up...");
const amount = 1 * LAMPORTS_PER_SOL;
const tokenType = "LAMPORTS";
const topUpTxData = await elusiv.buildTopUpTx(amount, tokenType);
topUpTxData.tx.partialSign(keyPair);
const topUpSig: ConfirmedSignatureInfo = await elusiv.sendElusivTx(topUpTxData);
console.log(`Top-up complete with signature ${topUpSig.signature}`);
const signature: ConfirmedSignatureInfo = await send(elusiv, recipientPublicKey, 1 * LAMPORTS_PER_SOL, "LAMPORTS");
console.log(`Sent with signature ${signature.signature}`);
}
} catch (e) {
console.error(`Error sending SOL via Elusiv: ${e}`);
} finally {
console.log("Exiting program...");
process.exit(0);
}
};
const send = async (
elusiv: Elusiv,
recipient: PublicKey,
amount: number,
tokenType: TokenType
): Promise => {
const txt = await elusiv.buildSendTx(amount, recipient, tokenType);
return elusiv.sendElusivTx(txt);
};
const generateKeypair = (): Keypair => {
let keyPair = Keypair.generate();
console.log(`Public key: ${keyPair.publicKey.toBase58()}`);
console.log(`Private key: ${keyPair.secretKey}`);
return keyPair;
};
const airdropSol = async (wallet: Keypair) => {
try {
const connection = new Connection(clusterApiUrl("devnet"));
const airdropSignature = await connection.requestAirdrop(new PublicKey(wallet.publicKey), 1 * LAMPORTS_PER_SOL);
const latestBlockHash = await connection.getLatestBlockhash();
await connection.confirmTransaction({
blockhash: latestBlockHash.blockhash,
lastValidBlockHeight: latestBlockHash.lastValidBlockHeight,
signature: airdropSignature,
});
console.log(`Airdropped 1 SOL to ${wallet.publicKey.toBase58()}`);
} catch (e) {
console.error(`Error sending SOL via Elusiv: ${e}`);
}
};
main();分解 Elusiv 代码
import * as ed from "@noble/ed25519";
import { sha512 } from "@noble/hashes/sha512";
ed.etc.sha512Sync = (...m) => sha512(ed.etc.concatBytes(...m));首先,我们导入 noble-ed25519 库,因为目前尚未设置任何钱包连接。在生产环境中,你应改用 Solana Wallet Adapter 为交易签名。这里我们只需要 sign 功能,但使用 import { sign } from "@noble/ed25519"; 有时可能会返回 etc.sha512Sync 未设置的错误。为了避免此错误,我们自行进行设置,无需过于关注这部分。
import {
Connection,
PublicKey,
Keypair,
ConfirmedSignatureInfo,
Cluster,
LAMPORTS_PER_SOL,
clusterApiUrl,
} from "@solana/web3.js";
import { Elusiv, TokenType, SEED_MESSAGE } from "@elusiv/sdk";接下来,我们导入 Solana 的 web3.js 和 Elusiv 的 TypeScript SDK,以及所需模块。
const CLUSTER: Cluster = "devnet";
const RPC = "https://rpc-devnet.helius.xyz";这里,我们将 CLUSTER 定义为 "devnet",并将 RPC 设置为 Helius devnet RPC。如果你想在 mainnet 上使用此脚本,可以将 CLUSTER 设为 "mainnet",并从以下任一套餐获取 Helius API 密钥 😎
const main = async () => {
const connection: Connection = new Connection(RPC);
const keyPair: Keypair = generateKeypair();
const recipientPublicKey: PublicKey = new PublicKey(generateKeypair().publicKey);
// Rest of the code
}我们将 main 函数标记为异步,因为会在其代码块内对多个函数使用 await。然后,我们使用 RPC 建立与 devnet 的连接,并通过工具函数 generateKeypair 创建一个 Keypair 对象。我们还使用上述 generateKeypair 函数创建一个 recipientPublicKey,以便在随机地址接收受保护的 SOL。作为参考,generateKeypair 函数定义如下:
const generateKeypair = (): Keypair => {
let keyPair = Keypair.generate();
console.log(`Public key: ${keyPair.publicKey.toBase58()}`);
console.log(`Private key: ${keyPair.secretKey}`);
return keyPair;
};此函数创建一个供该脚本使用的测试 Solana 密钥对。如果要在 mainnet 上使用,则应将其替换为你自己的钱包密钥对。切记,绝不要以明文存储私钥,并应使用正确的文件路径妥善导入。
await airdropSol(keyPair);由于使用的是新生成的测试密钥对,因此我们需要一些 devnet SOL。我们使用 aidropSol 工具函数向新密钥对空投 SOL,该函数定义如下:
const airdropSol = async (wallet: Keypair) => {
try {
const connection = new Connection(clusterApiUrl("devnet"));
const airdropSignature = await connection.requestAirdrop(new PublicKey(wallet.publicKey), 1 * LAMPORTS_PER_SOL);
const latestBlockHash = await connection.getLatestBlockhash();
await connection.confirmTransaction({
blockhash: latestBlockHash.blockhash,
lastValidBlockHeight: latestBlockHash.lastValidBlockHeight,
signature: airdropSignature,
});
console.log(`Airdropped 1 SOL to ${wallet.publicKey.toBase58()}`);
} catch (e) {
console.error(`Error sending SOL via Elusiv: ${e}`);
}
};这里,我们在 devnet 上向自己空投 1 SOL(1 * LAMPORTS_PER_SOL)。我们获取 latestBlockHash,以便将区块哈希和最后有效区块高度传入 connection.confirmTransaction(),从而确认已向正确地址空投 1 SOL。
const seed: Uint8Array = ed.sign(Buffer.from(SEED_MESSAGE, "utf-8"), keyPair.secretKey.slice(0, 32));Elusiv 需要输入种子来确保某些操作具有确定性,因此我们导入并使用 SEED_MESSAGE。SEED_MESSAGE 是必须签名的消息,因为它用于生成 Elusiv 种子;应用可以借此使用关联的秘密值解密你的私密资产,让你能够追踪自己的资金。我们使用 Buffer.from(),以 utf-8 编码从 SEED_MESSAGE 创建一个新缓冲区(一种原始二进制数据结构)。我们需要使用 slice,因为 Solana 的密钥对类型将前 32 个字节作为私钥,后 32 个字节作为公钥。因此,我们使用私钥为所需的种子消息签名。
const elusiv: Elusiv = await Elusiv.getElusivInstance(seed, keyPair.publicKey, connection, CLUSTER);这里,我们使用 seed、keyPair.publicKey、connection 和 CLUSTER 定义 elusiv,即一个 Elusiv 实例。也就是说,我们使用 devnet RPC、公钥以及刚签名的长消息,在 devnet 上创建一个 Elusiv 实例。
const balance: bigint = await elusiv.getLatestPrivateBalance("LAMPORTS");然后,我们获取私密余额,即 Elusiv 资金池中拥有的 Lamports 数量,其返回值为 BigInt。main 函数的其余部分封装在 try-catch-finally block 中,其定义如下:
try {
if (balance > BigInt(0)) {
const signature = await send(elusiv, recipientPublicKey, 1 * LAMPORTS_PER_SOL, "LAMPORTS");
console.log(`Sent with signature ${signature.signature}`);
} else {
// Rest of code
}
}如果我们有私密余额,balance 将大于 0,并执行 if-else 代码块的第一个分支。之所以在 if 条件中将 0 转换为 BigInt,是因为 getLatestPrivateBalance 的返回类型为 BigInt。之后,我们创建 signature,并将其设为 send() 的返回值。send() 函数定义如下:
const send = async (
elusiv: Elusiv,
recipient: PublicKey,
amount: number,
tokenType: TokenType
): Promise => {
const txt = await elusiv.buildSendTx(amount, recipient, tokenType);
return elusiv.sendElusivTx(txt);
};此函数通过 Elusiv 发送交易并返回一个 Promise,其类型为 ConfirmedSignatureInfo(包含状态的已确认签名)。参数包括 Elusiv 实例、接收方公钥、发送金额和代币类型(不必是 Lamports,也可以是 USDC、USDT、mSOL、BONK 和 SAMO 等其他代币)。然后,我们使用 elusiv.buildSendTx() 设置 txt。buildSendTx() 是 Elusiv 实例上的一个方法,它使用私密余额构建向指定接收方发送代币的交易。最后,我们通过 return elusiv.sendElusivTx(txt) 语句传入已构建的交易 txt,发送并返回该交易。
如果没有私密余额,则执行 else 代码块:
console.log("Private balance is empty. Topping up...");
const amount = 1 * LAMPORTS_PER_SOL;
const tokenType = "LAMPORTS";
const topUpTxData = await elusiv.buildTopUpTx(amount, tokenType);
topUpTxData.tx.partialSign(keyPair);
const topUpSig: ConfirmedSignatureInfo = await elusiv.sendElusivTx(topUpTxData);
console.log(`Top-up complete with signature ${topUpSig.signature}`);
const signature: ConfirmedSignatureInfo = await send(elusiv, recipientPublicKey, 1 * LAMPORTS_PER_SOL, "LAMPORTS");
console.log(`Sent with signature ${signature.signature}`);我们向用户输出日志,说明他们没有私密余额,并将为其充值。然后,我们使用 Elusiv 实例上的 .buildTopUpTx() 方法构建充值交易。由于发送的是 SOL,因此传入 1 SOL 的值和 Lamports 代币类型。接下来,由于充值资金来自我们的公钥,我们使用交易密钥对上的 .partialSign() 为充值签名。最后,使用 elusiv.sendElusivTx(topUpTxData) 发送构建好的交易,并输出交易签名。
try-catch-finally 代码块的其余部分如下:
} catch (e) {
console.error(`Error sending SOL via Elusiv: ${e}`);
} finally {
console.log("Exiting program...");
process.exit(0);
}如果通过 Elusiv 发送 SOL 时发生任何错误,我们使用 console.error() 将其输出到控制台。然后使用 process.exit(0) 退出程序。
为启动整个流程,我们在文件底部调用 main() 函数。
使用 Light Protocol 私密发送 SOL
完整代码
import { BN } from "@coral-xyz/anchor";
import { PublicKey, Keypair, Connection } from "@solana/web3.js";
import { User, Provider as LightProvider, TestRelayer, confirmConfig, airdropSol } from "@lightprotocol/zk.js";
const initializeSolanaWallet = async (): Promise => {
const wallet = Keypair.generate();
console.log("Wallet initialized");
return wallet;
};
const requestAirdrop = async (connection: Connection, publicKey: PublicKey): Promise => {
await airdropSol({
connection,
lamports: 2e9,
recipientPublicKey: publicKey,
});
console.log("Airdrop requested...");
};
const setupTestRelayer = async (solanaWallet: Keypair): Promise => {
const testRelayer = new TestRelayer({
relayerPubkey: solanaWallet.publicKey,
relayerRecipientSol: solanaWallet.publicKey,
relayerFee: new BN(100_000),
payer: solanaWallet,
});
console.log("Test relayer initialized");
return testRelayer;
};
const initializeLightProvider = async (solanaWallet: Keypair, testRelayer: TestRelayer): Promise => {
const lightProvider = await LightProvider.init({
wallet: solanaWallet,
relayer: testRelayer,
confirmConfig,
});
console.log("Light provider initialized");
return lightProvider;
};
const initializeLightUser = async (lightProvider: LightProvider): Promise => {
const user = await User.init({ provider: lightProvider });
console.log("Light user initialized");
return user;
};
const performShieldOperation = async (user: User) => {
await user.shield({
publicAmountSol: "1.1",
token: "SOL",
});
console.log("Performed shield operation");
};
const executePrivateTransfer = async (user: User, testRecipientPublicKey: string) => {
const response = await user.transfer({
amountSol: "1",
token: "SOL",
recipient: testRecipientPublicKey,
});
console.log(`Executed private transfer! Txt hash: ${response.txHash}`);
};
const main = async () => {
try {
const solanaWallet = await initializeSolanaWallet();
const connection = new Connection("http://127.0.0.1:8899");
await requestAirdrop(connection, solanaWallet.publicKey);
const testRelayer = await setupTestRelayer(solanaWallet);
const lightProvider = await initializeLightProvider(solanaWallet, testRelayer);
const user = await initializeLightUser(lightProvider);
await performShieldOperation(user);
const testRecipientKeypair = Keypair.generate();
await requestAirdrop(connection, testRecipientKeypair.publicKey);
const lightProviderRecipient = await initializeLightProvider(testRecipientKeypair, testRelayer);
const testRecipient = await initializeLightUser(lightProviderRecipient);
await executePrivateTransfer(user, testRecipient.account.getPublicKey());
console.log(`Successfully sent 1 $SOL to ${testRecipient.account.getPublicKey()} privately!`);
} catch (e) {
console.error(`Error sending SOL via Light: ${e}`);
} finally {
console.log("Exiting program...");
process.exit(0);
}
};
main();分解代码
import { BN } from "@coral-xyz/anchor";
import { PublicKey, Keypair, Connection } from "@solana/web3.js";
import { User, Provider as LightProvider, TestRelayer, confirmConfig, airdropSol } from "@lightprotocol/zk.js";首先,我们从 Anchor、Solana/web3.js 和 Light 导入必要模块,以便使用 Light Protocol 与 Solana 交互。接下来,在进入 main 函数之前,我们先定义多个工具函数。与 Elusiv 实现相比,Light 的初始化流程更为复杂。
const initializeSolanaWallet = async (): Promise => {
const wallet = Keypair.generate();
console.log("Wallet initialized");
return wallet;
};这里,我们创建 initializeSolanaWallet 函数,使用 Keypair.generate() 方法生成新的 Solana 钱包。
const requestAirdrop = async (connection: Connection, publicKey: PublicKey): Promise => {
await airdropSol({
connection,
lamports: 2e9,
recipientPublicKey: publicKey,
});
console.log("Airdrop requested...");
};与 Elusiv 不同,Light 的库提供了 airdropSol 函数,可以向指定公钥空投 Lamports。我们创建工具函数 requestAirdrop,向传入的 publicKey 发送 SOL。
const setupTestRelayer = async (solanaWallet: Keypair): Promise => {
const testRelayer = new TestRelayer({
relayerPubkey: solanaWallet.publicKey,
relayerRecipientSol: solanaWallet.publicKey,
relayerFee: new BN(100_000),
payer: solanaWallet,
});
console.log("Test relayer initialized");
return testRelayer;
};要通过 Light 发送受保护的 SOL,我们需要使用 TestRelayer 模块设置测试中继器。中继器在 Light 生态系统中发挥着重要作用。它们是 Web 服务器,负责将证明状态转换的 ZK 证明从客户端转发到相应的链上程序。证明验证成功后,中继器会收取费用,并代为支付交易费。费用为 10 万 Lamports,我们通过 new BN(100_000) 进行设置。
const initializeLightProvider = async (solanaWallet: Keypair, testRelayer: TestRelayer): Promise => {
const lightProvider = await LightProvider.init({
wallet: solanaWallet,
relayer: testRelayer,
confirmConfig,
});
console.log("Light provider initialized");
return lightProvider;
};然后,我们使用名称直观的 initializeLightProvider() 函数初始化 Light Provider。此函数会设置 Provider,并使用 Light 提供的配置 confirmConfig,将其与 Solana 钱包和测试中继器关联。该配置的类型为 ConfirmOptions,用于处理交易验证步骤、承诺级别等。
const initializeLightUser = async (lightProvider: LightProvider): Promise => {
const user = await User.init({ provider: lightProvider });
console.log("Light user initialized");
return user;
};initializeLightUser 函数的作用很直观:它使用传入的 lightProvider 为 Light Protocol 初始化用户。
const performShieldOperation = async (user: User) => {
await user.shield({
publicAmountSol: "1.1",
token: "SOL",
});
console.log("Performed shield operation");
};performShieldOperation 函数允许用户保护 SOL,使其成为私密资产。这里,我们保护的 SOL 超过 1 枚,但只发送 1 枚受保护的 SOL,以便覆盖手续费。
const executePrivateTransfer = async (user: User, testRecipientPublicKey: string) => {
const response = await user.transfer({
amountSol: "1",
token: "SOL",
recipient: testRecipientPublicKey,
});
console.log(`Executed private transfer! Txt hash: ${response.txHash}`);
};这可以说是最重要的工具函数,因为它实际执行私密转账。这里,我们将 1 SOL 从 user 私密转账给指定接收方 testRecipientPublicKey。
const main = async () => {
try {
const solanaWallet = await initializeSolanaWallet();
const connection = new Connection("http://127.0.0.1:8899");
await requestAirdrop(connection, solanaWallet.publicKey);
const testRelayer = await setupTestRelayer(solanaWallet);
const lightProvider = await initializeLightProvider(solanaWallet, testRelayer);
const user = await initializeLightUser(lightProvider);
await performShieldOperation(user);
const testRecipientKeypair = Keypair.generate();
await requestAirdrop(connection, testRecipientKeypair.publicKey);
const lightProviderRecipient = await initializeLightProvider(testRecipientKeypair, testRelayer);
const testRecipient = await initializeLightUser(lightProviderRecipient);
await executePrivateTransfer(user, testRecipient.account.getPublicKey());
console.log(`Successfully sent 1 $SOL to ${testRecipient.account.getPublicKey()} privately!`);
} catch (e) {
console.error(`Error sending SOL via Light: ${e}`);
} finally {
console.log("Exiting program...");
process.exit(0);
}
};main 函数是脚本的入口点。由于其作用域内调用了多个异步函数,我们将它标记为异步。它依次运行所有步骤,从初始化钱包开始,到执行私密转账结束。首先,我们设置 Solana 钱包和连接。然后向钱包空投 SOL,并初始化中继器和 Light Provider。接下来,将钱包初始化为 Light User,并保护我们的 SOL。随后创建测试接收方,向其空投一些 SOL,将其初始化为 Light User,并私密发送 1 SOL。与 Elusiv 代码一样,我们将逻辑放入 try-catch-finally 代码块中,以捕获所有错误,并在完成后自动退出程序。
你可能注意到,与使用 devnet 的 Elusiv 不同,这里将连接设置为“http://127.0.0.1:8899”。撰写本文时,Light Protocol 尚未部署到 devnet/mainnet,因此 Helius 密钥还无法使用(暂时如此 👀)。若要在 localhost 上运行代码,你需要启动一个预加载所需账户和程序的 test-validator。为此,可以安装 Light Protocol CLI 并运行以下命令:
light test-validator这将在后台启动一个验证器。目前,由于 UTXO 类中包含一些单元测试,你还需要手动添加 chai (一个用于简化测试的断言库)。不过,这个问题应会在下一个版本中解决。此脚本的 package.json 应大致如下:
{
"name": "helius-tutorial",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"@lightprotocol/cli": "^0.1.1-alpha.21",
"@types/node": "^20.6.0",
"chai": "^4.3.8",
"typescript": "^5.2.2"
},
"dependencies": {
"@coral-xyz/anchor": "^0.28.1-beta.2",
"@lightprotocol/zk.js": "^0.3.2-alpha.14",
"@solana/web3.js": "^1.78.4"
}
}总结
恭喜!在本教程中,我们深入探讨了隐私的复杂机制及其重要性,并介绍了如何使用 Elusiv 和 Light Protocol 私密交易 SOL。通过 Elusiv,我们了解了如何获取私密余额、私密发送 SOL,以及如何在私密余额耗尽或不存在时自动充值。通过 Light Protocol,我们了解了如何完成复杂且高度模块化的初始化流程、保护 SOL,以及执行私密转账。
你可能会问,应该使用哪一个?答案是:视情况而定!在 Elusiv 中,我们的代码侧重于从共享资金池为私密余额充值,以及私密发送交易。为实现这些功能,脚本会与管理 Elusiv 资金池的预定义智能合约交互。在 Light Protocol 中,我们建立了一个更灵活但也更复杂的初始化流程,创建了可管理多个用户与隐私保护型 Solana 程序交互的工作流。如有需要,我们还可以使用 Light 创建自己的自定义私密 Solana 程序(PSP)。两者在文档和具体实现等方面各有取舍,但都以实现隐私和安全交易为目标。如果你的应用需要更精细地控制隐私功能,并希望加密应用状态的特定部分,可以考虑使用 Light Protocol。或者,如果你要构建更简单的应用,只想为 devnet/mainnet 上的代币转账增加一层隐私保护,Elusiv 可能是更好的选择。
本文介绍的技术、代码和见解,为在 Solana 上构建注重隐私的应用提供了坚实起点。隐私在区块链技术中的重要性怎么强调都不为过。随着去中心化系统的需求不断增长,我们也越来越需要支持隐私的功能,以赋予用户自主权、保护用户权利,并实现早期区块链技术的真正目标。隐私至关重要。现在有了 Elusiv 和 Light Protocol,你可以让 Solana 成为更安全的区块链!
匿名朋友,如果你读到了这里,谢谢你!
其他资源 / 延伸阅读
- 密码朋克宣言
- Elusiv
- Elusiv 文档
- Elusiv SDK
- Elusiv 示例
- Light Protocol
- zk.js
- 私密 Solana 程序实现示例
相关文章
订阅 Helius
及时了解 Solana 开发的最新动态,并在我们发布新内容时收到更新


