Что такое обернутый SOL?
Обернутый SOL (WSOL) — это SOL, хранящийся в token account для нативного минта Token Program. Нативный минт — это адрес минта, который Token Program использует для token account, оборачивающих SOL. Нативный минт позволяет использовать SOL через инструкции Token Program.
| Программа | Адрес нативного минта |
|---|---|
| Token Program | So11111111111111111111111111111111111111112 |
| Token Extensions Program | 9pan9bMn5HatX4EJdBwg9VgCa7Uz5HL8N1m5D3NdXejP |
Обернутый SOL token account хранит SOL в поле lamports аккаунта, но учитывает
SOL, находящийся в обернутом SOL token account, как баланс токенов через поле
amount token account. Если вы переводите SOL в обернутый SOL token account,
баланс в lamport увеличивается немедленно, но поле amount не изменяется до тех
пор, пока вы не вызовете инструкцию SyncNative Token Program.
Как синхронизировать нативный SOL
Используйте инструкцию SyncNative Token Program после перевода SOL в обернутый
SOL token account. Инструкция SyncNative обновляет поле amount token account
в соответствии с количеством lamport, хранящихся в аккаунте сверх резерва,
необходимого для освобождения от арендной платы.
Ссылка на исходный код
| Элемент | Описание | Token Program | Token Extensions Program |
|---|---|---|---|
Account | Состояние token account использует is_native для пометки аккаунта как WSOL и хранит нативный резерв — минимальный баланс в lamport, освобождающий от арендной платы, который аккаунт должен сохранять, и отслеживаемое количество токенов. | Источник | Источник |
SyncNative | Инструкция, которая обновляет поле amount обернутого SOL token account в соответствии с количеством lamport, хранящихся в аккаунте сверх резерва, освобождающего от арендной платы. | Источник | Источник |
process_sync_native | Общая логика процессора для синхронизации балансов обернутого SOL. | Источник | Источник |
Typescript
Примеры ниже демонстрируют рекомендуемый подход с использованием Kit.
Устаревшие примеры с использованием @solana/kit приведены для справки.
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);
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);
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(())}
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())
Is this page helpful?