Last active
March 14, 2025 08:34
-
-
Save ParsaAminpour/eff9be1ef8b3e81beb1e7f87e6534c78 to your computer and use it in GitHub Desktop.
Hints to generate Accounts associated to SPL Accounts ecosystem (It's a quick script, doesn't followed the coding best practices)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as anchor from "@coral-xyz/anchor"; | |
import { BN, Program, web3, SystemProgram } from "@coral-xyz/anchor"; | |
import { StakingProgram } from "../target/types/staking_program"; | |
import { Connection, Keypair, PublicKey } from "@solana/web3.js"; | |
import { | |
createMint, | |
getOrCreateAssociatedTokenAccount, | |
mintTo, | |
TOKEN_PROGRAM_ID, | |
ASSOCIATED_TOKEN_PROGRAM_ID, | |
} from "@solana/spl-token"; | |
import { assert } from "chai"; | |
import { SYSTEM_PROGRAM_ID } from "@coral-xyz/anchor/dist/cjs/native/system"; | |
const APY50 = 50; | |
const FIFTY_DAYS = 1314871; | |
const confirmTransaction = async ( | |
connection: web3.Connection, | |
signature: web3.TransactionSignature, | |
desiredConfirmationStatus: web3.TransactionConfirmationStatus = 'confirmed', | |
timeout: number = 30000, | |
pollInterval: number = 1000, | |
searchTransactionHistory: boolean = false | |
): Promise<web3.SignatureStatus> => { | |
const start = Date.now(); | |
while (Date.now() - start < timeout) { | |
const { value: statuses } = await connection.getSignatureStatuses([signature], { searchTransactionHistory }); | |
if (!statuses || statuses.length === 0) { | |
throw new Error('Failed to get signature status'); | |
} | |
const status = statuses[0]; | |
if (status === null) { | |
await new Promise(resolve => setTimeout(resolve, pollInterval)); | |
continue; | |
} | |
if (status.err) throw new Error(`Transaction failed: ${JSON.stringify(status.err)}`); | |
if (status.confirmationStatus && status.confirmationStatus === desiredConfirmationStatus) return status; | |
if (status.confirmationStatus === 'finalized') return status; | |
await new Promise(resolve => setTimeout(resolve, pollInterval)); | |
} | |
throw new Error(`Transaction confirmation timeout after ${timeout}ms`); | |
} | |
describe("staking-program", () => { | |
const provider = anchor.AnchorProvider.env(); | |
anchor.setProvider(provider); | |
const payer = provider.wallet as anchor.Wallet; | |
const connection = new Connection("http://127.0.0.1:8899", "confirmed"); | |
const program = anchor.workspace.StakingProgram as Program<StakingProgram>; | |
const mintKeypair = Keypair.fromSecretKey( | |
new Uint8Array([ | |
174, 150, 97, 112, 185, 113, 75, 67, 230, 173, 126, 45, 51, 49, 109, 12, | |
55, 1, 3, 130, 159, 112, 162, 61, 10, 64, 126, 16, 126, 97, 103, 190, 11, | |
113, 252, 127, 124, 215, 55, 122, 108, 225, 121, 200, 175, 70, 95, 237, | |
178, 76, 120, 177, 207, 163, 95, 62, 191, 200, 244, 19, 55, 187, 123, 17, | |
]) | |
); | |
console.log("Mint pubkey: ", mintKeypair.publicKey.toString()); | |
console.log("Payer: ", payer.publicKey.toString()); | |
it("Is initialized!", async () => { | |
const mint = await createMint( | |
connection, | |
payer.payer, // signer | |
payer.publicKey, | |
payer.publicKey, | |
9, | |
mintKeypair | |
); | |
console.log("mint", mint); | |
let [vaultAccountPDA] = PublicKey.findProgramAddressSync( | |
[Buffer.from("vault")], | |
program.programId | |
); | |
let [treasuryAccountPDA] = PublicKey.findProgramAddressSync( | |
[ | |
Buffer.from("treasury_account_info"), | |
new BN(APY50).toArrayLike(Buffer, "le", 8), | |
], | |
program.programId | |
); | |
const tx = await program.methods | |
.initialize(new anchor.BN(APY50), new anchor.BN(FIFTY_DAYS)) | |
.accounts({ | |
treasuryAccountInfo: treasuryAccountPDA, | |
tokenVaultAccount: vaultAccountPDA, | |
signer: payer.publicKey, | |
mint: mintKeypair.publicKey, | |
} as any) | |
.rpc(); | |
await confirmTransaction(connection, tx); | |
console.log("Transaction confirmed", tx.toString()); | |
const treasuryAccount = await program.account.treasuryAccount.fetch(treasuryAccountPDA); | |
assert.equal(treasuryAccount.returnPercentage.toString(), APY50.toString()); | |
assert.equal(treasuryAccount.timeThreshold.toString(), FIFTY_DAYS.toString()); | |
assert.equal(treasuryAccount.totalBalance.toString(), "0"); | |
}); | |
it("Staking", async () => { | |
let userTokenAccount = await getOrCreateAssociatedTokenAccount( | |
connection, | |
payer.payer, | |
mintKeypair.publicKey, | |
payer.publicKey | |
); | |
await mintTo( | |
connection, | |
payer.payer, | |
mintKeypair.publicKey, | |
userTokenAccount.address, | |
payer.payer, | |
1e11 | |
); | |
// let [vaultAccountPDA] = PublicKey.findProgramAddressSync( | |
// [Buffer.from("vault")], | |
// program.programId | |
// ); | |
let [treasuryAccountPDA] = PublicKey.findProgramAddressSync( | |
[ | |
Buffer.from("treasury_account_info"), | |
new BN(APY50).toArrayLike(Buffer, "le", 8), | |
], | |
program.programId | |
); | |
let [stakeAccount] = PublicKey.findProgramAddressSync( | |
[Buffer.from("token"), payer.publicKey.toBuffer()], | |
program.programId | |
); | |
await getOrCreateAssociatedTokenAccount( | |
connection, | |
payer.payer, | |
mintKeypair.publicKey, | |
payer.publicKey | |
); | |
const tx = await program.methods | |
.stake(new anchor.BN(APY50), new anchor.BN(100)) // sending 100 tokens | |
.accounts({ | |
treasuryAccountInfo: treasuryAccountPDA, | |
stakeAccount: stakeAccount, | |
userTokenAccount: userTokenAccount.address, | |
signer: payer.publicKey, | |
mint: mintKeypair.publicKey, | |
tokenProgram: TOKEN_PROGRAM_ID, | |
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, | |
systemProgram: SYSTEM_PROGRAM_ID, | |
} as any) | |
.signers([payer.payer]) | |
.rpc(); | |
console.log("Staked transaction signature", tx); | |
const treasuryAccount = await program.account.treasuryAccount.fetch(treasuryAccountPDA); | |
const userBalance = treasuryAccount.userBalances.find((user) => user.owner.equals(payer.publicKey)); | |
console.log("stake start time", userBalance?.stakeStartTime.toNumber()); | |
assert.equal(treasuryAccount.totalBalance.toString(), "100000000000"); | |
assert.equal(userBalance?.balance.toString(), "100000000000"); | |
assert.equal(userBalance?.isStaked, true); | |
assert.equal(userBalance?.owner.toString(), payer.publicKey.toString()); | |
assert.equal(userBalance?.lastPointSnapshot, null); | |
assert.isAbove(userBalance?.stakeStartTime.toNumber(), 0); | |
}); | |
it("Destaking", async () => { | |
let userTokenAccount = await getOrCreateAssociatedTokenAccount( | |
connection, | |
payer.payer, | |
mintKeypair.publicKey, | |
payer.publicKey | |
); | |
let [vaultAccountPDA] = PublicKey.findProgramAddressSync( | |
[Buffer.from("vault")], | |
program.programId | |
); | |
let [treasuryAccountPDA] = PublicKey.findProgramAddressSync( | |
[ | |
Buffer.from("treasury_account_info"), | |
new BN(APY50).toArrayLike(Buffer, "le", 8), | |
], | |
program.programId | |
); | |
let [stakeAccount] = PublicKey.findProgramAddressSync( | |
[Buffer.from("token"), payer.publicKey.toBuffer()], | |
program.programId | |
); | |
const tx = await program.methods | |
.destake(new anchor.BN(APY50)) | |
.accounts({ | |
treasuryAccountInfo: treasuryAccountPDA, | |
tokenVaultAccount: vaultAccountPDA, | |
stakeAccount: stakeAccount, | |
userTokenAccount: userTokenAccount.address, | |
signer: payer.publicKey, | |
mint: mintKeypair.publicKey, | |
tokenProgram: TOKEN_PROGRAM_ID, | |
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, | |
systemProgram: SYSTEM_PROGRAM_ID, | |
} as any) | |
.signers([payer.payer]) | |
.rpc(); | |
console.log("Staked transaction signature", tx); | |
const treasuryAccount = await program.account.treasuryAccount.fetch(treasuryAccountPDA); | |
const userBalance = treasuryAccount.userBalances.find((user) => user.owner.equals(payer.publicKey)); | |
assert.equal(treasuryAccount.totalBalance.toString(), "0"); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment