Skip to content

Instantly share code, notes, and snippets.

@omgbbqhaxx
Created December 21, 2021 20:58
Show Gist options
  • Save omgbbqhaxx/5236a1abc864e2dceb28fe2b8ad914f9 to your computer and use it in GitHub Desktop.
Save omgbbqhaxx/5236a1abc864e2dceb28fe2b8ad914f9 to your computer and use it in GitHub Desktop.
lib.rs
//! 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