Change to spl_token transfer
This commit is contained in:
parent
f83a8142bb
commit
bc16d7d509
|
@ -138,6 +138,7 @@ dependencies = [
|
|||
"num",
|
||||
"num-derive",
|
||||
"num-traits",
|
||||
"spl-token",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
||||
|
|
|
@ -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
|
||||
);
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue