什么是包装 SOL?
包装 SOL (WSOL) 是指存储在 Token Program 原生铸币地址的 token account 中的 SOL。原生铸币地址是 Token Program 用于包装 SOL 的 token account 的铸币地址。原生铸币使 SOL 能够通过 Token Program 的指令进行使用。
| 程序 | 原生铸币地址 |
|---|---|
| Token Program | So11111111111111111111111111111111111111112 |
| Token Extension Program | 9pan9bMn5HatX4EJdBwg9VgCa7Uz5HL8N1m5D3NdXejP |
包装 SOL token account 将 SOL 存储在账户的 lamports 字段中,但通过 token
account 的 amount
字段将持有的 SOL 作为代币余额进行跟踪。如果您将 SOL 转入包装 SOL token
account,lamport 余额会立即增加,但 amount 字段不会改变,直到您调用 Token
Program 的 SyncNative 指令。
如何同步原生 SOL
在将 SOL 转入包装 SOL token account 后,使用 Token Program 的 SyncNative
指令。SyncNative 指令会更新 token account 的 amount
字段,使其与账户中超出免租金储备的 lamport 数量相匹配。
源代码参考
| 项目 | 描述 | Token Program | Token Extension Program |
|---|---|---|---|
Account | token account 状态使用 is_native 来标记账户为 WSOL,并存储原生储备、账户必须保留的免租金最低 lamport 余额以及跟踪的代币金额。 | 源代码 | 源代码 |
SyncNative | 该指令更新包装 SOL token account 的 amount 字段,使其与账户中超出免租金储备的 lamport 数量相匹配。 | 源代码 | 源代码 |
process_sync_native | 用于同步包装 SOL 余额的共享处理器逻辑。 | 源代码 | 源代码 |
Typescript
以下 Kit 示例展示了使用 @solana/kit 的推荐方法。同时包含使用
@solana/web3.js 的旧版示例以供参考。
Kit
import { address } from "@solana/kit";import { createLocalClient } from "@solana/kit-client-rpc";import { systemProgram } from "@solana-program/system";import {findAssociatedTokenPda,getCreateAssociatedTokenInstructionAsync,tokenProgram,TOKEN_PROGRAM_ADDRESS} from "@solana-program/token";const client = await createLocalClient().use(systemProgram()).use(tokenProgram());const NATIVE_MINT = address("So11111111111111111111111111111111111111112");const [tokenAccount] = await findAssociatedTokenPda({mint: NATIVE_MINT,owner: client.payer.address,tokenProgram: TOKEN_PROGRAM_ADDRESS});const result = await client.sendTransaction([client.system.instructions.transferSol({source: client.payer, // Account sending the SOL to wrap.destination: tokenAccount, // WSOL token account receiving the SOL.amount: 1_000_000n // SOL amount in lamports.}),client.token.instructions.syncNative({account: tokenAccount // WSOL token account to synchronize.})]);const tokenAccountData = await client.token.accounts.token.fetch(tokenAccount);console.log("WSOL Token Account Address:", tokenAccount);console.log("WSOL Token Account:", tokenAccountData.data);console.log("\nTransaction Signature:", result.context.signature);
Console
Click to execute the code.
Web3.js
import {Connection,Keypair,sendAndConfirmTransaction,LAMPORTS_PER_SOL,SystemProgram,Transaction} from "@solana/web3.js";import {createAssociatedTokenAccount,getAccount,NATIVE_MINT,syncNative,TOKEN_PROGRAM_ID} from "@solana/spl-token";const result = await syncNative(connection,feePayer, // Account paying transaction fees.associatedTokenAccount, // WSOL token account to synchronize.{commitment: "confirmed"},TOKEN_PROGRAM_ID // Token program to invoke.);const tokenAccountData = await getAccount(connection,associatedTokenAccount,"confirmed",TOKEN_PROGRAM_ID);console.log("WSOL Token Account Address:", associatedTokenAccount.toBase58());console.log("WSOL Token Account:", tokenAccountData);console.log("\nTransaction Signature:", result);
Console
Click to execute the code.
Rust
Rust
use anyhow::Result;use solana_client::nonblocking::rpc_client::RpcClient;use solana_commitment_config::CommitmentConfig;use solana_sdk::{program_pack::Pack,signature::{Keypair, Signer},transaction::Transaction,};use solana_system_interface::instruction::transfer;use spl_associated_token_account_interface::{address::get_associated_token_address, instruction::create_associated_token_account,};use spl_token_interface::{id as token_program_id,instruction::sync_native,native_mint::ID as NATIVE_MINT_ID,state::Account,};#[tokio::main]async fn main() -> Result<()> {let client = RpcClient::new_with_commitment(String::from("http://localhost:8899"),CommitmentConfig::confirmed(),);let associated_token_address = get_associated_token_address(&fee_payer.pubkey(), &NATIVE_MINT_ID);let sync_amount = 1_000_000;let transaction = Transaction::new_signed_with_payer(&[transfer(&fee_payer.pubkey(), // Account sending the SOL to wrap.&associated_token_address, // WSOL token account receiving the SOL.sync_amount, // SOL amount in lamports.),sync_native(&token_program_id(), // Token program to invoke.&associated_token_address, // WSOL token account to synchronize.)?,],Some(&fee_payer.pubkey()),&[&fee_payer],latest_blockhash,);let transaction_signature = client.send_and_confirm_transaction(&transaction).await?;let token_account = client.get_account(&associated_token_address).await?;let token_data = Account::unpack(&token_account.data)?;println!("WSOL Token Account Address: {}", associated_token_address);println!("WSOL Token Account: {:#?}", token_data);println!("\nTransaction Signature: {}", transaction_signature);Ok(())}
Console
Click to execute the code.
Python
Python
#!/usr/bin/env python3import asyncioimport jsonfrom solana.rpc.async_api import AsyncClientfrom solders.keypair import Keypairfrom solders.message import Messagefrom solders.pubkey import Pubkeyfrom solders.transaction import Transactionfrom solders.system_program import transfer, TransferParamsfrom spl.token.async_client import AsyncTokenfrom spl.token.instructions import (create_associated_token_account,get_associated_token_address,sync_native,SyncNativeParams,)from spl.token.constants import TOKEN_PROGRAM_ID, WRAPPED_SOL_MINTAMOUNT_TO_WRAP = 1_000_000async def main():rpc = AsyncClient("http://localhost:8899")async with rpc:sync_native_instructions = [transfer(TransferParams(from_pubkey=fee_payer.pubkey(), # Account sending SOL to the wrapped SOL token account.to_pubkey=wrapped_sol_account, # Wrapped SOL token account receiving the lamports.lamports=AMOUNT_TO_WRAP, # Lamports to wrap as WSOL.)),sync_native(SyncNativeParams(program_id=TOKEN_PROGRAM_ID, # Token program to invoke.account=wrapped_sol_account, # Wrapped SOL token account whose amount field updates.)),]latest_blockhash = await rpc.get_latest_blockhash()transaction = Transaction([fee_payer],Message(sync_native_instructions, fee_payer.pubkey()),latest_blockhash.value.blockhash,)result = await rpc.send_transaction(transaction)token_account_info = await token.get_account_info(wrapped_sol_account)token_account = {key: str(value) if isinstance(value, Pubkey) else valuefor key, value in token_account_info._asdict().items()}print("Native Mint Address:", WRAPPED_SOL_MINT)print("\nWrapped SOL Token Account Address:", wrapped_sol_account)print("Token Account:")print(json.dumps(token_account, indent=2))print("\nTransaction Signature:", result.value)if __name__ == "__main__":asyncio.run(main())
Console
Click to execute the code.
Is this page helpful?