Add token pre-minting (#596)

This commit is contained in:
Jordan Prince 2021-10-03 18:02:47 -05:00 committed by GitHub
parent e7973ba7a0
commit 93a8816f11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 181 additions and 6 deletions

View File

@ -1882,13 +1882,74 @@ program
fairLaunch,
fairLaunchLotteryBitmap,
authority: walletKeyPair.publicKey,
clock: anchor.web3.SYSVAR_CLOCK_PUBKEY,
//@ts-ignore
tokenMint: fairLaunchObj.tokenMint,
},
});
console.log(`Dang son, phase three.`);
});
program
.command('mint_flp_tokens')
.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();
const walletKeyPair = loadWalletKey(keypair);
const amountNumber = parseInt(amount);
const anchorProgram = await loadFairLaunchProgram(walletKeyPair, env);
const fairLaunchKey = new anchor.web3.PublicKey(fairLaunch);
const fairLaunchObj = await anchorProgram.account.fairLaunch.fetch(
fairLaunchKey,
);
const tokenAccount = //@ts-ignore
(await getAtaForMint(fairLaunchObj.tokenMint, walletKeyPair.publicKey))[0];
const exists = await anchorProgram.provider.connection.getAccountInfo(
tokenAccount,
);
const instructions = [];
if (!exists) {
instructions.push(
createAssociatedTokenAccountInstruction(
tokenAccount,
walletKeyPair.publicKey,
walletKeyPair.publicKey,
//@ts-ignore
fairLaunchObj.tokenMint,
),
);
}
await anchorProgram.rpc.mintTokens(new anchor.BN(amountNumber), {
accounts: {
fairLaunch: fairLaunchKey,
authority: walletKeyPair.publicKey,
//@ts-ignore
tokenMint: fairLaunchObj.tokenMint,
tokenProgram: TOKEN_PROGRAM_ID,
tokenAccount,
},
instructions: instructions.length ? instructions : undefined,
});
console.log(`Added ${amountNumber} tokens to ${tokenAccount.toBase58()}`);
});
program
.command('withdraw_funds')
.option(
@ -2227,10 +2288,19 @@ program
);
const statesFlat = states.flat();
const token = new Token(
anchorProgram.provider.connection,
//@ts-ignore
new anchor.web3.PublicKey(fairLaunchObj.tokenMint),
TOKEN_PROGRAM_ID,
walletKeyPair,
);
const mintInfo = await token.getMintInfo();
let numWinnersRemaining = Math.min(
//@ts-ignore;
fairLaunchObj.data.numberOfTokens,
fairLaunchObj.data.numberOfTokens.sub(mintInfo.supply),
//@ts-ignore;
statesFlat.filter(s => s.eligible).length,
);

View File

