ÖdemelerGelişmiş ödemeler

Ertelenmiş yürütme

Her Solana işlemi yakın zamanlı bir blok hash'i içerir—işlemin "şimdi" oluşturulduğunu kanıtlayan yakın zamanlı bir ağ durumuna referans. Ağ, ~150 bloktan (~60-90 saniye) daha eski blok hash'ine sahip herhangi bir işlemi reddeder, böylece tekrar saldırılarını ve eski gönderimleri önler. Bu, gerçek zamanlı ödemeler için mükemmel çalışır. Ancak imzalama ve gönderim arasında boşluk gerektiren iş akışlarını bozar, örneğin:

SenaryoStandart işlemler neden başarısız olur
Hazine operasyonlarıTokyo'daki CFO imzalar, New York'taki kontrolör onaylar—90 saniye yeterli değil
Uyumluluk iş akışlarıİşlemlerin yürütülmeden önce yasal/uyumluluk incelemesi gerekir
Soğuk depolama imzalamaHava boşluklu makineler, imzalı işlemlerin manuel transferini gerektirir
Toplu hazırlıkBordro veya ödemeleri mesai saatlerinde hazırlayın, gece yürütün
Çoklu imza koordinasyonuFarklı zaman dilimlerindeki birden fazla onaylayıcı
Planlanmış ödemelerÖdemeleri gelecekteki bir tarihte yürütülmek üzere planlayın

Geleneksel finansta, imzalanmış bir çek 90 saniyede geçerliliğini yitirmez. Belirli blokzincir operasyonları da yitirmemeli. Dayanıklı nonce'lar bunu, yakın zamanlı blok hash'ini yalnızca kullandığınızda ilerleyen, depolanmış, kalıcı bir değerle değiştirerek çözer—size göndermek için hazır olana kadar geçerli kalan işlemler sunar.

Nasıl çalışır

Yakın zamanlı bir blockhash (~150 blok geçerli) yerine, bir blockhash yerine kullanılabilecek benzersiz bir değer saklayan özel bir hesap olan nonce hesabı kullanırsınız. Bu nonce'u kullanan her işlem, ilk talimat olarak onu "ilerletmelidir". Her nonce değeri yalnızca bir işlem için kullanılabilir.

Durable Nonce
Standard Blockhash

Nonce hesabı, rent muafiyeti için ~0.0015 SOL maliyete sahiptir. Bir nonce hesabı = aynı anda bir bekleyen işlem. Paralel iş akışları için birden fazla nonce hesabı oluşturun.

Nonce hesabı oluşturma

Bir nonce hesabı oluşturmak, tek bir işlemde iki talimat gerektirir:

  1. System Program'dan getCreateAccountInstruction kullanarak hesabı oluşturun
  2. getInitializeNonceAccountInstruction kullanarak nonce olarak başlatın

Keypair oluşturma

Nonce hesap adresi olarak kullanmak üzere yeni bir keypair oluşturun ve gerekli alanı ve rent'i hesaplayın.

Create Nonce Account
const nonceKeypair = await generateKeyPairSigner();
const nonceSpace = BigInt(getNonceSize());
const nonceRent = await rpc
.getMinimumBalanceForRentExemption(nonceSpace)
.send();

Hesap oluşturma talimatı

Rent muafiyeti için yeterli lamport ile System Program'a ait hesabı oluşturun.

Create Nonce Account
const nonceKeypair = await generateKeyPairSigner();
const nonceSpace = BigInt(getNonceSize());
const nonceRent = await rpc
.getMinimumBalanceForRentExemption(nonceSpace)
.send();
const createNonceAccountIx = getCreateAccountInstruction({
payer: sender,
newAccount: nonceKeypair,
lamports: nonceRent,
space: nonceSpace,
programAddress: SYSTEM_PROGRAM_ADDRESS
});

Nonce başlatma talimatı

Hesabı nonce hesabı olarak başlatın ve onu ilerletebilecek yetkiyi ayarlayın.

