1
1
// No imports needed: web3, anchor, pg and more are globally available
2
2
import * as anchor from "@coral-xyz/anchor" ;
3
- import { BankrunProvider } from "anchor-bankrun" ;
4
- import { TOKEN_PROGRAM_ID } from "@solana/spl-token" ;
3
+ import { ASSOCIATED_TOKEN_PROGRAM_ID , TOKEN_PROGRAM_ID } from "@solana/spl-token" ;
5
4
import { BN , Program } from "@coral-xyz/anchor" ;
5
+ import { createMint , getOrCreateAssociatedTokenAccount , mintTo } from "@solana/spl-token" ;
6
6
7
- import {
8
- startAnchor ,
9
- Clock ,
10
- BanksClient ,
11
- ProgramTestContext ,
12
- } from "solana-bankrun" ;
13
-
14
- import { createMint , mintTo } from "spl-token-bankrun" ;
15
- import { PublicKey , Keypair } from "@solana/web3.js" ;
16
- import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet" ;
7
+ import { PublicKey , Keypair , Connection , LAMPORTS_PER_SOL } from "@solana/web3.js" ;
17
8
18
9
import IDL from "../target/idl/vesting.json" ;
19
10
import { Vesting } from "../target/types/vesting" ;
20
11
import { SYSTEM_PROGRAM_ID } from "@coral-xyz/anchor/dist/cjs/native/system" ;
21
12
13
+ // Original method is using bankrun libraries, but since it has been deprecated,
14
+ // I refactored using native anchor testing framework
15
+
22
16
describe ( "Vesting Smart Contract Tests" , ( ) => {
23
17
const companyName = "Company" ;
24
18
let beneficiary : Keypair ;
25
19
let vestingAccountKey : PublicKey ;
26
20
let treasuryTokenAccount : PublicKey ;
27
21
let employeeAccount : PublicKey ;
28
- let provider : BankrunProvider ;
22
+ let provider : anchor . AnchorProvider ;
29
23
let program : Program < Vesting > ;
30
- let banksClient : BanksClient ;
31
24
let employer : Keypair ;
25
+ let payer : Keypair ;
32
26
let mint : PublicKey ;
33
- let beneficiaryProvider : BankrunProvider ;
34
- let program2 : Program < Vesting > ;
35
- let context : ProgramTestContext ;
27
+ // let beneficiaryProvider: anchor.AnchorProvider ;
28
+ // let program2: Program<Vesting>;
29
+ const MY_DECIMALS = 2 ;
36
30
37
31
beforeAll ( async ( ) => {
38
32
beneficiary = new anchor . web3 . Keypair ( ) ;
39
33
40
- // set up bankrun
41
- context = await startAnchor (
42
- "" ,
43
- [ { name : "vesting" , programId : new PublicKey ( IDL . address ) } ] ,
44
- [
45
- {
46
- address : beneficiary . publicKey ,
47
- info : {
48
- lamports : 1_000_000_000 ,
49
- data : Buffer . alloc ( 0 ) ,
50
- owner : SYSTEM_PROGRAM_ID ,
51
- executable : false ,
52
- } ,
53
- } ,
54
- ]
55
- ) ;
56
- provider = new BankrunProvider ( context ) ;
57
-
34
+ provider = anchor . AnchorProvider . env ( ) ;
35
+ // rent is needed when claiming tokens for creating employee_token_acount
36
+ await provider . connection . requestAirdrop ( beneficiary . publicKey ,
37
+ 1 * LAMPORTS_PER_SOL ) ;
58
38
anchor . setProvider ( provider ) ;
39
+ program = anchor . workspace . Vesting as Program < Vesting > ;
40
+ console . log ( "program id:" , program . programId . toString ( ) ,
41
+ ",beneficiary:" , beneficiary . publicKey . toString ( ) ) ;
59
42
60
- program = new Program < Vesting > ( IDL as Vesting , provider ) ;
61
-
62
- banksClient = context . banksClient ;
63
-
64
- employer = provider . wallet . payer ;
43
+ employer = ( provider . wallet as anchor . Wallet ) . payer ;
44
+ payer = employer ;
65
45
66
46
// Create a new mint
67
- // @ts -ignore
68
- mint = await createMint ( banksClient , employer , employer . publicKey , null , 2 ) ;
69
-
70
- // Generate a new keypair for the beneficiary
71
- beneficiaryProvider = new BankrunProvider ( context ) ;
72
- beneficiaryProvider . wallet = new NodeWallet ( beneficiary ) ;
73
-
74
- program2 = new Program < Vesting > ( IDL as Vesting , beneficiaryProvider ) ;
47
+ mint = await createMint ( provider . connection , payer ,
48
+ payer . publicKey , null , MY_DECIMALS ) ;
49
+ console . log ( "Mint address:" , mint . toBase58 ( ) , "payer:" , payer . publicKey . toString ( ) ) ;
75
50
76
51
// Derive PDAs
77
52
[ vestingAccountKey ] = PublicKey . findProgramAddressSync (
@@ -118,13 +93,22 @@ describe("Vesting Smart Contract Tests", () => {
118
93
119
94
it ( "should fund the treasury token account" , async ( ) => {
120
95
const amount = 10_000 * 10 ** 9 ;
96
+
97
+ // 创建 employer 的 ATA(关联账户)
98
+ // const employerTokenAccount = await getOrCreateAssociatedTokenAccount(
99
+ // provider.connection,
100
+ // payer,
101
+ // mint,
102
+ // payer.publicKey
103
+ // );
104
+
105
+ // 给 treasuryTokenAccount 铸币
121
106
const mintTx = await mintTo (
122
- // @ts -ignores
123
- banksClient ,
124
- employer ,
107
+ provider . connection ,
108
+ payer ,
125
109
mint ,
126
110
treasuryTokenAccount ,
127
- employer ,
111
+ payer , // mint authority/signer
128
112
amount
129
113
) ;
130
114
@@ -139,34 +123,75 @@ describe("Vesting Smart Contract Tests", () => {
139
123
vestingAccount : vestingAccountKey ,
140
124
} )
141
125
. rpc ( { commitment : "confirmed" , skipPreflight : true } ) ;
126
+ //skipPreflight: 适合你确信交易不会失败,或者预检经常报奇怪的错误但实际能成功时
142
127
143
128
console . log ( "Create Employee Account Transaction Signature:" , tx2 ) ;
144
129
console . log ( "Employee account" , employeeAccount . toBase58 ( ) ) ;
145
130
} ) ;
146
131
147
132
it ( "should claim tokens" , async ( ) => {
148
- await new Promise ( ( resolve ) => setTimeout ( resolve , 1000 ) ) ;
149
-
150
- const currentClock = await banksClient . getClock ( ) ;
151
- context . setClock (
152
- new Clock (
153
- currentClock . slot ,
154
- currentClock . epochStartTimestamp ,
155
- currentClock . epoch ,
156
- currentClock . leaderScheduleEpoch ,
157
- 1000n
158
- )
159
- ) ;
160
-
161
- console . log ( "Employee account" , employeeAccount . toBase58 ( ) ) ;
162
-
163
- const tx3 = await program2 . methods
133
+ //await new Promise((resolve) => setTimeout(resolve, 1000));
134
+
135
+ // author says: the signer for this instruction is goint to be the beneficiary and not the employer
136
+ /*
137
+ The following is what I found by trial and error:
138
+
139
+ 1. If not perform beneficiary airdrop,report:(won't be printed without try/catch):
140
+ Error: SendTransactionError: Simulation failed.
141
+ Message: Transaction simulation failed: Error processing Instruction 0: custom program error: 0x1.
142
+ Logs:
143
+ [
144
+ "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 1595 of 181545 compute units",
145
+ "Program return: TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA pQAAAAAAAAA=",
146
+ "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success",
147
+ "Program 11111111111111111111111111111111 invoke [3]",
148
+ "Transfer: insufficient lamports 0, need 2039280",
149
+ "Program 11111111111111111111111111111111 failed: custom program error: 0x1"
150
+
151
+ 2. unknown signer: xxx When only commenting out the line
152
+ // beneficiary: beneficiary.publicKey,
153
+
154
+ 3. when commenting out the line,report:
155
+ Missing signature for public key xxx(beneficiary's key)
156
+ Solana 要求:只要合约指令声明了某个账户为 signer,交易就必须用对应私钥签名
157
+ // .signers([beneficiary])
158
+
159
+ 4. 除了tokenProgram, beneficiary,其他字段似乎都可注释掉,用例可过
160
+ 如果仅注释了tokenProgram,则会报错:
161
+ Reached maximum depth for account resolution. Unresolved accounts: `employeeTokenAccount
162
+ 原因(copilot gives): 它是 SPL Token 程序的地址,不是 PDA,也不是可以自动推导的账户,
163
+ 但它的 presence 让 Anchor 能正确识别和推导后续的 token 相关账户(比如 employeeTokenAccount
164
+
165
+ 5. 同时注释掉beneficiary和signers,报错:
166
+ AnchorError caused by account: employee_account. Error Code:
167
+ AccountNotInitialized. Error Number: 3012. Error Message:
168
+ The program expected this account to be already initialize
169
+ 6. 既然第5点报employee_acount 未初使化,则尝试在同时注释它俩时,添加employeeAccount: 报:
170
+ AnchorError caused by account: employee_account. Error Code: ConstraintSeeds.
171
+ Error Number: 2006. Error Message: A seeds constraint was violated.
172
+ Program log: Left:
173
+ Program log: BJRNd9PYp6oJNkioxJAdoZgNgt4TnNqGbKd6KuQVw9TS
174
+ Program log: Right:
175
+ Program log: 6xyHAzfxnWrjqK7zXTrTc9uw5zMh47Yr4VLFqYAu6mP
176
+ 以上这个报错在 .anchor/ 中没找到相关日志,但错误描述是在anchor 源码中的
177
+ */
178
+ try {
179
+ const tx3 = await program . methods
164
180
. claimTokens ( companyName )
165
181
. accounts ( {
182
+ beneficiary : beneficiary . publicKey ,
183
+ //employeeAccount: employeeAccount, // pda 帐户可自动推导
184
+ //vestingAccount: vestingAccountKey,
185
+ //mint,
186
+ //treasuryTokenAccount: treasuryTokenAccount,
187
+ //employeeTokenAccount: employeeTokenAccountPda,
166
188
tokenProgram : TOKEN_PROGRAM_ID ,
189
+ //associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
167
190
} )
191
+ . signers ( [ beneficiary ] )
168
192
. rpc ( { commitment : "confirmed" } ) ;
169
-
170
- console . log ( "Claim Tokens transaction signature" , tx3 ) ;
193
+ } catch ( err ) {
194
+ throw err ;
195
+ }
171
196
} ) ;
172
197
} ) ;
0 commit comments