well, a lot of stuff.

This commit is contained in:
Jordan Prince 2021-09-11 01:29:14 -05:00
parent b6ac259413
commit ff339ed482
5 changed files with 224 additions and 10 deletions

View File

@ -3,7 +3,7 @@ import * as fs from 'fs';
import { program } from 'commander';
import * as anchor from '@project-serum/anchor';
import { LAMPORTS_PER_SOL } from '@solana/web3.js';
import { Token } from '@solana/spl-token';
import { CACHE_PATH, TOKEN_PROGRAM_ID } from './helpers/constants';
import {
loadFairLaunchProgram,
@ -11,7 +11,11 @@ import {
getTokenMint,
getFairLaunch,
getTreasury,
getFairLaunchTicket,
getAtaForMint,
getFairLaunchTicketSeqLookup,
} from './helpers/accounts';
import { sleep } from './helpers/various';
program.version('0.0.1');
if (!fs.existsSync(CACHE_PATH)) {
@ -145,6 +149,137 @@ program
console.log(`create fair launch Done: ${fairLaunch.toBase58()}`);
});
program
.command('purchase_ticket')
.option(
'-e, --env <string>',
'Solana cluster env name',
'devnet', //mainnet-beta, testnet, devnet
)
.option(
'-k, --keypair <path>',
`Solana wallet location`,
'--keypair not provided',
)
.option('-f, --fair-launch <string>', 'fair launch id')
.option('-a, --amount <string>', 'amount')
.action(async (_, cmd) => {
const { env, keypair, fairLaunch, amount } = cmd.opts();
let amountNumber = parseFloat(amount);
const walletKeyPair = loadWalletKey(keypair);
const anchorProgram = await loadFairLaunchProgram(walletKeyPair, env);
const fairLaunchKey = new anchor.web3.PublicKey(fairLaunch);
const fairLaunchObj = await anchorProgram.account.fairLaunch.fetch(
fairLaunchKey,
);
const [fairLaunchTicket, bump] = await getFairLaunchTicket(
//@ts-ignore
fairLaunchObj.tokenMint,
walletKeyPair.publicKey,
);
const remainingAccounts = [];
const instructions = [];
const signers = [];
//@ts-ignore
if (!fairLaunchObj.treasuryMint) {
amountNumber = Math.ceil(amountNumber * LAMPORTS_PER_SOL);
} else {
const transferAuthority = anchor.web3.Keypair.generate();
signers.push(transferAuthority);
instructions.push(
Token.createApproveInstruction(
TOKEN_PROGRAM_ID,
//@ts-ignore
fairLaunchObj.treasuryMint,
transferAuthority.publicKey,
walletKeyPair.publicKey,
[],
//@ts-ignore
amountNumber + fairLaunchObj.data.fees.toNumber(),
),
);
remainingAccounts.push({
//@ts-ignore
pubkey: fairLaunchObj.treasuryMint,
isWritable: true,
isSigner: false,
});
remainingAccounts.push({
pubkey: (
await getAtaForMint(
//@ts-ignore
fairLaunchObj.treasuryMint,
walletKeyPair.publicKey,
)
)[0],
isWritable: true,
isSigner: false,
});
remainingAccounts.push({
pubkey: transferAuthority.publicKey,
isWritable: false,
isSigner: true,
});
remainingAccounts.push({
pubkey: TOKEN_PROGRAM_ID,
isWritable: false,
isSigner: false,
});
}
await anchorProgram.rpc.purchaseTicket(bump, new anchor.BN(amountNumber), {
accounts: {
fairLaunchTicket,
fairLaunch,
//@ts-ignore
treasury: fairLaunchObj.treasury,
buyer: walletKeyPair.publicKey,
payer: walletKeyPair.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
clock: anchor.web3.SYSVAR_CLOCK_PUBKEY,
},
//__private: { logAccounts: true },
remainingAccounts,
signers,
instructions: instructions.length > 0 ? instructions : undefined,
});
console.log(
`create fair launch ticket Done: ${fairLaunchTicket.toBase58()}. Trying to create seq now...we may or may not get a validator with data on chain. Either way, your ticket is secure.`,
);
await sleep(5000);
const fairLaunchTicketObj =
await anchorProgram.account.fairLaunchTicket.fetch(fairLaunchTicket);
const [fairLaunchTicketSeqLookup, seqBump] =
await getFairLaunchTicketSeqLookup(
//@ts-ignore
fairLaunchObj.tokenMint,
//@ts-ignore
fairLaunchTicketObj.seq,
);
await anchorProgram.rpc.createTicketSeq(seqBump, {
accounts: {
fairLaunchTicketSeqLookup,
fairLaunch,
fairLaunchTicket,
payer: walletKeyPair.publicKey,
systemProgram: anchor.web3.SystemProgram.programId,
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
},
signers: [],
});
});
program
.command('show')
.option(
@ -290,4 +425,51 @@ program
);
});
program
.command('show_ticket')
.option(
'-e, --env <string>',
'Solana cluster env name',
'devnet', //mainnet-beta, testnet, devnet
)
.option(
'-k, --keypair <path>',
`Solana wallet location`,
'--keypair not provided',
)
.option('-f, --fair-launch <string>', 'fair launch id')
.action(async (options, cmd) => {
const { env, fairLaunch, keypair } = cmd.opts();
const walletKeyPair = loadWalletKey(keypair);
const anchorProgram = await loadFairLaunchProgram(walletKeyPair, env);
const fairLaunchObj = await anchorProgram.account.fairLaunch.fetch(
fairLaunch,
);
const fairLaunchTicket = (
await getFairLaunchTicket(
//@ts-ignore
fairLaunchObj.tokenMint,
walletKeyPair.publicKey,
)
)[0];
const fairLaunchTicketObj =
await anchorProgram.account.fairLaunchTicket.fetch(fairLaunchTicket);
//@ts-ignore
console.log('Buyer', fairLaunchTicketObj.buyer.toBase58());
//@ts-ignore
console.log('Fair Launch', fairLaunchTicketObj.fairLaunch.toBase58());
//@ts-ignore
console.log('Current Amount', fairLaunchTicketObj.amount.toNumber());
//@ts-ignore
console.log('State', fairLaunchTicketObj.state);
//@ts-ignore
console.log('Bump', fairLaunchTicketObj.bump);
//@ts-ignore
console.log('Sequence', fairLaunchTicketObj.seq.toNumber());
});
program.parse(process.argv);

