UNPKG

solmash-whitelist-sdk-v2

Version:

A sdk for interacting Solmash Whitelist program

544 lines (469 loc) 16 kB
import assert from "assert"; import BigNumber from "bignumber.js"; import { BN, utils } from "@project-serum/anchor"; import { getAssociatedTokenAddressSync } from "@solana/spl-token"; import { Connection, LAMPORTS_PER_SOL, PublicKey, Signer, Transaction, VersionedTransaction, } from "@solana/web3.js"; import { SOLMASH_SEEDS, TEN_BIGNUM } from "./constants"; import { AuctionInfo } from "./definitions/auctionInfo"; import { BuyerInfo } from "./definitions/buyerInfo"; import { SolmashWhitelistInstructions } from "./instructions"; import { SolmashWhitelistPayload } from "./payload"; import { getDecimals } from "./utils"; export class SolmashWhitelistService { private readonly _programId: PublicKey; static deriveAuctionAddress(auctionName: string, programId: string | PublicKey): PublicKey { const _programId = new PublicKey(programId); const [auction] = PublicKey.findProgramAddressSync( [ Buffer.from(utils.bytes.utf8.encode(SOLMASH_SEEDS.auctionSeed)), Buffer.from(utils.bytes.utf8.encode(auctionName)), ], _programId, ); return auction; } static deriveAuctionVaultAddress( auction: string | PublicKey, programId: string | PublicKey, ): PublicKey { const _auction = new PublicKey(auction); const _programId = new PublicKey(programId); const [auctionVault] = PublicKey.findProgramAddressSync( [Buffer.from(utils.bytes.utf8.encode(SOLMASH_SEEDS.auctionVaultSeed)), _auction.toBuffer()], _programId, ); return auctionVault; } static deriveBuyerPdaAddress( auction: string | PublicKey, buyer: string | PublicKey, programId: string | PublicKey, ): PublicKey { const _auction = new PublicKey(auction); const _buyer = new PublicKey(buyer); const _programId = new PublicKey(programId); const [buyerPda] = PublicKey.findProgramAddressSync( [ Buffer.from(utils.bytes.utf8.encode(SOLMASH_SEEDS.buyerSeed)), _buyer.toBuffer(), _auction.toBuffer(), ], _programId, ); return buyerPda; } constructor( readonly instructions: SolmashWhitelistInstructions, 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(); for (let i = 0; i < this.instructions.program.idl.errors.length; i++) { const error = this.instructions.program.idl.errors[i]; errorMap.set(error.code, error.msg); } return new SolmashWhitelistPayload( this._connection, this._signTransaction, errorMap, tx, signers, ); } async initAuction(params: { creatorAddress: string | PublicKey; auctionTokenAddress: string | PublicKey; bidTokenAddress: string | PublicKey; claimTime: number; enabled: boolean; name: string; preSaleEndTime: number; preSaleStartTime: number; ticketPriceInBid: string; ticketPriceInSol: string; ticketsInPool: string; tokenQuantityPerTicket: string; }) { const creator = new PublicKey(params.creatorAddress); const auctionToken = new PublicKey(params.auctionTokenAddress); const bidToken = new PublicKey(params.bidTokenAddress); const auction = SolmashWhitelistService.deriveAuctionAddress(params.name, this._programId); console.debug("auction:", auction.toString()); const auctionVault = SolmashWhitelistService.deriveAuctionVaultAddress( auction, this._programId, ); console.debug("auction vault:", auctionVault.toString()); const auctionVaultTokenAccount = getAssociatedTokenAddressSync( auctionToken, auctionVault, true, ); const bidTokenDecimals = await getDecimals(this._connection, bidToken); const auctionTokenDecimals = await getDecimals(this._connection, auctionToken); const ticketPriceInSol = BigNumber(params.ticketPriceInSol).times(LAMPORTS_PER_SOL).toFixed(0); const ticketPriceInBid = BigNumber(params.ticketPriceInBid) .times(TEN_BIGNUM.pow(bidTokenDecimals)) .toFixed(0); const tokenQuantityPerTicket = BigNumber(params.tokenQuantityPerTicket) .times(TEN_BIGNUM.pow(auctionTokenDecimals)) .toFixed(0); const ix = await this.instructions.getInitAuctionInstruction( auction, auctionVault, auctionVaultTokenAccount, creator, { auctionToken, bidToken, claimTime: new BN(params.claimTime), enabled: params.enabled, name: params.name, preSaleEndTime: new BN(params.preSaleEndTime), preSaleStartTime: new BN(params.preSaleStartTime), ticketPriceInBid: new BN(ticketPriceInBid), ticketPriceInSol: new BN(ticketPriceInSol), ticketsInPool: new BN(params.ticketsInPool), tokenQuantityPerTicket: new BN(tokenQuantityPerTicket), }, ); const { blockhash, lastValidBlockHeight } = await this._connection.getLatestBlockhash(); const tx = new Transaction({ feePayer: creator, blockhash, lastValidBlockHeight, }).add(ix); return this._createPayload(tx, []); } async addToken(params: { auctionAddress: string | PublicKey; creatorAddress: string | PublicKey; }) { const creator = new PublicKey(params.creatorAddress); const auction = new PublicKey(params.auctionAddress); const auctionData = await this.instructions.program.account.auction.fetch(auction, "confirmed"); const auctionToken = auctionData.auctionToken; const auctionVault = SolmashWhitelistService.deriveAuctionVaultAddress( auction, this._programId, ); const auctionVaultTokenAccount = getAssociatedTokenAddressSync( auctionToken, auctionVault, true, ); const creatorAuctionTokenAccount = getAssociatedTokenAddressSync(auctionToken, creator); const ix = await this.instructions.getAddTokenInstruction( auction, auctionToken, auctionVault, auctionVaultTokenAccount, creator, creatorAuctionTokenAccount, ); const { blockhash, lastValidBlockHeight } = await this._connection.getLatestBlockhash(); const tx = new Transaction({ feePayer: creator, blockhash, lastValidBlockHeight, }).add(ix); return this._createPayload(tx, []); } async withdrawFunds(params: { auctionAddress: string | PublicKey; creatorAddress: string | PublicKey; withdrawSol: boolean; }) { const { auctionAddress, creatorAddress, withdrawSol } = params; const auction = new PublicKey(auctionAddress); const auctionData = await this.instructions.program.account.auction.fetch(auction, "confirmed"); const auctionToken = auctionData.auctionToken; const bidToken = auctionData.bidToken; 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 ix = await this.instructions.getWithdrawFundsInstruction( auction, auctionBidTokenAccount, auctionToken, auctionVault, auctionVaultTokenAccount, bidToken, creator, createAuctionTokenAccount, creatorBidTokenAccount, withdrawSol, ); const { blockhash, lastValidBlockHeight } = await this._connection.getLatestBlockhash(); const tx = new Transaction({ feePayer: creator, blockhash, lastValidBlockHeight, }); 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; buyerAddress: string }) { const { auctionAddress, buyerAddress } = params; const auction = new PublicKey(auctionAddress); const auctionData = await this.instructions.program.account.auction.fetch(auction, "confirmed"); const auctionToken = auctionData.auctionToken; 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 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, }); 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); const bidTokenDecimals = await getDecimals(this._connection, decoded.bidToken); const auctionTokenDecimals = await getDecimals(this._connection, decoded.auctionToken); const accumulatedBidToken = BigNumber(decoded.accumulatedBid.toString()) .div(TEN_BIGNUM.pow(bidTokenDecimals)) .toFixed(); const accumulatedSol = BigNumber(decoded.accumulatedSol.toString()) .div(LAMPORTS_PER_SOL) .toFixed(); const ticketPriceInBid = BigNumber(decoded.ticketPriceInBid.toString()) .div(TEN_BIGNUM.pow(bidTokenDecimals)) .toFixed(); const ticketPriceInSol = BigNumber(decoded.ticketPriceInSol.toString()) .div(LAMPORTS_PER_SOL) .toFixed(); const tokenQuantityPerTicket = BigNumber(decoded.tokenQuantityPerTicket.toString()) .div(TEN_BIGNUM.pow(auctionTokenDecimals)) .toFixed(); return { accumulatedBidToken, accumulatedSol, 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(), ticketPriceInBid, ticketPriceInSol, ticketsInPool: decoded.ticketsInPool.toString(), tokenQuantityPerTicket, claimTime: decoded.claimTime.toNumber(), remainingTickets: decoded.remainingTickets.toString(), ticketsClaimed: decoded.ticketsClaimed.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 { auctionAddress: decoded.auctionAddress.toString(), buyerAddress: decoded.buyerAddress.toString(), claimed: decoded.claimed, participated: decoded.participated, whitelisted: decoded.whitelisted, blacklisted: decoded.blacklisted, }; } async isBuyerWhitelisted(auctionAddress: string, buyerAddress: string) { try { const buyerPdaData = await this.getBuyerInfo(auctionAddress, buyerAddress); return buyerPdaData.whitelisted; } catch (err) { return false; } } async buyerParticipated(auctionAddress: string, buyerAddress: string) { try { const info = await this.getBuyerInfo(auctionAddress, buyerAddress); return info.participated; } catch (err) { return false; } } async buyerClaimed(auctionAddress: string, buyerAddress: string) { try { const info = await this.getBuyerInfo(auctionAddress, buyerAddress); return info.claimed; } catch (err) { return false; } } }