Change to spl_token transfer

This commit is contained in:
Karl Kempe 2022-06-02 15:16:34 +00:00
parent f83a8142bb
commit bc16d7d509
8 changed files with 79 additions and 27 deletions

View File

@ -138,6 +138,7 @@ dependencies = [
"num",
"num-derive",
"num-traits",
"spl-token",
]
[[package]]

View File

@ -22,6 +22,7 @@ overflow-checks = true
[dependencies]
anchor-lang = { version= "0.24.2", features = ["init-if-needed"]}
anchor-spl = "0.24.2"
spl-token = "3.3.0"
num-traits = "0.2"
num-derive = "0.3"
borsh = "0.9.3"

View File

@ -41,12 +41,15 @@ pub enum SaleError {
#[msg("SaleEnded")]
SaleEnded,
#[msg("SaleNotFinished")]
SaleNotFinished,
#[msg("SaleNotAborted")]
SaleNotAborted,
#[msg("SaleNotAttestable")]
SaleNotAttestable,
#[msg("SaleNotFinished")]
SaleNotFinished,
#[msg("SaleNotSealed")]
SaleNotSealed,

View File

@ -24,6 +24,7 @@ pub mod anchor_contributor {
use super::*;
use anchor_spl::*;
use spl_token;
pub fn create_custodian(ctx: Context<CreateCustodian>) -> Result<()> {
let custodian = &mut ctx.accounts.custodian;
@ -69,14 +70,15 @@ pub mod anchor_contributor {
let owner = &ctx.accounts.owner;
//let ata_seeds: &'a [&[u8]] = &[&owner.key().as_ref(), &token::ID.as_ref(), &mint.as_ref()];
/*
let (ata, bump) = Pubkey::find_program_address(
&[&owner.key().as_ref(), &token::ID.as_ref(), &mint.as_ref()],
&associated_token::AssociatedToken::id(),
);
msg!("ata: {:?}, bump: {:?}", ata, bump);
*/
// spl transfer contribution
/*
let ix = spl_token::instruction::transfer(
&token::ID,
&ctx.accounts.buyer_ata.key(),
@ -95,8 +97,8 @@ pub mod anchor_contributor {
ctx.accounts.token_program.to_account_info(),
],
)?;
*/
/*
token::transfer(
CpiContext::new_with_signer(
ctx.accounts.token_program.to_account_info(),
@ -109,6 +111,7 @@ pub mod anchor_contributor {
),
amount,
)?;
*/
/*
let custodian_bump = ctx.bumps["custodian"];
@ -253,7 +256,7 @@ pub mod anchor_contributor {
let refunds = ctx.accounts.buyer.claim_refunds(&sale.totals)?;
let atas = &ctx.remaining_accounts;
require!(
atas.len() == sale.totals.len(),
atas.len() == 2 * sale.totals.len(),
SaleError::InvalidRemainingAccounts
);

View File

@ -191,7 +191,7 @@ impl Sale {
}
pub fn serialize_contributions(&self, block_time: i64) -> Result<Vec<u8>> {
require!(self.is_attestable(block_time), SaleError::SaleNotFinished);
require!(self.is_attestable(block_time), SaleError::SaleNotAttestable);
let totals = &self.totals;
let mut attested: Vec<u8> = Vec::with_capacity(
@ -211,6 +211,7 @@ impl Sale {
}
pub fn parse_sale_sealed(&mut self, payload: &[u8]) -> Result<()> {
require!(!self.has_ended(), SaleError::SaleEnded);
// check that the payload has at least the number of bytes
// required to define the number of allocations
require!(
@ -296,8 +297,7 @@ impl Sale {
}
pub fn has_ended(&self) -> bool {
return self.initialized && self.status == SaleStatus::Sealed
|| self.status == SaleStatus::Aborted;
return self.initialized && self.status != SaleStatus::Active;
}
pub fn is_sealed(&self) -> bool {

View File

@ -133,7 +133,6 @@ describe("anchor-contributor", () => {
});
});
/*
describe("Conduct Successful Sale", () => {
// global contributions for test
const contributions = new Map<web3.PublicKey, string[]>();
@ -194,6 +193,7 @@ describe("anchor-contributor", () => {
let caughtError = false;
try {
const tx = await contributor.initSale(orchestrator, dummyConductor.initSaleVaa);
console.log("should not happen", tx);
} catch (e) {
// pda init should fail
caughtError = "programErrorStack" in e;
@ -212,9 +212,9 @@ describe("anchor-contributor", () => {
try {
const mint = hexToPublicKey(dummyConductor.acceptedTokens[0].address);
const tx = await contributor.contribute(buyer, saleId, mint, new BN(amount));
console.log("should not happen", tx);
} catch (e) {
//console.log("too early", e);
caughtError = e.msg == "ContributionTooEarly";
caughtError = verifyErrorMsg(e, "ContributionTooEarly");
}
if (!caughtError) {
@ -328,10 +328,13 @@ describe("anchor-contributor", () => {
let caughtError = false;
try {
const tx = await contributor.attestContributions(orchestrator, saleId);
console.log(tx);
console.log("should not happen", tx);
} catch (e) {
console.log(e.error.errorCode.code);
caughtError = e.error.errorCode.code == "ContributionTooEarly";
caughtError = verifyErrorMsg(e, "SaleNotAttestable");
}
if (!caughtError) {
throw Error("did not catch expected error");
}
});
@ -353,7 +356,19 @@ describe("anchor-contributor", () => {
// TODO
it("Orchestrator Cannot Attest Contributions Again", async () => {
expect(false).to.be.true;
const saleId = dummyConductor.getSaleId();
let caughtError = false;
try {
const tx = await contributor.attestContributions(orchestrator, saleId);
console.log("should not happen", tx);
} catch (e) {
caughtError = verifyErrorMsg(e, "SaleNotAttestable");
}
if (!caughtError) {
throw Error("did not catch expected error");
}
});
it("User Cannot Contribute After Sale Ended", async () => {
@ -364,8 +379,9 @@ describe("anchor-contributor", () => {
try {
const mint = hexToPublicKey(dummyConductor.acceptedTokens[0].address);
const tx = await contributor.contribute(buyer, saleId, mint, amount);
console.log("should not happen", tx);
} catch (e) {
caughtError = e.msg == "SaleEnded";
caughtError = verifyErrorMsg(e, "SaleEnded");
}
if (!caughtError) {
@ -398,9 +414,9 @@ describe("anchor-contributor", () => {
let caughtError = false;
try {
const tx = await contributor.sealSale(orchestrator, saleSealedVaa);
console.log("should not happen", tx);
} catch (e) {
//caughtError = e.error.errorCode.code == "SaleEnded";
console.log(e.error.errorCode.code);
caughtError = verifyErrorMsg(e, "SaleEnded");
}
if (!caughtError) {
@ -425,7 +441,7 @@ describe("anchor-contributor", () => {
expect(false).to.be.true;
});
});
*/
describe("Conduct Aborted Sale", () => {
// global contributions for test
const contributions = new Map<web3.PublicKey, string[]>();
@ -530,8 +546,9 @@ describe("anchor-contributor", () => {
let caughtError = false;
try {
const tx = await contributor.abortSale(orchestrator, saleAbortedVaa);
console.log("should not happen", tx);
} catch (e) {
caughtError = e.error.errorCode.code == "SaleEnded";
caughtError = verifyErrorMsg(e, "SaleEnded");
}
if (!caughtError) {
@ -559,9 +576,9 @@ describe("anchor-contributor", () => {
let caughtError = false;
try {
//const tx = await contributor.claimRefund(saleId, buyer, acceptedMints);
//console.log("should not happen", tx);
} catch (e) {
console.log(e);
caughtError = e.error.errorCode.code == "SaleEnded";
caughtError = verifyErrorMsg(e, "BuyerInactive");
}
if (!caughtError) {
@ -570,3 +587,22 @@ describe("anchor-contributor", () => {
});
});
});
function verifyErrorMsg(e: any, msg: string): boolean {
if (e.msg) {
const result = e.msg == msg;
if (!result) {
console.error(e);
}
return result;
} else if (e.error.errorMessage) {
const result = e.error.errorMessage == msg;
if (!result) {
console.error(e);
}
return result;
}
console.error(e);
throw Error("unknown error");
}

View File

@ -11,7 +11,7 @@ import { getAccount, getAssociatedTokenAddress, TOKEN_PROGRAM_ID } from "@solana
import { findBuyerAccount, findCustodianAccount, findSaleAccount, findSignedVaaAccount, KeyBump } from "./accounts";
import { getBuyerState, getCustodianState, getSaleState } from "./fetch";
import { postVaa } from "./wormhole";
import { getPdaAssociatedTokenAddress } from "./utils";
import { getPdaAssociatedTokenAddress, makeWritableAccountMeta } from "./utils";
import { ASSOCIATED_PROGRAM_ID } from "@project-serum/anchor/dist/cjs/utils/token";
export class IccoContributor {
@ -173,10 +173,10 @@ export class IccoContributor {
const buyerAccount = findBuyerAccount(program.programId, saleId, payer.publicKey);
const saleAccount = findSaleAccount(program.programId, saleId);
const remainingAccounts = [];
const remainingAccounts: web3.AccountMeta[] = [];
for (const mint of acceptedMints) {
remainingAccounts.push(await getAssociatedTokenAddress(mint, payer.publicKey));
remainingAccounts.push(await getPdaAssociatedTokenAddress(mint, custodian));
remainingAccounts.push(makeWritableAccountMeta(await getAssociatedTokenAddress(mint, payer.publicKey)));
remainingAccounts.push(makeWritableAccountMeta(await getPdaAssociatedTokenAddress(mint, custodian)));
}
return program.methods

View File

@ -38,3 +38,11 @@ export function hexToPublicKey(hexlified: string): web3.PublicKey {
export async function getPdaAssociatedTokenAddress(mint: web3.PublicKey, pda: web3.PublicKey): Promise<web3.PublicKey> {
return getAssociatedTokenAddress(mint, pda, true);
}
export function makeWritableAccountMeta(pubkey: web3.PublicKey): web3.AccountMeta {
return {
pubkey,
isWritable: true,
isSigner: false,
};
}