UNPKG

solmash-whitelist-sdk

Version:

A sdk for interacting Solmash Whitelist program

532 lines (453 loc) 15.1 kB
import assert from "assert"; import BigNumber from "bignumber.js"; import { BN, utils } from "@project-serum/anchor"; import { createAssociatedTokenAccountInstruction, getAssociatedTokenAddressSync, } from "@solana/spl-token"; import { Connection, LAMPORTS_PER_SOL, PublicKey, Signer, Transaction, VersionedTransaction, } from "@solana/web3.js"; import { SOLMASH_SEEDS } from "./constants"; import { ISolmashWhitelistInstructions } from "./definitions"; import { AuctionInfo } from "./definitions/auctionInfo"; import { BuyerInfo } from "./definitions/buyerInfo"; import { SolmashWhitelistPayload } from "./payload"; import { getDecimals } from "./utils"; export class SolmashWhitelistService { private readonly _programId: PublicKey; static deriveAuctionAddress(auctionName: string, programId: PublicKey): PublicKey { const [auctionAddress] = PublicKey.findProgramAddressSync( [ Buffer.from(utils.bytes.utf8.encode(SOLMASH_SEEDS.auctionSeed)), Buffer.from(utils.bytes.utf8.encode(auctionName)), ], programId, ); return auctionAddress; } static deriveAuctionVaultAddress(auctionAddress: PublicKey, programId: PublicKey): PublicKey { const [auctionVaultAddress] = PublicKey.findProgramAddressSync( [ Buffer.from(utils.bytes.utf8.encode(SOLMASH_SEEDS.auctionVaultSeed)), auctionAddress.toBuffer(), ], programId, ); return auctionVaultAddress; } static deriveBuyerPdaAddress( auctionAddress: PublicKey, buyer: PublicKey, programId: PublicKey, ): PublicKey { const [auctionVaultAddress] = PublicKey.findProgramAddressSync( [ Buffer.from(utils.bytes.utf8.encode(SOLMASH_SEEDS.buyerSeed)), buyer.toBuffer(), auctionAddress.toBuffer(), ], programId, ); return auctionVaultAddress; } constructor( readonly instructions: ISolmashWhitelistInstructions, readonly _connection: Connection, private readonly _signTransaction: <T extends Transaction | VersionedTransaction>( transaction: T, ) => Promise<T>, ) { this._programId = this.instructions.program.programId; } private _createPayload(tx: Transaction, signers: Signer[]) { const errorMap: Map<number, string> = new Map(); this.instructions.program.idl.errors.forEach((error) => errorMap.set(error.code, error.msg)); return new SolmashWhitelistPayload( this._connection, this._signTransaction, errorMap, tx, signers, ); } async initAuction(params: { ownerAddress: string; auctionTokenAddress: string; bidTokenAddress: string; enabled: boolean; name: string; preSaleEndTime: number; preSaleStartTime: number; ticketPriceInSobb: string; ticketPriceInSol: string; ticketsInPool: string; tokenQuantityPerTicket: string; }) { const owner = new PublicKey(params.ownerAddress); const auctionToken = new PublicKey(params.auctionTokenAddress); const bidToken = new PublicKey(params.bidTokenAddress); const auction = SolmashWhitelistService.deriveAuctionAddress(params.name, this._programId); console.debug("auction address:", auction.toString()); const auctionVault = SolmashWhitelistService.deriveAuctionVaultAddress( auction, this._programId, ); const ticketPriceInSol = BigNumber(params.ticketPriceInSol).times(LAMPORTS_PER_SOL).toFixed(0); const bidTokenDecimals = await getDecimals(this._connection, bidToken); const ticketPriceInSobb = BigNumber(params.ticketPriceInSobb) .times(BigNumber(10).pow(bidTokenDecimals)) .toFixed(0); const ix = await this.instructions.getInitAuctionInstruction(auction, auctionVault, owner, { enabled: params.enabled, name: params.name, preSaleEndTime: new BN(params.preSaleEndTime), preSaleStartTime: new BN(params.preSaleStartTime), ticketPriceInSobb: new BN(ticketPriceInSobb), ticketPriceInSol: new BN(ticketPriceInSol), ticketsInPool: new BN(params.ticketsInPool), tokenQuantityPerTicket: new BN(params.tokenQuantityPerTicket), auctionToken, bidToken, }); const { blockhash, lastValidBlockHeight } = await this._connection.getLatestBlockhash(); const tx = new Transaction({ feePayer: owner, blockhash, lastValidBlockHeight, }).add(ix); return this._createPayload(tx, []); } async addToken(params: { auctionAddress: string; auctionTokenAddress: string; ownerAddress: string; }) { const owner = new PublicKey(params.ownerAddress); const auction = new PublicKey(params.auctionAddress); const auctionToken = new PublicKey(params.auctionTokenAddress); const auctionVault = SolmashWhitelistService.deriveAuctionVaultAddress( auction, this._programId, ); const auctionVaultTokenAccount = getAssociatedTokenAddressSync( auctionToken, auctionVault, true, ); const ownerAuctionTokenAccount = getAssociatedTokenAddressSync(auctionToken, owner); const ix = await this.instructions.getAddTokenInstruction( auction, auctionToken, auctionVault, auctionVaultTokenAccount, owner, ownerAuctionTokenAccount, ); const { blockhash, lastValidBlockHeight } = await this._connection.getLatestBlockhash(); const tx = new Transaction({ feePayer: owner, blockhash, lastValidBlockHeight, }).add(ix); return this._createPayload(tx, []); } async withdrawFunds(params: { auctionAddress: string; auctionTokenAddress: string; bidTokenAddress: string; creatorAddress: string; }) { const { auctionAddress, auctionTokenAddress, bidTokenAddress, creatorAddress } = params; const auction = new PublicKey(auctionAddress); const auctionToken = new PublicKey(auctionTokenAddress); const bidToken = new PublicKey(bidTokenAddress); const creator = new PublicKey(creatorAddress); const auctionVault = SolmashWhitelistService.deriveAuctionVaultAddress( auction, this._programId, ); const auctionBidTokenAccount = getAssociatedTokenAddressSync(bidToken, auctionVault, true); const auctionVaultTokenAccount = getAssociatedTokenAddressSync( auctionToken, auctionVault, true, ); const createAuctionTokenAccount = getAssociatedTokenAddressSync(auctionToken, creator); const creatorBidTokenAccount = getAssociatedTokenAddressSync(bidToken, creator); const creatorBidTokenAccountInfo = await this._connection.getAccountInfo( creatorBidTokenAccount, "confirmed", ); const auctionVaultTokenAccountInfo = await this._connection.getAccountInfo( auctionVaultTokenAccount, "confirmed", ); const ix = await this.instructions.getWithdrawFundsInstruction( auction, auctionBidTokenAccount, auctionToken, auctionVault, auctionVaultTokenAccount, bidToken, creator, createAuctionTokenAccount, creatorBidTokenAccount, ); const { blockhash, lastValidBlockHeight } = await this._connection.getLatestBlockhash(); const tx = new Transaction({ feePayer: creator, blockhash, lastValidBlockHeight, }); if (!auctionVaultTokenAccountInfo) { tx.add( createAssociatedTokenAccountInstruction( creator, auctionVaultTokenAccount, auctionVault, auctionToken, ), ); } if (!creatorBidTokenAccountInfo) { console.info("Creator doesn't have bid token account"); tx.add( createAssociatedTokenAccountInstruction(creator, creatorBidTokenAccount, creator, bidToken), ); } tx.add(ix); return this._createPayload(tx, []); } async whitelist(params: { auctionAddress: string; creatorAddress: string; whitelistUserAddressList: string[]; }) { const { auctionAddress, creatorAddress, whitelistUserAddressList } = params; const auction = new PublicKey(auctionAddress); const creator = new PublicKey(creatorAddress); assert(whitelistUserAddressList.length, "Empty whitelist user list"); const ixs = await Promise.all( whitelistUserAddressList.map(async (user) => { const whitelistUser = new PublicKey(user); const buyerPda = SolmashWhitelistService.deriveBuyerPdaAddress( auction, whitelistUser, this._programId, ); const ix = await this.instructions.getWhitelistInstruction( auction, buyerPda, creator, whitelistUser, ); return ix; }), ); const { blockhash, lastValidBlockHeight } = await this._connection.getLatestBlockhash(); const tx = new Transaction({ feePayer: creator, blockhash, lastValidBlockHeight, }).add(...ixs); return this._createPayload(tx, []); } async preSaleBuyUsingSpl(params: { auctionAddress: string; bidTokenAddress: string; buyerAddress: string; }) { const { auctionAddress, bidTokenAddress, buyerAddress } = params; const auction = new PublicKey(auctionAddress); const bidToken = new PublicKey(bidTokenAddress); const buyer = new PublicKey(buyerAddress); const auctionVault = SolmashWhitelistService.deriveAuctionVaultAddress( auction, this._programId, ); const buyerPda = SolmashWhitelistService.deriveBuyerPdaAddress(auction, buyer, this._programId); const auctionVaultBidTokenAccount = getAssociatedTokenAddressSync(bidToken, auctionVault, true); const buyerBidTokenAccount = getAssociatedTokenAddressSync(bidToken, buyer); const auctionVaultBidTokenAccountInfo = await this._connection.getAccountInfo( auctionVaultBidTokenAccount, "confirmed", ); const ix = await this.instructions.getPreSaleBuyUsingSplInstruction( auction, auctionVault, auctionVaultBidTokenAccount, bidToken, buyer, buyerBidTokenAccount, buyerPda, ); const { blockhash, lastValidBlockHeight } = await this._connection.getLatestBlockhash(); const tx = new Transaction({ feePayer: buyer, blockhash, lastValidBlockHeight, }); if (!auctionVaultBidTokenAccountInfo) { tx.add( createAssociatedTokenAccountInstruction( buyer, auctionVaultBidTokenAccount, auctionVault, bidToken, ), ); } tx.add(ix); return this._createPayload(tx, []); } async preSaleBuyUsingSol(params: { auctionAddress: string; buyerAddress: string }) { const { auctionAddress, buyerAddress } = params; const auction = new PublicKey(auctionAddress); const buyer = new PublicKey(buyerAddress); const auctionVault = SolmashWhitelistService.deriveAuctionVaultAddress( auction, this._programId, ); const buyerPda = SolmashWhitelistService.deriveBuyerPdaAddress(auction, buyer, this._programId); const ix = await this.instructions.getPreSaleBuyUsingSolInstruction( auction, auctionVault, buyer, buyerPda, ); const { blockhash, lastValidBlockHeight } = await this._connection.getLatestBlockhash(); const tx = new Transaction({ feePayer: buyer, blockhash, lastValidBlockHeight, }).add(ix); return this._createPayload(tx, []); } async claimTokens(params: { auctionAddress: string; auctionTokenAddress: string; buyerAddress: string; }) { const { auctionAddress, auctionTokenAddress, buyerAddress } = params; const auction = new PublicKey(auctionAddress); const auctionToken = new PublicKey(auctionTokenAddress); const buyer = new PublicKey(buyerAddress); const auctionVault = SolmashWhitelistService.deriveAuctionVaultAddress( auction, this._programId, ); const buyerPda = SolmashWhitelistService.deriveBuyerPdaAddress(auction, buyer, this._programId); const auctionVaultTokenAccount = getAssociatedTokenAddressSync( auctionToken, auctionVault, true, ); const buyerAuctionTokenAccount = getAssociatedTokenAddressSync(auctionToken, buyer); const buyerAuctionTokenAccountInfo = await this._connection.getAccountInfo(buyerAuctionTokenAccount); const ix = await this.instructions.getClaimTokensInstruction( auction, auctionToken, auctionVault, auctionVaultTokenAccount, buyer, buyerAuctionTokenAccount, buyerPda, ); const { blockhash, lastValidBlockHeight } = await this._connection.getLatestBlockhash(); const tx = new Transaction({ feePayer: buyer, blockhash, lastValidBlockHeight, }); if (!buyerAuctionTokenAccountInfo) { console.info("Claimer doesn't have auction token account"); tx.add( createAssociatedTokenAccountInstruction( buyer, buyerAuctionTokenAccount, buyer, auctionToken, ), ); } tx.add(ix); return this._createPayload(tx, []); } async changeTime(params: { auctionAddress: string; creatorAddress: string; newStartTime: number; newEndTime: number; }) { const auction = new PublicKey(params.auctionAddress); const creator = new PublicKey(params.creatorAddress); const newStartTime = new BN(params.newStartTime); const newEndTime = new BN(params.newEndTime); const ix = await this.instructions.getChangeTimeInstruction( auction, creator, newStartTime, newEndTime, ); const { blockhash, lastValidBlockHeight } = await this._connection.getLatestBlockhash(); const tx = new Transaction({ feePayer: creator, blockhash, lastValidBlockHeight, }).add(ix); return this._createPayload(tx, []); } async getAuctionInfo(auctionAddress: string): Promise<AuctionInfo> { const auction = new PublicKey(auctionAddress); const decoded = await this.instructions.program.account.auction.fetch(auction); return { accumulatedSobb: decoded.accumulatedSobb.toString(), accumulatedSol: decoded.accumulatedSol.toString(), auctionToken: decoded.auctionToken.toString(), bidToken: decoded.bidToken.toString(), enabled: decoded.enabled, name: decoded.name, owner: decoded.owner.toString(), preSaleEndTime: decoded.preSaleEndTime.toNumber(), preSaleStartTime: decoded.preSaleStartTime.toNumber(), ticketPriceInSobb: decoded.ticketPriceInSobb.toString(), ticketPriceInSol: decoded.ticketPriceInSol.toString(), ticketsInPool: decoded.ticketsInPool.toString(), tokenQuantityPerTicket: decoded.tokenQuantityPerTicket.toString(), }; } async getBuyerInfo(auctionAddress: string, buyerAddress: string): Promise<BuyerInfo> { const auction = new PublicKey(auctionAddress); const buyer = new PublicKey(buyerAddress); const buyerPda = SolmashWhitelistService.deriveBuyerPdaAddress(auction, buyer, this._programId); const decoded = await this.instructions.program.account.buyer.fetch(buyerPda); return { claimed: decoded.claimed, participated: decoded.participated, whitelisted: decoded.whitelisted, blacklisted: decoded.blacklisted, }; } async isBuyerWhitelisted(auctionAddress: string, buyerAddress: string) { const auction = new PublicKey(auctionAddress); const buyer = new PublicKey(buyerAddress); const buyerPda = SolmashWhitelistService.deriveBuyerPdaAddress(auction, buyer, this._programId); const accountInfo = await this._connection.getAccountInfo(buyerPda, "confirmed"); return accountInfo !== null; } async buyerParticipated(auctionAddress: string, buyerAddress: string) { const info = await this.getBuyerInfo(auctionAddress, buyerAddress); return info.participated; } async buyerClaimed(auctionAddress: string, buyerAddress: string) { const info = await this.getBuyerInfo(auctionAddress, buyerAddress); return info.claimed; } }