Create Nonce Account
const nonceKeypair = await generateKeyPairSigner();
const nonceSpace = BigInt(getNonceSize());
const nonceRent = await rpc
.getMinimumBalanceForRentExemption(nonceSpace)
.send();
const createNonceAccountIx = getCreateAccountInstruction({
payer: sender,
newAccount: nonceKeypair,
lamports: nonceRent,
space: nonceSpace,
programAddress: SYSTEM_PROGRAM_ADDRESS
});
const initNonceIx = getInitializeNonceAccountInstruction({
nonceAccount: nonceKeypair.address,
nonceAuthority: sender.address
});

İşlem oluşturma

Her iki talimatı içeren bir işlem oluşturun.

Create Nonce Account
const nonceKeypair = await generateKeyPairSigner();
const nonceSpace = BigInt(getNonceSize());
const nonceRent = await rpc
.getMinimumBalanceForRentExemption(nonceSpace)
.send();
const createNonceAccountIx = getCreateAccountInstruction({
payer: sender,
newAccount: nonceKeypair,
lamports: nonceRent,
space: nonceSpace,
programAddress: SYSTEM_PROGRAM_ADDRESS
});
const initNonceIx = getInitializeNonceAccountInstruction({
nonceAccount: nonceKeypair.address,
nonceAuthority: sender.address
});
const { value: blockhash } = await rpc.getLatestBlockhash().send();
const createNonceTx = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(sender, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(blockhash, tx),
(tx) =>
appendTransactionMessageInstructions(
[createNonceAccountIx, initNonceIx],
tx
)
);

İmzalama ve gönderme

Nonce hesabını oluşturmak ve başlatmak için işlemi imzalayın ve gönderin.

Keypair oluşturma

Nonce hesap adresi olarak kullanmak üzere yeni bir keypair oluşturun ve gerekli alanı ve rent'i hesaplayın.

Hesap oluşturma talimatı

Rent muafiyeti için yeterli lamport ile System Program'a ait hesabı oluşturun.

Nonce başlatma talimatı

Hesabı nonce hesabı olarak başlatın ve onu ilerletebilecek yetkiyi ayarlayın.

İşlem oluşturma

Her iki talimatı içeren bir işlem oluşturun.

İmzalama ve gönderme

Nonce hesabını oluşturmak ve başlatmak için işlemi imzalayın ve gönderin.

Create Nonce Account
const nonceKeypair = await generateKeyPairSigner();
const nonceSpace = BigInt(getNonceSize());
const nonceRent = await rpc
.getMinimumBalanceForRentExemption(nonceSpace)
.send();

Ertelenmiş işlem oluşturma

Yakın zamanlı bir blok hash'i yerine, nonce hesabının blockhash değerini işlemin ömrü olarak kullanın.

Nonce'u getir

Nonce hesabından veriyi getirin. Nonce hesabındaki blockhash değerini işlemin ömrü olarak kullanın.

Example Nonce Account Data
{
version: 1,
state: 1,
authority: 'HgjaL8artMtmntaQDVM2UBk3gppsYYERS4PkUhiaLZD1',
blockhash: '5U7seXqfgZx1uh5DFhdH1vyBhr7XGRrKxBAnJJTbbUa',
lamportsPerSignature: 5000n
}

Transfer talimatı oluştur

Ödemeniz için talimat oluşturun. Bu örnek bir token transferini gösterir.

Kalıcı nonce ile işlem oluştur

setTransactionMessageLifetimeUsingDurableNonce kullanın, bu nonce'u blok hash'i olarak ayarlar ve otomatik olarak nonce ilerleme talimatını başa ekler.

İşlemi imzala

İşlemi imzalayın. Artık standart bir blok hash'i yerine kalıcı nonce kullanıyor.

Nonce'u getir

Nonce hesabından veriyi getirin. Nonce hesabındaki blockhash değerini işlemin ömrü olarak kullanın.

Example Nonce Account Data
{
version: 1,
state: 1,
authority: 'HgjaL8artMtmntaQDVM2UBk3gppsYYERS4PkUhiaLZD1',
blockhash: '5U7seXqfgZx1uh5DFhdH1vyBhr7XGRrKxBAnJJTbbUa',
lamportsPerSignature: 5000n
}

Transfer talimatı oluştur

Ödemeniz için talimat oluşturun. Bu örnek bir token transferini gösterir.

