UNPKG

@mihalex/farms-sdk-tests

Version:
572 lines (491 loc) 13.4 kB
import { Connection, ConnectionConfig, Keypair, PublicKey, } from "@solana/web3.js"; import * as anchor from "@coral-xyz/anchor"; import { collToLamportsDecimal, createMint, endpointFromCluster, getFarmAuthorityPDA, getFarmsProgramId, getFarmVaultPDA, getRewardVaultPDA, getTreasuryAuthorityPDA, getTreasuryVaultPDA, getUserStatePDA, GlobalConfigAccounts, mintTo, setupAta, solAirdrop, createGlobalConfigPublicKeyRentExempt, sleep, } from "./utils"; import Decimal from "decimal.js"; import { getMintDecimals } from "@project-serum/serum/lib/market"; import { Cluster, FarmsIdl, UserAccounts, FarmAccounts, parseKeypairFile, } from "./utils"; import { FarmState, GlobalConfig, UserState } from "../rpc_client/accounts"; import { Farms } from "../Farms"; import { FarmConfigOption } from "../rpc_client/types"; export const SIZE_GLOBAL_CONFIG = 2136; export const SIZE_FARM_STATE = 8336; export type Env = { provider: anchor.AnchorProvider; program: anchor.Program; initialOwner: Keypair; cluster: Cluster; }; export type Config = { strategyInfos: FarmInfo[]; }; export type FarmInfo = { address: PublicKey; owner: PublicKey; baseVaultAuthority: PublicKey; pool: PublicKey; globalConfig: PublicKey; tokenAMint: PublicKey; tokenAVault: PublicKey; tokenAVaultBump: number; tokenBMint: PublicKey; tokenBVault: PublicKey; tokenBVaultBump: number; sharesMint: PublicKey; sharesMintAuthority: PublicKey; sharesMintAuthorityBump: number; poolProgramId: PublicKey; yvaultsProgramId: PublicKey; }; export function setUpProgram(args: { clusterOverride?: string; adminFilePath?: string; programOverride?: PublicKey; }): Env { // Cluster & admin if (!args.clusterOverride) { throw new Error("Cluster is required"); } if (!args.adminFilePath) { throw new Error("Admin is required"); } const cluster = args.clusterOverride; const config: ConnectionConfig = { commitment: anchor.AnchorProvider.defaultOptions().commitment, confirmTransactionInitialTimeout: 220000, }; const connection = new Connection(endpointFromCluster(cluster), config); const payer = parseKeypairFile(args.adminFilePath); // @ts-ignore const wallet = new anchor.Wallet(payer); const provider = new anchor.AnchorProvider( connection, wallet, anchor.AnchorProvider.defaultOptions(), ); const initialOwner = payer; anchor.setProvider(provider); // Programs const farmsProgramId = args.programOverride || getFarmsProgramId(cluster); const program = new anchor.Program(FarmsIdl, farmsProgramId); return { initialOwner, provider, program, cluster: cluster as Cluster, }; } export async function createGlobalAccountsWithAirdrop( env: Env, owner: Keypair = env.initialOwner, rewardTokens: Array<PublicKey>, ): Promise<GlobalConfigAccounts> { const globalConfig: Keypair = Keypair.generate(); let rewardAtas = new Array<PublicKey>(); let treasuryVaults = new Array<PublicKey>(); for (let index = 0; index < rewardTokens.length; index++) { rewardAtas.push(await setupAta(env.provider, rewardTokens[index], owner)); treasuryVaults.push( await getTreasuryVaultPDA( env.program.programId, globalConfig.publicKey, rewardTokens[index], ), ); } let treasuryVaultAuthority = await getTreasuryAuthorityPDA( env.program.programId, globalConfig.publicKey, ); const globalAccounts: GlobalConfigAccounts = { globalAdmin: owner, globalConfig, treasuryVaults, globalAdminRewardAtas: rewardAtas, treasuryVaultAuthority, }; return globalAccounts; } export async function createGlobalAccounts( env: Env, owner: Keypair = env.initialOwner, ): Promise<GlobalConfigAccounts> { let bufferSpaceZeroAccount = 0; const globalConfig: Keypair = await createGlobalConfigPublicKeyRentExempt( env.provider, env.program.programId, ); let rewardAtas = new Array<PublicKey>(); let treasuryVaults = new Array<PublicKey>(); let treasuryVaultAuthority = await getTreasuryAuthorityPDA( env.program.programId, globalConfig.publicKey, ); const globalAccounts: GlobalConfigAccounts = { globalAdmin: owner, globalConfig, treasuryVaults, globalAdminRewardAtas: rewardAtas, treasuryVaultAuthority, }; return globalAccounts; } export async function setUpGlobalConfigWithAirdrop( env: Env, owner: Keypair = env.initialOwner, rewardTokens: Array<PublicKey>, ): Promise<GlobalConfigAccounts> { const globalAccounts = await createGlobalAccountsWithAirdrop( env, owner, rewardTokens, ); const farmClient = new Farms(env.provider.connection); await farmClient.createGlobalConfig( globalAccounts.globalAdmin, globalAccounts.globalConfig, ); return globalAccounts; } export async function setUpGlobalConfig( env: Env, owner: Keypair = env.initialOwner, ): Promise<GlobalConfigAccounts> { const globalAccounts = await createGlobalAccounts(env, owner); const farmClient = new Farms(env.provider.connection); await farmClient.createGlobalConfig( globalAccounts.globalAdmin, globalAccounts.globalConfig, ); return globalAccounts; } export async function createUser( env: Env, farmAccounts: FarmAccounts, solAirdropAmount: Decimal, tokenAirdropAmount: Decimal, rewardAirdropAmounts: Array<Decimal>, owner?: Keypair, ): Promise<UserAccounts> { if (!owner) { owner = new anchor.web3.Keypair(); } const userState = await getUserStatePDA( env.program.programId, farmAccounts.farmState.publicKey, owner.publicKey, ); if (solAirdropAmount.gt(0)) { await solAirdrop(env.provider, owner.publicKey, solAirdropAmount); await sleep(1000); } let farmState = await FarmState.fetch( env.provider.connection, farmAccounts.farmState.publicKey, ); if (!farmState) { throw new Error("Farm state not found"); } const tokenAta = await setupAta(env.provider, farmState.token.mint, owner); let rewardAtas = new Array<PublicKey>(); for (let index = 0; index < farmState.numRewardTokens.toNumber(); index++) { rewardAtas.push( await setupAta( env.provider, farmState.rewardInfos[index].token.mint, owner, ), ); } await sleep(2000); if (tokenAirdropAmount.gt(0)) { await mintTo( env.provider, farmState.token.mint, tokenAta, collToLamportsDecimal( tokenAirdropAmount, farmState.token.decimals.toNumber(), ).toNumber(), ); } const testingUser: UserAccounts = { owner, userState: userState, tokenAta, rewardAtas, }; return testingUser; } export async function setUpUser( env: Env, farmAccounts: FarmAccounts, rewardTokens: Array<PublicKey>, owner?: Keypair, ): Promise<UserAccounts> { if (!owner) { owner = new anchor.web3.Keypair(); } const solAirdropAmount = new Decimal(5); const tokenAirdropAmount = new Decimal(2000000); let rewardAirdropAmounts = new Array<Decimal>(rewardTokens.length); rewardAirdropAmounts.fill(new Decimal(20000000)); const userAccounts = await createUser( env, farmAccounts, solAirdropAmount, tokenAirdropAmount, rewardAirdropAmounts, owner, ); const farmClient = new Farms(env.provider.connection); await farmClient.createNewUser( userAccounts.owner, farmAccounts.farmState.publicKey, ); return userAccounts; } export async function createFarmAccountsWithAirdrops( env: Env, rewardTokens: Array<PublicKey>, tokenMint: PublicKey, solAirdropAmount: Decimal, rewardAirdropAmounts: Array<Decimal>, farmAdmin?: Keypair, ): Promise<FarmAccounts> { if (!farmAdmin) { farmAdmin = new anchor.web3.Keypair(); } const farmState: Keypair = Keypair.generate(); if (solAirdropAmount.gt(0)) { await solAirdrop(env.provider, farmAdmin.publicKey, solAirdropAmount); await sleep(1000); } const farmVault = await getFarmVaultPDA( env.program.programId, farmState.publicKey, tokenMint, ); const farmVaultAuthority = await getFarmAuthorityPDA( env.program.programId, farmState.publicKey, ); let rewardVaults = new Array<PublicKey>(); let adminRewardAtas = new Array<PublicKey>(); for (let index = 0; index < rewardTokens.length; index++) { rewardVaults.push( await getRewardVaultPDA( env.program.programId, farmState.publicKey, rewardTokens[index], ), ); adminRewardAtas.push( await setupAta(env.provider, rewardTokens[index], farmAdmin), ); } await sleep(2000); for (let index = 0; index < rewardTokens.length; index++) { let tokenDecimals = await getMintDecimals( env.provider.connection, rewardTokens[index], ); if (rewardAirdropAmounts[index].gt(0)) { await mintTo( env.provider, rewardTokens[index], adminRewardAtas[index], collToLamportsDecimal( rewardAirdropAmounts[index], tokenDecimals, ).toNumber(), ); } } let farmAccounts: FarmAccounts = { farmAdmin: farmAdmin, farmState: farmState, tokenMint, farmVault, rewardVaults, farmVaultAuthority, rewardMints: rewardTokens, adminRewardAtas, }; return farmAccounts; } export async function createFarmAccounts( env: Env, rewardTokens: Array<PublicKey>, tokenMint: PublicKey, farmAdmin: Keypair, ): Promise<FarmAccounts> { const farmState: Keypair = Keypair.generate(); const farmVault = await getFarmVaultPDA( env.program.programId, farmState.publicKey, tokenMint, ); const farmVaultAuthority = await getFarmAuthorityPDA( env.program.programId, farmState.publicKey, ); let rewardVaults = new Array<PublicKey>(); let adminRewardAtas = new Array<PublicKey>(); let farmAccounts: FarmAccounts = { farmAdmin: farmAdmin, farmState: farmState, tokenMint, farmVault, rewardVaults, farmVaultAuthority, rewardMints: rewardTokens, adminRewardAtas, }; return farmAccounts; } export async function setUpFarmWithAirdrops( env: Env, globalAccounts: GlobalConfigAccounts, rewardTokens: Array<PublicKey>, farmAdmin?: Keypair, tokenMint?: PublicKey, ): Promise<FarmAccounts> { if (!farmAdmin) { farmAdmin = new anchor.web3.Keypair(); } const solAirdropAmount = new Decimal(5); let rewardAirdropAmounts = new Array<Decimal>(rewardTokens.length); rewardAirdropAmounts.fill(new Decimal(10000)); if (!tokenMint) { tokenMint = await createMint(env.provider, env.initialOwner.publicKey); } const farmAccounts = await createFarmAccountsWithAirdrops( env, rewardTokens, tokenMint, solAirdropAmount, rewardAirdropAmounts, ); const farmClient = new Farms(env.provider.connection); await farmClient.createFarm( farmAccounts.farmAdmin, globalAccounts.globalConfig.publicKey, farmAccounts.farmState, tokenMint, ); return farmAccounts; } export async function setUpFarm( env: Env, globalConfig: PublicKey, tokenMint: PublicKey, farmAdmin: Keypair, ): Promise<FarmAccounts> { let rewardTokens = new Array<PublicKey>(); const farmAccounts = await createFarmAccounts( env, rewardTokens, tokenMint, farmAdmin, ); const farmClient = new Farms(env.provider.connection); await farmClient.createFarm( farmAccounts.farmAdmin, globalConfig, farmAccounts.farmState, tokenMint, ); return farmAccounts; } export async function setupFarmsEnvironment( env: Env, numRewardTokens: number, minClaimDurationSeconds: number = 60, rewardRps: number = 50, ) { let rewardTokens = Array<PublicKey>(); for (let i = 0; i < numRewardTokens; i++) { rewardTokens.push( await createMint(env.provider, env.initialOwner.publicKey), ); } const globalAccounts = await setUpGlobalConfigWithAirdrop( env, env.initialOwner, rewardTokens, ); const farmAccounts = await setUpFarmWithAirdrops( env, globalAccounts, rewardTokens, ); const farmsClient = new Farms(env.provider.connection); for (let i = 0; i < numRewardTokens; i++) { await farmsClient.addRewardToFarm( farmAccounts.farmAdmin, globalAccounts.globalConfig.publicKey, farmAccounts.farmState.publicKey, rewardTokens[i], ); } for (let i = 0; i < numRewardTokens; i++) { await farmsClient.addRewardAmountToFarm( farmAccounts.farmAdmin, farmAccounts.farmState.publicKey, rewardTokens[i], new Decimal(100), ); } for (let i = 0; i < numRewardTokens; i++) { await farmsClient.updateRewardToFarm( farmAccounts.farmAdmin, farmAccounts.farmState.publicKey, rewardTokens[i], new FarmConfigOption.UpdateRewardRps(), rewardRps, ); await farmsClient.updateRewardToFarm( farmAccounts.farmAdmin, farmAccounts.farmState.publicKey, rewardTokens[i], new FarmConfigOption.UpdateRewardMinClaimDuration(), minClaimDurationSeconds, ); } const userAccounts = await setUpUser(env, farmAccounts, rewardTokens); return { farmsClient, farmAccounts, globalAccounts, userAccounts, rewardTokens, }; }