@ -17,7 +17,7 @@ use {
},
AnchorDeserialize, AnchorSerialize,
},
anchor_spl::token::Mint,
anchor_spl::token::{Mint, TokenAccount},
spl_token::{
instruction::{initialize_account2, mint_to},
state::Account,
@ -179,10 +179,15 @@ pub mod fair_launch {
pub fn start_phase_three(ctx: Context<StartPhaseThree>) -> ProgramResult {
let fair_launch = &mut ctx.accounts.fair_launch;
let fair_launch_lottery_bitmap = &ctx.accounts.fair_launch_lottery_bitmap;
let token_mint = &ctx.accounts.token_mint;
if fair_launch_lottery_bitmap.bitmap_ones
!= std::cmp::min(
fair_launch.data.number_of_tokens,
fair_launch
.data
.number_of_tokens
.checked_sub(token_mint.supply)
.ok_or(ErrorCode::NumericalOverflowError)?,
fair_launch.current_eligible_holders,
)
{
@ -1513,6 +1518,82 @@ pub mod fair_launch {
Ok(())
}
pub fn mint_tokens<'info>(
ctx: Context<'_, '_, '_, 'info, MintTokens<'info>>,
amount: u64,
) -> ProgramResult {
let fair_launch = &mut ctx.accounts.fair_launch;
let token_account = &mut ctx.accounts.token_account;
let token_mint = &mut ctx.accounts.token_mint;
let authority = &mut ctx.accounts.authority;
let token_program = &ctx.accounts.token_program;
if token_program.key != &spl_token::id() {
return Err(ErrorCode::InvalidTokenProgram.into());
}
if token_account.mint != fair_launch.token_mint {
return Err(ErrorCode::TokenMintMismatch.into());
}
if fair_launch.number_tickets_sold
> fair_launch.number_tickets_dropped + fair_launch.number_tickets_punched
{
return Err(ErrorCode::CannotMintTokensUntilAllCashedOut.into());
}
let token_account_info = &token_account.to_account_info();
assert_owned_by(token_account_info, &token_program.key)?;
// assert is an ATA
assert_derivation(
&spl_associated_token_account::id(),
token_account_info,
&[
authority.key.as_ref(),
token_program.key.as_ref(),
&token_mint.key().as_ref(),
],
)?;
if token_account.delegate.is_some() {
return Err(ErrorCode::AccountShouldHaveNoDelegates.into());
}
if token_account.owner != *authority.key {
return Err(ErrorCode::AccountOwnerShouldBeBuyer.into());
}
let total_new = token_mint
.supply
.checked_add(amount)
.ok_or(ErrorCode::NumericalOverflowError)?;
if total_new > fair_launch.data.number_of_tokens {
return Err(ErrorCode::CannotMintMoreTokensThanTotal.into());
}
let signer_seeds = [
PREFIX.as_bytes(),
fair_launch.token_mint.as_ref(),
&[fair_launch.bump],
];
spl_token_mint_to(
token_mint.to_account_info(),
token_account_info.clone(),
amount,
fair_launch.to_account_info(),
&signer_seeds,
ctx.accounts.token_program.clone(),
)?;
if !fair_launch.phase_three_started {
fair_launch.number_tokens_preminted = total_new
}
Ok(())
}
}
#[derive(Accounts)]
#[instruction(bump: u8, treasury_bump: u8, token_mint_bump: u8, data: FairLaunchData)]
@ -1549,12 +1630,14 @@ pub struct UpdateFairLaunch<'info> {
/// Limited Update that only sets phase 3 dates once bitmap is in place and fully setup.
#[derive(Accounts)]
pub struct StartPhaseThree<'info> {
#[account(mut, seeds=[PREFIX.as_bytes(), fair_launch.token_mint.as_ref()], bump=fair_launch.bump, has_one=authority)]
#[account(mut, seeds=[PREFIX.as_bytes(), fair_launch.token_mint.as_ref()], bump=fair_launch.bump, has_one=authority, has_one=token_mint)]
fair_launch: ProgramAccount<'info, FairLaunch>,
#[account(seeds=[PREFIX.as_bytes(), fair_launch.token_mint.as_ref(), LOTTERY.as_bytes()], constraint=fair_launch_lottery_bitmap.to_account_info().data_len() > 0, bump=fair_launch_lottery_bitmap.bump, has_one=fair_launch)]
fair_launch_lottery_bitmap: ProgramAccount<'info, FairLaunchLotteryBitmap>,
#[account(signer)]
authority: AccountInfo<'info>,
#[account(mut, seeds=[PREFIX.as_bytes(), fair_launch.authority.as_ref(), MINT.as_bytes(), fair_launch.data.uuid.as_bytes()], bump=fair_launch.token_mint_bump)]
token_mint: CpiAccount<'info, Mint>,
}
/// Restarts phase two with as much time as the lottery duration had if duration is passed
@ -1831,6 +1914,20 @@ pub struct MintParticipationNFT<'info> {
rent: Sysvar<'info, Rent>,
}
#[derive(Accounts)]
pub struct MintTokens<'info> {
#[account(mut, seeds=[PREFIX.as_bytes(), fair_launch.token_mint.as_ref()], bump=fair_launch.bump, has_one=authority, has_one=token_mint)]
fair_launch: ProgramAccount<'info, FairLaunch>,
#[account(signer)]
authority: AccountInfo<'info>,
#[account(mut)]
token_account: CpiAccount<'info, TokenAccount>,
#[account(address = spl_token::id())]
token_program: AccountInfo<'info>,
#[account(mut, seeds=[PREFIX.as_bytes(), fair_launch.authority.as_ref(), MINT.as_bytes(), fair_launch.data.uuid.as_bytes()], bump=fair_launch.token_mint_bump)]
token_mint: CpiAccount<'info, Mint>,
}
pub const FAIR_LAUNCH_LOTTERY_SIZE: usize = 8 + // discriminator
32 + // fair launch
1 + // bump
@ -2136,4 +2233,12 @@ pub enum ErrorCode {
AccountOwnerShouldBeBuyer,
#[msg("Account owner should be fair launch authority")]
AccountOwnerShouldBeAuthority,
#[msg("Token mint mismatch")]
TokenMintMismatch,
#[msg("Cannot mint more tokens than are allowed by the fair launch")]
CannotMintMoreTokensThanTotal,
#[msg("Due to concerns that you might mint, burn, then mint again and mess up the counter, you can only mint once before the FLP")]
CanOnlyPremintOnce,
#[msg("Once phase three has begun, no more FLP tokens can be minted until all ticket holders have been given tokens")]
CannotMintTokensUntilAllCashedOut,
}

File diff suppressed because one or more lines are too long