Kalıcı nonce ile işlem oluştur

setTransactionMessageLifetimeUsingDurableNonce kullanın, bu nonce'u blok hash'i olarak ayarlar ve otomatik olarak nonce ilerleme talimatını başa ekler.

İşlemi imzala

İşlemi imzalayın. Artık standart bir blok hash'i yerine kalıcı nonce kullanıyor.

Build Deferred Transaction
const { data: nonceData } = await fetchNonce(rpc, nonceKeypair.address);

İşlemi saklama veya gönderme

İmzaladıktan sonra, işlemi depolama için kodlayın. Hazır olduğunuzda, ağa gönderin.

Depolama için kodlama

İmzalanmış işlemi base64 formatına kodlayın. Bu değeri veritabanınızda saklayın.

İşlemi gönderme

Hazır olduğunuzda imzalanmış işlemi gönderin. İşlem, nonce ilerletilene kadar geçerli kalır.

Depolama için kodlama

İmzalanmış işlemi base64 formatına kodlayın. Bu değeri veritabanınızda saklayın.

İşlemi gönderme

Hazır olduğunuzda imzalanmış işlemi gönderin. İşlem, nonce ilerletilene kadar geçerli kalır.

Store and Execute
const signedTransaction =
await signTransactionMessageWithSigners(transactionMessage);
const base64EncodedTransaction =
getBase64EncodedWireTransaction(signedTransaction);
// Store base64EncodedTransaction in your database

Demo

