diff --git a/js/packages/cli/src/cli.ts b/js/packages/cli/src/candy-machine-cli.ts similarity index 100% rename from js/packages/cli/src/cli.ts rename to js/packages/cli/src/candy-machine-cli.ts diff --git a/js/packages/cli/src/fair-launch-cli.ts b/js/packages/cli/src/fair-launch-cli.ts new file mode 100755 index 0000000..eea3372 --- /dev/null +++ b/js/packages/cli/src/fair-launch-cli.ts @@ -0,0 +1,756 @@ +#!/usr/bin/env node +import * as fs from 'fs'; +import Arweave from 'arweave'; +import * as path from 'path'; +import fetch from 'node-fetch'; +import FormData from 'form-data'; +import { program } from 'commander'; +import * as anchor from '@project-serum/anchor'; +import BN from 'bn.js'; +import { MintLayout, Token } from '@solana/spl-token'; + +import { sendTransactionWithRetryWithKeypair, fromUTF8Array } from './helper'; +import { + LAMPORTS_PER_SOL, + PublicKey, + SystemProgram, + SYSVAR_RENT_PUBKEY, + TransactionInstruction, +} from '@solana/web3.js'; +import { token } from '@project-serum/anchor/dist/utils'; + +const CACHE_PATH = './.cache'; +const PAYMENT_WALLET = new anchor.web3.PublicKey( + 'HvwC9QSAzvGXhhVrgPmauVwFWcYZhne3hVot9EbHuFTm', +); +const ENV = 'devnet'; +const CANDY_MACHINE = 'candy_machine'; + +const programId = new anchor.web3.PublicKey( + 'cndyAnrLdpjq1Ssp1z8xxDsB8dxe7u4HL5Nxi2K5WXZ', +); +const TOKEN_METADATA_PROGRAM_ID = new PublicKey( + 'metaqbxxUerdq28cj1RbAWkYQm3ybzjb6a8bt518x1s', +); + +const SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID = new PublicKey( + 'ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL', +); +const TOKEN_PROGRAM_ID = new PublicKey( + 'TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA', +); +const getTokenWallet = async function (wallet: PublicKey, mint: PublicKey) { + return ( + await PublicKey.findProgramAddress( + [wallet.toBuffer(), TOKEN_PROGRAM_ID.toBuffer(), mint.toBuffer()], + SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID, + ) + )[0]; +}; + +export function createAssociatedTokenAccountInstruction( + associatedTokenAddress: PublicKey, + payer: PublicKey, + walletAddress: PublicKey, + splTokenMintAddress: PublicKey, +) { + const keys = [ + { + pubkey: payer, + isSigner: true, + isWritable: true, + }, + { + pubkey: associatedTokenAddress, + isSigner: false, + isWritable: true, + }, + { + pubkey: walletAddress, + isSigner: false, + isWritable: false, + }, + { + pubkey: splTokenMintAddress, + isSigner: false, + isWritable: false, + }, + { + pubkey: SystemProgram.programId, + isSigner: false, + isWritable: false, + }, + { + pubkey: TOKEN_PROGRAM_ID, + isSigner: false, + isWritable: false, + }, + { + pubkey: SYSVAR_RENT_PUBKEY, + isSigner: false, + isWritable: false, + }, + ]; + return new TransactionInstruction({ + keys, + programId: SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID, + data: Buffer.from([]), + }); +} + +function chunks(array, size) { + return Array.apply(0, new Array(Math.ceil(array.length / size))).map( + (_, index) => array.slice(index * size, (index + 1) * size), + ); +} + +const configArrayStart = + 32 + // authority + 4 + + 6 + // uuid + u32 len + 4 + + 10 + // u32 len + symbol + 2 + // seller fee basis points + 1 + + 4 + + 5 * 34 + // optional + u32 len + actual vec + 8 + //max supply + 1 + //is mutable + 1 + // retain authority + 4; // max number of lines; +const configLineSize = 4 + 32 + 4 + 200; +program.version('0.0.1'); + +if (!fs.existsSync(CACHE_PATH)) { + fs.mkdirSync(CACHE_PATH); +} + +const getCandyMachine = async (config: anchor.web3.PublicKey, uuid: string) => { + return await anchor.web3.PublicKey.findProgramAddress( + [Buffer.from(CANDY_MACHINE), config.toBuffer(), Buffer.from(uuid)], + programId, + ); +}; + +const getConfig = async (authority: anchor.web3.PublicKey, uuid: string) => { + return await anchor.web3.PublicKey.findProgramAddress( + [Buffer.from(CANDY_MACHINE), authority.toBuffer(), Buffer.from(uuid)], + programId, + ); +}; + +const getMetadata = async ( + mint: anchor.web3.PublicKey, +): Promise => { + return ( + await anchor.web3.PublicKey.findProgramAddress( + [ + Buffer.from('metadata'), + TOKEN_METADATA_PROGRAM_ID.toBuffer(), + mint.toBuffer(), + ], + TOKEN_METADATA_PROGRAM_ID, + ) + )[0]; +}; + +const getMasterEdition = async ( + mint: anchor.web3.PublicKey, +): Promise => { + return ( + await anchor.web3.PublicKey.findProgramAddress( + [ + Buffer.from('metadata'), + TOKEN_METADATA_PROGRAM_ID.toBuffer(), + mint.toBuffer(), + Buffer.from('edition'), + ], + TOKEN_METADATA_PROGRAM_ID, + ) + )[0]; +}; + +const createConfig = async function ( + anchorProgram: anchor.Program, + payerWallet: anchor.web3.Keypair, + configData: { + maxNumberOfLines: BN; + symbol: string; + sellerFeeBasisPoints: number; + isMutable: boolean; + maxSupply: BN; + retainAuthority: boolean; + creators: { + address: anchor.web3.PublicKey; + verified: boolean; + share: number; + }[]; + }, +) { + const size = + configArrayStart + + 4 + + configData.maxNumberOfLines.toNumber() * configLineSize + + 4 + + Math.ceil(configData.maxNumberOfLines.toNumber() / 8); + + const config = anchor.web3.Keypair.generate(); + const uuid = config.publicKey.toBase58().slice(0, 6); + + return { + config: config.publicKey, + uuid, + txId: await anchorProgram.rpc.initializeConfig( + { + uuid, + ...configData, + }, + { + accounts: { + config: config.publicKey, + authority: payerWallet.publicKey, + payer: payerWallet.publicKey, + systemProgram: anchor.web3.SystemProgram.programId, + rent: anchor.web3.SYSVAR_RENT_PUBKEY, + }, + signers: [payerWallet, config], + instructions: [ + anchor.web3.SystemProgram.createAccount({ + fromPubkey: payerWallet.publicKey, + newAccountPubkey: config.publicKey, + space: size, + lamports: + await anchorProgram.provider.connection.getMinimumBalanceForRentExemption( + size, + ), + programId: programId, + }), + ], + }, + ), + }; +}; + +program + .command('upload') + .argument( + '', + 'Directory containing images named from 0-n', + val => { + return fs.readdirSync(`${val}`).map(file => path.join(val, file)); + }, + ) + .option( + '-u, --url', + 'Solana cluster url', + 'https://api.mainnet-beta.solana.com/', + ) + .option('-k, --keypair ', 'Solana wallet') + // .argument('[second]', 'integer argument', (val) => parseInt(val), 1000) + .option('-s, --start-with', 'Image index to start with', '0') + .option('-n, --number', 'Number of images to upload', '10000') + .option('-c, --cache-name ', 'Cache file name') + .action(async (files: string[], options, cmd) => { + const extension = '.png'; + const { startWith, keypair } = cmd.opts(); + const cacheName = program.getOptionValue('cacheName') || 'temp'; + const cachePath = path.join(CACHE_PATH, cacheName); + const savedContent = fs.existsSync(cachePath) + ? JSON.parse(fs.readFileSync(cachePath).toString()) + : undefined; + const cacheContent = savedContent || {}; + + if (!cacheContent.program) { + cacheContent.program = {}; + } + + let existingInCache = []; + if (!cacheContent.items) { + cacheContent.items = {}; + } else { + existingInCache = Object.keys(cacheContent.items); + } + + const seen = {}; + const newFiles = []; + + files.forEach(f => { + if (!seen[f.replace(extension, '').split('/').pop()]) { + seen[f.replace(extension, '').split('/').pop()] = true; + newFiles.push(f); + } + }); + existingInCache.forEach(f => { + if (!seen[f]) { + seen[f] = true; + newFiles.push(f + '.png'); + } + }); + + const images = newFiles.filter(val => path.extname(val) === extension); + const SIZE = images.length; // images.length; + const walletKey = anchor.web3.Keypair.fromSecretKey( + new Uint8Array(JSON.parse(fs.readFileSync(keypair).toString())), + ); + + // const conversionRates = JSON.parse( + // await ( + // await fetch( + // 'https://api.coingecko.com/api/v3/simple/price?ids=solana,arweave&vs_currencies=usd', + // ) + // ).text(), + // ); + // const baseCost = fetch(``); + // const increment = fetch(``); + + const solConnection = new anchor.web3.Connection( + `https://api.${ENV}.solana.com/`, + ); + + const walletWrapper = new anchor.Wallet(walletKey); + const provider = new anchor.Provider(solConnection, walletWrapper, { + preflightCommitment: 'recent', + }); + const idl = await anchor.Program.fetchIdl(programId, provider); + const anchorProgram = new anchor.Program(idl, programId, provider); + let config = cacheContent.program.config + ? new anchor.web3.PublicKey(cacheContent.program.config) + : undefined; + + const block = await solConnection.getRecentBlockhash(); + for (let i = 0; i < SIZE; i++) { + const image = images[i]; + const imageName = path.basename(image); + const index = imageName.replace(extension, ''); + + console.log(`Processing file: ${index}`); + + const storageCost = 10; + + let link = cacheContent?.items?.[index]?.link; + if (!link || !cacheContent.program.uuid) { + const imageBuffer = Buffer.from(fs.readFileSync(image)); + const manifestPath = image.replace(extension, '.json'); + const manifestContent = fs + .readFileSync(manifestPath) + .toString() + .replace(imageName, 'image.png') + .replace(imageName, 'image.png'); + const manifest = JSON.parse(manifestContent); + + const manifestBuffer = Buffer.from(JSON.stringify(manifest)); + const sizeInBytes = imageBuffer.length + manifestBuffer.length; + + if (i === 0 && !cacheContent.program.uuid) { + // initialize config + try { + const res = await createConfig(anchorProgram, walletKey, { + maxNumberOfLines: new BN(SIZE), + symbol: manifest.symbol, + sellerFeeBasisPoints: manifest.seller_fee_basis_points, + isMutable: true, + maxSupply: new BN(0), + retainAuthority: true, + creators: manifest.properties.creators.map(creator => { + return { + address: new anchor.web3.PublicKey(creator.address), + verified: false, + share: creator.share, + }; + }), + }); + cacheContent.program.uuid = res.uuid; + cacheContent.program.config = res.config.toBase58(); + config = res.config; + + fs.writeFileSync( + path.join(CACHE_PATH, cacheName), + JSON.stringify(cacheContent), + ); + } catch (exx) { + console.error('Error deploying config to Solana network.', exx); + // console.error(exx); + } + } + + if (!link) { + let instructions = [ + anchor.web3.SystemProgram.transfer({ + fromPubkey: walletKey.publicKey, + toPubkey: PAYMENT_WALLET, + lamports: storageCost, + }), + ]; + + const tx = await sendTransactionWithRetryWithKeypair( + solConnection, + walletKey, + instructions, + [], + 'single', + ); + console.info('transaction for arweave payment:', tx); + + // data.append('tags', JSON.stringify(tags)); + // payment transaction + const data = new FormData(); + data.append('transaction', tx['txid']); + data.append('env', ENV); + data.append('file[]', fs.createReadStream(image), `image.png`); + data.append('file[]', manifestBuffer, 'metadata.json'); + try { + const result = await ( + await fetch( + 'https://us-central1-principal-lane-200702.cloudfunctions.net/uploadFile3', + { + method: 'POST', + body: data, + }, + ) + ).json(); + + const metadataFile = result.messages?.find( + m => m.filename === 'manifest.json', + ); + if (metadataFile?.transactionId) { + link = `https://arweave.net/${metadataFile.transactionId}`; + console.log(`File uploaded: ${link}`); + } + + cacheContent.items[index] = { + link, + name: manifest.name, + onChain: false, + }; + fs.writeFileSync( + path.join(CACHE_PATH, cacheName), + JSON.stringify(cacheContent), + ); + } catch (er) { + console.error(`Error uploading file ${index}`, er); + } + } + } + } + + const keys = Object.keys(cacheContent.items); + try { + await Promise.all( + chunks(Array.from(Array(keys.length).keys()), 1000).map( + async allIndexesInSlice => { + for ( + let offset = 0; + offset < allIndexesInSlice.length; + offset += 10 + ) { + const indexes = allIndexesInSlice.slice(offset, offset + 10); + const onChain = indexes.filter(i => { + const index = keys[i]; + return cacheContent.items[index]?.onChain; + }); + const ind = keys[indexes[0]]; + + if (onChain.length != indexes.length) { + console.log( + 'Writing indices ', + ind, + '-', + keys[indexes[indexes.length - 1]], + ); + const txId = await anchorProgram.rpc.addConfigLines( + ind, + indexes.map(i => ({ + uri: cacheContent.items[keys[i]].link, + name: cacheContent.items[keys[i]].name, + })), + { + accounts: { + config, + authority: walletKey.publicKey, + }, + signers: [walletKey], + }, + ); + indexes.forEach(i => { + cacheContent.items[keys[i]] = { + ...cacheContent.items[keys[i]], + onChain: true, + }; + }); + fs.writeFileSync( + path.join(CACHE_PATH, cacheName), + JSON.stringify(cacheContent), + ); + } + } + }, + ), + ); + } catch (e) { + console.error(e); + } finally { + fs.writeFileSync( + path.join(CACHE_PATH, cacheName), + JSON.stringify(cacheContent), + ); + } + console.log('Done'); + // TODO: start candy machine + }); +program + .command('set_start_date') + .option('-k, --keypair ', 'Solana wallet') + .option('-c, --cache-name ', 'Cache file name') + .option('-d, --date ', 'timestamp - eg "04 Dec 1995 00:12:00 GMT"') + .action(async (directory, cmd) => { + const solConnection = new anchor.web3.Connection( + `https://api.${ENV}.solana.com/`, + ); + + const { keypair } = cmd.opts(); + + const cacheName = cmd.getOptionValue('cacheName') || 'temp'; + const cachePath = path.join(CACHE_PATH, cacheName); + const cachedContent = fs.existsSync(cachePath) + ? JSON.parse(fs.readFileSync(cachePath).toString()) + : undefined; + + const date = cmd.getOptionValue('date'); + const secondsSinceEpoch = (date ? Date.parse(date) : Date.now()) / 1000; + const walletKey = anchor.web3.Keypair.fromSecretKey( + new Uint8Array(JSON.parse(fs.readFileSync(keypair).toString())), + ); + const walletWrapper = new anchor.Wallet(walletKey); + const provider = new anchor.Provider(solConnection, walletWrapper, { + preflightCommitment: 'recent', + }); + const idl = await anchor.Program.fetchIdl(programId, provider); + const anchorProgram = new anchor.Program(idl, programId, provider); + const [candyMachine, _] = await getCandyMachine( + new anchor.web3.PublicKey(cachedContent.program.config), + cachedContent.program.uuid, + ); + const tx = await anchorProgram.rpc.updateCandyMachine( + null, + new anchor.BN(secondsSinceEpoch), + { + accounts: { + candyMachine, + authority: walletKey.publicKey, + }, + }, + ); + + console.log('Done', secondsSinceEpoch, tx); + }); + +program + .command('create_candy_machine') + .option('-k, --keypair ', 'Solana wallet') + .option('-c, --cache-name ', 'Cache file name') + .option('-p, --price ', 'SOL price') + .action(async (directory, cmd) => { + const solConnection = new anchor.web3.Connection( + `https://api.${ENV}.solana.com/`, + ); + + const { keypair } = cmd.opts(); + const solPriceStr = cmd.getOptionValue('price') || '1'; + + const lamports = parseInt(solPriceStr) * LAMPORTS_PER_SOL; + + const cacheName = program.getOptionValue('cacheName') || 'temp'; + const cachePath = path.join(CACHE_PATH, cacheName); + const cachedContent = fs.existsSync(cachePath) + ? JSON.parse(fs.readFileSync(cachePath).toString()) + : undefined; + + const walletKey = anchor.web3.Keypair.fromSecretKey( + new Uint8Array(JSON.parse(fs.readFileSync(keypair).toString())), + ); + const walletWrapper = new anchor.Wallet(walletKey); + const provider = new anchor.Provider(solConnection, walletWrapper, { + preflightCommitment: 'recent', + }); + const idl = await anchor.Program.fetchIdl(programId, provider); + const anchorProgram = new anchor.Program(idl, programId, provider); + const config = new anchor.web3.PublicKey(cachedContent.program.config); + const [candyMachine, bump] = await getCandyMachine( + config, + cachedContent.program.uuid, + ); + const tx = await anchorProgram.rpc.initializeCandyMachine( + bump, + { + uuid: cachedContent.program.uuid, + price: new anchor.BN(lamports), + itemsAvailable: new anchor.BN(Object.keys(cachedContent.items).length), + goLiveDate: null, + }, + { + accounts: { + candyMachine, + wallet: walletKey.publicKey, + config: config, + authority: walletKey.publicKey, + payer: walletKey.publicKey, + systemProgram: anchor.web3.SystemProgram.programId, + rent: anchor.web3.SYSVAR_RENT_PUBKEY, + }, + signers: [], + }, + ); + + console.log(`Done: CANDYMACHINE: ${candyMachine.toBase58()}`); + }); + +program + .command('mint_one_token') + .option('-k, --keypair ', `The purchaser's wallet key`) + .option('-c, --cache-name ', 'Cache file name') + .action(async (directory, cmd) => { + const solConnection = new anchor.web3.Connection( + `https://api.${ENV}.solana.com/`, + ); + + const { keypair } = cmd.opts(); + const solPriceStr = program.getOptionValue('price') || '1'; + const lamports = parseInt(solPriceStr) * LAMPORTS_PER_SOL; + + const cacheName = program.getOptionValue('cacheName') || 'temp'; + const cachePath = path.join(CACHE_PATH, cacheName); + const cachedContent = fs.existsSync(cachePath) + ? JSON.parse(fs.readFileSync(cachePath).toString()) + : undefined; + const mint = anchor.web3.Keypair.generate(); + + const walletKey = anchor.web3.Keypair.fromSecretKey( + new Uint8Array(JSON.parse(fs.readFileSync(keypair).toString())), + ); + const token = await getTokenWallet(walletKey.publicKey, mint.publicKey); + const walletWrapper = new anchor.Wallet(walletKey); + const provider = new anchor.Provider(solConnection, walletWrapper, { + preflightCommitment: 'recent', + }); + const idl = await anchor.Program.fetchIdl(programId, provider); + const anchorProgram = new anchor.Program(idl, programId, provider); + const config = new anchor.web3.PublicKey(cachedContent.program.config); + const [candyMachine, bump] = await getCandyMachine( + config, + cachedContent.program.uuid, + ); + const candy = await anchorProgram.account.candyMachine.fetch(candyMachine); + const metadata = await getMetadata(mint.publicKey); + const masterEdition = await getMasterEdition(mint.publicKey); + const tx = await anchorProgram.rpc.mintNft({ + accounts: { + config: config, + candyMachine: candyMachine, + payer: walletKey.publicKey, + //@ts-ignore + wallet: candy.wallet, + mint: mint.publicKey, + metadata, + masterEdition, + mintAuthority: walletKey.publicKey, + updateAuthority: walletKey.publicKey, + tokenMetadataProgram: TOKEN_METADATA_PROGRAM_ID, + tokenProgram: TOKEN_PROGRAM_ID, + systemProgram: SystemProgram.programId, + rent: anchor.web3.SYSVAR_RENT_PUBKEY, + clock: anchor.web3.SYSVAR_CLOCK_PUBKEY, + }, + signers: [mint, walletKey], + instructions: [ + anchor.web3.SystemProgram.createAccount({ + fromPubkey: walletKey.publicKey, + newAccountPubkey: mint.publicKey, + space: MintLayout.span, + lamports: await provider.connection.getMinimumBalanceForRentExemption( + MintLayout.span, + ), + programId: TOKEN_PROGRAM_ID, + }), + Token.createInitMintInstruction( + TOKEN_PROGRAM_ID, + mint.publicKey, + 0, + walletKey.publicKey, + walletKey.publicKey, + ), + createAssociatedTokenAccountInstruction( + token, + walletKey.publicKey, + walletKey.publicKey, + mint.publicKey, + ), + Token.createMintToInstruction( + TOKEN_PROGRAM_ID, + mint.publicKey, + token, + walletKey.publicKey, + [], + 1, + ), + ], + }); + + console.log('Done', tx); + }); +program + .command('verify') + .option('-c, --cache-name ', 'Cache file name') + .action(async (directory, second, options) => { + const solConnection = new anchor.web3.Connection( + `https://api.${ENV}.solana.com/`, + ); + const cacheName = program.getOptionValue('cacheName') || 'temp'; + const cachePath = path.join(CACHE_PATH, cacheName); + const cachedContent = fs.existsSync(cachePath) + ? JSON.parse(fs.readFileSync(cachePath).toString()) + : undefined; + + const config = await solConnection.getAccountInfo( + new PublicKey(cachedContent.program.config), + ); + const number = new BN(config.data.slice(247, 247 + 4), undefined, 'le'); + console.log('Number', number.toNumber()); + + const keys = Object.keys(cachedContent.items); + for (let i = 0; i < keys.length; i++) { + console.log('Looking at key ', i); + const key = keys[i]; + const thisSlice = config.data.slice( + configArrayStart + 4 + configLineSize * i, + configArrayStart + 4 + configLineSize * (i + 1), + ); + const name = fromUTF8Array([...thisSlice.slice(4, 36)]); + const uri = fromUTF8Array([...thisSlice.slice(40, 240)]); + const cacheItem = cachedContent.items[key]; + if (!name.match(cacheItem.name) || !uri.match(cacheItem.link)) { + console.log( + 'Name', + name, + 'or uri', + uri, + 'didnt match cache values of', + cacheItem.name, + 'and', + cacheItem.link, + ' marking to rerun for image', + key, + ); + cacheItem.onChain = false; + } else { + console.log('Name', name, 'with', uri, 'checked out'); + } + } + fs.writeFileSync( + path.join(CACHE_PATH, cacheName), + JSON.stringify(cachedContent), + ); + }); + +program.command('find-wallets').action(() => {}); + +program.parse(process.argv); diff --git a/rust/test/fair-launch-types.ts b/rust/test/fair-launch-types.ts new file mode 100644 index 0000000..b6e5448 --- /dev/null +++ b/rust/test/fair-launch-types.ts @@ -0,0 +1,23 @@ +export type FairLaunchIDL = {"version":"0.0.0","name":"fair_launch","instructions":[{"name":"initializeFairLaunch","accounts":[{"name":"fairLaunch","isMut":true,"isSigner":false},{"name":"tokenMint","isMut":true,"isSigner":false},{"name":"treasury","isMut":false,"isSigner":false},{"name":"authority","isMut":false,"isSigner":false},{"name":"payer","isMut":true,"isSigner":true},{"name":"tokenProgram","isMut":false,"isSigner":false},{"name":"systemProgram","isMut":false,"isSigner":false},{"name":"rent","isMut":false,"isSigner":false}],"args":[{"name":"bump","type":"u8"},{"name":"treasuryBump","type":"u8"},{"name":"tokenMintBump","type":"u8"},{"name":"data","type":{"defined":"FairLaunchData"}}]},{"name":"updateFairLaunch","accounts":[{"name":"fairLaunch","isMut":true,"isSigner":false},{"name":"authority","isMut":false,"isSigner":true}],"args":[{"name":"data","type":{"defined":"FairLaunchData"}}]},{"name":"startPhaseThree","accounts":[{"name":"fairLaunch","isMut":true,"isSigner":false},{"name":"fairLaunchLotteryBitmap","isMut":false,"isSigner":false},{"name":"authority","isMut":false,"isSigner":true}],"args":[]},{"name":"updateFairLaunchLotteryBitmap","accounts":[{"name":"fairLaunch","isMut":false,"isSigner":false},{"name":"fairLaunchLotteryBitmap","isMut":true,"isSigner":false},{"name":"authority","isMut":false,"isSigner":true}],"args":[{"name":"index","type":"u32"},{"name":"bytes","type":"bytes"}]},{"name":"createFairLaunchLotteryBitmap","accounts":[{"name":"fairLaunch","isMut":false,"isSigner":false},{"name":"fairLaunchLotteryBitmap","isMut":true,"isSigner":false},{"name":"authority","isMut":false,"isSigner":true},{"name":"payer","isMut":true,"isSigner":true},{"name":"systemProgram","isMut":false,"isSigner":false},{"name":"rent","isMut":false,"isSigner":false},{"name":"clock","isMut":false,"isSigner":false}],"args":[{"name":"bump","type":"u8"}]},{"name":"purchaseTicket","accounts":[{"name":"fairLaunch","isMut":true,"isSigner":false},{"name":"treasury","isMut":true,"isSigner":false},{"name":"fairLaunchTicket","isMut":true,"isSigner":false},{"name":"buyer","isMut":true,"isSigner":true},{"name":"payer","isMut":true,"isSigner":true},{"name":"systemProgram","isMut":false,"isSigner":false},{"name":"rent","isMut":false,"isSigner":false},{"name":"clock","isMut":false,"isSigner":false}],"args":[{"name":"bump","type":"u8"},{"name":"amount","type":"u64"}]},{"name":"createTicketSeq","accounts":[{"name":"fairLaunch","isMut":true,"isSigner":false},{"name":"fairLaunchTicket","isMut":true,"isSigner":false},{"name":"fairLaunchTicketSeqLookup","isMut":true,"isSigner":false},{"name":"payer","isMut":true,"isSigner":true},{"name":"systemProgram","isMut":false,"isSigner":false},{"name":"rent","isMut":false,"isSigner":false}],"args":[{"name":"bump","type":"u8"}]},{"name":"adjustTicket","accounts":[{"name":"fairLaunchTicket","isMut":true,"isSigner":false},{"name":"fairLaunch","isMut":true,"isSigner":false},{"name":"fairLaunchLotteryBitmap","isMut":false,"isSigner":false},{"name":"treasury","isMut":true,"isSigner":false},{"name":"buyer","isMut":true,"isSigner":false},{"name":"systemProgram","isMut":false,"isSigner":false}],"args":[{"name":"amount","type":"u64"}]},{"name":"punchTicket","accounts":[{"name":"fairLaunchTicket","isMut":true,"isSigner":false},{"name":"fairLaunch","isMut":false,"isSigner":false},{"name":"fairLaunchLotteryBitmap","isMut":false,"isSigner":false},{"name":"payer","isMut":true,"isSigner":true},{"name":"buyerTokenAccount","isMut":true,"isSigner":false},{"name":"tokenMint","isMut":false,"isSigner":false},{"name":"tokenProgram","isMut":false,"isSigner":false}],"args":[]},{"name":"withdrawFunds","accounts":[{"name":"fairLaunch","isMut":false,"isSigner":false},{"name":"treasury","isMut":true,"isSigner":false},{"name":"authority","isMut":true,"isSigner":false},{"name":"systemProgram","isMut":false,"isSigner":false}],"args":[]}],"accounts":[{"name":"fairLaunch","type":{"kind":"struct","fields":[{"name":"tokenMint","type":"publicKey"},{"name":"treasury","type":"publicKey"},{"name":"treasuryMint","type":{"option":"publicKey"}},{"name":"authority","type":"publicKey"},{"name":"bump","type":"u8"},{"name":"treasuryBump","type":"u8"},{"name":"tokenMintBump","type":"u8"},{"name":"data","type":{"defined":"FairLaunchData"}},{"name":"numberTicketsUnSeqed","type":"u64"},{"name":"numberTicketsSold","type":"u64"},{"name":"numberTicketsDropped","type":"u64"},{"name":"numberTicketsPunched","type":"u64"},{"name":"phaseThreeStarted","type":"bool"},{"name":"currentMedian","type":"u64"},{"name":"countsAtEachTick","type":{"vec":"u64"}}]}},{"name":"fairLaunchLotteryBitmap","type":{"kind":"struct","fields":[{"name":"fairLaunch","type":"publicKey"},{"name":"bump","type":"u8"},{"name":"bitmapOnes","type":"u64"}]}},{"name":"fairLaunchTicket","type":{"kind":"struct","fields":[{"name":"fairLaunch","type":"publicKey"},{"name":"buyer","type":"publicKey"},{"name":"amount","type":"u64"},{"name":"state","type":{"defined":"FairLaunchTicketState"}},{"name":"bump","type":"u8"},{"name":"seq","type":"u64"}]}},{"name":"fairLaunchTicketSeqLookup","type":{"kind":"struct","fields":[{"name":"fairLaunchTicket","type":"publicKey"},{"name":"buyer","type":"publicKey"},{"name":"seq","type":"u64"},{"name":"bump","type":"u8"}]}}],"types":[{"name":"FairLaunchData","type":{"kind":"struct","fields":[{"name":"uuid","type":"string"},{"name":"priceRangeStart","type":"u64"},{"name":"priceRangeEnd","type":"u64"},{"name":"phaseOneStart","type":"i64"},{"name":"phaseOneEnd","type":"i64"},{"name":"phaseTwoEnd","type":"i64"},{"name":"tickSize","type":"u64"},{"name":"numberOfTokens","type":"u64"}]}},{"name":"FairLaunchTicketState","type":{"kind":"enum","variants":[{"name":"NoSequenceStruct"},{"name":"Unpunched"},{"name":"Punched"},{"name":"Withdrawn"}]}}],"errors":[{"code":300,"name":"IncorrectOwner","msg":"Account does not have correct owner!"},{"code":301,"name":"Uninitialized","msg":"Account is not initialized!"},{"code":302,"name":"MintMismatch","msg":"Mint Mismatch!"},{"code":303,"name":"TokenTransferFailed","msg":"Token transfer failed"},{"code":304,"name":"NumericalOverflowError","msg":"Numerical overflow error"},{"code":305,"name":"TimestampsDontLineUp","msg":"Timestamps of phases should line up"},{"code":306,"name":"CantSetPhaseThreeDatesYet","msg":"Cant set phase 3 dates yet"},{"code":307,"name":"UuidMustBeExactly6Length","msg":"Uuid must be exactly of 6 length"},{"code":308,"name":"TickSizeTooSmall","msg":"Tick size too small"},{"code":309,"name":"CannotGiveZeroTokens","msg":"Cannot give zero tokens"},{"code":310,"name":"InvalidPriceRanges","msg":"Invalid price ranges"},{"code":311,"name":"TooMuchGranularityInRange","msg":"With this tick size and price range, you will have too many ticks(>"},{"code":312,"name":"CannotUseTickSizeThatGivesRemainder","msg":"Cannot use a tick size with a price range that results in a remainder when doing (end-start)/ticksize"},{"code":313,"name":"DerivedKeyInvalid","msg":"Derived key invalid"},{"code":314,"name":"TreasuryAlreadyExists","msg":"Treasury Already Exists"},{"code":315,"name":"LotteryBitmapOnesMustEqualNumberOfTicketsSold","msg":"The number of ones in the lottery must equal the number of tickets sold in phase 1"},{"code":316,"name":"InvalidPurchaseAmount","msg":"Amount must be between price ranges and at a tick mark"},{"code":317,"name":"TreasuryMintMismatch","msg":"Treasury mint does not match"},{"code":318,"name":"NotEnoughTokens","msg":"Not enough tokens to pay for this minting"},{"code":319,"name":"NotEnoughSOL","msg":"Not enough SOL to pay for this minting"},{"code":320,"name":"InvalidTokenProgram","msg":"Sent up invalid token program"},{"code":321,"name":"CannotBuyTicketsOutsidePhaseOne","msg":"Cannot buy tickets outside phase one"},{"code":322,"name":"CannotCreateFairLaunchLotteryBitmapBeforePhaseTwoEnd","msg":"Cannot create the bitmap before phase two end"},{"code":323,"name":"CannotUpdateFairLaunchLotteryOncePhaseThreeLocked","msg":"Cannot update fair launch lottery once phase three locked"},{"code":324,"name":"SeqAlreadyExists","msg":"Seq already exists"},{"code":325,"name":"CannotSetFairLaunchLotteryUntilAllTicketsAreSequenced","msg":"Cannot set lottery until all tickets have sequence lookups using permissionless crank endpoint. Use CLI to make."},{"code":326,"name":"CanOnlySubmitZeroDuringPhaseThree","msg":"During phase three, since you did not pay up to the median, you can only withdraw your funds"},{"code":327,"name":"CanOnlySubmitDifferenceDuringPhaseThree","msg":"During phase three, since you paid above median, you can only withdraw the difference"},{"code":328,"name":"DidNotWinLotteryCanOnlyWithdraw","msg":"You did not win the lottery, therefore you can only withdraw your funds"},{"code":329,"name":"AccountShouldHaveNoDelegates","msg":"This account should have no delegates"},{"code":330,"name":"TokenMintToFailed","msg":"Token minting failed"},{"code":331,"name":"DuringPhaseTwoAndOneBuyerMustBeSigner","msg":"During phase two and one buyer must be signer"},{"code":332,"name":"InvalidFairLaunchTicketState","msg":"Invalid fair launch ticket state for this operation"},{"code":333,"name":"CannotCashOutUntilAllRefundsAndPunchesHaveBeenProcessed","msg":"Cannot cash out until all refunds and punches (permissionless calls) have been processed. Use the CLI."},{"code":334,"name":"CannotCashOutUntilPhaseThree","msg":"Cannot cash out until phase three"}]}; +import { IdlAccounts } from '@project-serum/anchor'; + +export type FairLaunchTicketState = Record> +export const FairLaunchTicketState = { + NoSequenceStruct: { nosequencestruct: {} }, + Unpunched: { unpunched: {} }, + Punched: { punched: {} }, + Withdrawn: { withdrawn: {} } +} + + + + +export type FairLaunch = IdlAccounts["fairLaunch"] + +export type FairLaunchLotteryBitmap = IdlAccounts["fairLaunchLotteryBitmap"] + +export type FairLaunchTicket = IdlAccounts["fairLaunchTicket"] + +export type FairLaunchTicketSeqLookup = IdlAccounts["fairLaunchTicketSeqLookup"] + + \ No newline at end of file