Created
December 21, 2021 20:58
-
-
Save omgbbqhaxx/5236a1abc864e2dceb28fe2b8ad914f9 to your computer and use it in GitHub Desktop.
lib.rs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//! An IDO pool program implementing the Mango Markets token sale design here: | |
//! https://docs.mango.markets/litepaper#token-sale. | |
use anchor_lang::prelude::*; | |
use anchor_lang::solana_program::program_option::COption; | |
use anchor_spl::token::{self, Burn, Mint, MintTo, TokenAccount, Transfer}; | |
declare_id!("2xYSvW9TbU7wnefXnBrnAqpwTnMckMG53XeENv1kdrdw"); | |
#[program] | |
pub mod ido_pool { | |
use super::*; | |
#[access_control(InitializePool::accounts(&ctx, nonce) future_start_time(&ctx, start_ido_ts))] | |
pub fn initialize_pool( | |
ctx: Context<InitializePool>, | |
num_ido_tokens: u64, | |
nonce: u8, | |
start_ido_ts: i64, | |
end_deposits_ts: i64, | |
end_ido_ts: i64, | |
) -> Result<()> { | |
if !(start_ido_ts < end_deposits_ts && end_deposits_ts < end_ido_ts) { | |
return Err(ErrorCode::SeqTimes.into()); | |
} | |
let pool_account = &mut ctx.accounts.pool_account; | |
pool_account.redeemable_mint = *ctx.accounts.redeemable_mint.to_account_info().key; | |
pool_account.pool_watermelon = *ctx.accounts.pool_watermelon.to_account_info().key; | |
pool_account.watermelon_mint = ctx.accounts.pool_watermelon.mint; | |
pool_account.distribution_authority = *ctx.accounts.distribution_authority.key; | |
pool_account.nonce = nonce; | |
pool_account.num_ido_tokens = num_ido_tokens; | |
pool_account.start_ido_ts = start_ido_ts; | |
pool_account.end_deposits_ts = end_deposits_ts; | |
pool_account.end_ido_ts = end_ido_ts; | |
// Transfer Watermelon from creator to pool account. | |
let cpi_accounts = Transfer { | |
from: ctx.accounts.creator_watermelon.to_account_info(), | |
to: ctx.accounts.pool_watermelon.to_account_info(), | |
authority: ctx.accounts.distribution_authority.to_account_info(), | |
}; | |
let cpi_program = ctx.accounts.token_program.clone(); | |
let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts); | |
token::transfer(cpi_ctx, num_ido_tokens)?; | |
Ok(()) | |
} | |
//Yarattığımız token'i blockchain'e başarılı bir şekilde upload etttik yani kendi kontratımıza ait account'a şimdi de withdrawal our | |
//adında bir fonssiyon yazalım ve bu yarattığımız tokenları yatırdığımız kontrattan geri çekelim!!!!!!!!!! | |
//#[access_control(ido_over(&ctx.accounts.pool_account, &ctx.accounts.clock))] | |
pub fn exchange_redeemable_for_watermelon( | |
ctx: Context<ExchangeRedeemableForWatermelon>, | |
) -> Result<()> { | |
// While token::burn will check this, we prefer a verbose err msg. | |
//Burada isterseniz burn edebilirsiniz ama biz err mesajı vermeyi uygun gördük diyor | |
// if ctx.accounts.user_redeemable.amount < amount { | |
// return Err(ErrorCode::LowRedeemable.into()); | |
// } | |
// Calculate watermelon tokens due. | |
let watermelon_amount = 444000000 as u64; | |
// Burn the user's redeemable tokens. | |
// let cpi_accounts = Burn { | |
// mint: ctx.accounts.redeemable_mint.to_account_info(), | |
// to: ctx.accounts.user_redeemable.to_account_info(), | |
// authority: ctx.accounts.user_authority.to_account_info(), | |
// }; | |
// let cpi_program = ctx.accounts.token_program.clone(); | |
// let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts); | |
// token::burn(cpi_ctx, amount)?; | |
// Transfer Watermelon from pool account to user. | |
let seeds = &[ | |
ctx.accounts.pool_account.watermelon_mint.as_ref(), | |
&[ctx.accounts.pool_account.nonce], | |
]; | |
let signer = &[&seeds[..]]; | |
let cpi_accounts = Transfer { | |
from: ctx.accounts.pool_watermelon.to_account_info(), | |
to: ctx.accounts.user_watermelon.to_account_info(), | |
authority: ctx.accounts.pool_signer.to_account_info(), | |
}; | |
let cpi_program = ctx.accounts.token_program.clone(); | |
let cpi_ctx = CpiContext::new_with_signer(cpi_program, cpi_accounts, signer); | |
token::transfer(cpi_ctx, watermelon_amount as u64)?; | |
msg!("Just learn rustlang or have fun staying poor"); | |
Ok(()) | |
} | |
} | |
#[derive(Accounts)] | |
pub struct InitializePool<'info> { | |
#[account(zero)] | |
pub pool_account: Box<Account<'info, PoolAccount>>, | |
pub pool_signer: AccountInfo<'info>, | |
#[account( | |
constraint = redeemable_mint.mint_authority == COption::Some(*pool_signer.key), | |
constraint = redeemable_mint.supply == 0 | |
)] | |
pub redeemable_mint: Account<'info, Mint>, | |
#[account(mut, constraint = pool_watermelon.owner == *pool_signer.key)] | |
pub pool_watermelon: Account<'info, TokenAccount>, | |
#[account(signer)] | |
pub distribution_authority: AccountInfo<'info>, | |
#[account(mut, constraint = creator_watermelon.owner == *distribution_authority.key)] | |
pub creator_watermelon: Account<'info, TokenAccount>, | |
#[account(constraint = token_program.key == &token::ID)] | |
pub token_program: AccountInfo<'info>, | |
pub clock: Sysvar<'info, Clock>, | |
} | |
impl<'info> InitializePool<'info> { | |
fn accounts(ctx: &Context<InitializePool<'info>>, nonce: u8) -> Result<()> { | |
let expected_signer = Pubkey::create_program_address( | |
&[ctx.accounts.pool_watermelon.mint.as_ref(), &[nonce]], | |
ctx.program_id, | |
) | |
.map_err(|_| ErrorCode::InvalidNonce)?; | |
if ctx.accounts.pool_signer.key != &expected_signer { | |
return Err(ErrorCode::InvalidNonce.into()); | |
} | |
Ok(()) | |
} | |
} | |
#[derive(Accounts)] | |
pub struct ExchangeRedeemableForWatermelon<'info> { | |
#[account(has_one = pool_watermelon)] | |
pub pool_account: Account<'info, PoolAccount>, | |
#[account( | |
seeds = [pool_account.watermelon_mint.as_ref()], | |
bump = pool_account.nonce, | |
)] | |
pool_signer: AccountInfo<'info>, | |
#[account(mut, constraint = pool_watermelon.owner == *pool_signer.key)] | |
pub pool_watermelon: Account<'info, TokenAccount>, | |
#[account(signer)] | |
pub user_authority: AccountInfo<'info>, | |
#[account(mut, constraint = user_watermelon.owner == *user_authority.key)] | |
pub user_watermelon: Account<'info, TokenAccount>, | |
#[account(constraint = token_program.key == &token::ID)] | |
pub token_program: AccountInfo<'info>, | |
pub clock: Sysvar<'info, Clock>, | |
} | |
#[account] | |
pub struct PoolAccount { | |
pub redeemable_mint: Pubkey, | |
pub pool_watermelon: Pubkey, | |
pub watermelon_mint: Pubkey, | |
pub pool_usdc: Pubkey, | |
pub distribution_authority: Pubkey, | |
pub nonce: u8, | |
pub num_ido_tokens: u64, | |
pub start_ido_ts: i64, | |
pub end_deposits_ts: i64, | |
pub end_ido_ts: i64, | |
} | |
// Access control modifiers. | |
// Asserts the IDO starts in the future. | |
fn future_start_time<'info>(ctx: &Context<InitializePool<'info>>, start_ido_ts: i64) -> Result<()> { | |
if !(ctx.accounts.clock.unix_timestamp < start_ido_ts) { | |
return Err(ErrorCode::IdoFuture.into()); | |
} | |
Ok(()) | |
} | |
#[error] | |
pub enum ErrorCode { | |
#[msg("IDO must start in the future")] | |
IdoFuture, | |
#[msg("IDO times are non-sequential")] | |
SeqTimes, | |
#[msg("IDO has not started")] | |
StartIdoTime, | |
#[msg("Deposits period has ended")] | |
EndDepositsTime, | |
#[msg("IDO has ended")] | |
EndIdoTime, | |
#[msg("IDO has not finished yet")] | |
IdoNotOver, | |
#[msg("Insufficient USDC")] | |
LowUsdc, | |
#[msg("Insufficient redeemable tokens")] | |
LowRedeemable, | |
#[msg("USDC total and redeemable total don't match")] | |
UsdcNotEqRedeem, | |
#[msg("Given nonce is invalid")] | |
InvalidNonce, | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment