Κλιμακωμένο ποσό UI

Τι Είναι η Επέκταση Scaled UI Amount;

Η επέκταση mint ScaledUiAmount του Token Extensions Program επιτρέπει σε ένα mint να εφαρμόζει έναν ενημερώσιμο πολλαπλασιαστή στο ποσό UI που εμφανίζεται για τα υπόλοιπα token.

Αυτό είναι χρήσιμο όταν ένα token αντιπροσωπεύει ένα περιουσιακό στοιχείο ή χρηματοπιστωτικό μέσο του πραγματικού κόσμου, όπως ένα διαχωρισμό μετοχών ή μέρισμα. Για παράδειγμα, ένας διαχωρισμός μετοχών διπλασιάζει τον αριθμό των μετοχών για όλους τους κατόχους. Χωρίς να αλλάξει το υπόλοιπο κάθε token account, το ScaledUiAmount επιτρέπει στα πορτοφόλια και τις εφαρμογές να εμφανίζουν ένα νέο ποσό UI χρησιμοποιώντας τον πολλαπλασιαστή του mint.

Αυτή η λειτουργία μπορεί επίσης να χρησιμοποιηθεί για μερίσματα ή διανομή απόδοσης.

Δεν δημιουργούνται νέα token. Το ποσό token που αποθηκεύεται στους token accounts παραμένει το ίδιο. Μόνο το εμφανιζόμενο ποσό UI αλλάζει.

Ασύμβατη Επέκταση

Μην ενεργοποιείτε το ScaledUiAmount και το InterestBearingConfig στο ίδιο mint. Το Token Extensions Program απορρίπτει αυτόν τον συνδυασμό επεκτάσεων.

Πώς Λειτουργεί το Scaled UI Amount

  • Το ScaledUiAmountConfig αποθηκεύει την αρχή ενημέρωσης, το multiplier, το new_multiplier και το new_multiplier_effective_timestamp.
  • Πριν από το new_multiplier_effective_timestamp, οι μετατροπές χρησιμοποιούν το multiplier. Κατά τη διάρκεια ή μετά από αυτήν τη χρονική σήμανση, οι μετατροπές χρησιμοποιούν το new_multiplier.
  • Το UpdateMultiplier μπορεί να εφαρμόσει έναν νέο πολλαπλασιαστή άμεσα ή να τον προγραμματίσει για μια μελλοντική χρονική σήμανση Unix.
  • Τα AmountToUiAmount, UiAmountToAmount και οι βοηθοί μετατροπής της επέκτασης χρησιμοποιούν αριθμητική κινητής υποδιαστολής για mint με scaled UI amount, επομένως οι μετατροπές δεν εγγυώνται ακριβή αντιστροφή.

Πώς να Χρησιμοποιήσετε το Scaled UI Amount

Για να χρησιμοποιήσετε το scaled UI amount:

  1. Υπολογίστε το μέγεθος του mint account και το rent που απαιτείται για το mint και την επέκταση ScaledUiAmount.
  2. Δημιουργήστε το mint account με το CreateAccount, αρχικοποιήστε το ScaledUiAmount και αρχικοποιήστε το mint με το InitializeMint.
  3. Χρησιμοποιήστε τα AmountToUiAmount, UiAmountToAmount ή τους βοηθούς πελάτη όταν εμφανίζετε υπόλοιπα ή μετατρέπετε ποσά UI.
  4. Χρησιμοποιήστε το UpdateMultiplier για να ενημερώσετε τον εμφανιζόμενο πολλαπλασιαστή άμεσα ή σε μια μελλοντική χρονική σήμανση Unix.

Σειρά Εντολών

Η ScaledUiAmountMintInstruction::Initialize πρέπει να προηγείται της InitializeMint. Οι CreateAccount, ScaledUiAmountMintInstruction::Initialize και InitializeMint πρέπει να περιλαμβάνονται στην ίδια συναλλαγή.

Οδηγοί

Αναφορά Πηγής

