|
|
|
@ -18,10 +18,8 @@ pub mod lottery_simple { |
|
|
|
state.total_supply = 0; |
|
|
|
state.total_supply = 0; |
|
|
|
state.dev_fee_bps = 300; // 3%
|
|
|
|
state.dev_fee_bps = 300; // 3%
|
|
|
|
state.dividend_fee_bps = 200; // 2%
|
|
|
|
state.dividend_fee_bps = 200; // 2%
|
|
|
|
state.token_price_initial = 100_000; // 0.0001 SOL
|
|
|
|
|
|
|
|
state.token_price_increment = 10_000; // 0.00001 SOL per token
|
|
|
|
|
|
|
|
state.profit_per_share = 0; |
|
|
|
state.profit_per_share = 0; |
|
|
|
msg!("PoWH initialized with mint: {}", ctx.accounts.mint.key()); |
|
|
|
msg!("Init: {}", ctx.accounts.mint.key()); |
|
|
|
Ok(()) |
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -30,7 +28,7 @@ pub mod lottery_simple { |
|
|
|
user.owner = ctx.accounts.owner.key(); |
|
|
|
user.owner = ctx.accounts.owner.key(); |
|
|
|
user.token_account = ctx.accounts.token_account.key(); |
|
|
|
user.token_account = ctx.accounts.token_account.key(); |
|
|
|
user.dividends_withdrawn = 0; |
|
|
|
user.dividends_withdrawn = 0; |
|
|
|
msg!("User registered: {}", ctx.accounts.owner.key()); |
|
|
|
msg!("User: {}", ctx.accounts.owner.key()); |
|
|
|
Ok(()) |
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -91,7 +89,7 @@ pub mod lottery_simple { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Calculate tokens to mint using bonding curve
|
|
|
|
// Calculate tokens to mint using bonding curve
|
|
|
|
let tokens_to_mint = calculate_tokens_for_sol(net_purchase as u64, state.total_supply, state)?; |
|
|
|
let tokens_to_mint = calculate_tokens_for_sol(net_purchase as u64, state.total_supply)?; |
|
|
|
|
|
|
|
|
|
|
|
// Mint tokens to buyer
|
|
|
|
// Mint tokens to buyer
|
|
|
|
let seeds = &[b"state".as_ref(), &[state_bump]]; |
|
|
|
let seeds = &[b"state".as_ref(), &[state_bump]]; |
|
|
|
@ -117,7 +115,7 @@ pub mod lottery_simple { |
|
|
|
is_buy: true, |
|
|
|
is_buy: true, |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
msg!("Bought {} tokens for {} SOL", tokens_to_mint, sol_amount); |
|
|
|
msg!("Buy: {} for {}", tokens_to_mint, sol_amount); |
|
|
|
Ok(()) |
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -127,12 +125,12 @@ pub mod lottery_simple { |
|
|
|
require!(ctx.accounts.seller_token_account.amount >= tokens_to_sell, ErrorCode::InsufficientFunds); |
|
|
|
require!(ctx.accounts.seller_token_account.amount >= tokens_to_sell, ErrorCode::InsufficientFunds); |
|
|
|
|
|
|
|
|
|
|
|
// Calculate SOL to return using bonding curve
|
|
|
|
// Calculate SOL to return using bonding curve
|
|
|
|
let calculated_sol = calculate_sol_for_tokens(tokens_to_sell, state.total_supply, state)?; |
|
|
|
let calculated_sol = calculate_sol_for_tokens(tokens_to_sell, state.total_supply)?; |
|
|
|
|
|
|
|
|
|
|
|
// Safety check: limit to vault balance to prevent errors
|
|
|
|
// Safety check: limit to vault balance to prevent errors
|
|
|
|
let vault_balance = ctx.accounts.vault.to_account_info().lamports(); |
|
|
|
let vault_balance = ctx.accounts.vault.to_account_info().lamports(); |
|
|
|
let sol_to_return = if calculated_sol > vault_balance { |
|
|
|
let sol_to_return = if calculated_sol > vault_balance { |
|
|
|
msg!("Calculated return {} exceeds vault balance {}, limiting to vault balance", calculated_sol, vault_balance); |
|
|
|
msg!("Limit: {} > {}", calculated_sol, vault_balance); |
|
|
|
// Leave enough for rent exemption - be more conservative
|
|
|
|
// Leave enough for rent exemption - be more conservative
|
|
|
|
vault_balance.saturating_sub(5000) // Leave 5000 lamports for rent exemption
|
|
|
|
vault_balance.saturating_sub(5000) // Leave 5000 lamports for rent exemption
|
|
|
|
} else { |
|
|
|
} else { |
|
|
|
@ -159,7 +157,7 @@ pub mod lottery_simple { |
|
|
|
**ctx.accounts.vault.to_account_info().try_borrow_mut_lamports()? -= sol_to_return; |
|
|
|
**ctx.accounts.vault.to_account_info().try_borrow_mut_lamports()? -= sol_to_return; |
|
|
|
**ctx.accounts.seller.to_account_info().try_borrow_mut_lamports()? += sol_to_return; |
|
|
|
**ctx.accounts.seller.to_account_info().try_borrow_mut_lamports()? += sol_to_return; |
|
|
|
|
|
|
|
|
|
|
|
msg!("Transferred {} lamports from vault to seller", sol_to_return); |
|
|
|
msg!("Transfer: {}", sol_to_return); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
emit!(TradeEvent { |
|
|
|
emit!(TradeEvent { |
|
|
|
@ -169,7 +167,7 @@ pub mod lottery_simple { |
|
|
|
is_buy: false, |
|
|
|
is_buy: false, |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
msg!("Sold {} tokens for {} SOL", tokens_to_sell, sol_to_return); |
|
|
|
msg!("Sell: {} for {}", tokens_to_sell, sol_to_return); |
|
|
|
Ok(()) |
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -196,13 +194,13 @@ pub mod lottery_simple { |
|
|
|
amount: available_dividends as u64, |
|
|
|
amount: available_dividends as u64, |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
msg!("Withdrew {} lamports in dividends", available_dividends); |
|
|
|
msg!("Withdraw: {}", available_dividends); |
|
|
|
Ok(()) |
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Realistic bonding curve based on actual SOL in vault
|
|
|
|
// Realistic bonding curve based on actual SOL in vault
|
|
|
|
fn calculate_tokens_for_sol(sol: u64, supply: u64, _state: &PowhState) -> Result<u64> { |
|
|
|
fn calculate_tokens_for_sol(sol: u64, supply: u64) -> Result<u64> { |
|
|
|
// Linear bonding curve: price increases with supply
|
|
|
|
// Linear bonding curve: price increases with supply
|
|
|
|
// Base price: 0.0001 SOL per token (100,000 lamports per token)
|
|
|
|
// Base price: 0.0001 SOL per token (100,000 lamports per token)
|
|
|
|
// Price increases by 0.00001 SOL per billion tokens in supply
|
|
|
|
// Price increases by 0.00001 SOL per billion tokens in supply
|
|
|
|
@ -213,11 +211,11 @@ fn calculate_tokens_for_sol(sol: u64, supply: u64, _state: &PowhState) -> Result |
|
|
|
let current_price = base_price_lamports + (price_increment * supply_factor); |
|
|
|
let current_price = base_price_lamports + (price_increment * supply_factor); |
|
|
|
let tokens = (sol as u128 * 1_000_000_000) / current_price; // Convert lamports to tokens
|
|
|
|
let tokens = (sol as u128 * 1_000_000_000) / current_price; // Convert lamports to tokens
|
|
|
|
|
|
|
|
|
|
|
|
msg!("Buy: {} lamports -> {} tokens at price {} lamports per token", sol, tokens, current_price); |
|
|
|
msg!("Buy calc: {}->{}", sol, tokens); |
|
|
|
Ok(tokens as u64) |
|
|
|
Ok(tokens as u64) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn calculate_sol_for_tokens(tokens: u64, supply: u64, _state: &PowhState) -> Result<u64> { |
|
|
|
fn calculate_sol_for_tokens(tokens: u64, supply: u64) -> Result<u64> { |
|
|
|
// Sell at 90% of current buy price to create spread
|
|
|
|
// Sell at 90% of current buy price to create spread
|
|
|
|
let base_price_lamports = 100_000u128; |
|
|
|
let base_price_lamports = 100_000u128; |
|
|
|
let price_increment = 10_000u128; |
|
|
|
let price_increment = 10_000u128; |
|
|
|
@ -227,7 +225,7 @@ fn calculate_sol_for_tokens(tokens: u64, supply: u64, _state: &PowhState) -> Res |
|
|
|
let sell_price = (current_price * 90) / 100; // 90% of buy price
|
|
|
|
let sell_price = (current_price * 90) / 100; // 90% of buy price
|
|
|
|
let sol_lamports = (tokens as u128 * sell_price) / 1_000_000_000; |
|
|
|
let sol_lamports = (tokens as u128 * sell_price) / 1_000_000_000; |
|
|
|
|
|
|
|
|
|
|
|
msg!("Sell: {} tokens -> {} lamports at price {} lamports per token", tokens, sol_lamports, sell_price); |
|
|
|
msg!("Sell calc: {}->{}", tokens, sol_lamports); |
|
|
|
Ok(sol_lamports as u64) |
|
|
|
Ok(sol_lamports as u64) |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -419,8 +417,6 @@ pub struct PowhState { |
|
|
|
pub total_supply: u64, |
|
|
|
pub total_supply: u64, |
|
|
|
pub dev_fee_bps: u16, |
|
|
|
pub dev_fee_bps: u16, |
|
|
|
pub dividend_fee_bps: u16, |
|
|
|
pub dividend_fee_bps: u16, |
|
|
|
pub token_price_initial: u64, |
|
|
|
|
|
|
|
pub token_price_increment: u64, |
|
|
|
|
|
|
|
pub profit_per_share: u128, |
|
|
|
pub profit_per_share: u128, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -448,10 +444,10 @@ pub struct WithdrawalEvent { |
|
|
|
|
|
|
|
|
|
|
|
#[error_code] |
|
|
|
#[error_code] |
|
|
|
pub enum ErrorCode { |
|
|
|
pub enum ErrorCode { |
|
|
|
#[msg("Insufficient funds")] |
|
|
|
#[msg("Low funds")] |
|
|
|
InsufficientFunds, |
|
|
|
InsufficientFunds, |
|
|
|
#[msg("Invalid amount")] |
|
|
|
#[msg("Bad amount")] |
|
|
|
InvalidAmount, |
|
|
|
InvalidAmount, |
|
|
|
#[msg("No dividends available")] |
|
|
|
#[msg("No dividends")] |
|
|
|
NoDividends, |
|
|
|
NoDividends, |
|
|
|
} |
|
|
|
} |