import * as anchor from "@project-serum/anchor"; import { getAssociatedTokenAddress, getAccount, createAssociatedTokenAccountInstruction, } from "@solana/spl-token"; import { getStrikr, getStrikrAuthority } from "../../utils"; import { TOKEN_METADATA_PROGRAM_ID, STRIKR_COLLECTION_MINT, } from "../../constants"; import { requestComputeUnits } from "../../actions/request-compute-units"; import { getFloorOption } from "./get-floor-option"; import { Response } from "../../types/types"; /** * Exercise the put option * @param provider Anchor provider * @param optionKey Option key representing a unique option * @param assetNftMint Asset NFT which underlies the option * @param whitelistProof The Merkle proof of the NFT wrt the mint list tree * @param assetNftTokenAccount Optional: The token account of the user wrt the NFT * @returns Promise resolving to the transaction signature */ export const floorExercisePutOption = async ( provider: anchor.AnchorProvider, optionKey: anchor.web3.PublicKey, assetNftMint: anchor.web3.PublicKey, whitelistProof: number[][], assetNftTokenAccount?: anchor.web3.PublicKey ): Promise => { const strikr = getStrikr(provider); const depositTransaction = new anchor.web3.Transaction(); const exerciseTransaction = new anchor.web3.Transaction(); const strikrAuthority = await getStrikrAuthority(); const optionState = await getFloorOption(provider.connection, optionKey); // Request additional compute units and attach the instruction const computeUnitsIx = requestComputeUnits(provider, 400_000, 0); depositTransaction.add(computeUnitsIx); exerciseTransaction.add(computeUnitsIx); const strikrAssetNftTokenAccount = await getAssociatedTokenAddress( assetNftMint, strikrAuthority, true ); const buyerPositionNftTokenAccount = await getAssociatedTokenAddress( optionState.buyerPositionNftMint, provider.wallet.publicKey, true ); if (!optionState.isCollateralDeposited) { // Use wallet's ATA as the NFT token account if not passed as argument if (!assetNftTokenAccount) { assetNftTokenAccount = await getAssociatedTokenAddress( assetNftMint, provider.wallet.publicKey ); // Check if ATA exists, otherwise initialize it try { await getAccount(provider.connection, assetNftTokenAccount); } catch { depositTransaction.add( createAssociatedTokenAccountInstruction( provider.wallet.publicKey, assetNftTokenAccount, provider.wallet.publicKey, assetNftMint ) ); } } depositTransaction.add( await strikr.methods .floorDepositAssetBeforeExercise(whitelistProof) .accounts({ signer: provider.wallet.publicKey, optionKey: optionKey, collectionIdentifierKey: optionState.collectionIdentifierKey, assetNftMint: assetNftMint, strikrCollectionMint: STRIKR_COLLECTION_MINT, signerAssetNftTokenAccount: assetNftTokenAccount, strikrAssetNftTokenAccount: strikrAssetNftTokenAccount, tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID, }) .instruction() ); await provider.sendAndConfirm(depositTransaction); } exerciseTransaction.add( await strikr.methods .floorExercisePutOption() .accounts({ signer: provider.wallet.publicKey, optionKey: optionKey, collectionIdentifierKey: optionState.collectionIdentifierKey, strikrCollectionMint: STRIKR_COLLECTION_MINT, buyerPositionNftMint: optionState.buyerPositionNftMint, buyerPositionNftTokenAccount: buyerPositionNftTokenAccount, tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID, }) .instruction() ); const signature = await provider.sendAndConfirm(exerciseTransaction); return { signature, optionKey: optionState.optionKey, }; };