1
1
package net.avianlabs.solana.domain.program
2
2
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
4
7
import kotlinx.coroutines.test.runTest
5
8
import net.avianlabs.solana.SolanaClient
6
9
import net.avianlabs.solana.client.RpcKtorClient
7
10
import net.avianlabs.solana.domain.core.Commitment
8
11
import net.avianlabs.solana.domain.core.Transaction
9
12
import net.avianlabs.solana.domain.core.TransactionBuilder
10
- import net.avianlabs.solana.domain.core.decode
11
13
import net.avianlabs.solana.methods.*
12
14
import net.avianlabs.solana.tweetnacl.TweetNaCl
15
+ import net.avianlabs.solana.tweetnacl.ed25519.Ed25519Keypair
13
16
import kotlin.random.Random
14
17
import kotlin.test.Test
15
- import kotlin.time.Duration.Companion.seconds
18
+
19
+ private val logger = KotlinLogging .logger { }
16
20
17
21
class SystemProgramTest {
18
22
23
+ @Ignore
19
24
@Test
20
25
@Ignore
21
26
fun testCreateDurableNonceAccount () = runBlocking {
22
27
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)
23
62
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 " }
28
65
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)
33
118
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 )
35
124
36
- val blockhash = client. getRecentBlockhash()
125
+ val blockhash = getRecentBlockhash()
37
126
38
127
val initTransaction = Transaction ()
39
128
.addInstruction(
@@ -52,46 +141,21 @@ class SystemProgramTest {
52
141
)
53
142
.setRecentBlockHash(blockhash.blockhash)
54
143
.sign(listOf (keypair, nonceAccount))
144
+ return initTransaction
145
+ }
55
146
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()
96
160
}
97
161
}
0 commit comments