Demo
// Generate keypairs for sender and recipient
const sender = await generateKeyPairSigner();
const recipient = await generateKeyPairSigner();
console.log("Sender Address:", sender.address);
console.log("Recipient Address:", recipient.address);
// Demo Setup: Create RPC connection, mint, and token accounts
const { rpc, rpcSubscriptions, mint } = await demoSetup(sender, recipient);
// =============================================================================
// Step 1: Create a Nonce Account
// =============================================================================
const nonceKeypair = await generateKeyPairSigner();
console.log("\nNonce Account Address:", nonceKeypair.address);
const nonceSpace = BigInt(getNonceSize());
const nonceRent = await rpc
.getMinimumBalanceForRentExemption(nonceSpace)
.send();
// Instruction to create new account for the nonce
const createNonceAccountIx = getCreateAccountInstruction({
payer: sender,
newAccount: nonceKeypair,
lamports: nonceRent,
space: nonceSpace,
programAddress: SYSTEM_PROGRAM_ADDRESS
});
// Instruction to initialize the nonce account
const initNonceIx = getInitializeNonceAccountInstruction({
nonceAccount: nonceKeypair.address,
nonceAuthority: sender.address
});
// Build and send nonce account creation transaction
const { value: blockhash } = await rpc.getLatestBlockhash().send();
const createNonceTx = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(sender, tx),
(tx) => setTransactionMessageLifetimeUsingBlockhash(blockhash, tx),
(tx) =>
appendTransactionMessageInstructions(
[createNonceAccountIx, initNonceIx],
tx
)
);
const signedCreateNonceTx =
await signTransactionMessageWithSigners(createNonceTx);
assertIsTransactionWithBlockhashLifetime(signedCreateNonceTx);
await sendAndConfirmTransactionFactory({ rpc, rpcSubscriptions })(
signedCreateNonceTx,
{ commitment: "confirmed" }
);
console.log("Nonce Account created.");
// =============================================================================
// Step 2: Token Payment with Durable Nonce
// =============================================================================
// Fetch current nonce value from the nonce account
const { data: nonceData } = await fetchNonce(rpc, nonceKeypair.address);
console.log("Nonce Account data:", nonceData);
const [senderAta] = await findAssociatedTokenPda({
mint: mint.address,
owner: sender.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
const [recipientAta] = await findAssociatedTokenPda({
mint: mint.address,
owner: recipient.address,
tokenProgram: TOKEN_2022_PROGRAM_ADDRESS
});
console.log("\nMint Address:", mint.address);
console.log("Sender Token Account:", senderAta);
console.log("Recipient Token Account:", recipientAta);
const transferInstruction = getTransferInstruction({
source: senderAta,
destination: recipientAta,
authority: sender.address,
amount: 250_000n // 0.25 tokens
});
// Create transaction message using durable nonce lifetime
// setTransactionMessageLifetimeUsingDurableNonce automatically prepends
// the AdvanceNonceAccount instruction
const transactionMessage = pipe(
createTransactionMessage({ version: 0 }),
(tx) => setTransactionMessageFeePayerSigner(sender, tx),
(tx) =>
setTransactionMessageLifetimeUsingDurableNonce(
{
nonce: nonceData.blockhash as string as Nonce,
nonceAccountAddress: nonceKeypair.address,
nonceAuthorityAddress: nonceData.authority
},
tx
),
(tx) => appendTransactionMessageInstructions([transferInstruction], tx)
);
const signedTransaction =
await signTransactionMessageWithSigners(transactionMessage);
assertIsTransactionWithDurableNonceLifetime(signedTransaction);
const transactionSignature = getSignatureFromTransaction(signedTransaction);
// Encode the transaction to base64, optionally save and send at a later time
const base64EncodedTransaction =
getBase64EncodedWireTransaction(signedTransaction);
console.log("\nBase64 Encoded Transaction:", base64EncodedTransaction);
// Send the encoded transaction, blockhash does not expire
await rpc
.sendTransaction(base64EncodedTransaction, {
encoding: "base64",
skipPreflight: true
})
.send();
console.log("\n=== Token Payment with Durable Nonce Complete ===");
console.log("Transaction Signature:", transactionSignature);
// =============================================================================
// Demo Setup Helper Function
// =============================================================================
Console
Click to execute the code.

Bekleyen bir işlemi geçersiz kılma

Her nonce hesabı blockhash yalnızca bir kez kullanılabilir. Bekleyen bir işlemi geçersiz kılmak veya nonce hesabını yeniden kullanıma hazırlamak için manuel olarak ilerletin:

import { getAdvanceNonceAccountInstruction } from "@solana-program/system";
// Submit this instruction (with a regular blockhash) to invalidate any pending transaction
getAdvanceNonceAccountInstruction({
nonceAccount: nonceAddress,
nonceAuthority
});

Bu, yeni bir nonce değeri oluşturur ve eski değerle imzalanmış herhangi bir işlemi kalıcı olarak geçersiz kılar.

Çok taraflı onay iş akışı

Ek imzalar eklemek için işlemi deserialize edin, ardından depolama veya gönderim için tekrar serialize edin:

import {
getBase64Decoder,
getTransactionDecoder,
getBase64EncodedWireTransaction,
partiallySignTransaction
} from "@solana/kit";
// Deserialize the stored transaction
const txBytes = getBase64Decoder().decode(serializedString);
const partiallySignedTx = getTransactionDecoder().decode(txBytes);
// Each approver adds their signature
const fullySignedTx = await partiallySignTransaction(
[newSigner],
partiallySignedTx
);
// Serialize again for storage or submission
const serialized = getBase64EncodedWireTransaction(fullySignedTx);

İşlem serileştirilebilir, saklanabilir ve onaylayanlar arasında aktarılabilir. Gerekli tüm imzalar toplandığında, ağa gönderin.

Üretim ortamı için dikkat edilmesi gerekenler

Nonce hesabı yönetimi:

  • Paralel işlem hazırlığı için bir nonce hesabı havuzu oluşturun
  • Hangi nonce'ların "kullanımda" olduğunu takip edin (bekleyen imzalı işlemleri olan)
  • İşlemler gönderildikten veya iptal edildikten sonra nonce geri dönüşümünü uygulayın

Güvenlik:

  • Nonce yetkisi, işlemlerin geçersiz kılınıp kılınamayacağını kontrol eder. Ek kontrol ve görev ayrımı için nonce yetkisini işlem imzalayanlardan ayırmayı düşünün
  • Serileştirilmiş işlem baytlarına sahip olan herkes bunu ağa gönderebilir

İlgili kaynaklar

Is this page helpful?

İçindekiler

Sayfayı Düzenle

Yönetici

© 2026 Solana Vakfı.
Tüm hakları saklıdır.
Bağlanın