View File

@ -118,6 +118,36 @@ export const getFairLaunch = async (
);
};
export const getFairLaunchTicket = async (
tokenMint: anchor.web3.PublicKey,
buyer: anchor.web3.PublicKey,
): Promise<[anchor.web3.PublicKey, number]> => {
return await anchor.web3.PublicKey.findProgramAddress(
[Buffer.from('fair_launch'), tokenMint.toBuffer(), buyer.toBuffer()],
FAIR_LAUNCH_PROGRAM_ID,
);
};
export const getFairLaunchTicketSeqLookup = async (
tokenMint: anchor.web3.PublicKey,
seq: anchor.BN,
): Promise<[anchor.web3.PublicKey, number]> => {
return await anchor.web3.PublicKey.findProgramAddress(
[Buffer.from('fair_launch'), tokenMint.toBuffer(), seq.toBuffer()],
FAIR_LAUNCH_PROGRAM_ID,
);
};
export const getAtaForMint = async (
mint: anchor.web3.PublicKey,
buyer: anchor.web3.PublicKey,
): Promise<[anchor.web3.PublicKey, number]> => {
return await anchor.web3.PublicKey.findProgramAddress(
[buyer.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), mint.toBuffer()],
SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID,
);
};
export const getTreasury = async (
tokenMint: anchor.web3.PublicKey,
): Promise<[anchor.web3.PublicKey, number]> => {

View File

@ -799,13 +799,13 @@ pub struct UpdateFairLaunchLotteryBitmap<'info> {
#[derive(Accounts)]
#[instruction(bump: u8, amount: u64)]
pub struct PurchaseTicket<'info> {
#[account(init, seeds=[PREFIX.as_bytes(), fair_launch.token_mint.as_ref(), buyer.key.as_ref()], payer=payer, bump=bump, space=FAIR_LAUNCH_TICKET_SIZE)]
fair_launch_ticket: ProgramAccount<'info, FairLaunchTicket>,
#[account(mut, seeds=[PREFIX.as_bytes(), fair_launch.token_mint.as_ref()], bump=fair_launch.bump, has_one=treasury)]
fair_launch: ProgramAccount<'info, FairLaunch>,
#[account(mut)]
treasury: AccountInfo<'info>,
#[account(init, seeds=[PREFIX.as_bytes(), fair_launch.token_mint.as_ref(), buyer.key.as_ref()], payer=payer, bump=bump, space=FAIR_LAUNCH_TICKET_SIZE)]
fair_launch_ticket: ProgramAccount<'info, FairLaunchTicket>,
#[account(mut, signer, constraint= (treasury.owner == &spl_token::id() && buyer.owner == &spl_token::id()) || (treasury.owner != &spl_token::id() && buyer.data_is_empty() && buyer.lamports() > 0) )]
#[account(mut, signer, constraint= buyer.data_is_empty() && buyer.lamports() > 0)]
buyer: AccountInfo<'info>,
#[account(mut, signer)]
payer: AccountInfo<'info>,
@ -824,12 +824,12 @@ pub struct PurchaseTicket<'info> {
#[derive(Accounts)]
#[instruction(bump: u8)]
pub struct CreateTicketSeq<'info> {
#[account(init, seeds=[PREFIX.as_bytes(), fair_launch.token_mint.as_ref(), &fair_launch_ticket.seq.to_le_bytes()], payer=payer, bump=bump, space=FAIR_LAUNCH_TICKET_SEQ_SIZE)]
fair_launch_ticket_seq_lookup: ProgramAccount<'info, FairLaunchTicketSeqLookup>,
#[account(mut, seeds=[PREFIX.as_bytes(), fair_launch.token_mint.as_ref()], bump=fair_launch.bump)]
fair_launch: ProgramAccount<'info, FairLaunch>,
#[account(mut, seeds=[PREFIX.as_bytes(), fair_launch.token_mint.as_ref(), fair_launch_ticket.buyer.as_ref()], bump=fair_launch_ticket.bump, has_one=fair_launch)]
fair_launch_ticket: ProgramAccount<'info, FairLaunchTicket>,
#[account(init, seeds=[PREFIX.as_bytes(), fair_launch.token_mint.as_ref(), &fair_launch_ticket.seq.to_le_bytes()], payer=payer, bump=bump, space=FAIR_LAUNCH_TICKET_SEQ_SIZE)]
fair_launch_ticket_seq_lookup: ProgramAccount<'info, FairLaunchTicketSeqLookup>,
#[account(mut, signer)]
payer: AccountInfo<'info>,
#[account(address = system_program::ID)]

View File

@ -209,8 +209,10 @@ pub fn assert_valid_amount(data: &FairLaunchData, amount: u64) -> ProgramResult
return Err(ErrorCode::InvalidPurchaseAmount.into());
}
if amount.checked_rem(data.tick_size).is_some() {
return Err(ErrorCode::InvalidPurchaseAmount.into());
if let Some(val) = amount.checked_rem(data.tick_size) {
if val > 0 {
return Err(ErrorCode::InvalidPurchaseAmount.into());
}
}
Ok(())
@ -299,4 +301,4 @@ pub fn spl_token_mint_to<'a: 'b, 'b>(
&[authority_signer_seeds],
);
result.map_err(|_| ErrorCode::TokenMintToFailed.into())
}
}

File diff suppressed because one or more lines are too long