This commit is contained in:
bartosz-lipinski 2021-09-16 19:17:02 -05:00
commit 2769079e09
6 changed files with 141 additions and 35 deletions

View File

@ -1617,16 +1617,27 @@ program
const statesFlat = states.flat();
//@ts-ignore;
let numWinnersRemaining = fairLaunchObj.data.numberOfTokens;
let numWinnersRemaining = Math.min(
//@ts-ignore;
fairLaunchObj.data.numberOfTokens,
//@ts-ignore;
statesFlat.filter(s => s.eligible).length,
);
console.log(
'Dunn',
//@ts-ignore;
fairLaunchObj.numberTicketsSold - fairLaunchObj.numberTicketsDropped,
);
let chosen: { seq: anchor.BN; eligible: boolean; chosen: boolean }[];
if (numWinnersRemaining >= statesFlat.length) {
console.log('More or equal nfts than winners, everybody wins.');
chosen = statesFlat.map(s => ({ ...s, chosen: true }));
} else {
console.log('Doing lottery.');
chosen = statesFlat.map(s => ({ ...s, chosen: false }));
console.log('Doing lottery for', numWinnersRemaining);
while (numWinnersRemaining > 0) {
const rand = Math.round(Math.random() * (chosen.length - 1));
if (chosen[rand].chosen != true && chosen[rand].eligible) {
@ -1960,6 +1971,12 @@ program
fairLaunchObj.phaseThreeStarted,
);
console.log(
'Current Eligible Holders',
//@ts-ignore
fairLaunchObj.currentEligibleHolders.toNumber(),
);
console.log(
'Current Median',
//@ts-ignore

View File

@ -41,7 +41,9 @@ import {
import {
FairLaunchAccount,
FairLaunchTicket,
getFairLaunchLotteryBitmap,
getFairLaunchState,
punchTicket,
purchaseTicket,
withdrawFunds,
} from './fair-launch';
@ -129,6 +131,30 @@ export interface HomeProps {
txTimeout: number;
}
const FAIR_LAUNCH_LOTTERY_SIZE =
8 + // discriminator
32 + // fair launch
1 + // bump
8; // size of bitmask ones
const isWinner = (
phaseThree: boolean | undefined,
lottery: Uint8Array | null,
sequence: anchor.BN | undefined,
): boolean => {
if (!lottery || !lottery.length || !sequence || !phaseThree) {
return false;
}
const myByte =
lottery[FAIR_LAUNCH_LOTTERY_SIZE + Math.floor(sequence.toNumber() / 8)];
const positionFromRight = 7 - (sequence.toNumber() % 8);
const mask = Math.pow(2, positionFromRight);
const isWinner = myByte & mask;
return isWinner > 0;
};
const Home = (props: HomeProps) => {
const [balance, setBalance] = useState<number>();
const [isActive, setIsActive] = useState(false); // true when countdown completes
@ -138,6 +164,7 @@ const Home = (props: HomeProps) => {
const [selectedTab, setSelectedTab] = useState(0);
const [ticket, setTicket] = useState<FairLaunchTicket | null>(null);
const [treasury, setTreasury] = useState<number | null>(null);
const [lottery, setLottery] = useState<Uint8Array | null>(null);
const wallet = useWallet();
@ -282,6 +309,19 @@ const Home = (props: HomeProps) => {
state.state.treasury,
);
setTreasury(treasury);
const fairLaunchLotteryBitmap = (
await getFairLaunchLotteryBitmap(
//@ts-ignore
fairLaunchObj.tokenMint,
)
)[0];
const fairLaunchLotteryBitmapObj =
await state.program.provider.connection.getAccountInfo(
fairLaunchLotteryBitmap,
);
setLottery(new Uint8Array(fairLaunchLotteryBitmapObj?.data || []));
console.log();
} catch {
@ -339,6 +379,16 @@ const Home = (props: HomeProps) => {
purchaseTicket(contributed, anchorWallet, fairLaunch, ticket);
};
const onPunchTicket = () => {
if (!anchorWallet || !fairLaunch) {
return;
}
console.log('punch');
punchTicket(anchorWallet, fairLaunch);
};
const onWithdraw = () => {
if (!anchorWallet) {
return;
@ -411,9 +461,19 @@ const Home = (props: HomeProps) => {
{!ticket ? 'Place a bid' : 'Adjust your bid'}
</MintButton>
<Grid>
<Typography>How raffles works</Typography>
</Grid>
{isWinner(
fairLaunch?.state.phaseThreeStarted,
lottery,
ticket?.seq,
) && (
<MintButton onClick={onPunchTicket} variant="contained">
Punch Ticket
</MintButton>
)}
<Grid>
<Typography>How raffles works</Typography>
</Grid>
{wallet.connected && (
<p>Address: {shortenAddress(wallet.publicKey?.toBase58() || '')}</p>

View File

@ -2,7 +2,10 @@ import * as anchor from '@project-serum/anchor';
import { TOKEN_PROGRAM_ID, Token } from '@solana/spl-token';
import { LAMPORTS_PER_SOL } from '@solana/web3.js';
import { getAtaForMint } from './utils';
import {
createAssociatedTokenAccountInstruction,
getAtaForMint,
} from './utils';
export const FAIR_LAUNCH_PROGRAM = new anchor.web3.PublicKey(
'7HmfyvWK7LDohUL9TDAuGv9VFZHUce1SgYMkwti1xWwF',
@ -49,6 +52,7 @@ export interface FairLaunchState {
bump: number;
currentMedian: anchor.BN;
currentEligibleHolders: anchor.BN;
data: {
antiRugSetting?: AntiRugSetting;
fee: anchor.BN;
@ -121,8 +125,8 @@ export const getFairLaunchState = async (
},
};
};
/*
const punchTicket = async (
export const punchTicket = async (
anchorWallet: anchor.Wallet,
fairLaunch: FairLaunchAccount,
) => {
@ -134,9 +138,8 @@ const punchTicket = async (
)
)[0];
const fairLaunchLotteryBitmap = ( //@ts-ignore
await getFairLaunchLotteryBitmap(fairLaunchObj.tokenMint)
)[0];
const fairLaunchLotteryBitmap = //@ts-ignore
(await getFairLaunchLotteryBitmap(fairLaunchObj.tokenMint))[0];
const buyerTokenAccount = (
await getAtaForMint(
@ -167,7 +170,7 @@ const punchTicket = async (
),
],
});
};*/
};
export const getFairLaunchTicket = async (
tokenMint: anchor.web3.PublicKey,
@ -276,8 +279,9 @@ export const purchaseTicket = async (
);
if (ticket) {
const fairLaunchLotteryBitmap = //@ts-ignore
(await getFairLaunchLotteryBitmap(fairLaunch.state.tokenMint))[0];
const fairLaunchLotteryBitmap = ( //@ts-ignore
await getFairLaunchLotteryBitmap(fairLaunch.state.tokenMint)
)[0];
console.log(
'Anchor wallet',
anchorWallet.publicKey.toBase58(),

View File

@ -157,7 +157,7 @@ pub mod fair_launch {
if fair_launch_lottery_bitmap.bitmap_ones
!= std::cmp::min(
fair_launch.data.number_of_tokens,
fair_launch.number_tickets_sold,
fair_launch.current_eligible_holders,
)
{
return Err(ErrorCode::LotteryBitmapOnesMustEqualNumberOfTicketsSold.into());
@ -1195,6 +1195,7 @@ pub const FAIR_LAUNCH_SPACE_VEC_START: usize = 8 + // discriminator
8 + // number of tokens preminted
1 + // phase three started
9 + // treasury snapshot
8 + // current_eligible_holders
8 + // current median,
4 + // u32 representing number of amounts in vec so far
100; // padding
@ -1267,6 +1268,7 @@ pub struct FairLaunch {
pub phase_three_started: bool,
/// Snapshot of treasury taken on first withdrawal.
pub treasury_snapshot: Option<u64>,
pub current_eligible_holders: u64,
pub current_median: u64,
pub counts_at_each_tick: Vec<u64>,
}

View File

@ -121,15 +121,28 @@ pub fn adjust_counts(
}
let mut total_counts: u64 = 0;
let mut ticks: u64 = 0;
let mut first_val_seen = false;
let mut first_val = 0;
for n in &fair_launch.counts_at_each_tick {
total_counts = total_counts
.checked_add(*n)
.ok_or(ErrorCode::NumericalOverflowError)?;
if !first_val_seen && n > &0 {
first_val = ticks
.checked_add(fair_launch.data.price_range_start)
.ok_or(ErrorCode::NumericalOverflowError)?;
first_val_seen = true;
}
ticks = ticks
.checked_add(fair_launch.data.tick_size)
.ok_or(ErrorCode::NumericalOverflowError)?;
}
if total_counts == 1 {
// degen case
fair_launch.current_median = new_amount;
fair_launch.current_median = first_val;
fair_launch.current_eligible_holders = 1;
return Ok(());
}
@ -140,39 +153,49 @@ pub fn adjust_counts(
let mut counter: u64 = 0;
let mut ticks: u64 = 0;
let mut last_seen_tick_value_with_positive_counts: u64 = 0;
let mut current_eligible_holders: u64 = 0;
let mut done: bool = false;
for n in &fair_launch.counts_at_each_tick {
let is_possible_perfect_split = counter == median_location;
counter = counter
.checked_add(*n)
.ok_or(ErrorCode::NumericalOverflowError)?;
if counter > median_location {
if let Some(val) = total_counts.checked_rem(2) {
if val == 0 && is_possible_perfect_split {
let half_way = ticks
.checked_sub(last_seen_tick_value_with_positive_counts)
.ok_or(ErrorCode::NumericalOverflowError)?;
ticks = half_way
.checked_div(2)
.ok_or(ErrorCode::NumericalOverflowError)?;
ticks = last_seen_tick_value_with_positive_counts
.checked_add(ticks)
.ok_or(ErrorCode::NumericalOverflowError)?;
if !done {
if let Some(val) = total_counts.checked_rem(2) {
if val == 0 && is_possible_perfect_split {
let half_way = ticks
.checked_sub(last_seen_tick_value_with_positive_counts)
.ok_or(ErrorCode::NumericalOverflowError)?;
ticks = half_way
.checked_div(2)
.ok_or(ErrorCode::NumericalOverflowError)?;
ticks = last_seen_tick_value_with_positive_counts
.checked_add(ticks)
.ok_or(ErrorCode::NumericalOverflowError)?;
}
}
done = true;
}
break;
current_eligible_holders += n;
}
if n > &0 {
last_seen_tick_value_with_positive_counts = ticks;
if !done {
if n > &0 {
last_seen_tick_value_with_positive_counts = ticks;
}
ticks = ticks
.checked_add(fair_launch.data.tick_size)
.ok_or(ErrorCode::NumericalOverflowError)?;
}
ticks = ticks
.checked_add(fair_launch.data.tick_size)
.ok_or(ErrorCode::NumericalOverflowError)?;
}
fair_launch.current_median = ticks
.checked_add(fair_launch.data.price_range_start)
.ok_or(ErrorCode::NumericalOverflowError)?;
fair_launch.current_eligible_holders = current_eligible_holders;
Ok(())
}

File diff suppressed because one or more lines are too long