import { publicKey, u64 } from '@project-serum/borsh' import { Account, Connection, PublicKey, Transaction, TransactionInstruction } from '@solana/web3.js' // @ts-ignore import { nu64, seq, struct, u8 } from 'buffer-layout' import { cloneDeep } from 'lodash-es' import { CLOCK_PROGRAM_ID, IDO_PROGRAM_ID, IDO_PROGRAM_ID_V2, IDO_PROGRAM_ID_V3, RENT_PROGRAM_ID, SYSTEM_PROGRAM_ID, TOKEN_PROGRAM_ID } from './ids' import { getBigNumber } from './layouts' import { TokenAmount } from './safe-math' import { TokenInfo, TOKENS } from './tokens' import { createAssociatedTokenAccount, findProgramAddress, sendTransaction } from './web3' export interface IdoPoolInfo { startTime: number endTime: number startWithdrawTime: number minDepositLimit: TokenAmount maxDepositLimit: TokenAmount stakePoolId: PublicKey minStakeLimit: TokenAmount quoteTokenDeposited: TokenAmount } export interface IdoLotteryPoolInfo { status: number nonce: number startTime: number endTime: number startWithdrawTime: number numerator: number denominator: number quoteTokenDeposited: TokenAmount baseTokenSupply: TokenAmount perUserMaxLottery: number perUserMinLottery: number perLotteryNeedMinStake: number perLotteryWorthQuoteAmount: TokenAmount totalWinLotteryLimit: number totalDepositUserNumber: number currentLotteryNumber: number luckyInfos: Array<{ luckyTailDigits: number luckyTailNumber: number luckyWithinNumber: number luckyNumberExist: number }> quoteTokenMint: PublicKey baseTokenMint: PublicKey quoteTokenVault: PublicKey baseTokenVault: PublicKey stakePoolId: PublicKey stakeProgramId: PublicKey checkProgramId: PublicKey idoOwner: PublicKey poolSeedId: PublicKey isWinning: number // 0: not start 1: data is for choose win 2: data is for choose lose 3: all wins } export interface IdoUserInfo { deposited: TokenAmount snapshoted: boolean } export interface IdoLotteryUserInfo { deposited: TokenAmount snapshoted: boolean eligibleTicketAmount: number quoteTokenDeposited: number quoteTokenWithdrawn: number baseTokenWithdrawn: number lotteryBeginNumber: number lotteryEndNumber: number } export interface IdoPool { base: TokenInfo quote: TokenInfo version: number programId: string snapshotProgramId: string isRayPool: boolean isPrivate: boolean status?: string idoId: string baseVault: string quoteVault: string info?: IdoPoolInfo | IdoLotteryPoolInfo userInfo?: IdoUserInfo | IdoLotteryUserInfo price: TokenAmount raise: TokenAmount seedId?: string // it's a string give from backend } export const IDO_POOLS: IdoPool[] = [ { base: { ...TOKENS.HAWK }, quote: { ...TOKENS.USDC }, price: new TokenAmount(0.012, TOKENS.USDC.decimals, false), raise: new TokenAmount(30000000, TOKENS.HAWK.decimals, false), version: 3, // just an identify for Lottery activity programId: IDO_PROGRAM_ID_V3, snapshotProgramId: '4kCccBVdQpsonm2jL2TRV1noMdarsWR2mhwwkxUTqW3W', isRayPool: true, isPrivate: false, idoId: 'J8SYuY4PHJ8Z5FGDUvmzREKqXRSMY9zr88D6szpbMKNg', baseVault: 'FdvbwAgaUaaEfx3fvscVoHZ6tULLs6xdhyMZukJaoZEe', quoteVault: 'B5KFqoJ7w7tJ7LTXTEZZSWuHF192HmRUeAxJyXkBkw79', seedId: 'FCFfK84Lwn9BPGwfJZvVgazjiNaWUVhBTB4Wxx4Aq4sz' }, { base: { ...TOKENS.prANA }, quote: { ...TOKENS.USDC }, price: new TokenAmount(2, TOKENS.USDC.decimals, false), raise: new TokenAmount(125000, TOKENS.prANA.decimals, false), version: 3, // just an identify for Lottery activity programId: IDO_PROGRAM_ID_V3, snapshotProgramId: '4kCccBVdQpsonm2jL2TRV1noMdarsWR2mhwwkxUTqW3W', isRayPool: true, isPrivate: false, idoId: '3XJpeTMso92CxkNEKp9n6cBtRu89FsC3cUerkGUGtsSp', baseVault: 'ApJd77jrJc6zURdWmHCdNF9r6TT8LJixd6DKdrSzbbDQ', quoteVault: 'G1XxQPhMZgHULnqArgRf92WEA6YJyGjak9ihAVUuEhUZ', seedId: '5Fq2mGHnaVgvS1hxUMrdQrGbtScoeW32Y5BLCzoRCWnz' }, { base: { ...TOKENS.ZBC }, quote: { ...TOKENS.USDC }, price: new TokenAmount(0.021, TOKENS.USDC.decimals, false), raise: new TokenAmount(50000000, TOKENS.ZBC.decimals, false), version: 3, // just an identify for Lottery activity programId: IDO_PROGRAM_ID_V3, snapshotProgramId: '4kCccBVdQpsonm2jL2TRV1noMdarsWR2mhwwkxUTqW3W', isRayPool: true, isPrivate: false, idoId: '3dzFshf1hTJ4xLt8uG87cGFA3fzBmUtT1hoVFc3vNPbN', baseVault: 'DoGu2pNFFwjMaQYnkMcEz8GKTBSPPbJkCwgEw2o2KvWV', quoteVault: 'BYMo31vjmaDWYWVs3j364XDeXRssYgwbnqXZi3wMeUz2', seedId: 'As7Qo4axkCLULMSJcRb88Hd944LtoJgppR5EcPapM66x' }, { base: { ...TOKENS.YAW }, quote: { ...TOKENS.USDC }, price: new TokenAmount(0.2, TOKENS.USDC.decimals, false), raise: new TokenAmount(7500000, TOKENS.YAW.decimals, false), version: 3, // just an identify for Lottery activity programId: IDO_PROGRAM_ID_V3, snapshotProgramId: '4kCccBVdQpsonm2jL2TRV1noMdarsWR2mhwwkxUTqW3W', isRayPool: true, isPrivate: false, idoId: 'ELmdR1aviPeBcJPPSA3UcKHZKBKgSoCrAKyUbXCfFW9H', baseVault: 'HLGPz2igA44qwu2weF1tSvMXc5gT4aojwVwqiv19DXFn', quoteVault: 'AngzxwJCyMCY6vA8o8QxTsLFezzoztq6jNC7iByHUmGR', seedId: 'GawJp2GhDEm9FG3tLNMTHXP8GN4N1E33Sf26jVZp13GV' }, { base: { ...TOKENS.FCON }, quote: { ...TOKENS.USDC }, price: new TokenAmount(0.002, TOKENS.USDC.decimals, false), raise: new TokenAmount(250000000, TOKENS.FCON.decimals, false), version: 3, // just an identify for Lottery activity programId: IDO_PROGRAM_ID_V3, snapshotProgramId: '4kCccBVdQpsonm2jL2TRV1noMdarsWR2mhwwkxUTqW3W', isRayPool: true, isPrivate: false, idoId: '3Ebtuv5yEqMGLFXmt1eESwCa28pkwnkJXKr1FxrvLtiV', baseVault: '7Xexuz32nhfz867i5eFtCTCuHAyUFZsoqh1fzuybetxQ', quoteVault: 'FXWB1tERoJPqHZGqz8L6pn9d1bXeVBxK9ijuX8JTLWt2', seedId: 'HRv8kW1iHgufMwNC9XjfNFqkh679CeZmsUi8NndgZrQ2' }, { base: { ...TOKENS.REAL }, quote: { ...TOKENS.USDC }, price: new TokenAmount(1, TOKENS.USDC.decimals, false), raise: new TokenAmount(500000, TOKENS.REAL.decimals, false), version: 3, // just an identify for Lottery activity programId: IDO_PROGRAM_ID_V3, snapshotProgramId: '4kCccBVdQpsonm2jL2TRV1noMdarsWR2mhwwkxUTqW3W', isRayPool: true, isPrivate: false, idoId: 'J4FwTbrLf4xMu6QMHFbmFRxv3KbZmsA2oUVEoXrR61a2', baseVault: 'J2VuN1YdJKuqaYUbJR127oHuLPfdvTdmDE54oVuDHuLs', quoteVault: '3CL33RsJk3661mYKV8W1LP3fpcxRF8MmNdeH54KFTPvW', seedId: 'G8vdpPXZSRuk6n2EByPHTEJA8fxyQQZVD2LUEKYodNmu' }, { base: { ...TOKENS.RUN }, quote: { ...TOKENS.USDC }, price: new TokenAmount(0.06, TOKENS.USDC.decimals, false), raise: new TokenAmount(16666667, TOKENS.RUN.decimals, false), version: 3, // just an identify for Lottery activity programId: IDO_PROGRAM_ID_V3, snapshotProgramId: '4kCccBVdQpsonm2jL2TRV1noMdarsWR2mhwwkxUTqW3W', isRayPool: true, isPrivate: false, idoId: 'BnoL9CM6FFRV3fyYAdfpvLnXkgRGXC1MkYFAriDXGuiX', baseVault: '8Z5aiAYi6tDurpnLhrLnSMJs1koXDvst3HznAik2LZ6W', quoteVault: 'AyG1o1gxDGEfd4Lv8LLnaxf3MfQEotbo2AeWn6bWhkCQ', seedId: 'AkpPozZ22LsiFuMX4zjTn1bMB5tGgTY2naxhyeV9n3Ms' }, { base: { ...TOKENS.TTT }, quote: { ...TOKENS.USDC }, price: new TokenAmount(0.1, TOKENS.USDC.decimals, false), raise: new TokenAmount(10000000, TOKENS.TTT.decimals, false), version: 3, // just an identify for Lottery activity programId: IDO_PROGRAM_ID_V3, snapshotProgramId: '4kCccBVdQpsonm2jL2TRV1noMdarsWR2mhwwkxUTqW3W', isRayPool: true, isPrivate: false, idoId: '6vr62dLQL1Cwc8gP5RvPUqQ1JxAeP5kDayzghfLbCo7A', baseVault: 'DDAP7hw4uvy8JudwhjM8tH8pfpnM5vpeAuAu4FUz7gXG', quoteVault: 'HgS6LxpsaxUepTdiz8i9jBrGhadaFyDx9cwso5P825rg', seedId: '4Z1jpanh6irMnQ2BS2dAD8mbxeZVRFxzjuEG3vUWLu8r' }, { base: { ...TOKENS.DFL }, quote: { ...TOKENS.USDC }, price: new TokenAmount(0.005, TOKENS.USDC.decimals, false), raise: new TokenAmount(70000000, TOKENS.DFL.decimals, false), version: 3, // just an identify for Lottery activity programId: IDO_PROGRAM_ID_V3, snapshotProgramId: '4kCccBVdQpsonm2jL2TRV1noMdarsWR2mhwwkxUTqW3W', isRayPool: true, isPrivate: false, idoId: 'DTfvaFt5bZiS1Ak8S7dbviTvj5Gwamb4NZewV1prdPzN', baseVault: '5VKAhVUyqdppFdp5cdMAhifMYbA2rKSFhSNWLJPyUJPk', quoteVault: '7fPNyszoEwrT81vdFPATi1f6wBEcx17ycvPEgGGf6T1z', seedId: '2F6kG1aEn6VD6ab7eB2oVvsG1wJ34kZtTNs4o3xizgMP' }, { base: { ...TOKENS.GENE }, quote: { ...TOKENS.USDC }, price: new TokenAmount(0.8, TOKENS.USDC.decimals, false), raise: new TokenAmount(500000, TOKENS.GENE.decimals, false), version: 3, // just an identify for Lottery activity programId: IDO_PROGRAM_ID_V3, snapshotProgramId: '4kCccBVdQpsonm2jL2TRV1noMdarsWR2mhwwkxUTqW3W', isRayPool: true, isPrivate: false, idoId: 'DGBnb4xRW3oZNa14F8h8WgsDWPFZQoX9Ffem9pPL8t1g', baseVault: 'GDDSZ2nhJVAXLULhfU5nwY2EMKXWM9dCK9KtMXtKHAH3', quoteVault: 'EwpeiGxn8kxFdL8jkdurw4k6sa3xxc53NRRtQLZgzAH2', seedId: '5PydzUPEHXFZbnUu1t71Kfjf1mhxDiHqYmQVoGoAkJDR' }, { base: { ...TOKENS.GRAPE }, quote: { ...TOKENS.USDC }, price: new TokenAmount(0.02, TOKENS.USDC.decimals, false), raise: new TokenAmount(30000000, TOKENS.GRAPE.decimals, false), version: 3, // just an identify for Lottery activity programId: IDO_PROGRAM_ID_V3, snapshotProgramId: '4kCccBVdQpsonm2jL2TRV1noMdarsWR2mhwwkxUTqW3W', isRayPool: true, isPrivate: false, idoId: 'E4CvLEhwih2BekPtoAExKg4hFDxAnKGehC8nsEiKVoJy', baseVault: 'HGGGN5EW85q2b65ANC7PibnwY6cUBabmnZStiXQWa1g8', quoteVault: '6oW75ZhEpi7Xf4FFihtdkKsuMYw4peX6VtvWLVKq88dQ', seedId: 'H5uXejEcXqQgtcfkqaCnwY3vTjTaNvJwyrWxmpk7ipzM' }, { base: { ...TOKENS.ATLAS }, quote: { ...TOKENS.USDC }, price: new TokenAmount(0.00138, TOKENS.USDC.decimals, false), raise: new TokenAmount(180000000, TOKENS.ATLAS.decimals, false), version: 3, // just an identify for Lottery activity programId: IDO_PROGRAM_ID_V3, // snapshotProgramId: '4kCccBVdQpsonm2jL2TRV1noMdarsWR2mhwwkxUTqW3W', isRayPool: true, isPrivate: false, idoId: '5VUvtxLeEZhqw22gLb47oKT4zi9MfnD9Lm8wtoXoxXe2', baseVault: 'EjrYFq71uhywEEKu5t1Pug5hnuASyXCGJTvU4h9Pirov', quoteVault: 'DvAB5zNynTwYfjrz3XkgrrXvNxuBr1dZKfv82XvhKZkv', seedId: 'Gez2YfnhhSY2aUphAfK7GDWLaDN9b4z2dfe7jH2oi7Xj' }, { base: { ...TOKENS.POLIS }, quote: { ...TOKENS.USDC }, price: new TokenAmount(0.138, TOKENS.USDC.decimals, false), raise: new TokenAmount(1800000, TOKENS.POLIS.decimals, false), version: 3, // just an identify for Lottery activity programId: IDO_PROGRAM_ID_V3, snapshotProgramId: '4kCccBVdQpsonm2jL2TRV1noMdarsWR2mhwwkxUTqW3W', isRayPool: true, isPrivate: false, idoId: 'FzwVZtojkp2PMhReaqmw1a42pz9rvk9vE9MunCNUkDvM', baseVault: 'GXcxqbecKQYe7t9Vk5EtGJmQEbyT8D2JwFRAeysUPysT', quoteVault: 'ABoVH9ya22W7ghER3NHCvrJoBeKXXunccaJpBacAtWop', seedId: 'Gez2YfnhhSY2aUphAfK7GDWLaDN9b4z2dfe7jH2oi7Xj' }, { base: { ...TOKENS.LIKE }, quote: { ...TOKENS.USDC }, price: new TokenAmount(0.06, TOKENS.USDC.decimals, false), raise: new TokenAmount(1666667, TOKENS.LIKE.decimals, false), version: 3, // just an identify for Lottery activity programId: IDO_PROGRAM_ID_V3, snapshotProgramId: '4kCccBVdQpsonm2jL2TRV1noMdarsWR2mhwwkxUTqW3W', isRayPool: true, isPrivate: false, idoId: '6tVhfpkvg4JTYpDCrDgjb5tAEFSzvpZXLgPtAos5xThD', baseVault: '91MgsAE7qotAtYAd9k7YVZqjs2RfW44zJMQ3gLxAGEur', quoteVault: 'PsqkXYFRAM5PjWgyVSjYMMJGG2dqkfaWe2whUXHtEAh', seedId: 'H8yyqemdjWgD2zkhhaMRsoWKUJSGWSb7kDaCEG16WH63' }, { base: { ...TOKENS.SLRS }, quote: { ...TOKENS.USDC }, price: new TokenAmount(0.05, TOKENS.USDC.decimals, false), raise: new TokenAmount(2000000, TOKENS.SLRS.decimals, false), version: 3, // just an identify for Lottery activity programId: IDO_PROGRAM_ID_V3, snapshotProgramId: '4kCccBVdQpsonm2jL2TRV1noMdarsWR2mhwwkxUTqW3W', isRayPool: true, isPrivate: false, idoId: '6djgqw4EXwjGJMPuxH43RdCih5DQgwop1UK5Wk2FDvWt', baseVault: 'E6A985RSVzJYhfEzW9B7e86xtYfHz5h9wxRe2KLHWnTZ', quoteVault: '8Q8xr7X7asGL82SdniAcrN8f9hTa1DjDcbJVLNVN38zg', seedId: 'APDE8Mc9abyigJb9cWcS95mMCyyA4QN4kv5Zi4YePygt' }, { base: { ...TOKENS.SLRS }, quote: { ...TOKENS.USDC }, price: new TokenAmount(0.05, TOKENS.USDC.decimals, false), raise: new TokenAmount(480000, TOKENS.SLRS.decimals, false), version: 2, programId: IDO_PROGRAM_ID_V2, snapshotProgramId: '4kCccBVdQpsonm2jL2TRV1noMdarsWR2mhwwkxUTqW3W', isRayPool: false, isPrivate: true, idoId: '7nJQCQFNNqrp2VXQM5u9CZ98LBH2EYk62V2zuKRBvw8G', baseVault: 'C3qE7ErgGDWKiz8h9Pv6FBjfnfzJFDrF5Ubb3zacMnbL', quoteVault: '5AmMZChuCAw8XWCF6RRhWTaaosemKzHc6HV89nx2Qp6z', seedId: 'FUbckyz9EKqTYvoPPRF3A2JpGJTJHRbHi2J6rJYhqCay' }, { base: { ...TOKENS.SNY }, quote: { ...TOKENS.USDC }, price: new TokenAmount(1.5, TOKENS.USDC.decimals, false), raise: new TokenAmount(700000, TOKENS.SNY.decimals, false), version: 3, // just an identify for Lottery activity programId: IDO_PROGRAM_ID_V3, snapshotProgramId: '4kCccBVdQpsonm2jL2TRV1noMdarsWR2mhwwkxUTqW3W', isRayPool: true, isPrivate: false, idoId: '9aAMMBcRVfPEa7quoRyofR3rG7qF4QJTehUhV3o1mPzf', baseVault: 'D9X5KoDgC9sKFwPQcjYySGkHpe7akMvSSVDsorRgXYER', quoteVault: 'Emuu4LH3Y2c7RmC97RWw944foRUSU28QbAyx9ocyMJsS', seedId: 'AjLbEuXP49PTx1Hwb93gNC4EbeCSATWDbDoo2nyAzVrT' }, { base: { ...TOKENS.MER }, quote: { ...TOKENS.USDC }, price: new TokenAmount(0.125, TOKENS.USDC.decimals, false), raise: new TokenAmount(1000000, TOKENS.MER.decimals, false), version: 2, programId: IDO_PROGRAM_ID_V2, snapshotProgramId: '4kCccBVdQpsonm2jL2TRV1noMdarsWR2mhwwkxUTqW3W', isRayPool: true, isPrivate: false, idoId: '3GANPMCSLb1NeQZZ1VNKXHrH5jCyK3DQLr4tmhvkaYng', baseVault: 'Hw41WUxQjuEbNK21nBRdoefqVhgWFe6vjJ1CTJXtXryo', quoteVault: 'AdeaHKgjYDfvzdmiaj3WSTRh6rGUF5Rf2bdgm6c9DEni', seedId: 'CAQi1pkhRPsCi24uyF6NnGm5Two1Bq2AhrDZrM9Mtfjs' }, { base: { ...TOKENS.MER }, quote: { ...TOKENS.USDC }, price: new TokenAmount(0.125, TOKENS.USDC.decimals, false), raise: new TokenAmount(1000000, TOKENS.MER.decimals, false), version: 2, programId: IDO_PROGRAM_ID_V2, snapshotProgramId: '4kCccBVdQpsonm2jL2TRV1noMdarsWR2mhwwkxUTqW3W', isRayPool: true, isPrivate: false, idoId: 'F5Rk8Eht3JU69146uc9piwmMGCdPwAmYgJKRUaWxhwim', baseVault: '3CDLcsVhRReJ4otXhfi2kD2FrppRUqQYtXXZ7LgQrNy5', quoteVault: 'HrKrc1mh6jQr6Sa1DAZ9JBbpKDvTTrgkEkAHSp28tven', seedId: 'CAQi1pkhRPsCi24uyF6NnGm5Two1Bq2AhrDZrM9Mtfjs' }, { base: { ...TOKENS.MEDIA }, quote: { ...TOKENS.USDC }, price: new TokenAmount(10, TOKENS.USDC.decimals, false), raise: new TokenAmount(50000, TOKENS.MEDIA.decimals, false), version: 1, programId: IDO_PROGRAM_ID, snapshotProgramId: '4kCccBVdQpsonm2jL2TRV1noMdarsWR2mhwwkxUTqW3W', isRayPool: true, isPrivate: false, idoId: 'EFnvwDxehFLycdUp6DiwcyBTz88qcZFP3KUDfmPU4Fdc', baseVault: '2WCoJRu1w6awJR7PvCc1mWKR9XpPNZDFyBDBX713k8ng', quoteVault: '21XBxBZn3tX8aaJKm1KKm6sWsLUxsMedV3a1CvNBW2m9' }, { base: { ...TOKENS.MEDIA }, quote: { ...TOKENS.USDC }, price: new TokenAmount(10, TOKENS.USDC.decimals, false), raise: new TokenAmount(50000, TOKENS.MEDIA.decimals, false), version: 1, programId: IDO_PROGRAM_ID, snapshotProgramId: '11111111111111111111111111111111', isRayPool: false, isPrivate: false, idoId: '3phgXrkHbMmVLUbUvXPXsnot9WxkdyvVEyiA8odyWY8s', baseVault: '2Gxcw4Vo7zGGNg9JxksrWYazcpQTWNi8JdQkF3bF5yaN', quoteVault: '6TyVHwiEaDRQCf398QjvC6JLqPzK9REvMiS6DsCWG5o4' } ] export function getIdoPoolById(idoId: string) { const pool = IDO_POOLS.find((pool) => pool.idoId === idoId) if (pool) { return cloneDeep(pool) } return pool } export const IDO_POOL_INFO_LAYOUT = struct([ u64('status'), u64('nonce'), u64('startTime'), u64('endTime'), u64('startWithdrawTime'), u64('numerator'), u64('denominator'), u64('quoteTokenDeposited'), u64('baseTokenSupply'), u64('minDepositLimit'), u64('maxDepositLimit'), u64('minStakeLimit'), publicKey('quoteTokenMint'), publicKey('baseTokenMint'), publicKey('quoteTokenVault'), publicKey('baseTokenVault'), publicKey('stakePoolId'), publicKey('stakeProgramId'), publicKey('checkProgramId'), publicKey('idoOwner') ]) export const IDO_LOTTERY_POOL_INFO_LAYOUT = struct([ u64('status'), u64('nonce'), u64('startTime'), u64('endTime'), u64('startWithdrawTime'), u64('numerator'), u64('denominator'), u64('quoteTokenDeposited'), u64('baseTokenSupply'), u64('perUserMaxLottery'), u64('perUserMinLottery'), u64('perLotteryNeedMinStake'), u64('perLotteryWorthQuoteAmount'), u64('totalWinLotteryLimit'), u64('totalDepositUserNumber'), u64('currentLotteryNumber'), seq( struct([u64('luckyTailDigits'), u64('luckyTailNumber'), u64('luckyWithinNumber'), u64('luckyNumberExist')]), 10, 'luckyInfos' ), publicKey('quoteTokenMint'), publicKey('baseTokenMint'), publicKey('quoteTokenVault'), publicKey('baseTokenVault'), publicKey('stakePoolId'), publicKey('stakeProgramId'), publicKey('checkProgramId'), publicKey('idoOwner'), publicKey('poolSeedId'), u64('isWinning') // 0: not start 1: data is for choose win 2: data is for choose lose 3: all wins ]) export const IDO_USER_INFO_LAYOUT = struct([ u64('state'), publicKey('idoPoolId'), publicKey('owner'), u64('quoteTokenDeposited') ]) export const IDO_LOTTERY_USER_INFO_LAYOUT = struct([ u64('state'), publicKey('idoPoolId'), publicKey('owner'), u64('quoteTokenDeposited'), u64('quoteTokenWithdrawn'), u64('baseTokenWithdrawn'), u64('lotteryBeginNumber'), u64('lotteryEndNumber') ]) export const IDO_LOTTERY_SNAPSHOT_DATA_LAYOUT = struct([u64('eligibleTicketAmount')]) export async function findAssociatedIdoInfoAddress(idoId: PublicKey, walletAddress: PublicKey, programId: PublicKey) { const { publicKey } = await findProgramAddress( [idoId.toBuffer(), walletAddress.toBuffer(), new Uint8Array(Buffer.from('ido_associated_seed', 'utf-8'))], programId ) return publicKey } export async function findAssociatedIdoCheckAddress( idoId: PublicKey, walletAddress: PublicKey, snapshotProgramId: PublicKey ) { const { publicKey } = await findProgramAddress( [idoId.toBuffer(), walletAddress.toBuffer(), snapshotProgramId.toBuffer()], snapshotProgramId ) return publicKey } export async function purchase({ connection, wallet, poolInfo, userQuoteTokenAccount, stakeInfoAccount, amount }: { connection: Connection wallet: any poolInfo: IdoPool userQuoteTokenAccount: string stakeInfoAccount: string amount: string | number }) { if (!connection || !wallet) throw new Error('Miss connection') if (!poolInfo) throw new Error('Miss pool infomations') if (!amount) throw new Error('Miss amount infomations') const transaction = new Transaction() const signers: Account[] = [] const owner = wallet.publicKey const { publicKey: idoAuthority } = await findProgramAddress( [new PublicKey(poolInfo.idoId).toBuffer()], new PublicKey(poolInfo.programId) ) const userIdoInfo = await findAssociatedIdoInfoAddress( new PublicKey(poolInfo.idoId), owner, new PublicKey(poolInfo.programId) ) const userIdoCheck = poolInfo.version === 1 ? await findAssociatedIdoCheckAddress( new PublicKey(poolInfo.idoId), owner, new PublicKey(poolInfo.snapshotProgramId) ) : await findAssociatedIdoCheckAddress( new PublicKey(poolInfo.seedId ?? 'CAQi1pkhRPsCi24uyF6NnGm5Two1Bq2AhrDZrM9Mtfjs'), owner, new PublicKey(poolInfo.snapshotProgramId) ) transaction.add( poolInfo.version === 3 // transaction point to lottery ? purchaseInstruction<'3'>( { programId: new PublicKey(poolInfo.programId), amount }, { idoId: new PublicKey(poolInfo.idoId), authority: idoAuthority, poolQuoteTokenAccount: new PublicKey(poolInfo.quoteVault), userQuoteTokenAccount: new PublicKey(userQuoteTokenAccount), userIdoInfo, userOwner: owner, userIdoCheck } ) : poolInfo.isPrivate ? purchaseInstruction<'private'>( { programId: new PublicKey(poolInfo.programId), amount: getBigNumber(new TokenAmount(amount, poolInfo.quote.decimals, false).wei) }, { idoId: new PublicKey(poolInfo.idoId), authority: idoAuthority, poolQuoteTokenAccount: new PublicKey(poolInfo.quoteVault), userQuoteTokenAccount: new PublicKey(userQuoteTokenAccount), userIdoInfo, userOwner: owner, userIdoCheck } ) : purchaseInstruction( { programId: new PublicKey(poolInfo.programId), amount: getBigNumber(new TokenAmount(amount, poolInfo.quote.decimals, false).wei) }, { idoId: new PublicKey(poolInfo.idoId), authority: idoAuthority, poolQuoteTokenAccount: new PublicKey(poolInfo.quoteVault), userQuoteTokenAccount: new PublicKey(userQuoteTokenAccount), userIdoInfo, userOwner: owner, userStakeInfo: new PublicKey(stakeInfoAccount), userIdoCheck } ) ) return await sendTransaction(connection, wallet, transaction, signers) } export async function claim({ connection, wallet, poolInfo, userBaseTokenAccount, userQuoteTokenAccount, aim }: { connection: Connection wallet: any poolInfo: IdoPool userBaseTokenAccount: string userQuoteTokenAccount: string /** * this is only for lottery * the property indicate which coin user want to withdraw */ aim?: 'quote' | 'base' }) { if (!connection || !wallet) throw new Error('Miss connection') if (!poolInfo) throw new Error('Miss pool infomations') const transaction = new Transaction() const signers: Account[] = [] const owner = wallet.publicKey const newUserBaseTokenAccount = userBaseTokenAccount ? new PublicKey(userBaseTokenAccount) : await createAssociatedTokenAccount(new PublicKey(poolInfo.base.mintAddress), owner, transaction) const newUserQuoteTokenAccount = userQuoteTokenAccount ? new PublicKey(userQuoteTokenAccount) : await createAssociatedTokenAccount(new PublicKey(poolInfo.quote.mintAddress), owner, transaction) const { publicKey: idoAuthority } = await findProgramAddress( [new PublicKey(poolInfo.idoId).toBuffer()], new PublicKey(poolInfo.programId) ) const userIdoInfo = await findAssociatedIdoInfoAddress( new PublicKey(poolInfo.idoId), owner, new PublicKey(poolInfo.programId) ) transaction.add( poolInfo.version === 3 // transaction point to lottery ? claimInstruction<'3'>( { programId: new PublicKey(poolInfo.programId) }, { idoId: new PublicKey(poolInfo.idoId), authority: idoAuthority, poolTokenAccount: new PublicKey(aim === 'base' ? poolInfo.baseVault : poolInfo.quoteVault), userTokenAccount: aim === 'base' ? newUserBaseTokenAccount : newUserQuoteTokenAccount, userIdoInfo, userOwner: owner } ) : claimInstruction( { programId: new PublicKey(poolInfo.programId) }, { idoId: new PublicKey(poolInfo.idoId), authority: idoAuthority, poolQuoteTokenAccount: new PublicKey(poolInfo.quoteVault), poolBaseTokenAccount: new PublicKey(poolInfo.baseVault), userQuoteTokenAccount: newUserQuoteTokenAccount, userBaseTokenAccount: newUserBaseTokenAccount, userIdoInfo, userOwner: owner } ) ) return await sendTransaction(connection, wallet, transaction, signers) } interface PurchaseInstructionKeys { // ido idoId: PublicKey authority: PublicKey poolQuoteTokenAccount: PublicKey // user userQuoteTokenAccount: PublicKey userIdoInfo: PublicKey userStakeInfo: PublicKey userIdoCheck: PublicKey userOwner: PublicKey } interface PurchaseInstructionKeysV3 { // ido idoId: PublicKey authority: PublicKey poolQuoteTokenAccount: PublicKey // user userQuoteTokenAccount: PublicKey userIdoInfo: PublicKey userIdoCheck: PublicKey userOwner: PublicKey } interface PurchaseInstructionKeysPrivate { // ido idoId: PublicKey authority: PublicKey poolQuoteTokenAccount: PublicKey // user userQuoteTokenAccount: PublicKey userIdoInfo: PublicKey userIdoCheck: PublicKey userOwner: PublicKey } export function purchaseInstruction<Flag extends '' | '3' | 'private' = ''>( { programId, amount }: { programId: PublicKey; amount: string | number }, instructionKeys: Flag extends '3' ? PurchaseInstructionKeysV3 : Flag extends 'private' ? PurchaseInstructionKeysPrivate : PurchaseInstructionKeys ): TransactionInstruction { const dataLayout = struct([u8('instruction'), nu64('amount')]) const keys = [ // system { pubkey: SYSTEM_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: RENT_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: CLOCK_PROGRAM_ID, isSigner: false, isWritable: false }, // pubkeys ...Object.entries(instructionKeys).map(([name, pubkey]) => ({ pubkey, isSigner: name === 'userOwner', isWritable: !['authority', 'userOwner', 'userIdoCheck', 'userStakeInfo'].includes(name) })) ] const data = Buffer.alloc(dataLayout.span) dataLayout.encode({ instruction: 1, amount: Number(amount) }, data) return new TransactionInstruction({ keys, programId, data }) } interface ClaimInstructionKeys { // ido idoId: PublicKey authority: PublicKey poolQuoteTokenAccount: PublicKey poolBaseTokenAccount: PublicKey // user userQuoteTokenAccount: PublicKey userBaseTokenAccount: PublicKey userIdoInfo: PublicKey userOwner: PublicKey } interface ClaimInstructionKeysV3 { // ido idoId: PublicKey authority: PublicKey poolTokenAccount: PublicKey // NEED_CHECK: is it Quote or Base? // user userTokenAccount: PublicKey // NEED_CHECK: is it Quote or Base? // differernt account in user wallet userIdoInfo: PublicKey userOwner: PublicKey } export function claimInstruction<Version extends '' | '3' = ''>( { programId }: { programId: PublicKey }, instructionKeys: Version extends '3' ? ClaimInstructionKeysV3 : ClaimInstructionKeys ): TransactionInstruction { const dataLayout = struct([u8('instruction')]) const keys = [ { pubkey: TOKEN_PROGRAM_ID, isSigner: false, isWritable: false }, { pubkey: CLOCK_PROGRAM_ID, isSigner: false, isWritable: false }, ...Object.entries(instructionKeys).map(([name, pubkey]) => ({ pubkey, isSigner: name === 'userOwner', isWritable: !['authority', 'userOwner'].includes(name) })) ] const data = Buffer.alloc(dataLayout.span) dataLayout.encode({ instruction: 2 }, data) return new TransactionInstruction({ keys, programId, data }) }