Added total token contributions to saleState account.

This commit is contained in:
skojenov 2022-05-10 19:26:21 +00:00 committed by Karl Kempe
parent 14faa868c8
commit 9d26669a4c
13 changed files with 347 additions and 95 deletions

View File

@ -28,6 +28,7 @@ import {
abort_icco_sale_ix,
contribute_icco_sale_ix,
Pubkey,
// test_account_address,
} from "../../solana/icco_contributor-node";
// Solana
@ -444,6 +445,158 @@ describe("Solana dev Tests", () => {
}
})();
});
xtest("call into init_icco_sale minitest", (done) => {
(async () => {
try {
console.log("-->> minitest");
// create initSale using conductor on ETH.
const ethProvider = new ethers.providers.WebSocketProvider(
ETH_NODE_URL
);
const contributorConfigs: EthContributorConfig[] = [
{
chainId: CHAIN_ID_ETH,
wallet: new ethers.Wallet(ETH_PRIVATE_KEY1, ethProvider),
collateralAddress: WETH_ADDRESS,
conversionRate: "1",
},
// TBD Need to add solana?
];
const conductorConfig = contributorConfigs[0];
// make sale token. mint 10 and sell 10%
const tokenAddress = await deployTokenOnEth(
ETH_NODE_URL,
"Icco-Test",
"ICCO",
ethers.utils.parseUnits("10").toString(),
conductorConfig.wallet
);
console.log("Token Address: ", tokenAddress);
const buyers: EthBuyerConfig[] = [
// native weth
{
chainId: CHAIN_ID_ETH,
wallet: new ethers.Wallet(ETH_PRIVATE_KEY2, ethProvider),
collateralAddress: WETH_ADDRESS,
contribution: "6",
tokenIndex: 0,
},
];
// we need to set up all of the accepted tokens (natives plus their wrapped versions)
const acceptedTokens = await makeAcceptedTokensFromConfigs(
contributorConfigs,
buyers
);
const tokenAmount = "1";
const minRaise = "10"; // eth units
const maxRaise = "14";
const saleDuration = 60; // seconds
// get the time
const saleStart =
(await makeSaleStartFromLastBlock(contributorConfigs)) + 20; // So it can be aborted "early".
const decimals = 9;
const saleEnd = saleStart + saleDuration;
console.info("--> Sale Start: ", saleStart);
const saleInitVaa = await createSaleOnEthAndGetVaa(
conductorConfig.wallet,
conductorConfig.chainId,
tokenAddress,
ethers.utils.parseUnits(tokenAmount, decimals),
ethers.utils.parseUnits(minRaise),
ethers.utils.parseUnits(maxRaise),
saleStart,
saleEnd,
acceptedTokens
);
const saleInit = await parseSaleInit(saleInitVaa);
console.info(
"Sale Init VAA:",
Buffer.from(saleInitVaa).toString("hex")
);
// Wallet (payer) account decode
const privateKeyDecoded = Uint8Array.from(
SOLANA_WALLET_PK.split(",").map((s) => parseInt(s))
);
const walletAccount = Keypair.fromSecretKey(privateKeyDecoded);
// console.log(walletAccount.publicKey.toString()); // check "6sbzC1eH4FTujJXWj51eQe25cYvr4xfXbJ1vAj7j2k5J"
// Log Solana VAA PDA address.
const init_vaa_pda_pk = new PublicKey(
vaa_address(SOLANA_BRIDGE_ADDR, saleInitVaa)
);
// console.log("bbrp init_sale vaa PDA: ", init_vaa_pda_pk.toString());
// Make init_icco_sale_ix and call it
{
// post VAA on solana.
await postVaaSolanaWithRetry(
solanaConnection,
async (transaction) => {
transaction.partialSign(walletAccount);
return transaction;
},
SOLANA_BRIDGE_ADDR,
walletAccount.publicKey.toString(),
Buffer.from(saleInitVaa),
0
);
/*
const ta_key = test_account_address(
SOLANA_CONTRIBUTOR_ADDR,
BigInt(saleInit.saleId.toString())
);
console.log("test_account_address: ", ta_key.toString());
*/
// Create custody account(s) to hold contributet tokens.
const custody_addr = icco_sale_custody_account_address(
SOLANA_CONTRIBUTOR_ADDR,
BigInt(saleInit.saleId.toString()),
SOLANA_TEST_TOKEN_MINT
);
console.log("custody_addr: ", custody_addr.toString());
const ix_create_custudy_acct = ixFromRust(
create_icco_sale_custody_account_ix(
SOLANA_CONTRIBUTOR_ADDR,
SOLANA_BRIDGE_ADDR,
walletAccount.publicKey.toString(),
saleInitVaa,
SOLANA_TEST_TOKEN_MINT, // see wormhole/docs/devnet.md
0
)
);
const tx_create_custudy_acct = new Transaction().add(
ix_create_custudy_acct
);
const tx_id_create_custudy_acct =
await solanaConnection.sendTransaction(
tx_create_custudy_acct,
[walletAccount],
{
skipPreflight: false,
preflightCommitment: "singleGossip",
}
);
await solanaConnection.confirmTransaction(tx_id_create_custudy_acct);
}
// Done here.
ethProvider.destroy();
console.log("----- init_icco_sale + abort_icco_sale done -----");
done();
} catch (e) {
console.error(e);
done(
"An error occurred in init_icco_sale abort_icco_sale contributor test"
);
}
})();
});
});
function dumpInstructionAccounts(ixw: any) {

View File

@ -1 +1,6 @@
[14,173,153,4,176,224,201,111,32,237,183,185,159,247,22,161,89,84,215,209,212,137,10,92,157,49,29,192,101,164,152,70,87,65,8,174,214,157,175,126,98,90,54,24,100,177,247,77,19,112,47,44,165,109,233,102,14,86,109,29,134,145,132,141]
[
14, 173, 153, 4, 176, 224, 201, 111, 32, 237, 183, 185, 159, 247, 22, 161, 89,
84, 215, 209, 212, 137, 10, 92, 157, 49, 29, 192, 101, 164, 152, 70, 87, 65,
8, 174, 214, 157, 175, 126, 98, 90, 54, 24, 100, 177, 247, 77, 19, 112, 47,
44, 165, 109, 233, 102, 14, 86, 109, 29, 134, 145, 132, 141
]

View File

@ -17,8 +17,9 @@ pub type CoreBridge<'a, const STATE: AccountState> = Data<'a, BridgeData, { STAT
pub type EmitterAccount<'b> = Derive<Info<'b>, "emitter">;
///-------------------------------------------------------------------
/// Cntributor Config.
/// Contributor Config.
pub type ConfigAccount<'b, const STATE: AccountState> =
Derive<Data<'b, Config, { STATE }>, "config">;
@ -28,14 +29,14 @@ pub type ConfigAccount<'b, const STATE: AccountState> =
pub type SaleStateAccount<'b, const STATE: AccountState> =
Data<'b, SaleState, { STATE }>;
pub struct SaleStateDerivationData {
pub struct SaleStateAccountDerivationData {
pub sale_id: u128,
}
impl<'b, const STATE: AccountState> Seeded<&SaleStateDerivationData>
impl<'b, const STATE: AccountState> Seeded<&SaleStateAccountDerivationData>
for SaleStateAccount<'b, { STATE }>
{
fn seeds(accs: &SaleStateDerivationData) -> Vec<Vec<u8>> {
fn seeds(accs: &SaleStateAccountDerivationData) -> Vec<Vec<u8>> {
vec![
String::from("state").as_bytes().to_vec(),
accs.sale_id.to_be_bytes().to_vec(),

View File

@ -3,11 +3,10 @@
//#![allow(unused_imports)]
use crate::{
messages::SaleAbort,
messages::*,
accounts::{
ConfigAccount,
SaleStateAccount,
SaleStateDerivationData,
// SaleStateAccountDerivationData,
},
errors::Error::*,
};
@ -32,33 +31,32 @@ use bridge::{
};
#[derive(FromAccounts)]
pub struct AbortIccoSale<'b> {
pub payer: Mut<Signer<AccountInfo<'b>>>,
pub config: ConfigAccount<'b, { AccountState::Initialized }>,
pub sale_state: Mut<SaleStateAccount<'b, { AccountState::Initialized }>>,
pub abort_sale_vaa: ClaimableVAA<'b, SaleAbort>,
pub rent: Sysvar<'b, Rent>,
pub clock: Sysvar<'b, Clock>,
// Sale state is in ctx.accounts[7];
}
impl<'a> From<&AbortIccoSale<'a>> for SaleStateDerivationData {
/*
// May need this later Just for PDA verification.
impl<'a> From<&AbortIccoSale<'a>> for SaleStateAccountDerivationData {
fn from(accs: &AbortIccoSale<'a>) -> Self {
SaleStateDerivationData {
SaleStateAccountDerivationData {
sale_id: accs.abort_sale_vaa.sale_id,
}
}
}
*/
// No data so far.
#[derive(BorshDeserialize, BorshSerialize, Default)]
pub struct AbortIccoSaleData {
}
// impl<'b> InstructionContext<'b> for AbortIccoSale<'b> {
// }
pub fn abort_icco_sale(
ctx: &ExecutionContext,
accs: &mut AbortIccoSale,
@ -81,25 +79,22 @@ pub fn abort_icco_sale(
// let end_time = accs.init_sale_vaa.get_sale_end(&accs.init_sale_vaa.meta().payload[..]).1 as i64;
// msg!("time: {:?} start: {:?} end: {:?}", now_time, start_time, end_time);
// let sale_id = accs.init_sale_vaa.sale_id;
// Verify that the sale_state account PDA was derived correctly
let derivation_data: SaleStateDerivationData = (&*accs).into();
accs.sale_state.verify_derivation(ctx.program_id, &derivation_data)?;
// let sale_id = accs.init_sale_vaa.sale_id;
// let derivation_data: SaleStateAccountDerivationData = (&*accs).into();
// accs.sale_state.verify_derivation(ctx.program_id, &derivation_data)?;
let sale_state_account_info = &ctx.accounts[7];
//msg!("state_key: {:?}", sale_state_account_info.key);
msg!("state_key: {:?}", accs.sale_state.info().key);
// sale_state account set
if accs.sale_state.is_sealed {
let mut state_data = sale_state_account_info.data.borrow_mut();
if get_sale_state_sealed(&state_data) {
return Err(SaleHasBeenSealed.into());
}
if accs.sale_state.is_aborted {
if get_sale_state_aborted(&state_data) {
return Err(SaleHasBeenAborted.into());
}
// Set sale as aborted and claim VAA on this chain
accs.sale_state.is_aborted = true;
set_sale_state_aborted(& mut state_data, true);
accs.abort_sale_vaa.claim(ctx, accs.payer.key)?;
Ok(())

View File

@ -4,11 +4,11 @@
use std::mem::size_of_val;
use crate::{
messages::SaleInit,
messages::*,
accounts::{
ConfigAccount,
SaleStateAccount,
SaleStateDerivationData,
// SaleStateAccountDerivationData,
CustodySigner,
CustodyAccount,
CustodyAccountDerivationData,
@ -58,7 +58,6 @@ use bridge::{
pub struct ContributeIccoSale<'b> {
pub payer: Mut<Signer<AccountInfo<'b>>>,
pub config: ConfigAccount<'b, { AccountState::Initialized }>,
pub sale_state: SaleStateAccount<'b, { AccountState::Initialized }>, // R/O here
pub init_sale_vaa: ClaimedVAA<'b, SaleInit>, // Was claimed.
pub contribution_state: Mut<ContributionStateAccount<'b, { AccountState::MaybeInitialized }>>,
@ -70,15 +69,18 @@ pub struct ContributeIccoSale<'b> {
pub custody: Mut<CustodyAccount<'b, { AccountState::Initialized }>>,
pub clock: Sysvar<'b, Clock>,
// Sale state is in ctx.accounts[11];
}
impl<'a> From<&ContributeIccoSale<'a>> for SaleStateDerivationData {
/*
impl<'a> From<&ContributeIccoSale<'a>> for SaleStateAccountDerivationData {
fn from(accs: &ContributeIccoSale<'a>) -> Self {
SaleStateDerivationData {
SaleStateAccountDerivationData {
sale_id: accs.init_sale_vaa.sale_id,
}
}
}
*/
impl<'a> From<&ContributeIccoSale<'a>> for CustodyAccountDerivationData {
fn from(accs: &ContributeIccoSale<'a>) -> Self {
@ -116,14 +118,18 @@ pub fn contribute_icco_sale(
) -> Result<()> {
msg!("In contribute_icco_sale!");
let sale_state_account_info = &ctx.accounts[11];
//msg!("state_key: {:?}", sale_state_account_info.key);
let mut state_data = sale_state_account_info.data.borrow_mut();
// Check sale status.
if accs.sale_state.is_sealed || accs.sale_state.is_aborted {
if get_sale_state_sealed(&state_data) || get_sale_state_aborted(&state_data) {
return Err(SaleSealedOrAborted.into());
}
/*
// TBD This does not work yet. EVM Time is not Linux.
// Check if sale started.
/*
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());
@ -132,6 +138,7 @@ pub fn contribute_icco_sale(
return Err(SaleHasEnded.into());
}
*/
// Make sure token Idx matches passed in token mint addr.
/*
let token_idx = data.token_idx;
@ -165,7 +172,11 @@ pub fn contribute_icco_sale(
// invoke_seeded(&transfer_ix, ctx, &accs.payer, None)?;
// invoke_seeded(&transfer_ix, ctx, &accs.authority_signer, None)?;
// store new amount.
// store new amount in Custody and State accounts.
let token_idx = data.token_idx;
let tmp_v = get_sale_state_contribution(&state_data, token_idx) + data.amount;
set_sale_state_contribution(& mut state_data, token_idx, tmp_v);
// accs.sale_state.contributions[token_idx] = accs.sale_state.contributions[token_idx] + data.amount;
accs.contribution_state.amount = accs.contribution_state.amount + data.amount;
Ok(())
}

View File

@ -2,27 +2,13 @@
//#![allow(unused_must_use)]
//#![allow(unused_imports)]
//use core::convert::TryInto;
//use std::mem::size_of_val;
// use std::{
// error::Error,
// io::{
// Cursor,
// Read,
// Write,
// },
// // str::Utf8Error,
// // string::FromUtf8Error,
// };
use crate::{
messages::SaleInit,
accounts::{
simple_account::create_simple_account,
accounts::{
ConfigAccount,
SaleStateAccount,
SaleStateDerivationData,
// CustodySigner,
SaleStateAccountDerivationData,
CustodyAccount,
CustodyAccountDerivationData,
},
@ -33,7 +19,10 @@ use crate::{
use solana_program::msg;
use solana_program::{
// pubkey::Pubkey,
// system_instruction,
account_info::AccountInfo,
// program::invoke,
program::invoke_signed,
// program_error::ProgramError,
// pubkey::Pubkey,
@ -46,17 +35,10 @@ use solitaire::{
*,
};
// use wormhole_sdk::{VAA};
use bridge::{
vaa::{
ClaimableVAA,
},
// error::Error::{
// VAAAlreadyExecuted,
// VAAInvalid,
// },
// CHAIN_ID_SOLANA,
};
@ -77,6 +59,7 @@ pub struct CreateIccoSaleCustodyAccount<'b> {
pub rent: Sysvar<'b, Rent>,
pub clock: Sysvar<'b, Clock>,
// Account [11] is the test.
}
impl<'a> From<&CreateIccoSaleCustodyAccount<'a>> for CustodyAccountDerivationData {
@ -93,6 +76,7 @@ impl<'a> From<&CreateIccoSaleCustodyAccount<'a>> for CustodyAccountDerivationDat
pub struct CreateIccoSaleCustodyAccountData {
}
pub fn create_icco_sale_custody_account(
ctx: &ExecutionContext,
accs: &mut CreateIccoSaleCustodyAccount,
@ -115,7 +99,7 @@ pub fn create_icco_sale_custody_account(
let sale_id = accs.init_sale_vaa.sale_id;
msg!("sale_id: {:?}", sale_id);
// Create and init custody account if needed. It may be iunitialized if previous init sale failed after accounts were created.
// Create and init custody account as needed. It may be initialized already, if previous init sale failed after accounts were created.
// https://github.com/certusone/wormhole/blob/1792141307c3979b1f267af3e20cfc2f011d7051/solana/modules/token_bridge/program/src/api/transfer.rs#L159
if !accs.custody.is_initialized() {
accs.custody.create(&(&*accs).into(), ctx, accs.payer.key, Exempt)?;
@ -132,30 +116,28 @@ pub fn create_icco_sale_custody_account(
Ok(())
}
// ctx.program_id, // accs.payer.info().key, // accs.custody_signer.key,
#[derive(FromAccounts)]
pub struct InitIccoSale<'b> {
pub payer: Mut<Signer<AccountInfo<'b>>>,
pub config: ConfigAccount<'b, { AccountState::Initialized }>, // Must be created before Init
pub sale_state: Mut<SaleStateAccount<'b, { AccountState::Uninitialized }>>, // Must not be created yet
pub init_sale_vaa: ClaimableVAA<'b, SaleInit>, // Claimed here.
pub rent: Sysvar<'b, Rent>,
pub clock: Sysvar<'b, Clock>,
// Sale state is in ctx.accounts[7];
}
impl<'a> From<&InitIccoSale<'a>> for SaleStateDerivationData {
/*
// May need this later Just for PDA verification.
impl<'a> From<&InitIccoSale<'a>> for SaleStateAccountDerivationData {
fn from(accs: &InitIccoSale<'a>) -> Self {
SaleStateDerivationData {
SaleStateAccountDerivationData {
sale_id: accs.init_sale_vaa.sale_id,
}
}
}
*/
// No data so far. All is in VAA Account
#[derive(BorshDeserialize, BorshSerialize, Default)]
@ -184,30 +166,39 @@ pub fn init_icco_sale(
return Err(VAAInvalidEmitterChain.into());
}
let now_time = accs.clock.unix_timestamp;
let start_time = accs.init_sale_vaa.get_sale_start(&accs.init_sale_vaa.meta().payload[..]).1 as i64;
let end_time = accs.init_sale_vaa.get_sale_end(&accs.init_sale_vaa.meta().payload[..]).1 as i64;
msg!("time: {:?} start: {:?} end: {:?}", now_time, start_time, end_time);
let sale_id = accs.init_sale_vaa.sale_id;
msg!("sale_id: {:?}", sale_id);
/* BEFORE
// Verify that the sale_state account PDA was derived correctly
let derivation_data: SaleStateDerivationData = (&*accs).into();
accs.sale_state.verify_derivation(ctx.program_id, &derivation_data)?;
// msg!("state_key: {:?}", accs.sale_state.info().key);
// Create sale_state account. (it was Uninitialized coming in)
// if !accs.sale_state.is_initialized() {
accs.sale_state.create(&(&*accs).into(), ctx, accs.payer.key, Exempt)?;
//}
// [Check if all Solana tokens exist??] Custodian accounts are created before this call.
*/
// Create account using Solana API.
msg!("ctx accounts Cnt: {}", ctx.accounts.len());
let sale_state_account_info = &ctx.accounts[7];
if **sale_state_account_info.lamports.borrow() > 0 {
return Err(SaleStateIsAlredyInitialized.into());
} else {
create_simple_account (ctx,
sale_state_account_info.key,
accs.payer.key,
2 + 8 * accs.init_sale_vaa.token_cnt as usize,
&SaleStateAccount::<'_, { AccountState::Uninitialized }>::seeds(&SaleStateAccountDerivationData{sale_id: sale_id}
))?;
}
// If all good - Prevent vaa double processing
accs.init_sale_vaa.claim(ctx, accs.payer.key)?;
Ok(())
}

View File

@ -17,6 +17,9 @@ pub enum Error {
SaleHasEnded,
SaleHasBeenSealed,
SaleHasBeenAborted,
VAATokenCountExceeded,
SaleStateIsAlredyInitialized,
TestAccountError,
}
/// Errors thrown by the program will bubble up to the solitaire wrapper, which needs a way to

View File

@ -7,18 +7,17 @@ use crate::{
AuthoritySigner,
ConfigAccount,
SaleStateAccount,
SaleStateDerivationData,
SaleStateAccountDerivationData,
CustodyAccount,
CustodyAccountDerivationData,
CustodySigner,
EmitterAccount,
// Endpoint,
// EndpointDerivationData,
// MintSigner,
SplTokenMeta,
SplTokenMetaDerivationData,
ContributionStateAccount,
ContributionStateAccountDerivationData,
// TestAccount,
// TestAccountDerivationData,
},
api::{
CreateIccoSaleCustodyAccountData,
@ -130,6 +129,7 @@ pub fn create_icco_sale_custody_account(
_token_index: u8, // TBD For validation against VAA.
) -> Instruction {
let config_key = ConfigAccount::<'_, { AccountState::Initialized }>::key(None, &program_id);
// let test_key = TestAccount::<'_, { AccountState::Uninitialized }>::key(&TestAccountDerivationData{sale_id: sale_id}, &program_id);
let custody_key = CustodyAccount::<'_, { AccountState::MaybeInitialized }>::key(&CustodyAccountDerivationData{sale_id: sale_id, mint: token_mint}, &program_id);
let claim = Claim::<'_, { AccountState::Uninitialized }>::key(
&ClaimDerivationData {
@ -154,6 +154,7 @@ pub fn create_icco_sale_custody_account(
AccountMeta::new_readonly(solana_program::sysvar::clock::id(), false),
AccountMeta::new_readonly(solana_program::system_program::id(), false),
AccountMeta::new_readonly(spl_token::id(), false),
// AccountMeta::new(test_key, false),
],
data: (
crate::instruction::Instruction::CreateIccoSaleCustodyAccount,
@ -176,7 +177,7 @@ pub fn init_icco_sale(
sequence: u64,
) -> Instruction {
let config_key = ConfigAccount::<'_, { AccountState::Initialized }>::key(None, &program_id);
let state_key = SaleStateAccount::<'_, { AccountState::Uninitialized }>::key(&SaleStateDerivationData{sale_id: sale_id}, &program_id);
let state_key = SaleStateAccount::<'_, { AccountState::Uninitialized }>::key(&SaleStateAccountDerivationData{sale_id: sale_id}, &program_id);
let claim = Claim::<'_, { AccountState::Uninitialized }>::key(
&ClaimDerivationData {
@ -192,13 +193,12 @@ pub fn init_icco_sale(
accounts: vec![
AccountMeta::new(payer, true),
AccountMeta::new_readonly(config_key, false),
AccountMeta::new(state_key, false),
AccountMeta::new_readonly(payload_message, false),
AccountMeta::new(claim, false),
// AccountMeta::new(program_id, false),
AccountMeta::new_readonly(solana_program::sysvar::rent::id(), false),
AccountMeta::new_readonly(solana_program::sysvar::clock::id(), false),
AccountMeta::new_readonly(solana_program::system_program::id(), false),
AccountMeta::new(state_key, false),
],
data: (
@ -210,8 +210,14 @@ pub fn init_icco_sale(
}
}
/*
pub fn get_test_account_address (program_id: Pubkey, sale_id: u128) -> Pubkey {
TestAccount::<'_, { AccountState::Initialized }>::key(&TestAccountDerivationData{sale_id: sale_id}, &program_id)
}
*/
pub fn get_icco_state_address (program_id: Pubkey, sale_id: u128) -> Pubkey {
SaleStateAccount::<'_, { AccountState::Initialized }>::key(&SaleStateDerivationData{sale_id: sale_id}, &program_id)
SaleStateAccount::<'_, { AccountState::Initialized }>::key(&SaleStateAccountDerivationData{sale_id: sale_id}, &program_id)
}
pub fn get_icco_sale_custody_account_address(program_id: Pubkey, sale_id: u128, token_mint: Pubkey) -> Pubkey {
@ -228,7 +234,7 @@ pub fn abort_icco_sale(
sequence: u64,
) -> Instruction {
let config_key = ConfigAccount::<'_, { AccountState::Initialized }>::key(None, &program_id);
let state_key = SaleStateAccount::<'_, { AccountState::Initialized }>::key(&SaleStateDerivationData{sale_id: sale_id}, &program_id);
let state_key = SaleStateAccount::<'_, { AccountState::Initialized }>::key(&SaleStateAccountDerivationData{sale_id: sale_id}, &program_id);
let claim = Claim::<'_, { AccountState::Uninitialized }>::key(
&ClaimDerivationData {
@ -244,13 +250,13 @@ pub fn abort_icco_sale(
accounts: vec![
AccountMeta::new(payer, true),
AccountMeta::new_readonly(config_key, false),
AccountMeta::new(state_key, false),
AccountMeta::new_readonly(payload_message, false),
AccountMeta::new(claim, false),
// AccountMeta::new(program_id, false),
AccountMeta::new_readonly(solana_program::sysvar::rent::id(), false),
AccountMeta::new_readonly(solana_program::sysvar::clock::id(), false),
AccountMeta::new_readonly(solana_program::system_program::id(), false),
AccountMeta::new(state_key, false),
],
data: (
@ -277,7 +283,7 @@ pub fn contribute_icco_sale(
amount: u64,
) -> Instruction {
let config_key = ConfigAccount::<'_, { AccountState::Initialized }>::key(None, &program_id);
let state_key = SaleStateAccount::<'_, { AccountState::Initialized }>::key(&SaleStateDerivationData{sale_id: sale_id}, &program_id);
let state_key = SaleStateAccount::<'_, { AccountState::Initialized }>::key(&SaleStateAccountDerivationData{sale_id: sale_id}, &program_id);
let contribution_state_key =
ContributionStateAccount::<'_, { AccountState::MaybeInitialized }>::key(&ContributionStateAccountDerivationData{
sale_id: sale_id,
@ -291,7 +297,6 @@ pub fn contribute_icco_sale(
accounts: vec![
AccountMeta::new(payer, true),
AccountMeta::new_readonly(config_key, false),
AccountMeta::new_readonly(state_key, false),
AccountMeta::new_readonly(payload_message, false),
AccountMeta::new(contribution_state_key, false),
AccountMeta::new(from_account, false),
@ -302,6 +307,7 @@ pub fn contribute_icco_sale(
AccountMeta::new_readonly(solana_program::sysvar::rent::id(), false),
AccountMeta::new_readonly(solana_program::system_program::id(), false),
AccountMeta::new_readonly(spl_token::id(), false),
AccountMeta::new(state_key, false),
],
data: (
crate::instruction::Instruction::ContributeIccoSale,

View File

@ -21,6 +21,7 @@ pub mod errors;
pub mod messages;
pub mod types;
pub mod claimed_vaa;
pub mod simple_account;
pub use api::{
contribute_icco_sale, init_icco_sale, initialize, create_icco_sale_custody_account, abort_icco_sale,

View File

@ -26,6 +26,10 @@ fn read_u16(buf: &[u8]) -> u16 {
u16::from_be_bytes(buf[0..2].try_into().unwrap())
}
fn read_u64(buf: &[u8]) -> u64 {
u64::from_be_bytes(buf[0..8].try_into().unwrap())
}
fn read_u128(buf: &[u8]) -> u128 {
u128::from_be_bytes(buf[0..16].try_into().unwrap())
}
@ -35,7 +39,31 @@ fn read_u256(buf: &[u8]) -> (u128, u128) {
}
/// -------------------------------------------------------------------
/// Zero-copy from VAA payload for Init Sale.
/// sale_state getters/setters
pub fn get_sale_state_sealed(bf: &[u8]) -> bool {
bf[0] != 0
}
pub fn set_sale_state_sealed(bf: & mut [u8], v: bool) {
bf[0] = if v {1} else {0};
}
pub fn get_sale_state_aborted(bf: &[u8]) -> bool {
bf[1] != 0
}
pub fn set_sale_state_aborted(bf: & mut [u8], v: bool) {
bf[1] = if v {1} else {0};
}
pub fn get_sale_state_contribution(bf: &[u8], token_idx: u8) -> u64 {
read_u64(&bf[(2 + 8 * token_idx) as usize..])
}
pub fn set_sale_state_contribution(bf: & mut [u8], token_idx: u8, v: u64) {
let n = (2 + 8 * token_idx) as usize;
bf[n..n+8].clone_from_slice(&v.to_be_bytes()[..]);
}
/// -------------------------------------------------------------------
/// From VAA payload for SaleAbort.
#[derive(PartialEq, Debug)]
#[allow(non_snake_case)]
pub struct SaleAbort {

View File

@ -0,0 +1,37 @@
use solana_program::{
pubkey::Pubkey,
system_instruction,
//account_info::AccountInfo,
program::invoke,
program::invoke_signed,
// program_error::ProgramError,
// pubkey::Pubkey,
sysvar::rent::Rent,
};
use solitaire::*;
pub fn create_simple_account (ctx: &ExecutionContext, pubkey: &Pubkey, payer: &Pubkey, size: usize, vseeds: &Vec<Vec<u8>>) -> Result<()> {
let target_rent = Rent::default().minimum_balance(size);
// top up account to target rent
let transfer_ix = system_instruction::transfer(payer, pubkey, target_rent);
invoke(&transfer_ix, ctx.accounts)?;
// msg!("transferred {} lamports", target_rent);
// invoke is just a synonym for invoke_signed with an empty list
// Temp vars are needed to hold values.
let mut tmp_v_seeds: Vec<&[u8]> = vseeds.iter().map(|x| &x[..]).collect();
let (_, bump_seed) = Pubkey::find_program_address(&tmp_v_seeds[..], ctx.program_id);
let bsr = [&[bump_seed][..]];
tmp_v_seeds.extend(bsr);
let sig_seeds = &[&tmp_v_seeds[..]][..];
// allocate space
let allocate_ix = system_instruction::allocate(pubkey, size as u64);
invoke_signed(&allocate_ix, ctx.accounts, sig_seeds)?;
// assign ownership
let assign_ix = system_instruction::assign(pubkey, ctx.program_id);
invoke_signed(&assign_ix, ctx.accounts, sig_seeds)?;
Ok(())
}

View File

@ -24,11 +24,25 @@ impl Owned for Config {
}
}
/// Temp test account data. If needed.
#[derive(Default, Clone, Copy, BorshDeserialize, BorshSerialize)]
pub struct TestStruct {
}
impl Owned for TestStruct {
fn owner(&self) -> AccountOwner {
AccountOwner::This
}
}
/// icco sale state. Writeable in init, seal, abort.
#[derive(Default, Clone, Copy, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
/// Only static sizing is working well in here, so 256 is preallocated.
//#[derive(Clone, Copy, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
#[derive(Default, Clone, Copy, BorshDeserialize, BorshSerialize)]
pub struct SaleState {
pub is_sealed: bool,
pub is_aborted: bool,
}
impl Owned for SaleState {
@ -37,7 +51,6 @@ impl Owned for SaleState {
}
}
/// icco contribution state. Writeable in contribute, redeem, refund.
#[derive(Default, Clone, Copy, BorshDeserialize, BorshSerialize, Serialize, Deserialize)]
pub struct ContributionState {

View File

@ -14,6 +14,7 @@ use crate::{
instructions::{
create_icco_sale_custody_account,
get_icco_sale_custody_account_address,
// get_test_account_address,
get_icco_state_address,
init_icco_sale,
abort_icco_sale,
@ -151,6 +152,13 @@ pub fn vaa_address(bridge_id: String, vaa: Vec<u8>) -> Vec<u8> {
message_key.to_bytes().to_vec()
}
/*
#[wasm_bindgen]
pub fn test_account_address(program_id: String, sale_id: u64) -> Pubkey {
get_test_account_address (Pubkey::from_str(program_id.as_str()).unwrap(), sale_id as u128)
}
*/
#[wasm_bindgen]
pub fn icco_state_address(program_id: String, sale_id: u64) -> Pubkey {
get_icco_state_address (Pubkey::from_str(program_id.as_str()).unwrap(), sale_id as u128)