UNPKG

@wuwei-labs/srsly

Version:
133 lines 6.18 kB
/** * @purpose Simplified closeRental instruction wrapper * * Thin convenience wrapper around Codama-generated closeRental instruction. * Closes a completed rental and returns the fleet to the owner. */ import { address } from '@solana/kit'; import { isOption, unwrapOption } from '@solana/kit'; import { getCloseRentalInstructionAsync } from '../generated/codama/instructions'; import { mergeConfig, getAddresses } from '../utils/config'; import { toTransactionSigner } from '../utils/signer'; import { fetchConfig } from '../accounts/config'; import { fetchContract } from '../accounts/contract'; import { fetchFleet } from '../accounts/fleet'; import { fetchRental } from '../accounts/rental'; import { deriveGameAccounts } from '../pda/sage'; import { deriveActiveRental, deriveBorrowerState, deriveQueuedRental, deriveRentalAuthority, } from '../pda/srsly'; import { deriveContractThread, deriveFiber } from '../pda/thread'; import { deriveProfileFaction } from '../pda/sage'; import { deriveAssociatedTokenAccount } from '../pda/token'; import { prepareInstructions } from '../utils/instructions'; /** * Finalize a completed rental and return the fleet to the owner. * * @param params - Rental closure parameters (payer, contract) * @param config - Optional SDK configuration overrides * @returns Kit instruction (or web3.js if PublicKey in config) * * @example * ```typescript * const ix = await closeRental({ * payer: ownerWallet, * contract: contractAddress * }); * ``` */ export async function closeRental(params, config) { // Merge config const finalConfig = mergeConfig(config); // Validate required params if (!params.payer) { throw new Error('payer is required'); } if (!params.contract) { throw new Error('contract is required'); } // Fetch config and contract const configAccount = await fetchConfig(finalConfig.rpcUrl); const atlasMint = configAccount.data.atlasMint; const contractAccount = await fetchContract(params.contract, finalConfig.rpcUrl); const fleet = contractAccount.data.fleet; const gameId = contractAccount.data.gameId; // Check if contract has a queued rental waiting to activate const SYSTEM_PROGRAM_ID = '11111111111111111111111111111111'; const hasQueuedRental = contractAccount.data.queuedRental !== SYSTEM_PROGRAM_ID; let queuedRentalAddress; let queuedBorrowerProfileAddress; let queuedBorrowerProfileFactionAddress; if (hasQueuedRental) { queuedRentalAddress = await deriveQueuedRental(params.contract); const queuedRentalState = await fetchRental(queuedRentalAddress, finalConfig.rpcUrl); queuedBorrowerProfileAddress = queuedRentalState.data.borrowerProfile; queuedBorrowerProfileFactionAddress = await deriveProfileFaction(queuedBorrowerProfileAddress); } // Thread accounts needed for inline activation restage const hasThread = contractAccount.data.thread !== SYSTEM_PROGRAM_ID; let contractThreadAddress; let closeRentalFiberAddress; if (hasQueuedRental && hasThread) { const rentalAuthority = await deriveRentalAuthority(); contractThreadAddress = await deriveContractThread(params.contract, rentalAuthority); closeRentalFiberAddress = await deriveFiber(contractThreadAddress, 1); } // Convert payer to transaction signer const payerSigner = toTransactionSigner(params.payer); // Derive active rental PDA (no more slot logic) const rentalState = await deriveActiveRental(params.contract); // Fetch rental state for borrower, referrer let borrower; let referrer; const rental = await fetchRental(rentalState, finalConfig.rpcUrl); borrower = params.borrower ? address(params.borrower) : rental.data.borrower; referrer = isOption(rental.data.referrer) ? (unwrapOption(rental.data.referrer) ?? undefined) : undefined; // Derive borrower state PDA const borrowerState = await deriveBorrowerState(borrower); // Fetch fleet to get faction and derive SAGE accounts // During an active rental, fleet.subProfile IS the current borrower's profile const fleetState = await fetchFleet(fleet, finalConfig.rpcUrl); const borrowerProfile = fleetState.subProfile.key; const faction = fleetState.faction; // Derive SAGE game accounts using borrower's profile const gameAccounts = await deriveGameAccounts(borrowerProfile, faction, gameId); // Get addresses const addresses = getAddresses(config); const sageProgram = address(addresses.sage); const programAddress = address(addresses.srsly); const contractAddress = address(params.contract); // Derive fee flush accounts const vaultAddress = address(configAccount.data.slyvault); const vaultTokenAccount = await deriveAssociatedTokenAccount(vaultAddress, atlasMint); const contractTokenAccount = await deriveAssociatedTokenAccount(contractAddress, atlasMint); // Borrower's managed ATA for discount refund const borrowerTokenAccount = await deriveAssociatedTokenAccount(borrowerState, atlasMint); // Call Codama-generated instruction const kitInstruction = await getCloseRentalInstructionAsync({ payer: payerSigner, borrowerState, contract: contractAddress, rentalState, fleet: address(fleet), gameId: address(gameId), starbase: gameAccounts.starbase, starbasePlayer: gameAccounts.starbasePlayer, contractTokenAccount, vault: vaultAddress, vaultTokenAccount, referrer, borrowerTokenAccount, queuedRental: queuedRentalAddress ?? programAddress, queuedBorrowerProfile: queuedBorrowerProfileAddress ?? programAddress, queuedBorrowerProfileFaction: queuedBorrowerProfileFactionAddress ?? programAddress, contractThread: contractThreadAddress, closeRentalFiber: closeRentalFiberAddress, sageProgram, }, { programAddress }); return prepareInstructions(kitInstruction, { computeUnits: params.computeUnits, PublicKey: finalConfig.PublicKey, }); } //# sourceMappingURL=closeRental.js.map