ΣτοιχείοΠεριγραφήΠηγή
ScaledUiAmountConfigΚατάσταση επέκτασης mint που αποθηκεύει την αρχή, τον τρέχοντα πολλαπλασιαστή, τον επόμενο πολλαπλασιαστή και τη χρονική σήμανση όταν τίθεται σε ισχύ.Πηγή
ScaledUiAmountMintInstruction::InitializeΕντολή που αρχικοποιεί το ScaledUiAmount σε ένα mint πριν από το InitializeMint.Πηγή
ScaledUiAmountMintInstruction::UpdateMultiplierΕντολή που ορίζει έναν νέο πολλαπλασιαστή και τη χρονική σήμανση Unix όταν τίθεται σε ισχύ.Πηγή
amount_to_ui_amountΒοηθητική συνάρτηση που μετατρέπει ένα ποσό token σε συμβολοσειρά ποσού UI χρησιμοποιώντας τον τρέχοντα πολλαπλασιαστή, τα δεκαδικά ψηφία και τη χρονική σήμανση.Πηγή
try_ui_amount_into_amountΒοηθητική συνάρτηση που μετατρέπει μια συμβολοσειρά ποσού UI πίσω σε ποσό token χρησιμοποιώντας τον τρέχοντα πολλαπλασιαστή, τα δεκαδικά ψηφία και τη χρονική σήμανση.Πηγή
process_initializeΕπεξεργαστής που αρχικοποιεί το ScaledUiAmountConfig και αποθηκεύει τον αρχικό πολλαπλασιαστή σε ένα μη αρχικοποιημένο mint.Πηγή
process_update_multiplierΕπεξεργαστής που επικυρώνει την αρχή, ενημερώνει τον προγραμματισμένο πολλαπλασιαστή και τον εφαρμόζει άμεσα όταν χρειάζεται.Πηγή
process_amount_to_ui_amountΔιαδρομή μετατροπής προγράμματος token που χρησιμοποιεί το ScaledUiAmountConfig όταν ένα mint έχει ενεργοποιημένη την επέκταση.Πηγή
process_ui_amount_to_amountΔιαδρομή μετατροπής προγράμματος token που μετατρέπει ένα ποσό UI πίσω σε ποσό token για mint με scaled UI amount.Πηγή

Typescript

Το παράδειγμα Kit παρακάτω χρησιμοποιεί τις δημιουργημένες οδηγίες απευθείας. Παραδείγματα παλαιού τύπου που χρησιμοποιούν @solana/web3.js και @solana/spl-token περιλαμβάνονται για αναφορά.

Kit

