More Solana Contribute functionality
This commit is contained in:
parent
61083a86e3
commit
213f999cd2
|
@ -74,6 +74,7 @@ impl<'b, const STATE: AccountState> Seeded<&ContributionStateAccountDerivationDa
|
||||||
pub type CustodyAccount<'b, const STATE: AccountState> = Data<'b, SplAccount, { STATE }>;
|
pub type CustodyAccount<'b, const STATE: AccountState> = Data<'b, SplAccount, { STATE }>;
|
||||||
|
|
||||||
pub struct CustodyAccountDerivationData {
|
pub struct CustodyAccountDerivationData {
|
||||||
|
pub sale_id: u128,
|
||||||
pub mint: Pubkey,
|
pub mint: Pubkey,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,9 @@ use crate::{
|
||||||
CustodyAccountDerivationData,
|
CustodyAccountDerivationData,
|
||||||
ContributionStateAccount,
|
ContributionStateAccount,
|
||||||
ContributionStateAccountDerivationData,
|
ContributionStateAccountDerivationData,
|
||||||
|
AuthoritySigner,
|
||||||
},
|
},
|
||||||
|
errors::Error::*,
|
||||||
types::*,
|
types::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -62,6 +64,7 @@ pub struct ContributeIccoSale<'b> {
|
||||||
|
|
||||||
pub from: Mut<Data<'b, SplAccount, { AccountState::Initialized }>>, // From account
|
pub from: Mut<Data<'b, SplAccount, { AccountState::Initialized }>>, // From account
|
||||||
pub mint: Mut<Data<'b, SplMint, { AccountState::Initialized }>>, // From token
|
pub mint: Mut<Data<'b, SplMint, { AccountState::Initialized }>>, // From token
|
||||||
|
pub authority_signer: AuthoritySigner<'b>,
|
||||||
|
|
||||||
pub custody_signer: CustodySigner<'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.
|
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 {
|
impl<'a> From<&ContributeIccoSale<'a>> for CustodyAccountDerivationData {
|
||||||
fn from(accs: &ContributeIccoSale<'a>) -> Self {
|
fn from(accs: &ContributeIccoSale<'a>) -> Self {
|
||||||
CustodyAccountDerivationData {
|
CustodyAccountDerivationData {
|
||||||
|
sale_id: accs.init_sale_vaa.sale_id,
|
||||||
mint: *accs.mint.info().key,
|
mint: *accs.mint.info().key,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -98,7 +102,8 @@ impl<'a> From<&ContributeIccoSale<'a>> for ContributionStateAccountDerivationDat
|
||||||
|
|
||||||
#[derive(BorshDeserialize, BorshSerialize, Default)]
|
#[derive(BorshDeserialize, BorshSerialize, Default)]
|
||||||
pub struct ContributeIccoSaleData {
|
pub struct ContributeIccoSaleData {
|
||||||
amount: u128,
|
amount: u64,
|
||||||
|
token_idx: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'b> InstructionContext<'b> for ContributeIccoSale<'b> {
|
impl<'b> InstructionContext<'b> for ContributeIccoSale<'b> {
|
||||||
|
@ -111,6 +116,34 @@ pub fn contribute_icco_sale(
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
msg!("bbrp in contribute_icco_sale!");
|
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.
|
// Create and init custody account as needed.
|
||||||
// https://github.com/certusone/wormhole/blob/1792141307c3979b1f267af3e20cfc2f011d7051/solana/modules/token_bridge/program/src/api/transfer.rs#L159
|
// https://github.com/certusone/wormhole/blob/1792141307c3979b1f267af3e20cfc2f011d7051/solana/modules/token_bridge/program/src/api/transfer.rs#L159
|
||||||
if !accs.custody.is_initialized() {
|
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)?;
|
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.
|
// store new amount.
|
||||||
accs.contribution_state.amount = accs.contribution_state.amount + data.amount;
|
accs.contribution_state.amount = accs.contribution_state.amount + data.amount;
|
||||||
|
|
|
@ -29,15 +29,11 @@ use crate::{
|
||||||
SaleStateAccount,
|
SaleStateAccount,
|
||||||
SaleStateDerivationData,
|
SaleStateDerivationData,
|
||||||
},
|
},
|
||||||
};
|
|
||||||
|
|
||||||
use crate:: {
|
|
||||||
errors::Error::{
|
errors::Error::{
|
||||||
VAAInvalidEmitterChain,
|
VAAInvalidEmitterChain,
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
use solana_program::msg;
|
use solana_program::msg;
|
||||||
|
|
||||||
use solana_program::{
|
use solana_program::{
|
||||||
|
|
|
@ -9,6 +9,11 @@ pub enum Error {
|
||||||
VAAAlreadyExecuted,
|
VAAAlreadyExecuted,
|
||||||
VAAInvalidEmitterChain,
|
VAAInvalidEmitterChain,
|
||||||
VAAInvalid,
|
VAAInvalid,
|
||||||
|
InvalidTokenAddress,
|
||||||
|
InvalidTokenIndex,
|
||||||
|
SaleSealedOrAborted,
|
||||||
|
SaleHasNotStarted,
|
||||||
|
SaleHasEnded,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Errors thrown by the program will bubble up to the solitaire wrapper, which needs a way to
|
/// Errors thrown by the program will bubble up to the solitaire wrapper, which needs a way to
|
||||||
|
|
|
@ -41,8 +41,8 @@ fn read_u256(buf: &[u8]) -> (u128, u128) {
|
||||||
#[derive(PartialEq, Debug)]
|
#[derive(PartialEq, Debug)]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub struct SaleInit {
|
pub struct SaleInit {
|
||||||
payload_id: u8, // Sale ID
|
payload_id: u8, // 1
|
||||||
token_cnt: u8,
|
pub token_cnt: u8,
|
||||||
pub sale_id: u128,
|
pub sale_id: u128,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,8 @@ impl Owned for Config {
|
||||||
/// icco sale state. Writeable in init, seal, abort.
|
/// icco sale state. Writeable in init, seal, abort.
|
||||||
#[derive(Default, Clone, Copy, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
|
#[derive(Default, Clone, Copy, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
|
||||||
pub struct SaleState {
|
pub struct SaleState {
|
||||||
pub is_sealed: u8,
|
pub is_sealed: bool,
|
||||||
pub is_aborted: u8,
|
pub is_aborted: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Owned for SaleState {
|
impl Owned for SaleState {
|
||||||
|
@ -41,7 +41,7 @@ impl Owned for SaleState {
|
||||||
/// icco contribution state. Writeable in contribute, redeem, refund.
|
/// icco contribution state. Writeable in contribute, redeem, refund.
|
||||||
#[derive(Default, Clone, Copy, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
|
#[derive(Default, Clone, Copy, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
|
||||||
pub struct ContributionState {
|
pub struct ContributionState {
|
||||||
pub amount: u128,
|
pub amount: u64,
|
||||||
pub is_redeemed_or_refunded: u8,
|
pub is_redeemed_or_refunded: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue