11package net.avianlabs.solana.domain.program
22
3- import kotlinx.coroutines.delay
3+ import io.github.oshai.kotlinlogging.KotlinLogging
4+ import kotlinx.coroutines.async
5+ import kotlinx.coroutines.awaitAll
6+ import kotlinx.coroutines.coroutineScope
47import kotlinx.coroutines.test.runTest
58import net.avianlabs.solana.SolanaClient
69import net.avianlabs.solana.client.RpcKtorClient
710import net.avianlabs.solana.domain.core.Commitment
811import net.avianlabs.solana.domain.core.Transaction
912import net.avianlabs.solana.domain.core.TransactionBuilder
10- import net.avianlabs.solana.domain.core.decode
1113import net.avianlabs.solana.methods.*
1214import net.avianlabs.solana.tweetnacl.TweetNaCl
15+ import net.avianlabs.solana.tweetnacl.ed25519.Ed25519Keypair
1316import kotlin.random.Random
1417import kotlin.test.Test
15- import kotlin.time.Duration.Companion.seconds
18+
19+ private val logger = KotlinLogging .logger { }
1620
1721class SystemProgramTest {
1822
23+ @Ignore
1924 @Test
2025 @Ignore
2126 fun testCreateDurableNonceAccount () = runBlocking {
2227 val client = SolanaClient (client = RpcKtorClient (" http://localhost:8899" ))
28+ val owner = TweetNaCl .Signature .generateKey(Random .nextBytes(32 ))
29+ logger.info { " Keypair: ${owner.publicKey} " }
30+ val nonce1 = TweetNaCl .Signature .generateKey(Random .nextBytes(32 ))
31+ logger.info { " Nonce account 1: ${nonce1.publicKey} " }
32+ val nonce2 = TweetNaCl .Signature .generateKey(Random .nextBytes(32 ))
33+ logger.info { " Nonce account 2: ${nonce2.publicKey} " }
34+ val destination = TweetNaCl .Signature .generateKey(Random .nextBytes(32 ))
35+ logger.info { " Destination: ${destination.publicKey} " }
36+
37+ val airdrop = client.requestAirdrop(owner.publicKey, 2_000_000_000 )
38+ val airdrop2 = client.requestAirdrop(destination.publicKey, 2_000_000_000 )
39+ client.waitForTransaction(airdrop, airdrop2)
40+
41+ val balance = client.getBalance(owner.publicKey)
42+ logger.info { " Balance: $balance " }
43+
44+ val nonce1tx = client.createNonceAccountSigned(
45+ keypair = owner,
46+ nonceAccount = nonce1,
47+ )
48+ val init1Sig = client.sendTransaction(nonce1tx)
49+
50+ logger.info { " Initialized nonce account 1: $init1Sig " }
51+
52+ val nonce2tx = client.createNonceAccountSigned(
53+ keypair = owner,
54+ nonceAccount = nonce2,
55+ )
56+
57+ val init2Sig = client.sendTransaction(nonce2tx)
58+
59+ logger.info { " Initialized nonce account 2: $init2Sig " }
60+
61+ client.waitForTransaction(init1Sig, init2Sig)
2362
24- val keypair = TweetNaCl .Signature .generateKey(Random .nextBytes(32 ))
25- println (" Keypair: ${keypair.publicKey} " )
26- val nonceAccount = TweetNaCl .Signature .generateKey(Random .nextBytes(32 ))
27- println (" Nonce account: ${nonceAccount.publicKey} " )
63+ val nonceAccount1 = client.getNonce(nonce1.publicKey, Commitment .Confirmed )
64+ logger.info { " Nonce account 1 info: $nonceAccount1 " }
2865
29- client.requestAirdrop(keypair.publicKey, 2_000_000_000 )
30- delay(15 .seconds)
31- val balance = client.getBalance(keypair.publicKey)
32- println (" Balance: $balance " )
66+ val tx1 = transferTransaction(
67+ nonceKeypair = nonce1,
68+ owner = owner,
69+ destination = destination,
70+ nonceAccount = nonceAccount1,
71+ )
72+
73+ val nonceAccount2 = client.getNonce(nonce2.publicKey, Commitment .Confirmed )
74+ logger.info { " Nonce account 2 info: $nonceAccount2 " }
75+
76+ val tx2 = transferTransaction(
77+ nonceKeypair = nonce2,
78+ owner = owner,
79+ destination = destination,
80+ nonceAccount = nonceAccount2,
81+ )
82+
83+ val tx2Sig = client.sendTransaction(tx2)
84+
85+ client.waitForTransaction(tx2Sig)
86+
87+ val tx1Sig = client.sendTransaction(tx1)
88+ logger.info { " Advanced nonce account: $tx1Sig " }
89+
90+ client.waitForTransaction(tx1Sig)
91+
92+ val newNonce = client.getNonce(nonce1.publicKey, Commitment .Confirmed )
93+ logger.info { " New nonce: ${newNonce?.nonce} " }
94+ }
95+
96+ private fun transferTransaction (
97+ nonceKeypair : Ed25519Keypair ,
98+ owner : Ed25519Keypair ,
99+ destination : Ed25519Keypair ,
100+ nonceAccount : NonceAccount ?
101+ ) = TransactionBuilder ()
102+ .addInstruction(
103+ SystemProgram .nonceAdvance(
104+ nonceAccount = nonceKeypair.publicKey,
105+ authorized = owner.publicKey,
106+ )
107+ )
108+ .addInstruction(
109+ SystemProgram .transfer(
110+ fromPublicKey = owner.publicKey,
111+ toPublicKey = destination.publicKey,
112+ lamports = 1_000 ,
113+ )
114+ )
115+ .setRecentBlockHash(nonceAccount!! .nonce)
116+ .build()
117+ .sign(owner)
33118
34- val rentExempt = client.getMinimumBalanceForRentExemption(SystemProgram .NONCE_ACCOUNT_LENGTH )
119+ private suspend fun SolanaClient.createNonceAccountSigned (
120+ keypair : Ed25519Keypair ,
121+ nonceAccount : Ed25519Keypair
122+ ): Transaction {
123+ val rentExempt = getMinimumBalanceForRentExemption(SystemProgram .NONCE_ACCOUNT_LENGTH )
35124
36- val blockhash = client. getRecentBlockhash()
125+ val blockhash = getRecentBlockhash()
37126
38127 val initTransaction = Transaction ()
39128 .addInstruction(
@@ -52,46 +141,21 @@ class SystemProgramTest {
52141 )
53142 .setRecentBlockHash(blockhash.blockhash)
54143 .sign(listOf (keypair, nonceAccount))
144+ return initTransaction
145+ }
55146
56-
57- val initSignature = client.sendTransaction(initTransaction)
58-
59- println (" Initialized nonce account: $initSignature " )
60- delay(15 .seconds)
61-
62- val lamportsPerSignature = client.getFeeForMessage(initTransaction.message.serialize())
63- println (" Lamports per signature: $lamportsPerSignature " )
64-
65- val nonce = client.getNonce(nonceAccount.publicKey, Commitment .Processed )
66- println (" Nonce account info: $nonce " )
67-
68- val testTransaction = TransactionBuilder ()
69- .addInstruction(
70- SystemProgram .nonceAdvance(
71- nonceAccount = nonceAccount.publicKey,
72- authorized = keypair.publicKey,
73- )
74- )
75- .addInstruction(
76- SystemProgram .transfer(
77- fromPublicKey = keypair.publicKey,
78- toPublicKey = nonceAccount.publicKey,
79- lamports = 1_000_000_000 ,
80- )
81- )
82- .setRecentBlockHash(nonce!! .nonce)
83- .build()
84- .sign(keypair)
85-
86- val testSignature = client.sendTransaction(testTransaction)
87- println (" Advanced nonce account: $testSignature " )
88-
89- delay(15 .seconds)
90-
91- val testTxInfo = client.getTransaction(testSignature, Commitment .Confirmed )
92- println (" Transaction info: ${testTxInfo?.decode()} " )
93-
94- val newNonce = client.getNonce(nonceAccount.publicKey, Commitment .Processed )
95- println (" New nonce account info: $newNonce " )
147+ private suspend fun SolanaClient.waitForTransaction (
148+ vararg signatures : String ,
149+ commitment : Commitment = Commitment .Finalized ,
150+ ) = coroutineScope {
151+ signatures.map { signature ->
152+ async {
153+ var transactionResponse: TransactionResponse ?
154+ do {
155+ transactionResponse = getTransaction(signature, commitment)
156+ } while (transactionResponse == null )
157+ logger.info { " Transaction $commitment $signature " }
158+ }
159+ }.awaitAll()
96160 }
97161}
0 commit comments