Participation nfts in fl (#537)
* fix some boolean checks and add check for 0 sol * Fixes for eligible count, not having enough sol, and couple other things like rug verbiage * Make punching faster in cli and make rug screen better * Added try catches for errors around txns * Work in progress on NFTs * Still wip * continuation * still working * WIP on stuff * Assert ownership of ATAs * Continue adding participation nfts * WIP on participation * Fix to lottery call * Looks like participation is getting close, just need to test the negative. * Participation complete
This commit is contained in:
parent
9ca7b7bec9
commit
446470ae27
|
@ -21,6 +21,10 @@ import {
|
|||
getFairLaunchTicketSeqLookup,
|
||||
getFairLaunchLotteryBitmap,
|
||||
getMetadata,
|
||||
getParticipationMint,
|
||||
getParticipationToken,
|
||||
getMasterEdition,
|
||||
getEditionMarkPda,
|
||||
} from './helpers/accounts';
|
||||
import { chunks, getMultipleAccounts, sleep } from './helpers/various';
|
||||
import { createAssociatedTokenAccountInstruction } from './helpers/instructions';
|
||||
|
@ -829,6 +833,214 @@ async function adjustTicket({
|
|||
);
|
||||
}
|
||||
|
||||
program
|
||||
.command('update_participation_nft')
|
||||
.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('-n, --name <string>', 'name')
|
||||
.option('-s, --symbol <string>', 'symbol')
|
||||
.option('-u, --uri <string>', 'uri')
|
||||
.option(
|
||||
'-sfbp, --seller-fee-basis-points <string>',
|
||||
'seller fee basis points',
|
||||
)
|
||||
.option(
|
||||
'-m, --participation-modulo <string>',
|
||||
'1 if everybody gets it, 4 if only 1 in 4 get it, etc',
|
||||
)
|
||||
.option(
|
||||
'-c, --creators <string>',
|
||||
'comma separated creator wallets like wallet1,73,true,wallet2,27,false where its wallet, then share, then verified true/false',
|
||||
)
|
||||
.option('-nm, --is_not_mutable', 'is not mutable')
|
||||
.action(async (_, cmd) => {
|
||||
const {
|
||||
env,
|
||||
keypair,
|
||||
fairLaunch,
|
||||
name,
|
||||
symbol,
|
||||
uri,
|
||||
sellerFeeBasisPoints,
|
||||
creators,
|
||||
isNotMutable,
|
||||
participationModulo,
|
||||
} = cmd.opts();
|
||||
const sellerFeeBasisPointsNumber = parseInt(sellerFeeBasisPoints);
|
||||
const participationModuloNumber = parseInt(participationModulo);
|
||||
|
||||
const creatorsListPre = creators ? creators.split(',') : [];
|
||||
const creatorsList = [];
|
||||
for (let i = 0; i < creatorsListPre.length; i += 3) {
|
||||
creatorsList.push({
|
||||
address: new anchor.web3.PublicKey(creatorsListPre[i]),
|
||||
share: parseInt(creatorsListPre[i + 1]),
|
||||
verified: creatorsListPre[i + 2] == 'true' ? true : false,
|
||||
});
|
||||
}
|
||||
const isMutableBool = isNotMutable ? false : true;
|
||||
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 participationMint = (
|
||||
await getParticipationMint(
|
||||
//@ts-ignore
|
||||
fairLaunchObj.authority,
|
||||
//@ts-ignore
|
||||
fairLaunchObj.data.uuid,
|
||||
)
|
||||
)[0];
|
||||
|
||||
await anchorProgram.rpc.updateParticipationNft(
|
||||
participationModuloNumber,
|
||||
{
|
||||
name,
|
||||
symbol,
|
||||
uri,
|
||||
sellerFeeBasisPoints: sellerFeeBasisPointsNumber,
|
||||
creators: creatorsList,
|
||||
isMutable: isMutableBool,
|
||||
},
|
||||
{
|
||||
accounts: {
|
||||
fairLaunch: fairLaunchKey,
|
||||
authority: walletKeyPair.publicKey,
|
||||
//@ts-ignore
|
||||
metadata: await getMetadata(participationMint),
|
||||
tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
|
||||
tokenProgram: TOKEN_PROGRAM_ID,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
console.log('Update participation metadata.');
|
||||
});
|
||||
|
||||
program
|
||||
.command('set_participation_nft')
|
||||
.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('-n, --name <string>', 'name')
|
||||
.option('-s, --symbol <string>', 'symbol')
|
||||
.option('-u, --uri <string>', 'uri')
|
||||
.option(
|
||||
'-sfbp, --seller-fee-basis-points <string>',
|
||||
'seller fee basis points',
|
||||
)
|
||||
.option(
|
||||
'-m, --participation-modulo <string>',
|
||||
'1 if everybody gets it, 4 if only 1 in 4 get it, etc',
|
||||
)
|
||||
.option(
|
||||
'-c, --creators <string>',
|
||||
'comma separated creator wallets like wallet1,73,true,wallet2,27,false where its wallet, then share, then verified true/false',
|
||||
)
|
||||
.option('-nm, --is_not_mutable', 'is not mutable')
|
||||
.action(async (_, cmd) => {
|
||||
const {
|
||||
env,
|
||||
keypair,
|
||||
fairLaunch,
|
||||
name,
|
||||
symbol,
|
||||
uri,
|
||||
sellerFeeBasisPoints,
|
||||
creators,
|
||||
isNotMutable,
|
||||
participationModulo,
|
||||
} = cmd.opts();
|
||||
const sellerFeeBasisPointsNumber = parseInt(sellerFeeBasisPoints);
|
||||
const participationModuloNumber = parseInt(participationModulo);
|
||||
|
||||
const creatorsListPre = creators ? creators.split(',') : [];
|
||||
const creatorsList = [];
|
||||
for (let i = 0; i < creatorsListPre.length; i += 3) {
|
||||
creatorsList.push({
|
||||
address: new anchor.web3.PublicKey(creatorsListPre[i]),
|
||||
share: parseInt(creatorsListPre[i + 1]),
|
||||
verified: creatorsListPre[i + 2] == 'true' ? true : false,
|
||||
});
|
||||
}
|
||||
const isMutableBool = isNotMutable ? false : true;
|
||||
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 [participationMint, mintBump] = await getParticipationMint(
|
||||
//@ts-ignore
|
||||
fairLaunchObj.authority,
|
||||
//@ts-ignore
|
||||
fairLaunchObj.data.uuid,
|
||||
);
|
||||
const [participationTokenAccount, tokenBump] = await getParticipationToken(
|
||||
//@ts-ignore
|
||||
fairLaunchObj.authority,
|
||||
//@ts-ignore
|
||||
fairLaunchObj.data.uuid,
|
||||
);
|
||||
|
||||
await anchorProgram.rpc.setParticipationNft(
|
||||
mintBump,
|
||||
tokenBump,
|
||||
participationModuloNumber,
|
||||
{
|
||||
name,
|
||||
symbol,
|
||||
uri,
|
||||
sellerFeeBasisPoints: sellerFeeBasisPointsNumber,
|
||||
creators: creatorsList,
|
||||
isMutable: isMutableBool,
|
||||
},
|
||||
{
|
||||
accounts: {
|
||||
fairLaunch: fairLaunchKey,
|
||||
authority: walletKeyPair.publicKey,
|
||||
payer: walletKeyPair.publicKey,
|
||||
participationMint,
|
||||
participationTokenAccount,
|
||||
//@ts-ignore
|
||||
metadata: await getMetadata(participationMint),
|
||||
//@ts-ignore
|
||||
masterEdition: await getMasterEdition(participationMint),
|
||||
tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
|
||||
tokenProgram: TOKEN_PROGRAM_ID,
|
||||
systemProgram: anchor.web3.SystemProgram.programId,
|
||||
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
||||
clock: anchor.web3.SYSVAR_CLOCK_PUBKEY,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
console.log('Set participation metadata.');
|
||||
});
|
||||
|
||||
program
|
||||
.command('set_token_metadata')
|
||||
.option(
|
||||
|
@ -1116,6 +1328,46 @@ program
|
|||
async allIndexesInSlice => {
|
||||
for (let i = 0; i < allIndexesInSlice.length; i++) {
|
||||
const ticket = ticketDataFlat[allIndexesInSlice[i]];
|
||||
if (!ticket.model.gottenParticipation) {
|
||||
let tries = 0;
|
||||
let done = false;
|
||||
while (tries < 3 && !done) {
|
||||
try {
|
||||
const nft = await getParticipationNft({
|
||||
payer: walletKeyPair,
|
||||
buyer: ticket.model.buyer,
|
||||
anchorProgram,
|
||||
fairLaunchTicket: ticket.key,
|
||||
fairLaunch,
|
||||
fairLaunchObj,
|
||||
fairLaunchTicketObj: ticket.model,
|
||||
});
|
||||
done = true;
|
||||
if (nft) {
|
||||
console.log(
|
||||
`Got participation nft and placed token in new account ${nft.toBase58()}.`,
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
if (tries > 3) {
|
||||
throw e;
|
||||
} else {
|
||||
tries++;
|
||||
}
|
||||
console.log(e);
|
||||
console.log(
|
||||
'Ticket failed to get participation nft, trying one more time',
|
||||
);
|
||||
await sleep(1000);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log(
|
||||
'Ticket',
|
||||
ticket.model.buyer.toBase58(),
|
||||
'already received participation',
|
||||
);
|
||||
}
|
||||
if (ticket.model.state.unpunched) {
|
||||
if (
|
||||
ticket.model.amount.toNumber() <
|
||||
|
@ -1187,29 +1439,35 @@ program
|
|||
}
|
||||
}
|
||||
let tries = 0;
|
||||
try {
|
||||
const buyerTokenAccount = await punchTicket({
|
||||
payer: walletKeyPair,
|
||||
puncher: ticket.model.buyer,
|
||||
anchorProgram,
|
||||
fairLaunchTicket: ticket.key,
|
||||
fairLaunch,
|
||||
fairLaunchLotteryBitmap,
|
||||
fairLaunchObj,
|
||||
});
|
||||
|
||||
console.log(
|
||||
`Punched ticket and placed token in new account ${buyerTokenAccount.toBase58()} for buyer `,
|
||||
allIndexesInSlice[i],
|
||||
);
|
||||
} catch (e) {
|
||||
if (tries > 3) {
|
||||
throw e;
|
||||
} else {
|
||||
tries++;
|
||||
let done = false;
|
||||
while (tries < 3 && !done) {
|
||||
try {
|
||||
const buyerTokenAccount = await punchTicket({
|
||||
payer: walletKeyPair,
|
||||
puncher: ticket.model.buyer,
|
||||
anchorProgram,
|
||||
fairLaunchTicket: ticket.key,
|
||||
fairLaunch,
|
||||
fairLaunchLotteryBitmap,
|
||||
fairLaunchObj,
|
||||
fairLaunchTicketObj: ticket.model,
|
||||
});
|
||||
done = true;
|
||||
console.log(
|
||||
`Punched ticket and placed token in new account ${buyerTokenAccount.toBase58()}.`,
|
||||
);
|
||||
} catch (e) {
|
||||
if (tries > 3) {
|
||||
throw e;
|
||||
} else {
|
||||
tries++;
|
||||
}
|
||||
console.log(e);
|
||||
console.log(
|
||||
'Ticket failed to punch, trying one more time',
|
||||
);
|
||||
await sleep(1000);
|
||||
}
|
||||
console.log('Ticket failed to punch, trying one more time');
|
||||
await sleep(1000);
|
||||
}
|
||||
} else {
|
||||
console.log(
|
||||
|
@ -1254,6 +1512,104 @@ program
|
|||
);
|
||||
});
|
||||
|
||||
async function getParticipationNft({
|
||||
buyer,
|
||||
payer,
|
||||
anchorProgram,
|
||||
fairLaunchTicket,
|
||||
fairLaunch,
|
||||
fairLaunchObj,
|
||||
fairLaunchTicketObj,
|
||||
}: {
|
||||
buyer: anchor.web3.PublicKey;
|
||||
anchorProgram: anchor.Program;
|
||||
payer: anchor.web3.Keypair;
|
||||
fairLaunchTicket: anchor.web3.PublicKey;
|
||||
fairLaunch: anchor.web3.PublicKey;
|
||||
fairLaunchObj: any;
|
||||
fairLaunchTicketObj: any;
|
||||
}): Promise<anchor.web3.PublicKey | null> {
|
||||
if (
|
||||
fairLaunchObj.participationMint &&
|
||||
fairLaunchTicketObj.seq.toNumber() % fairLaunchObj.participationModulo == 0
|
||||
) {
|
||||
console.log(buyer.toBase58(), 'gets participation token.');
|
||||
const mint = anchor.web3.Keypair.generate();
|
||||
let signers = [mint];
|
||||
const tokenAccount = (
|
||||
await getParticipationToken(
|
||||
fairLaunchObj.authority,
|
||||
fairLaunchObj.data.uuid,
|
||||
)
|
||||
)[0];
|
||||
const buyerTokenNft = (await getAtaForMint(mint.publicKey, buyer))[0];
|
||||
let instructions = [
|
||||
anchor.web3.SystemProgram.createAccount({
|
||||
fromPubkey: payer.publicKey,
|
||||
newAccountPubkey: mint.publicKey,
|
||||
space: MintLayout.span,
|
||||
lamports:
|
||||
await anchorProgram.provider.connection.getMinimumBalanceForRentExemption(
|
||||
MintLayout.span,
|
||||
),
|
||||
programId: TOKEN_PROGRAM_ID,
|
||||
}),
|
||||
Token.createInitMintInstruction(
|
||||
TOKEN_PROGRAM_ID,
|
||||
mint.publicKey,
|
||||
0,
|
||||
payer.publicKey,
|
||||
payer.publicKey,
|
||||
),
|
||||
createAssociatedTokenAccountInstruction(
|
||||
buyerTokenNft,
|
||||
payer.publicKey,
|
||||
buyer,
|
||||
mint.publicKey,
|
||||
),
|
||||
Token.createMintToInstruction(
|
||||
TOKEN_PROGRAM_ID,
|
||||
mint.publicKey,
|
||||
buyerTokenNft,
|
||||
payer.publicKey,
|
||||
[],
|
||||
1,
|
||||
),
|
||||
];
|
||||
await anchorProgram.rpc.mintParticipationNft({
|
||||
accounts: {
|
||||
fairLaunch,
|
||||
fairLaunchTicket,
|
||||
payer: payer.publicKey,
|
||||
participationMint: fairLaunchObj.participationMint,
|
||||
participationTokenAccount: tokenAccount,
|
||||
buyer,
|
||||
buyerNftTokenAccount: buyerTokenNft,
|
||||
newMetadata: await getMetadata(mint.publicKey),
|
||||
newEdition: await getMasterEdition(mint.publicKey),
|
||||
newMint: mint.publicKey,
|
||||
newMintAuthority: payer.publicKey,
|
||||
metadata: await getMetadata(fairLaunchObj.participationMint),
|
||||
masterEdition: await getMasterEdition(fairLaunchObj.participationMint),
|
||||
editionMarkPda: await getEditionMarkPda(
|
||||
fairLaunchObj.participationMint,
|
||||
fairLaunchTicketObj.seq.toNumber(),
|
||||
),
|
||||
tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID,
|
||||
tokenProgram: TOKEN_PROGRAM_ID,
|
||||
systemProgram: anchor.web3.SystemProgram.programId,
|
||||
rent: anchor.web3.SYSVAR_RENT_PUBKEY,
|
||||
},
|
||||
instructions,
|
||||
signers,
|
||||
});
|
||||
return buyerTokenNft;
|
||||
} else {
|
||||
console.log(buyer.toBase58(), 'doesnt get participation token.');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async function punchTicket({
|
||||
puncher,
|
||||
payer,
|
||||
|
@ -1262,6 +1618,7 @@ async function punchTicket({
|
|||
fairLaunch,
|
||||
fairLaunchLotteryBitmap,
|
||||
fairLaunchObj,
|
||||
fairLaunchTicketObj,
|
||||
}: {
|
||||
puncher: anchor.web3.PublicKey;
|
||||
anchorProgram: anchor.Program;
|
||||
|
@ -1270,6 +1627,7 @@ async function punchTicket({
|
|||
fairLaunch: anchor.web3.PublicKey;
|
||||
fairLaunchLotteryBitmap: anchor.web3.PublicKey;
|
||||
fairLaunchObj: any;
|
||||
fairLaunchTicketObj: any;
|
||||
}): Promise<anchor.web3.PublicKey> {
|
||||
const buyerTokenAccount = (
|
||||
await getAtaForMint(
|
||||
|
@ -1369,28 +1727,68 @@ program
|
|||
}
|
||||
|
||||
let tries = 0;
|
||||
try {
|
||||
const buyerTokenAccount = await punchTicket({
|
||||
puncher: walletKeyPair.publicKey,
|
||||
payer: walletKeyPair,
|
||||
anchorProgram,
|
||||
fairLaunchTicket,
|
||||
fairLaunch,
|
||||
fairLaunchLotteryBitmap,
|
||||
fairLaunchObj,
|
||||
});
|
||||
let done = false;
|
||||
//@ts-ignore
|
||||
if (!ticket.gottenParticipation) {
|
||||
while (tries < 3 && !done) {
|
||||
try {
|
||||
const nft = await getParticipationNft({
|
||||
buyer: walletKeyPair.publicKey,
|
||||
payer: walletKeyPair,
|
||||
anchorProgram,
|
||||
fairLaunchTicket,
|
||||
fairLaunch,
|
||||
fairLaunchObj,
|
||||
fairLaunchTicketObj: ticket,
|
||||
});
|
||||
done = true;
|
||||
|
||||
console.log(
|
||||
`Punched ticket and placed token in new account ${buyerTokenAccount.toBase58()}.`,
|
||||
);
|
||||
} catch (e) {
|
||||
if (tries > 3) {
|
||||
throw e;
|
||||
} else {
|
||||
tries++;
|
||||
if (nft) {
|
||||
console.log(
|
||||
`Punched participation NFT and placed token in new account ${nft.toBase58()}.`,
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
if (tries > 3) {
|
||||
throw e;
|
||||
} else {
|
||||
tries++;
|
||||
}
|
||||
console.log('Ticket failed to punch, trying one more time');
|
||||
await sleep(1000);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log('Already got participation');
|
||||
}
|
||||
|
||||
tries = 0;
|
||||
done = false;
|
||||
while (tries < 3 && !done) {
|
||||
try {
|
||||
const buyerTokenAccount = await punchTicket({
|
||||
puncher: walletKeyPair.publicKey,
|
||||
payer: walletKeyPair,
|
||||
anchorProgram,
|
||||
fairLaunchTicket,
|
||||
fairLaunch,
|
||||
fairLaunchLotteryBitmap,
|
||||
fairLaunchObj,
|
||||
fairLaunchTicketObj: ticket,
|
||||
});
|
||||
done = true;
|
||||
console.log(
|
||||
`Punched ticket and placed token in new account ${buyerTokenAccount.toBase58()}.`,
|
||||
);
|
||||
} catch (e) {
|
||||
if (tries > 3) {
|
||||
throw e;
|
||||
} else {
|
||||
tries++;
|
||||
}
|
||||
console.log('Ticket failed to punch, trying one more time');
|
||||
await sleep(1000);
|
||||
}
|
||||
console.log('Ticket failed to punch, trying one more time');
|
||||
await sleep(1000);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -2040,6 +2438,12 @@ program
|
|||
//@ts-ignore
|
||||
console.log('Treasury Mint', fairLaunchObj.treasuryMint?.toBase58());
|
||||
//@ts-ignore
|
||||
console.log(
|
||||
'Participation Mint',
|
||||
//@ts-ignore
|
||||
fairLaunchObj.participationMint?.toBase58(),
|
||||
);
|
||||
//@ts-ignore
|
||||
console.log('Authority', fairLaunchObj.authority.toBase58());
|
||||
//@ts-ignore
|
||||
console.log('Bump', fairLaunchObj.bump);
|
||||
|
@ -2048,6 +2452,8 @@ program
|
|||
//@ts-ignore
|
||||
console.log('Token Mint Bump', fairLaunchObj.tokenMintBump);
|
||||
//@ts-ignore
|
||||
console.log('Participation Modulo', fairLaunchObj.participationModulo);
|
||||
//@ts-ignore
|
||||
if (fairLaunchObj.data.antiRugSetting) {
|
||||
console.log('Anti-Rug Settings:');
|
||||
//@ts-ignore
|
||||
|
|
|
@ -163,6 +163,39 @@ export const getAtaForMint = async (
|
|||
);
|
||||
};
|
||||
|
||||
export const getParticipationMint = async (
|
||||
authority: anchor.web3.PublicKey,
|
||||
uuid: string,
|
||||
): Promise<[anchor.web3.PublicKey, number]> => {
|
||||
return await anchor.web3.PublicKey.findProgramAddress(
|
||||
[
|
||||
Buffer.from('fair_launch'),
|
||||
authority.toBuffer(),
|
||||
Buffer.from('mint'),
|
||||
Buffer.from(uuid),
|
||||
Buffer.from('participation'),
|
||||
],
|
||||
FAIR_LAUNCH_PROGRAM_ID,
|
||||
);
|
||||
};
|
||||
|
||||
export const getParticipationToken = async (
|
||||
authority: anchor.web3.PublicKey,
|
||||
uuid: string,
|
||||
): Promise<[anchor.web3.PublicKey, number]> => {
|
||||
return await anchor.web3.PublicKey.findProgramAddress(
|
||||
[
|
||||
Buffer.from('fair_launch'),
|
||||
authority.toBuffer(),
|
||||
Buffer.from('mint'),
|
||||
Buffer.from(uuid),
|
||||
Buffer.from('participation'),
|
||||
Buffer.from('account'),
|
||||
],
|
||||
FAIR_LAUNCH_PROGRAM_ID,
|
||||
);
|
||||
};
|
||||
|
||||
export const getTreasury = async (
|
||||
tokenMint: anchor.web3.PublicKey,
|
||||
): Promise<[anchor.web3.PublicKey, number]> => {
|
||||
|
@ -203,6 +236,25 @@ export const getMasterEdition = async (
|
|||
)[0];
|
||||
};
|
||||
|
||||
export const getEditionMarkPda = async (
|
||||
mint: anchor.web3.PublicKey,
|
||||
edition: number,
|
||||
): Promise<anchor.web3.PublicKey> => {
|
||||
const editionNumber = Math.floor(edition / 248);
|
||||
return (
|
||||
await anchor.web3.PublicKey.findProgramAddress(
|
||||
[
|
||||
Buffer.from('metadata'),
|
||||
TOKEN_METADATA_PROGRAM_ID.toBuffer(),
|
||||
mint.toBuffer(),
|
||||
Buffer.from('edition'),
|
||||
Buffer.from(editionNumber.toString()),
|
||||
],
|
||||
TOKEN_METADATA_PROGRAM_ID,
|
||||
)
|
||||
)[0];
|
||||
};
|
||||
|
||||
export function loadWalletKey(keypair): Keypair {
|
||||
if (!keypair || keypair == '') {
|
||||
throw new Error('Keypair is required!');
|
||||
|
|
|
@ -20,7 +20,7 @@ export const TOKEN_PROGRAM_ID = new PublicKey(
|
|||
'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA',
|
||||
);
|
||||
export const FAIR_LAUNCH_PROGRAM_ID = new PublicKey(
|
||||
'faircnAB9k59Y4TXmLabBULeuTLgV7TkGMGNkjnA15j',
|
||||
'7HmfyvWK7LDohUL9TDAuGv9VFZHUce1SgYMkwti1xWwF',
|
||||
);
|
||||
export const CONFIG_ARRAY_START =
|
||||
32 + // authority
|
||||
|
|
|
@ -18,14 +18,22 @@ use {
|
|||
AnchorDeserialize, AnchorSerialize,
|
||||
},
|
||||
anchor_spl::token::Mint,
|
||||
spl_token::{instruction::initialize_account2, state::Account},
|
||||
spl_token_metadata::instruction::{create_metadata_accounts, update_metadata_accounts},
|
||||
spl_token::{
|
||||
instruction::{initialize_account2, mint_to},
|
||||
state::Account,
|
||||
},
|
||||
spl_token_metadata::instruction::{
|
||||
create_master_edition, create_metadata_accounts,
|
||||
mint_new_edition_from_master_edition_via_token, update_metadata_accounts,
|
||||
},
|
||||
};
|
||||
|
||||
pub const PREFIX: &str = "fair_launch";
|
||||
pub const TREASURY: &str = "treasury";
|
||||
pub const MINT: &str = "mint";
|
||||
pub const LOTTERY: &str = "lottery";
|
||||
pub const PARTICIPATION: &str = "participation";
|
||||
pub const ACCOUNT: &str = "account";
|
||||
pub const MAX_GRANULARITY: u64 = 100;
|
||||
|
||||
#[program]
|
||||
|
@ -75,6 +83,10 @@ pub mod fair_launch {
|
|||
|
||||
fair_launch.treasury_mint = Some(*treasury_mint_info.key);
|
||||
|
||||
if treasury_info.data_len() > 0 {
|
||||
return Err(ErrorCode::TreasuryAlreadyExists.into());
|
||||
}
|
||||
|
||||
// make the treasury token account
|
||||
|
||||
create_or_allocate_account_raw(
|
||||
|
@ -1110,6 +1122,397 @@ pub mod fair_launch {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn set_participation_nft<'info>(
|
||||
ctx: Context<'_, '_, '_, 'info, SetParticipationNFT<'info>>,
|
||||
participation_mint_bump: u8,
|
||||
participation_token_bump: u8,
|
||||
participation_modulo: u8,
|
||||
data: TokenMetadata,
|
||||
) -> ProgramResult {
|
||||
let fair_launch = &mut ctx.accounts.fair_launch;
|
||||
let participation_mint = &ctx.accounts.participation_mint;
|
||||
let participation_token_info = &ctx.accounts.participation_token_account;
|
||||
let participation_mint_info = participation_mint.to_account_info();
|
||||
|
||||
let token_program = &ctx.accounts.token_program;
|
||||
|
||||
if token_program.key != &spl_token::id() {
|
||||
return Err(ErrorCode::InvalidTokenProgram.into());
|
||||
}
|
||||
|
||||
fair_launch.participation_mint_bump = participation_mint_bump;
|
||||
fair_launch.participation_token_bump = participation_token_bump;
|
||||
fair_launch.participation_mint = Some(participation_mint.key());
|
||||
fair_launch.participation_modulo = participation_modulo;
|
||||
|
||||
if participation_modulo == 0 {
|
||||
return Err(ErrorCode::InvalidParticipationModulo.into());
|
||||
}
|
||||
|
||||
// make the token account
|
||||
|
||||
let authority_seeds = [
|
||||
PREFIX.as_bytes(),
|
||||
fair_launch.token_mint.as_ref(),
|
||||
&[fair_launch.bump],
|
||||
];
|
||||
|
||||
let mut creators: Vec<spl_token_metadata::state::Creator> =
|
||||
vec![spl_token_metadata::state::Creator {
|
||||
address: fair_launch.key(),
|
||||
verified: true,
|
||||
share: 0,
|
||||
}];
|
||||
|
||||
if let Some(cre) = &data.creators {
|
||||
for c in cre {
|
||||
creators.push(spl_token_metadata::state::Creator {
|
||||
address: c.address,
|
||||
verified: c.verified,
|
||||
share: c.share,
|
||||
});
|
||||
}
|
||||
}
|
||||
assert_owned_by(&participation_mint_info, &spl_token::id())?;
|
||||
|
||||
assert_derivation(
|
||||
&ctx.program_id,
|
||||
participation_token_info,
|
||||
&[
|
||||
PREFIX.as_bytes(),
|
||||
fair_launch.authority.as_ref(),
|
||||
MINT.as_bytes(),
|
||||
fair_launch.data.uuid.as_bytes(),
|
||||
PARTICIPATION.as_bytes(),
|
||||
ACCOUNT.as_bytes(),
|
||||
],
|
||||
)?;
|
||||
|
||||
let signer_seeds = &[
|
||||
PREFIX.as_bytes(),
|
||||
fair_launch.authority.as_ref(),
|
||||
MINT.as_bytes(),
|
||||
fair_launch.data.uuid.as_bytes(),
|
||||
PARTICIPATION.as_bytes(),
|
||||
ACCOUNT.as_bytes(),
|
||||
&[participation_token_bump],
|
||||
];
|
||||
|
||||
if participation_token_info.data_len() > 0 {
|
||||
return Err(ErrorCode::ParticipationTokenAccountAlreadyExists.into());
|
||||
};
|
||||
|
||||
msg!("Allocating token account");
|
||||
|
||||
create_or_allocate_account_raw(
|
||||
*ctx.accounts.token_program.key,
|
||||
participation_token_info,
|
||||
&ctx.accounts.rent.to_account_info(),
|
||||
&ctx.accounts.system_program,
|
||||
&ctx.accounts.payer,
|
||||
Account::LEN,
|
||||
signer_seeds,
|
||||
)?;
|
||||
|
||||
invoke_signed(
|
||||
&initialize_account2(
|
||||
&ctx.accounts.token_program.key,
|
||||
participation_token_info.key,
|
||||
participation_mint_info.key,
|
||||
&fair_launch.key(),
|
||||
)
|
||||
.unwrap(),
|
||||
&[
|
||||
ctx.accounts.token_program.clone(),
|
||||
participation_token_info.clone(),
|
||||
fair_launch.to_account_info(),
|
||||
participation_mint_info.clone(),
|
||||
ctx.accounts.rent.to_account_info(),
|
||||
],
|
||||
&[signer_seeds],
|
||||
)?;
|
||||
msg!("Minting token");
|
||||
|
||||
invoke_signed(
|
||||
&mint_to(
|
||||
&ctx.accounts.token_program.key,
|
||||
participation_mint_info.key,
|
||||
participation_token_info.key,
|
||||
&fair_launch.key(),
|
||||
&[],
|
||||
1,
|
||||
)
|
||||
.unwrap(),
|
||||
&[
|
||||
ctx.accounts.token_program.clone(),
|
||||
participation_token_info.clone(),
|
||||
fair_launch.to_account_info(),
|
||||
participation_mint_info.clone(),
|
||||
ctx.accounts.rent.to_account_info(),
|
||||
],
|
||||
&[&authority_seeds],
|
||||
)?;
|
||||
|
||||
msg!("Creating metadata");
|
||||
let metadata_infos = vec![
|
||||
ctx.accounts.metadata.clone(),
|
||||
participation_mint_info.clone(),
|
||||
ctx.accounts.payer.clone(),
|
||||
ctx.accounts.token_metadata_program.clone(),
|
||||
ctx.accounts.token_program.clone(),
|
||||
ctx.accounts.system_program.clone(),
|
||||
ctx.accounts.rent.to_account_info().clone(),
|
||||
fair_launch.to_account_info(),
|
||||
];
|
||||
|
||||
let master_edition_infos = vec![
|
||||
ctx.accounts.master_edition.clone(),
|
||||
participation_mint_info.clone(),
|
||||
fair_launch.to_account_info(),
|
||||
ctx.accounts.payer.clone(),
|
||||
ctx.accounts.metadata.clone(),
|
||||
ctx.accounts.token_metadata_program.clone(),
|
||||
ctx.accounts.token_program.clone(),
|
||||
ctx.accounts.system_program.clone(),
|
||||
ctx.accounts.rent.to_account_info().clone(),
|
||||
];
|
||||
|
||||
invoke_signed(
|
||||
&create_metadata_accounts(
|
||||
*ctx.accounts.token_metadata_program.key,
|
||||
*ctx.accounts.metadata.key,
|
||||
*participation_mint_info.key,
|
||||
fair_launch.key(),
|
||||
*ctx.accounts.payer.key,
|
||||
fair_launch.key(),
|
||||
data.name,
|
||||
data.symbol.clone(),
|
||||
data.uri,
|
||||
Some(creators),
|
||||
data.seller_fee_basis_points,
|
||||
false,
|
||||
data.is_mutable,
|
||||
),
|
||||
metadata_infos.as_slice(),
|
||||
&[&authority_seeds],
|
||||
)?;
|
||||
|
||||
msg!("Creating master edition");
|
||||
invoke_signed(
|
||||
&create_master_edition(
|
||||
*ctx.accounts.token_metadata_program.key,
|
||||
*ctx.accounts.master_edition.key,
|
||||
*participation_mint_info.key,
|
||||
fair_launch.key(),
|
||||
fair_launch.key(),
|
||||
*ctx.accounts.metadata.key,
|
||||
*ctx.accounts.payer.key,
|
||||
None,
|
||||
),
|
||||
master_edition_infos.as_slice(),
|
||||
&[&authority_seeds],
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn update_participation_nft<'info>(
|
||||
ctx: Context<'_, '_, '_, 'info, UpdateParticipationNFT<'info>>,
|
||||
participation_modulo: u8,
|
||||
data: TokenMetadata,
|
||||
) -> ProgramResult {
|
||||
let fair_launch = &mut ctx.accounts.fair_launch;
|
||||
fair_launch.participation_modulo = participation_modulo;
|
||||
|
||||
let token_program = &ctx.accounts.token_program;
|
||||
|
||||
if token_program.key != &spl_token::id() {
|
||||
return Err(ErrorCode::InvalidTokenProgram.into());
|
||||
}
|
||||
|
||||
if participation_modulo == 0 {
|
||||
return Err(ErrorCode::InvalidParticipationModulo.into());
|
||||
}
|
||||
|
||||
let authority_seeds = [
|
||||
PREFIX.as_bytes(),
|
||||
fair_launch.token_mint.as_ref(),
|
||||
&[fair_launch.bump],
|
||||
];
|
||||
|
||||
let mut creators: Vec<spl_token_metadata::state::Creator> =
|
||||
vec![spl_token_metadata::state::Creator {
|
||||
address: fair_launch.key(),
|
||||
verified: true,
|
||||
share: 0,
|
||||
}];
|
||||
|
||||
if let Some(cre) = &data.creators {
|
||||
for c in cre {
|
||||
creators.push(spl_token_metadata::state::Creator {
|
||||
address: c.address,
|
||||
verified: c.verified,
|
||||
share: c.share,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let update_infos = vec![
|
||||
ctx.accounts.token_metadata_program.clone(),
|
||||
ctx.accounts.token_program.clone(),
|
||||
ctx.accounts.metadata.clone(),
|
||||
fair_launch.to_account_info().clone(),
|
||||
];
|
||||
|
||||
msg!("Updating metadata");
|
||||
invoke_signed(
|
||||
&update_metadata_accounts(
|
||||
*ctx.accounts.token_metadata_program.key,
|
||||
*ctx.accounts.metadata.key,
|
||||
fair_launch.key(),
|
||||
None,
|
||||
Some(spl_token_metadata::state::Data {
|
||||
name: data.name,
|
||||
symbol: data.symbol,
|
||||
uri: data.uri,
|
||||
creators: Some(creators),
|
||||
seller_fee_basis_points: data.seller_fee_basis_points,
|
||||
}),
|
||||
None,
|
||||
),
|
||||
update_infos.as_slice(),
|
||||
&[&authority_seeds],
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn mint_participation_nft<'info>(
|
||||
ctx: Context<'_, '_, '_, 'info, MintParticipationNFT<'info>>,
|
||||
) -> ProgramResult {
|
||||
let fair_launch = &ctx.accounts.fair_launch;
|
||||
let fair_launch_ticket = &mut ctx.accounts.fair_launch_ticket;
|
||||
let buyer = &ctx.accounts.buyer;
|
||||
let buyer_nft_token_account_info = &ctx.accounts.buyer_nft_token_account;
|
||||
|
||||
let token_program = &ctx.accounts.token_program;
|
||||
|
||||
if token_program.key != &spl_token::id() {
|
||||
return Err(ErrorCode::InvalidTokenProgram.into());
|
||||
}
|
||||
|
||||
if fair_launch.participation_modulo == 0 {
|
||||
return Err(ErrorCode::InvalidParticipationModulo.into());
|
||||
}
|
||||
|
||||
if fair_launch_ticket.gotten_participation {
|
||||
return Err(ErrorCode::AlreadyMintedParticipation.into());
|
||||
}
|
||||
|
||||
if let Some(val) = fair_launch_ticket
|
||||
.seq
|
||||
.checked_rem(fair_launch.participation_modulo as u64)
|
||||
{
|
||||
msg!("Val is {}", val);
|
||||
if val != 0 {
|
||||
return Err(ErrorCode::NotEligibleForParticipation.into());
|
||||
}
|
||||
} else {
|
||||
return Err(ErrorCode::NotEligibleForParticipation.into());
|
||||
}
|
||||
|
||||
fair_launch_ticket.gotten_participation = true;
|
||||
|
||||
let authority_seeds = [
|
||||
PREFIX.as_bytes(),
|
||||
fair_launch.token_mint.as_ref(),
|
||||
&[fair_launch.bump],
|
||||
];
|
||||
|
||||
let buyer_nft_token_account: Account = assert_initialized(&buyer_nft_token_account_info)?;
|
||||
|
||||
if buyer_nft_token_account.mint != *ctx.accounts.new_mint.key {
|
||||
return Err(ErrorCode::ParticipationMintMismatch.into());
|
||||
}
|
||||
|
||||
if buyer_nft_token_account.delegate.is_some() {
|
||||
return Err(ErrorCode::AccountShouldHaveNoDelegates.into());
|
||||
}
|
||||
|
||||
if buyer_nft_token_account.owner != *buyer.key {
|
||||
return Err(ErrorCode::AccountOwnerShouldBeBuyer.into());
|
||||
}
|
||||
|
||||
assert_owned_by(buyer_nft_token_account_info, &token_program.key)?;
|
||||
|
||||
// assert is an ATA
|
||||
assert_derivation(
|
||||
&spl_associated_token_account::id(),
|
||||
buyer_nft_token_account_info,
|
||||
&[
|
||||
buyer.key.as_ref(),
|
||||
token_program.key.as_ref(),
|
||||
&ctx.accounts.new_mint.key.as_ref(),
|
||||
],
|
||||
)?;
|
||||
|
||||
let edition_infos = vec![
|
||||
ctx.accounts.metadata.clone(),
|
||||
ctx.accounts.new_metadata.clone(),
|
||||
ctx.accounts.new_edition.clone(),
|
||||
ctx.accounts.master_edition.clone(),
|
||||
ctx.accounts.new_mint.clone(),
|
||||
ctx.accounts.participation_token_account.clone(),
|
||||
ctx.accounts.participation_mint.to_account_info(),
|
||||
ctx.accounts.payer.clone(),
|
||||
ctx.accounts.token_metadata_program.clone(),
|
||||
ctx.accounts.token_program.clone(),
|
||||
ctx.accounts.system_program.clone(),
|
||||
ctx.accounts.edition_mark_pda.clone(),
|
||||
ctx.accounts.rent.to_account_info(),
|
||||
fair_launch.to_account_info(),
|
||||
];
|
||||
|
||||
invoke_signed(
|
||||
&mint_new_edition_from_master_edition_via_token(
|
||||
*ctx.accounts.token_metadata_program.key,
|
||||
*ctx.accounts.new_metadata.key,
|
||||
*ctx.accounts.new_edition.key,
|
||||
*ctx.accounts.master_edition.key,
|
||||
*ctx.accounts.new_mint.key,
|
||||
*ctx.accounts.payer.key,
|
||||
*ctx.accounts.payer.key,
|
||||
fair_launch.key(),
|
||||
*ctx.accounts.participation_token_account.key,
|
||||
fair_launch.key(),
|
||||
*ctx.accounts.metadata.key,
|
||||
ctx.accounts.participation_mint.key(),
|
||||
fair_launch_ticket.seq,
|
||||
),
|
||||
edition_infos.as_slice(),
|
||||
&[&authority_seeds],
|
||||
)?;
|
||||
|
||||
invoke_signed(
|
||||
&update_metadata_accounts(
|
||||
*ctx.accounts.token_metadata_program.key,
|
||||
*ctx.accounts.new_metadata.key,
|
||||
fair_launch.key(),
|
||||
None,
|
||||
None,
|
||||
Some(true),
|
||||
),
|
||||
&[
|
||||
ctx.accounts.token_metadata_program.clone(),
|
||||
ctx.accounts.new_metadata.clone(),
|
||||
fair_launch.to_account_info(),
|
||||
],
|
||||
&[&authority_seeds],
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
#[derive(Accounts)]
|
||||
#[instruction(bump: u8, treasury_bump: u8, token_mint_bump: u8, data: FairLaunchData)]
|
||||
|
@ -1342,6 +1745,92 @@ pub struct SetTokenMetadata<'info> {
|
|||
clock: Sysvar<'info, Clock>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
#[instruction(participation_mint_bump: u8, participation_token_bump: u8)]
|
||||
pub struct SetParticipationNFT<'info> {
|
||||
#[account(mut, seeds=[PREFIX.as_bytes(), fair_launch.token_mint.as_ref()], bump=fair_launch.bump, has_one=authority)]
|
||||
fair_launch: ProgramAccount<'info, FairLaunch>,
|
||||
#[account(signer)]
|
||||
authority: AccountInfo<'info>,
|
||||
#[account(mut, signer)]
|
||||
payer: AccountInfo<'info>,
|
||||
#[account(init, seeds=[PREFIX.as_bytes(), authority.key.as_ref(), MINT.as_bytes(), fair_launch.data.uuid.as_bytes(), PARTICIPATION.as_bytes()], mint::authority=fair_launch, mint::decimals=0, payer=payer, bump=participation_mint_bump)]
|
||||
participation_mint: CpiAccount<'info, Mint>,
|
||||
#[account(mut, seeds=[PREFIX.as_bytes(), authority.key.as_ref(), MINT.as_bytes(), fair_launch.data.uuid.as_bytes(), PARTICIPATION.as_bytes(), ACCOUNT.as_bytes()], bump=participation_token_bump)]
|
||||
participation_token_account: AccountInfo<'info>,
|
||||
// With the following accounts we aren't using anchor macros because they are CPI'd
|
||||
// through to token-metadata which will do all the validations we need on them.
|
||||
#[account(mut)]
|
||||
metadata: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
master_edition: AccountInfo<'info>,
|
||||
#[account(address = spl_token_metadata::id())]
|
||||
token_metadata_program: AccountInfo<'info>,
|
||||
#[account(address = spl_token::id())]
|
||||
token_program: AccountInfo<'info>,
|
||||
#[account(address = system_program::ID)]
|
||||
system_program: AccountInfo<'info>,
|
||||
rent: Sysvar<'info, Rent>,
|
||||
clock: Sysvar<'info, Clock>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct UpdateParticipationNFT<'info> {
|
||||
#[account(mut, seeds=[PREFIX.as_bytes(), fair_launch.token_mint.as_ref()], bump=fair_launch.bump, has_one=authority)]
|
||||
fair_launch: ProgramAccount<'info, FairLaunch>,
|
||||
#[account(signer)]
|
||||
authority: AccountInfo<'info>,
|
||||
// With the following accounts we aren't using anchor macros because they are CPI'd
|
||||
// through to token-metadata which will do all the validations we need on them.
|
||||
#[account(mut)]
|
||||
metadata: AccountInfo<'info>,
|
||||
#[account(address = spl_token_metadata::id())]
|
||||
token_metadata_program: AccountInfo<'info>,
|
||||
#[account(address = spl_token::id())]
|
||||
token_program: AccountInfo<'info>,
|
||||
}
|
||||
|
||||
#[derive(Accounts)]
|
||||
pub struct MintParticipationNFT<'info> {
|
||||
#[account(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, has_one=buyer)]
|
||||
fair_launch_ticket: ProgramAccount<'info, FairLaunchTicket>,
|
||||
#[account(mut, signer)]
|
||||
payer: AccountInfo<'info>,
|
||||
#[account(mut, seeds=[PREFIX.as_bytes(), fair_launch.authority.as_ref(), MINT.as_bytes(), fair_launch.data.uuid.as_bytes(), PARTICIPATION.as_bytes()], bump=fair_launch.participation_mint_bump)]
|
||||
participation_mint: CpiAccount<'info, Mint>,
|
||||
#[account(mut, seeds=[PREFIX.as_bytes(), fair_launch.authority.as_ref(), MINT.as_bytes(), fair_launch.data.uuid.as_bytes(), PARTICIPATION.as_bytes(), ACCOUNT.as_bytes()], bump=fair_launch.participation_token_bump)]
|
||||
participation_token_account: AccountInfo<'info>,
|
||||
buyer: AccountInfo<'info>,
|
||||
buyer_nft_token_account: AccountInfo<'info>,
|
||||
// With the following accounts we aren't using anchor macros because they are CPI'd
|
||||
// through to token-metadata which will do all the validations we need on them.
|
||||
// This will fail if there is more than one token in existence and we force you to provide
|
||||
// an ata that must belong to buyer and we check that it has the token from this new_mint.
|
||||
#[account(mut)]
|
||||
new_metadata: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
new_edition: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
new_mint: AccountInfo<'info>,
|
||||
#[account(signer)]
|
||||
new_mint_authority: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
metadata: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
master_edition: AccountInfo<'info>,
|
||||
#[account(mut)]
|
||||
edition_mark_pda: AccountInfo<'info>,
|
||||
#[account(address = spl_token_metadata::id())]
|
||||
token_metadata_program: AccountInfo<'info>,
|
||||
#[account(address = spl_token::id())]
|
||||
token_program: AccountInfo<'info>,
|
||||
#[account(address = system_program::ID)]
|
||||
system_program: AccountInfo<'info>,
|
||||
rent: Sysvar<'info, Rent>,
|
||||
}
|
||||
|
||||
pub const FAIR_LAUNCH_LOTTERY_SIZE: usize = 8 + // discriminator
|
||||
32 + // fair launch
|
||||
1 + // bump
|
||||
|
@ -1379,7 +1868,11 @@ pub const FAIR_LAUNCH_SPACE_VEC_START: usize = 8 + // discriminator
|
|||
8 + // current_eligible_holders
|
||||
8 + // current median,
|
||||
4 + // u32 representing number of amounts in vec so far
|
||||
100; // padding
|
||||
1 + // participation modulo (added later)
|
||||
1 + // participation_mint_bump (added later)
|
||||
1 + // participation_token_bump (added later)
|
||||
33 + // participation_mint (added later)
|
||||
65; // padding
|
||||
|
||||
pub const FAIR_LAUNCH_TICKET_SIZE: usize = 8 + // discriminator
|
||||
32 + // fair launch reverse lookup
|
||||
|
@ -1388,7 +1881,8 @@ pub const FAIR_LAUNCH_TICKET_SIZE: usize = 8 + // discriminator
|
|||
1 + // state
|
||||
1 + // bump
|
||||
8 + // seq
|
||||
50; //padding
|
||||
1 + // gotten participation
|
||||
49; //padding
|
||||
|
||||
pub const FAIR_LAUNCH_TICKET_SEQ_SIZE: usize = 8 + //discriminator
|
||||
32 + // fair launch ticket reverse lookup
|
||||
|
@ -1477,7 +1971,10 @@ pub struct FairLaunch {
|
|||
pub current_eligible_holders: u64,
|
||||
pub current_median: u64,
|
||||
pub counts_at_each_tick: Vec<u64>,
|
||||
// Todo add participation fields in the future for participation NFTs
|
||||
pub participation_modulo: u8,
|
||||
pub participation_mint_bump: u8,
|
||||
pub participation_token_bump: u8,
|
||||
pub participation_mint: Option<Pubkey>,
|
||||
}
|
||||
|
||||
#[account]
|
||||
|
@ -1504,6 +2001,7 @@ pub struct FairLaunchTicket {
|
|||
pub state: FairLaunchTicketState,
|
||||
pub bump: u8,
|
||||
pub seq: u64,
|
||||
pub gotten_participation: bool,
|
||||
}
|
||||
|
||||
#[account]
|
||||
|
@ -1624,6 +2122,16 @@ pub enum ErrorCode {
|
|||
LotteryDurationHasntEndedYet,
|
||||
#[msg("Fair launch ticket and fair launch key mismatch")]
|
||||
FairLaunchMismatch,
|
||||
#[msg("Participation Token Account already exists")]
|
||||
ParticipationTokenAccountAlreadyExists,
|
||||
#[msg("Invalid participation modulo")]
|
||||
InvalidParticipationModulo,
|
||||
#[msg("Already got participation")]
|
||||
AlreadyMintedParticipation,
|
||||
#[msg("Not eligible for participation")]
|
||||
NotEligibleForParticipation,
|
||||
#[msg("The mint on this account does not match the participation nft mint")]
|
||||
ParticipationMintMismatch,
|
||||
#[msg("Account owner should be buyer")]
|
||||
AccountOwnerShouldBeBuyer,
|
||||
#[msg("Account owner should be fair launch authority")]
|
||||
|
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue