Skip to content

Instantly share code, notes, and snippets.

@ParsaAminpour
Last active March 14, 2025 08:34
Show Gist options
  • Save ParsaAminpour/eff9be1ef8b3e81beb1e7f87e6534c78 to your computer and use it in GitHub Desktop.
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)
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