Instructions
import {
lamports,
createClient,
generateKeyPairSigner,
unwrapOption
} from "@solana/kit";
import { solanaRpc, rpcAirdrop } from "@solana/kit-plugin-rpc";
import { generatedPayer, airdropPayer } from "@solana/kit-plugin-signer";
import { getCreateAccountInstruction } from "@solana-program/system";
import {
amountToUiAmountForMintWithoutSimulation,
extension,
fetchMint,
findAssociatedTokenPda,
getCreateAssociatedTokenInstructionAsync,
getInitializeMintInstruction,
getInitializeScaledUiAmountMintInstruction,
getMintSize,
getMintToCheckedInstruction,
getUpdateMultiplierScaledUiMintInstruction,
isExtension,
TOKEN_2022_PROGRAM_ADDRESS
} from "@solana-program/token-2022";
const client = await createClient()
.use(generatedPayer())
.use(
solanaRpc({
rpcUrl: "http://localhost:8899",
rpcSubscriptionsUrl: "ws://localhost:8900"
})
)
.use(rpcAirdrop())
.use(airdropPayer(lamports(1_000_000_000n)));
const mint = await generateKeyPairSigner();
const recipient = await generateKeyPairSigner();
const initialMultiplier = 5.0;
const updatedMultiplier = 10.0;
const tokenAmount = 1_000n;
const scaledUiAmountExtension = extension("ScaledUiAmountConfig", {
authority: client.payer.address,
multiplier: initialMultiplier,
newMultiplierEffectiveTimestamp: 0n,
newMultiplier: initialMultiplier
});
const mintSpace = BigInt(getMintSize([scaledUiAmountExtension]));
const mintRent = await client.rpc
.getMinimumBalanceForRentExemption(mintSpace)
.send();
await client.sendTransaction([
getCreateAccountInstruction({
payer: client.payer, // Account funding the new mint account.
newAccount: mint, // New mint account to create.
lamports: mintRent, // Lamports funding the mint account rent.
space: mintSpace, // Account size in bytes for the mint plus ScaledUiAmountConfig.
programAddress: TOKEN_2022_PROGRAM_ADDRESS // Program that owns the mint account.
}),
getInitializeScaledUiAmountMintInstruction({
mint: mint.address, // Mint account that stores the ScaledUiAmountConfig extension.
authority: client.payer.address, // Authority allowed to update the multiplier later.
multiplier: initialMultiplier // Initial multiplier used for displayed UI amounts.
}),
getInitializeMintInstruction({
mint: mint.address, // Mint account to initialize.
decimals: 0, // Number of decimals for the token.
mintAuthority: client.payer.address, // Authority allowed to mint new tokens.
freezeAuthority: client.payer.address // Authority allowed to freeze token accounts.
})
]);
const [tokenAccount] = await findAssociatedTokenPda({
mint: mint.address,
owner: recipient.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
await client.sendTransaction([
await getCreateAssociatedTokenInstructionAsync({
payer: client.payer, // Account funding the associated token account creation.
mint: mint.address, // Mint for the associated token account.
owner: recipient.address // Owner of the token account.
}),
getMintToCheckedInstruction({
mint: mint.address, // Mint account that issues the tokens.
token: tokenAccount, // Token account receiving the newly minted tokens.
mintAuthority: client.payer, // Signer authorized to mint new tokens.
amount: tokenAmount, // Token amount in base units.
decimals: 0 // Decimals defined on the mint.
})
]);
const calculatedUiAmountBeforeUpdate =
await amountToUiAmountForMintWithoutSimulation(
client.rpc,
mint.address,
tokenAmount
);
const updateMultiplierInstruction = getUpdateMultiplierScaledUiMintInstruction({
mint: mint.address, // Mint account that stores the ScaledUiAmountConfig extension.
authority: client.payer, // Signer authorized to update the multiplier.
multiplier: updatedMultiplier, // New multiplier used for displayed UI amounts.
effectiveTimestamp: 0n // Unix timestamp when the new multiplier takes effect.
});
await client.sendTransaction([updateMultiplierInstruction]);
const calculatedUiAmountAfterUpdate =
await amountToUiAmountForMintWithoutSimulation(
client.rpc,
mint.address,
tokenAmount
);
const mintAccount = await fetchMint(client.rpc, mint.address);
const scaledUiAmountConfig = (
unwrapOption(mintAccount.data.extensions) ?? []
).find((item) => isExtension("ScaledUiAmountConfig", item));
console.log("Mint Address:", mint.address);
console.log("Token Account:", tokenAccount);
console.log(
"Calculated UI Amount Before Update:",
calculatedUiAmountBeforeUpdate
);
console.log(
"Calculated UI Amount After Update:",
calculatedUiAmountAfterUpdate
);
console.log("ScaledUiAmountConfig:", scaledUiAmountConfig);
Console
Click to execute the code.

Web3.js

Instructions
import {
Connection,
Keypair,
PublicKey,
sendAndConfirmTransaction,
SystemProgram,
Transaction,
LAMPORTS_PER_SOL
} from "@solana/web3.js";
import {
ASSOCIATED_TOKEN_PROGRAM_ID,
createAssociatedTokenAccountInstruction,
createInitializeMintInstruction,
createInitializeScaledUiAmountConfigInstruction,
createMintToCheckedInstruction,
createUpdateMultiplierDataInstruction,
ExtensionType,
getAssociatedTokenAddressSync,
getMint,
getMintLen,
getScaledUiAmountConfig,
TOKEN_2022_PROGRAM_ID
} from "@solana/spl-token";
async function calculateScaledUiAmount(
connection: Connection,
mintPublicKey: PublicKey,
tokenAmount: bigint
) {
const mintAccount = await getMint(
connection,
mintPublicKey,
"confirmed",
TOKEN_2022_PROGRAM_ID
);
const scaledUiAmountConfig = getScaledUiAmountConfig(mintAccount);
if (!scaledUiAmountConfig) {
throw new Error("ScaledUiAmountConfig not found");
}
const clockAccount = await connection.getParsedAccountInfo(
new PublicKey("SysvarC1ock11111111111111111111111111111111")
);
if (
!clockAccount.value ||
typeof clockAccount.value.data !== "object" ||
!("parsed" in clockAccount.value.data)
) {
throw new Error("Failed to fetch clock sysvar");
}
const unixTimestamp = Number(
clockAccount.value.data.parsed.info.unixTimestamp
);
const multiplier =
unixTimestamp >=
Number(scaledUiAmountConfig.newMultiplierEffectiveTimestamp)
? scaledUiAmountConfig.newMultiplier
: scaledUiAmountConfig.multiplier;
const scaledAmount = Math.trunc(Number(tokenAmount) * multiplier);
const calculatedUiAmount = scaledAmount / 10 ** mintAccount.decimals;
return {
calculatedUiAmount: calculatedUiAmount.toString(),
scaledUiAmountConfig
};
}
const connection = new Connection("http://localhost:8899", "confirmed");
const feePayer = Keypair.generate();
const recipient = Keypair.generate();
const initialMultiplier = 5.0;
const updatedMultiplier = 10.0;
const tokenAmount = 1_000n;
const airdropSignature = await connection.requestAirdrop(
feePayer.publicKey,
2 * LAMPORTS_PER_SOL
);
await connection.confirmTransaction(airdropSignature, "confirmed");
const mint = Keypair.generate();
const mintLength = getMintLen([ExtensionType.ScaledUiAmountConfig]);
const mintRent = await connection.getMinimumBalanceForRentExemption(mintLength);
const tokenAccount = getAssociatedTokenAddressSync(
mint.publicKey,
recipient.publicKey,
false,
TOKEN_2022_PROGRAM_ID,
ASSOCIATED_TOKEN_PROGRAM_ID
);
const createMintAccountInstruction = SystemProgram.createAccount({
fromPubkey: feePayer.publicKey, // Account funding the new mint account.
newAccountPubkey: mint.publicKey, // New mint account to create.
space: mintLength, // Account size in bytes for the mint plus ScaledUiAmountConfig.
lamports: mintRent, // Lamports funding the mint account rent.
programId: TOKEN_2022_PROGRAM_ID // Program that owns the mint account.
});
const initializeScaledUiAmountInstruction =
createInitializeScaledUiAmountConfigInstruction(
mint.publicKey, // Mint account that stores the ScaledUiAmountConfig extension.
feePayer.publicKey, // Authority allowed to update the multiplier later.
initialMultiplier, // Initial multiplier used for displayed UI amounts.
TOKEN_2022_PROGRAM_ID // Token program that owns the mint.
);
const initializeMintInstruction = createInitializeMintInstruction(
mint.publicKey, // Mint account to initialize.
0, // Number of decimals for the token.
feePayer.publicKey, // Authority allowed to mint new tokens.
feePayer.publicKey, // Authority allowed to freeze token accounts.
TOKEN_2022_PROGRAM_ID // Program that owns the mint account.
);
await sendAndConfirmTransaction(
connection,
new Transaction().add(
createMintAccountInstruction,
initializeScaledUiAmountInstruction,
initializeMintInstruction
),
[feePayer, mint]
);
const createTokenAccountInstruction = createAssociatedTokenAccountInstruction(
feePayer.publicKey, // Account funding the associated token account creation.
tokenAccount, // Associated token account address to create.
recipient.publicKey, // Owner of the token account.
mint.publicKey, // Mint for the associated token account.
TOKEN_2022_PROGRAM_ID, // Token program that owns the token account.
ASSOCIATED_TOKEN_PROGRAM_ID // Associated Token Program that creates the account.
);
const mintToTokenAccountInstruction = createMintToCheckedInstruction(
mint.publicKey, // Mint account that issues the tokens.
tokenAccount, // Token account receiving the newly minted tokens.
feePayer.publicKey, // Signer authorized to mint new tokens.
tokenAmount, // Token amount in base units.
0, // Decimals defined on the mint.
[], // Additional multisig signers.
TOKEN_2022_PROGRAM_ID // Token program that owns the mint and token account.
);
await sendAndConfirmTransaction(
connection,
new Transaction().add(
createTokenAccountInstruction,
mintToTokenAccountInstruction
),
[feePayer]
);
const { calculatedUiAmount: calculatedUiAmountBeforeUpdate } =
await calculateScaledUiAmount(connection, mint.publicKey, tokenAmount);
const updateMultiplierInstruction = createUpdateMultiplierDataInstruction(
mint.publicKey, // Mint account that stores the ScaledUiAmountConfig extension.
feePayer.publicKey, // Signer authorized to update the multiplier.
updatedMultiplier, // New multiplier used for displayed UI amounts.
0n, // Unix timestamp when the new multiplier takes effect.
[], // Additional multisig signers.
TOKEN_2022_PROGRAM_ID // Token program that owns the mint.
);
await sendAndConfirmTransaction(
connection,
new Transaction().add(updateMultiplierInstruction),
[feePayer]
);
const {
calculatedUiAmount: calculatedUiAmountAfterUpdate,
scaledUiAmountConfig
} = await calculateScaledUiAmount(connection, mint.publicKey, tokenAmount);
console.log("Mint Address:", mint.publicKey.toBase58());
console.log("Token Account:", tokenAccount.toBase58());
console.log(
"Calculated UI Amount Before Update:",
calculatedUiAmountBeforeUpdate
);
console.log(
"Calculated UI Amount After Update:",
calculatedUiAmountAfterUpdate
);
console.log("ScaledUiAmountConfig:", scaledUiAmountConfig);
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::{
sysvar::clock::{self, Clock},
signature::{Keypair, Signer},
transaction::Transaction,
};
use solana_system_interface::instruction::create_account;
use spl_associated_token_account_interface::{
address::get_associated_token_address_with_program_id,
instruction::create_associated_token_account,
};
use spl_token_2022_interface::{
extension::{
scaled_ui_amount::{instruction, ScaledUiAmountConfig},
BaseStateWithExtensions, ExtensionType, StateWithExtensions,
},
instruction::{initialize_mint, mint_to_checked},
state::Mint,
ID as TOKEN_2022_PROGRAM_ID,
};
#[tokio::main]
async fn main() -> Result<()> {
let client = RpcClient::new_with_commitment(
String::from("http://localhost:8899"),
CommitmentConfig::confirmed(),
);
let fee_payer = Keypair::new();
let recipient = Keypair::new();
let initial_multiplier = 5.0;
let updated_multiplier = 10.0;
let token_amount = 1_000u64;
let airdrop_signature = client
.request_airdrop(&fee_payer.pubkey(), 2_000_000_000)
.await?;
loop {
let confirmed = client.confirm_transaction(&airdrop_signature).await?;
if confirmed {
break;
}
}
let mint = Keypair::new();
let mint_space =
ExtensionType::try_calculate_account_len::<Mint>(&[ExtensionType::ScaledUiAmount])?;
let mint_rent = client
.get_minimum_balance_for_rent_exemption(mint_space)
.await?;
let create_mint_account_instruction = create_account(
&fee_payer.pubkey(), // Account funding the new mint account.
&mint.pubkey(), // New mint account to create.
mint_rent, // Lamports funding the mint account rent.
mint_space as u64, // Account size in bytes for the mint plus ScaledUiAmountConfig.
&TOKEN_2022_PROGRAM_ID, // Program that owns the mint account.
);
let initialize_scaled_ui_amount_instruction = instruction::initialize(
&TOKEN_2022_PROGRAM_ID, // Token program that owns the mint.
&mint.pubkey(), // Mint account that stores the ScaledUiAmountConfig extension.
Some(fee_payer.pubkey()), // Authority allowed to update the multiplier later.
initial_multiplier, // Initial multiplier used for displayed UI amounts.
)?;
let initialize_mint_instruction = initialize_mint(
&TOKEN_2022_PROGRAM_ID, // Program that owns the mint account.
&mint.pubkey(), // Mint account to initialize.
&fee_payer.pubkey(), // Authority allowed to mint new tokens.
Some(&fee_payer.pubkey()), // Authority allowed to freeze token accounts.
0, // Number of decimals for the token.
)?;
let create_mint_transaction = Transaction::new_signed_with_payer(
&[
create_mint_account_instruction,
initialize_scaled_ui_amount_instruction,
initialize_mint_instruction,
],
Some(&fee_payer.pubkey()),
&[&fee_payer, &mint],
client.get_latest_blockhash().await?,
);
client
.send_and_confirm_transaction(&create_mint_transaction)
.await?;
let token_account = get_associated_token_address_with_program_id(
&recipient.pubkey(),
&mint.pubkey(),
&TOKEN_2022_PROGRAM_ID,
);
let create_token_account_instruction = create_associated_token_account(
&fee_payer.pubkey(), // Account funding the associated token account creation.
&recipient.pubkey(), // Owner of the token account.
&mint.pubkey(), // Mint for the associated token account.
&TOKEN_2022_PROGRAM_ID, // Token program that owns the token account.
);
let mint_to_token_account_instruction = mint_to_checked(
&TOKEN_2022_PROGRAM_ID, // Token program that owns the mint and token account.
&mint.pubkey(), // Mint account that issues the tokens.
&token_account, // Token account receiving the newly minted tokens.
&fee_payer.pubkey(), // Signer authorized to mint new tokens.
&[], // Additional multisig signers.
token_amount, // Token amount in base units.
0, // Decimals defined on the mint.
)?;
let create_token_account_transaction = Transaction::new_signed_with_payer(
&[
create_token_account_instruction,
mint_to_token_account_instruction,
],
Some(&fee_payer.pubkey()),
&[&fee_payer],
client.get_latest_blockhash().await?,
);
client
.send_and_confirm_transaction(&create_token_account_transaction)
.await?;
let mint_account_before_update = client.get_account(&mint.pubkey()).await?;
let mint_state_before_update = StateWithExtensions::<Mint>::unpack(&mint_account_before_update.data)?;
let scaled_ui_amount_config_before_update =
mint_state_before_update.get_extension::<ScaledUiAmountConfig>()?;
let clock_account = client.get_account(&clock::ID).await?;
let clock: Clock = clock_account.deserialize_data()?;
let calculated_ui_amount_before_update = scaled_ui_amount_config_before_update
.amount_to_ui_amount(
token_amount,
mint_state_before_update.base.decimals,
clock.unix_timestamp,
)
.unwrap();
let update_multiplier_instruction = instruction::update_multiplier(
&TOKEN_2022_PROGRAM_ID, // Token program that owns the mint.
&mint.pubkey(), // Mint account that stores the ScaledUiAmountConfig extension.
&fee_payer.pubkey(), // Signer authorized to update the multiplier.
&[], // Additional multisig signers.
updated_multiplier, // New multiplier used for displayed UI amounts.
0, // Unix timestamp when the new multiplier takes effect.
)?;
let update_multiplier_transaction = Transaction::new_signed_with_payer(
&[update_multiplier_instruction],
Some(&fee_payer.pubkey()),
&[&fee_payer],
client.get_latest_blockhash().await?,
);
client
.send_and_confirm_transaction(&update_multiplier_transaction)
.await?;
let mint_account_after_update = client.get_account(&mint.pubkey()).await?;
let mint_state_after_update = StateWithExtensions::<Mint>::unpack(&mint_account_after_update.data)?;
let scaled_ui_amount_config_after_update =
mint_state_after_update.get_extension::<ScaledUiAmountConfig>()?;
let calculated_ui_amount_after_update = scaled_ui_amount_config_after_update
.amount_to_ui_amount(
token_amount,
mint_state_after_update.base.decimals,
clock.unix_timestamp,
)
.unwrap();
println!("Mint Address: {}", mint.pubkey());
println!("Token Account: {}", token_account);
println!(
"Calculated UI Amount Before Update: {}",
calculated_ui_amount_before_update
);
println!(
"Calculated UI Amount After Update: {}",
calculated_ui_amount_after_update
);
println!("ScaledUiAmountConfig: {:#?}", scaled_ui_amount_config_after_update);
Ok(())
}
Console
Click to execute the code.

Is this page helpful?

Πίνακας Περιεχομένων

Επεξεργασία Σελίδας

Διαχειρίζεται από

© 2026 Ίδρυμα Solana.
Με επιφύλαξη παντός δικαιώματος.
Συνδεθείτε