import type { Wallet } from "@saberhq/solana-contrib"; import * as anchor from "@project-serum/anchor"; import * as stakePool from "@playrooniverse/stake-pool"; import * as web3 from "@solana/web3.js"; import * as splToken from "@solana/spl-token-v2"; import * as certificate from "@playrooniverse/certificates"; import * as metaplex from "@metaplex-foundation/mpl-token-metadata"; import { QUEST_POOL_PROGRAM_ID, QUEST_POOL_IDL, CRANK_PUB_KEY, withFindOrInitAssociatedTokenAccount, findQuestEntryId, findQuestPoolId, QUEST_POOL_PROGRAM, findExtendedQuestPoolId, findExtendedQuestEntryId, } from "."; export async function withInitStakePool( connection: web3.Connection, wallet: Wallet, transaction: web3.Transaction, params: { poolName: string; rewardDurationSeconds: number; stakeSecondsRequired: number; rewardMint: web3.PublicKey; rewardMintAuthority: web3.PublicKey; maxSupply: number; requiresHunrgy: boolean; singleLoot?: boolean; } ): Promise { if(!params.singleLoot){ params.singleLoot = false; } const provider = new anchor.AnchorProvider(connection, wallet, {}); const questPool = new anchor.Program( QUEST_POOL_IDL, QUEST_POOL_PROGRAM_ID, provider ); // stake pool const [stakePoolId, bump] = await findQuestPoolId(params.rewardMint); const [extendedStakePoolId] = await findExtendedQuestPoolId(stakePoolId); transaction.add( questPool.instruction.initStakePool( { rewardMint: params.rewardMint, name: params.poolName, rewardDurationSeconds: new anchor.BN(params.rewardDurationSeconds), stakeSecondsRequired: new anchor.BN(params.stakeSecondsRequired), maxSupply: new anchor.BN(params.maxSupply), requiresHungry: params.requiresHunrgy, singleLoot: params.singleLoot }, { accounts: { stakePool: stakePoolId, extendedStakePool: extendedStakePoolId, rewardMint: params.rewardMint, rewardMintAuthority: params.rewardMintAuthority, tokenProgram: splToken.TOKEN_PROGRAM_ID, systemProgram: anchor.web3.SystemProgram.programId, rent: web3.SYSVAR_RENT_PUBKEY, payer: wallet.publicKey, }, } ) ); return transaction; } export async function withInitStakeEntry( connection: web3.Connection, wallet: Wallet, transaction: web3.Transaction, params: { levelUpStakeEntryId: web3.PublicKey; originalMint: web3.PublicKey; certificateMint: web3.PublicKey; name: string; symbol: string; } ): Promise { const provider = new anchor.AnchorProvider(connection, wallet, {}); const questPool = new anchor.Program( QUEST_POOL_IDL, QUEST_POOL_PROGRAM_ID, provider ); // stake entry const [stakeEntryId, bump] = await web3.PublicKey.findProgramAddress( [ anchor.utils.bytes.utf8.encode(stakePool.STAKE_ENTRY_SEED), params.originalMint.toBytes(), ], questPool.programId ); // certificate mint token account const certificateMintTokenAccount = await splToken.getAssociatedTokenAddress( params.certificateMint, stakeEntryId, true, splToken.TOKEN_PROGRAM_ID, splToken.ASSOCIATED_TOKEN_PROGRAM_ID, ); // mint manager const [mintManagerId, mintManagerBump] = await web3.PublicKey.findProgramAddress( [ anchor.utils.bytes.utf8.encode(certificate.MINT_MANAGER_SEED), params.certificateMint.toBytes(), ], certificate.CERTIFICATE_PROGRAM_ID ); const [certificateMintMetadataId] = await web3.PublicKey.findProgramAddress( [ Buffer.from("metadata"), metaplex.PROGRAM_ID.toBuffer(), params.certificateMint.toBuffer(), ], metaplex.PROGRAM_ID ); transaction.add( questPool.instruction.initStakeEntry( { mintManagerBump, name: params.name, symbol: params.symbol, originalMint: params.originalMint, certificateMint: params.certificateMint, mintManager: mintManagerId, }, { accounts: { // accounts stakeEntry: stakeEntryId, levelUpStakeEntry: params.levelUpStakeEntryId, originalMint: params.originalMint, certificateMint: params.certificateMint, certificateMintTokenAccount: certificateMintTokenAccount, certificateMintMetadata: certificateMintMetadataId, mintManager: mintManagerId, // programs certificateProgram: certificate.CERTIFICATE_PROGRAM_ID, tokenMetadataProgram: metaplex.PROGRAM_ID, tokenProgram: splToken.TOKEN_PROGRAM_ID, associatedToken: splToken.ASSOCIATED_TOKEN_PROGRAM_ID, systemProgram: anchor.web3.SystemProgram.programId, rent: web3.SYSVAR_RENT_PUBKEY, payer: wallet.publicKey, }, } ) ); return transaction; } export async function withStake( connection: web3.Connection, wallet: Wallet, transaction: web3.Transaction, params: { originalMint: web3.PublicKey; certificateMint: web3.PublicKey; rewardMint: web3.PublicKey; userOriginalMintTokenAccountId: web3.PublicKey; userCertificateMintTokenAccountId: web3.PublicKey; } ): Promise { const provider = new anchor.AnchorProvider(connection, wallet, {}); const questPool = new anchor.Program( QUEST_POOL_IDL, QUEST_POOL_PROGRAM_ID, provider ); // stake pool const [stakePoolId] = await findQuestPoolId(params.rewardMint); const [extendedStakePoolId] = await findExtendedQuestPoolId(stakePoolId); // stake entry const [stakeEntryId] = await findQuestEntryId(params.originalMint); const [extendedStakeEntryId] = findExtendedQuestEntryId(stakeEntryId, stakePoolId); // stake entry const levelUpStakeEntryId = await stakePool.stakeEntryIdForMintId( params.originalMint ); // issued certificate address const [certificateId, certificateBump] = await web3.PublicKey.findProgramAddress( [ anchor.utils.bytes.utf8.encode("certificate"), params.certificateMint.toBytes(), ], certificate.CERTIFICATE_PROGRAM_ID ); // issued certificate token address const certificateTokenAccount = await withFindOrInitAssociatedTokenAccount( transaction, connection, params.certificateMint, certificateId, wallet.publicKey, true ); const stakeEntryOriginalMintTokenAccountId = await withFindOrInitAssociatedTokenAccount( transaction, connection, params.originalMint, stakeEntryId, wallet.publicKey, true ); // stake entry certificate mint token account const stakeEntryCertificateMintTokenAccountId = await splToken.getAssociatedTokenAddress( params.certificateMint, stakeEntryId, true, splToken.TOKEN_PROGRAM_ID, splToken.ASSOCIATED_TOKEN_PROGRAM_ID, ); // mint manager const [mintManagerId] = await web3.PublicKey.findProgramAddress( [ anchor.utils.bytes.utf8.encode(certificate.MINT_MANAGER_SEED), params.certificateMint.toBytes(), ], certificate.CERTIFICATE_PROGRAM_ID ); transaction.add( questPool.instruction.stake( { accounts: { stakeEntry: stakeEntryId, extendedStakeEntry: extendedStakeEntryId, stakePool: stakePoolId, extendedStakePool: extendedStakePoolId, levelUpStakeEntry: levelUpStakeEntryId, user: wallet.publicKey, originalMint: params.originalMint, certificateMint: params.certificateMint, rewardMint: params.rewardMint, stakeEntryOriginalMintTokenAccount: stakeEntryOriginalMintTokenAccountId, stakeEntryCertificateMintTokenAccount: stakeEntryCertificateMintTokenAccountId, userOriginalMintTokenAccount: params.userOriginalMintTokenAccountId, userCertificateMintTokenAccount: params.userCertificateMintTokenAccountId, mintManager: mintManagerId, certificate: certificateId, certificateTokenAccount: certificateTokenAccount, tokenProgram: splToken.TOKEN_PROGRAM_ID, certificateProgram: certificate.CERTIFICATE_PROGRAM_ID, associatedToken: splToken.ASSOCIATED_TOKEN_PROGRAM_ID, systemProgram: anchor.web3.SystemProgram.programId, payer: wallet.publicKey, }, } ) ); return transaction; } export async function withClaim( connection: web3.Connection, wallet: Wallet, transaction: web3.Transaction, params: { user: web3.PublicKey; originalMint: web3.PublicKey; certificateMint: web3.PublicKey; rewardMint: web3.PublicKey; userOriginalMintTokenAccountId: web3.PublicKey; userCertificateMintTokenAccountId: web3.PublicKey; userRewardMintTokenAccount: web3.PublicKey; } ): Promise { return await withUnstakeOrClaim( connection, wallet, transaction, params, true ) } export async function withUnstake( connection: web3.Connection, wallet: Wallet, transaction: web3.Transaction, params: { user: web3.PublicKey; originalMint: web3.PublicKey; certificateMint: web3.PublicKey; rewardMint: web3.PublicKey; userOriginalMintTokenAccountId: web3.PublicKey; userCertificateMintTokenAccountId: web3.PublicKey; userRewardMintTokenAccount: web3.PublicKey; } ): Promise { return await withUnstakeOrClaim( connection, wallet, transaction, params, false ) } async function withUnstakeOrClaim( connection: web3.Connection, wallet: Wallet, transaction: web3.Transaction, params: { user: web3.PublicKey; originalMint: web3.PublicKey; certificateMint: web3.PublicKey; rewardMint: web3.PublicKey; userOriginalMintTokenAccountId: web3.PublicKey; userCertificateMintTokenAccountId: web3.PublicKey; userRewardMintTokenAccount: web3.PublicKey; }, isClaim: boolean ): Promise { const provider = new anchor.AnchorProvider(connection, wallet, {}); const questPool = new anchor.Program( QUEST_POOL_IDL, QUEST_POOL_PROGRAM_ID, provider ); // stake pool const [stakePoolId] = await findQuestPoolId(params.rewardMint); // stake entry const [stakeEntryId] = await findQuestEntryId(params.originalMint); const [extendedStakeEntryId] = findExtendedQuestEntryId(stakeEntryId, stakePoolId); // stake entry original mint token account const stakeEntryOriginalMintTokenAccountId = await withFindOrInitAssociatedTokenAccount( transaction, connection, params.originalMint, stakeEntryId, wallet.publicKey, true ); // stake entry certificate mint token account const stakeEntryCertificateMintTokenAccountId = await withFindOrInitAssociatedTokenAccount( transaction, connection, params.certificateMint, stakeEntryId, wallet.publicKey, true ); // revoke certificate await certificate.withRevokeCertificateV2(connection, wallet, transaction, { certificateMint: params.certificateMint, revokeRecipient: CRANK_PUB_KEY, }); transaction.add( questPool.instruction.unstake( { isClaim: isClaim ? 1 : 0 }, { accounts: { stakePool: stakePoolId, stakeEntry: stakeEntryId, extendedStakeEntry: extendedStakeEntryId, user: params.user, originalMint: params.originalMint, certificateMint: params.certificateMint, rewardMint: params.rewardMint, stakeEntryOriginalMintTokenAccount: stakeEntryOriginalMintTokenAccountId, stakeEntryCertificateMintTokenAccount: stakeEntryCertificateMintTokenAccountId, userOriginalMintTokenAccount: params.userOriginalMintTokenAccountId, userCertificateMintTokenAccount: params.userCertificateMintTokenAccountId, userRewardMintTokenAccount: params.userRewardMintTokenAccount, tokenProgram: splToken.TOKEN_PROGRAM_ID, clock: web3.SYSVAR_CLOCK_PUBKEY, systemProgram: anchor.web3.SystemProgram.programId, payer: wallet.publicKey, }, }) ); return transaction; } export async function withClosePool( connection: web3.Connection, wallet: Wallet, transaction: web3.Transaction, params: { rewardMint: web3.PublicKey; authority: web3.PublicKey; } ): Promise { const provider = new anchor.AnchorProvider(connection, wallet, {}); const questPool = new anchor.Program( QUEST_POOL_IDL, QUEST_POOL_PROGRAM_ID, provider ); // stake pool const [stakePoolId] = await findQuestPoolId(params.rewardMint); transaction.add( questPool.instruction.closePool({ accounts: { stakePool: stakePoolId, authority: params.authority, }, }) ); return transaction; }