More Solana Contribute functionality

This commit is contained in:
skojenov 2022-04-26 20:25:41 +00:00 committed by Karl Kempe
parent 61083a86e3
commit 213f999cd2
6 changed files with 56 additions and 12 deletions

View File

@ -74,6 +74,7 @@ impl<'b, const STATE: AccountState> Seeded<&ContributionStateAccountDerivationDa
pub type CustodyAccount<'b, const STATE: AccountState> = Data<'b, SplAccount, { STATE }>;
pub struct CustodyAccountDerivationData {
pub sale_id: u128,
pub mint: Pubkey,
}

View File

@ -14,7 +14,9 @@ use crate::{
CustodyAccountDerivationData,
ContributionStateAccount,
ContributionStateAccountDerivationData,
AuthoritySigner,
},
errors::Error::*,
types::*,
};
@ -62,6 +64,7 @@ pub struct ContributeIccoSale<'b> {
pub from: Mut<Data<'b, SplAccount, { AccountState::Initialized }>>, // From account
pub mint: Mut<Data<'b, SplMint, { AccountState::Initialized }>>, // From token
pub authority_signer: AuthoritySigner<'b>,
pub custody_signer: CustodySigner<'b>,
pub custody: Mut<CustodyAccount<'b, { AccountState::MaybeInitialized }>>, // TBD Move custody Account init to separate call. By Sale creator before init sale. In case sale creator needs to pay for it.
@ -80,6 +83,7 @@ impl<'a> From<&ContributeIccoSale<'a>> for SaleStateDerivationData {
impl<'a> From<&ContributeIccoSale<'a>> for CustodyAccountDerivationData {
fn from(accs: &ContributeIccoSale<'a>) -> Self {
CustodyAccountDerivationData {
sale_id: accs.init_sale_vaa.sale_id,
mint: *accs.mint.info().key,
}
}
@ -98,7 +102,8 @@ impl<'a> From<&ContributeIccoSale<'a>> for ContributionStateAccountDerivationDat
#[derive(BorshDeserialize, BorshSerialize, Default)]
pub struct ContributeIccoSaleData {
amount: u128,
amount: u64,
token_idx: u8,
}
impl<'b> InstructionContext<'b> for ContributeIccoSale<'b> {
@ -111,6 +116,34 @@ pub fn contribute_icco_sale(
) -> Result<()> {
msg!("bbrp in contribute_icco_sale!");
// Check sale status.
if accs.sale_state.is_sealed || accs.sale_state.is_aborted {
return Err(SaleSealedOrAborted.into());
}
// Check if sale started.
// require(block.timestamp >= start, "sale not yet started");
// require(block.timestamp <= end, "sale has ended");
let now_time = accs.clock.unix_timestamp as u128; // i64 ->u128
if now_time < accs.init_sale_vaa.get_sale_start(&accs.init_sale_vaa.meta().payload[..]).0 {
return Err(SaleHasNotStarted.into());
}
if now_time > accs.init_sale_vaa.get_sale_end(&accs.init_sale_vaa.meta().payload[..]).0 {
return Err(SaleHasEnded.into());
}
// Make sure token Idx matches passed in token mint addr.
let token_idx = data.token_idx;
if token_idx >= accs.init_sale_vaa.token_cnt {
return Err(InvalidTokenIndex.into());
}
let token_idx = usize::from(token_idx);
let &token_addr = &accs.init_sale_vaa.get_accepted_token_address(token_idx, &accs.init_sale_vaa.meta().payload[..]);
let token_chain = accs.init_sale_vaa.get_accepted_token_chain(token_idx, &accs.init_sale_vaa.meta().payload[..]);
if &token_addr != accs.mint.info().key || token_chain != CHAIN_ID_SOLANA {
return Err(InvalidTokenAddress.into());
}
// Create and init custody account as needed.
// https://github.com/certusone/wormhole/blob/1792141307c3979b1f267af3e20cfc2f011d7051/solana/modules/token_bridge/program/src/api/transfer.rs#L159
if !accs.custody.is_initialized() {
@ -130,7 +163,16 @@ pub fn contribute_icco_sale(
accs.contribution_state.create(&(&*accs).into(), ctx, accs.payer.key, Exempt)?;
}
// TBD Do the from->custody non-WH transfer.
// TBD Transfer tokens from->custody non-WH transfer.
let transfer_ix = spl_token::instruction::transfer(
&spl_token::id(),
accs.from.info().key,
accs.custody.info().key,
accs.authority_signer.key,
&[],
data.amount,
)?;
invoke_seeded(&transfer_ix, ctx, &accs.authority_signer, None)?;
// store new amount.
accs.contribution_state.amount = accs.contribution_state.amount + data.amount;

View File

@ -29,15 +29,11 @@ use crate::{
SaleStateAccount,
SaleStateDerivationData,
},
};
use crate:: {
errors::Error::{
VAAInvalidEmitterChain,
}
},
};
use solana_program::msg;
use solana_program::{

View File

@ -9,6 +9,11 @@ pub enum Error {
VAAAlreadyExecuted,
VAAInvalidEmitterChain,
VAAInvalid,
InvalidTokenAddress,
InvalidTokenIndex,
SaleSealedOrAborted,
SaleHasNotStarted,
SaleHasEnded,
}
/// Errors thrown by the program will bubble up to the solitaire wrapper, which needs a way to

View File

@ -41,8 +41,8 @@ fn read_u256(buf: &[u8]) -> (u128, u128) {
#[derive(PartialEq, Debug)]
#[allow(non_snake_case)]
pub struct SaleInit {
payload_id: u8, // Sale ID
token_cnt: u8,
payload_id: u8, // 1
pub token_cnt: u8,
pub sale_id: u128,
}

View File

@ -27,8 +27,8 @@ impl Owned for Config {
/// icco sale state. Writeable in init, seal, abort.
#[derive(Default, Clone, Copy, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
pub struct SaleState {
pub is_sealed: u8,
pub is_aborted: u8,
pub is_sealed: bool,
pub is_aborted: bool,
}
impl Owned for SaleState {
@ -41,7 +41,7 @@ impl Owned for SaleState {
/// icco contribution state. Writeable in contribute, redeem, refund.
#[derive(Default, Clone, Copy, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
pub struct ContributionState {
pub amount: u128,
pub amount: u64,
pub is_redeemed_or_refunded: u8,
}