Add spl mints; fix accepted token max; fix tsconfig; add buyer keypair
This commit is contained in:
parent
e327eedc41
commit
cbf5b061d3
|
@ -8,7 +8,7 @@ url = "https://anchor.projectserum.com"
|
|||
|
||||
[provider]
|
||||
cluster = "localnet"
|
||||
wallet = "./tests/test_keypair.json"
|
||||
wallet = "./tests/test_orchestrator_keypair.json"
|
||||
|
||||
[scripts]
|
||||
test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
|
||||
|
|
|
@ -26,7 +26,10 @@ pub const INIT_INDEX_SALE_END: usize = 100;
|
|||
pub const INIT_INDEX_ACCEPTED_TOKENS_START: usize = 132;
|
||||
|
||||
pub const ACCEPTED_TOKENS_N_BYTES: usize = 33;
|
||||
pub const ACCEPTED_TOKENS_MAX: usize = 10;
|
||||
pub const ACCEPTED_TOKENS_MAX: usize = 8;
|
||||
pub const ACCEPTED_TOKENS_INDEX_TOKEN_INDEX: usize = 0;
|
||||
pub const ACCEPTED_TOKENS_INDEX_TOKEN_ADDRESS: usize = 1;
|
||||
pub const ACCEPTED_TOKENS_INDEX_END: usize = 33;
|
||||
|
||||
// for attest contributions
|
||||
pub const ATTEST_CONTRIBUTIONS_ELEMENT_LEN: usize = 33; // token index + amount
|
||||
|
|
|
@ -65,10 +65,15 @@ impl AssetTotal {
|
|||
pub const MAXIMUM_SIZE: usize = 1 + 32 + 8 + 8 + 8;
|
||||
|
||||
pub fn make_from_slice(bytes: &[u8]) -> Result<Self> {
|
||||
require!(bytes.len() == 33, SaleError::InvalidAcceptedTokenPayload);
|
||||
require!(
|
||||
bytes.len() == ACCEPTED_TOKENS_INDEX_END,
|
||||
SaleError::InvalidAcceptedTokenPayload
|
||||
);
|
||||
Ok(AssetTotal {
|
||||
token_index: bytes[0],
|
||||
mint: Pubkey::new(&bytes[1..33]),
|
||||
token_index: bytes[ACCEPTED_TOKENS_INDEX_TOKEN_INDEX],
|
||||
mint: Pubkey::new(
|
||||
&bytes[ACCEPTED_TOKENS_INDEX_TOKEN_ADDRESS..ACCEPTED_TOKENS_INDEX_END],
|
||||
),
|
||||
contributions: 0,
|
||||
allocations: 0,
|
||||
excess_contributions: 0,
|
||||
|
@ -84,6 +89,7 @@ impl Sale {
|
|||
+ (8 + 8)
|
||||
+ 32
|
||||
+ 1
|
||||
+ 1
|
||||
+ (4 + AssetTotal::MAXIMUM_SIZE * ACCEPTED_TOKENS_MAX)
|
||||
+ 1;
|
||||
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
import { AnchorProvider, workspace, web3, Program, setProvider } from "@project-serum/anchor";
|
||||
import { AnchorProvider, workspace, web3, Program, setProvider, BN } from "@project-serum/anchor";
|
||||
import { AnchorContributor } from "../target/types/anchor_contributor";
|
||||
import { expect } from "chai";
|
||||
import { readFileSync } from "fs";
|
||||
import { CHAIN_ID_SOLANA, setDefaultWasm, tryHexToNativeString, tryNativeToHexString } from "@certusone/wormhole-sdk";
|
||||
import { createAssociatedTokenAccount } from "@solana/spl-token";
|
||||
import {
|
||||
getOrCreateAssociatedTokenAccount,
|
||||
getAssociatedTokenAddress,
|
||||
createAssociatedTokenAccountInstruction,
|
||||
createSyncNativeInstruction,
|
||||
getAccount,
|
||||
createMint,
|
||||
getMint,
|
||||
mintTo,
|
||||
Account as AssociatedTokenAccount,
|
||||
} from "@solana/spl-token";
|
||||
|
||||
import { DummyConductor } from "./helpers/conductor";
|
||||
import { CONDUCTOR_ADDRESS, CONDUCTOR_CHAIN } from "./helpers/consts";
|
||||
import { DummyConductor, MAX_ACCEPTED_TOKENS } from "./helpers/conductor";
|
||||
import { IccoContributor } from "./helpers/contributor";
|
||||
import { getBlockTime, wait } from "./helpers/utils";
|
||||
import { BN } from "bn.js";
|
||||
import { getBlockTime, getSplBalance, hexToPublicKey, wait } from "./helpers/utils";
|
||||
|
||||
setDefaultWasm("node");
|
||||
|
||||
|
@ -20,8 +28,11 @@ describe("anchor-contributor", () => {
|
|||
const program = workspace.AnchorContributor as Program<AnchorContributor>;
|
||||
const connection = program.provider.connection;
|
||||
|
||||
const owner = web3.Keypair.fromSecretKey(
|
||||
Uint8Array.from(JSON.parse(readFileSync("./tests/test_keypair.json").toString()))
|
||||
const orchestrator = web3.Keypair.fromSecretKey(
|
||||
Uint8Array.from(JSON.parse(readFileSync("./tests/test_orchestrator_keypair.json").toString()))
|
||||
);
|
||||
const buyer = web3.Keypair.fromSecretKey(
|
||||
Uint8Array.from(JSON.parse(readFileSync("./tests/test_buyer_keypair.json").toString()))
|
||||
);
|
||||
|
||||
// TODO: we need other wallets for buyers
|
||||
|
@ -32,6 +43,39 @@ describe("anchor-contributor", () => {
|
|||
// our contributor
|
||||
const contributor = new IccoContributor(program);
|
||||
|
||||
describe("Test Preparation", () => {
|
||||
it("Create Dummy Sale Token", async () => {
|
||||
// mint 8 unique tokens
|
||||
const mint = await createMint(connection, orchestrator, orchestrator.publicKey, orchestrator.publicKey, 9);
|
||||
|
||||
// we need to simulate attesting the sale token on Solana.
|
||||
// this allows us to "redeem" the sale token prior to sealing the sale
|
||||
// (which in the case of this test means minting it on the contributor program's ATA)
|
||||
await dummyConductor.attestSaleToken(connection, orchestrator);
|
||||
});
|
||||
|
||||
it("Mint Accepted SPL Tokens to Buyer", async () => {
|
||||
// first create them and add them to the accepted tokens list
|
||||
const acceptedTokens = await dummyConductor.createAcceptedTokens(connection, orchestrator);
|
||||
|
||||
for (const token of acceptedTokens) {
|
||||
const mint = new web3.PublicKey(tryHexToNativeString(token.address, CHAIN_ID_SOLANA));
|
||||
const tokenAccount = await getOrCreateAssociatedTokenAccount(connection, orchestrator, mint, buyer.publicKey);
|
||||
await mintTo(
|
||||
connection,
|
||||
orchestrator,
|
||||
mint,
|
||||
tokenAccount.address,
|
||||
orchestrator,
|
||||
20000000000n // 20,000,000,000 lamports
|
||||
);
|
||||
|
||||
const balance = await getSplBalance(connection, mint, buyer.publicKey);
|
||||
expect(balance).to.equal(20000000000n);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("Sanity Checks", () => {
|
||||
it("Cannot Contribute to Non-Existent Sale", async () => {
|
||||
{
|
||||
|
@ -41,7 +85,7 @@ describe("anchor-contributor", () => {
|
|||
|
||||
let caughtError = false;
|
||||
try {
|
||||
const tx = await contributor.contribute(owner, saleId, tokenIndex, amount);
|
||||
const tx = await contributor.contribute(orchestrator, saleId, tokenIndex, amount);
|
||||
} catch (e) {
|
||||
caughtError = e.error.errorCode.code == "AccountNotInitialized";
|
||||
}
|
||||
|
@ -55,24 +99,32 @@ describe("anchor-contributor", () => {
|
|||
|
||||
describe("Conduct Successful Sale", () => {
|
||||
// contributor info
|
||||
const contributionTokenIndex = 2;
|
||||
const contributionAmounts = ["2000000000", "3000000000"];
|
||||
const totalContributionAmount = contributionAmounts.map((x) => new BN(x)).reduce((prev, curr) => prev.add(curr));
|
||||
const contributions = new Map<number, string[]>();
|
||||
contributions.set(2, ["1200000000", "3400000000"]);
|
||||
contributions.set(8, ["5600000000", "7800000000"]);
|
||||
|
||||
const totalContributions: BN[] = [];
|
||||
contributions.forEach((amounts) => {
|
||||
totalContributions.push(amounts.map((x) => new BN(x)).reduce((prev, curr) => prev.add(curr)));
|
||||
});
|
||||
|
||||
// squirrel away associated sale token account
|
||||
let saleTokenAccount: AssociatedTokenAccount;
|
||||
|
||||
it("Create ATA for Sale Token if Non-Existent", async () => {
|
||||
saleTokenAccount = await getOrCreateAssociatedTokenAccount(
|
||||
connection,
|
||||
orchestrator,
|
||||
dummyConductor.getSaleTokenOnSolana(),
|
||||
program.programId
|
||||
);
|
||||
});
|
||||
|
||||
it("Orchestrator Initialize Sale with Signed VAA", async () => {
|
||||
const tokenAccountKey = tryHexToNativeString(
|
||||
"00000000000000000000000083752ecafebf4707258dedffbd9c7443148169db",
|
||||
CHAIN_ID_SOLANA
|
||||
); // placeholder
|
||||
|
||||
const startTime = 10 + (await getBlockTime(connection));
|
||||
const duration = 5; // seconds
|
||||
const initSaleVaa = dummyConductor.createSale(
|
||||
await getBlockTime(connection),
|
||||
duration,
|
||||
new web3.PublicKey(tokenAccountKey)
|
||||
);
|
||||
const tx = await contributor.initSale(owner, initSaleVaa);
|
||||
const initSaleVaa = dummyConductor.createSale(startTime, duration, saleTokenAccount.address);
|
||||
const tx = await contributor.initSale(orchestrator, initSaleVaa);
|
||||
|
||||
{
|
||||
// get the first sale state
|
||||
|
@ -110,7 +162,7 @@ describe("anchor-contributor", () => {
|
|||
it("Orchestrator Cannot Initialize Sale Again with Signed VAA", async () => {
|
||||
let caughtError = false;
|
||||
try {
|
||||
const tx = await contributor.initSale(owner, dummyConductor.initSaleVaa);
|
||||
const tx = await contributor.initSale(orchestrator, dummyConductor.initSaleVaa);
|
||||
} catch (e) {
|
||||
// pda init should fail
|
||||
caughtError = "programErrorStack" in e;
|
||||
|
@ -121,21 +173,6 @@ describe("anchor-contributor", () => {
|
|||
}
|
||||
});
|
||||
|
||||
it("Create Associated Token Accounts for Token Custodian", async () => {
|
||||
// TODO: need to do sale token, too
|
||||
|
||||
const tokens = dummyConductor.acceptedTokens.map((token) => {
|
||||
return tryHexToNativeString(token.address, CHAIN_ID_SOLANA)
|
||||
});
|
||||
|
||||
/*
|
||||
for(let addr of tokens) {
|
||||
await createAssociatedTokenAccount(connection, owner, addr, program.programId);
|
||||
}
|
||||
*/
|
||||
|
||||
});
|
||||
|
||||
it("User Cannot Contribute Too Early", async () => {
|
||||
const saleId = dummyConductor.getSaleId();
|
||||
const tokenIndex = 2;
|
||||
|
@ -143,7 +180,7 @@ describe("anchor-contributor", () => {
|
|||
|
||||
let caughtError = false;
|
||||
try {
|
||||
const tx = await contributor.contribute(owner, saleId, tokenIndex, amount);
|
||||
const tx = await contributor.contribute(orchestrator, saleId, tokenIndex, amount);
|
||||
} catch (e) {
|
||||
caughtError = e.error.errorCode.code == "ContributionTooEarly";
|
||||
}
|
||||
|
@ -151,8 +188,6 @@ describe("anchor-contributor", () => {
|
|||
if (!caughtError) {
|
||||
throw Error("did not catch expected error");
|
||||
}
|
||||
|
||||
// TODO: check balances on contract and buyer
|
||||
});
|
||||
|
||||
it("User Contributes to Sale", async () => {
|
||||
|
@ -163,37 +198,62 @@ describe("anchor-contributor", () => {
|
|||
await wait(saleStart - blockTime + 1);
|
||||
}
|
||||
|
||||
// now go about your business
|
||||
const acceptedTokens = dummyConductor.acceptedTokens;
|
||||
const startingBalanceBuyer = await acceptedTokens.map(async (token) => {
|
||||
const mint = hexToPublicKey(token.address);
|
||||
return getSplBalance(connection, mint, buyer.publicKey);
|
||||
});
|
||||
const startingBalanceContributor = await acceptedTokens.map(async (token) => {
|
||||
const mint = hexToPublicKey(token.address);
|
||||
return getSplBalance(connection, mint, program.programId);
|
||||
});
|
||||
|
||||
// contribute twice
|
||||
// now go about your business
|
||||
// contribute multiple times
|
||||
const saleId = dummyConductor.getSaleId();
|
||||
for (const amount of contributionAmounts) {
|
||||
const tx = await contributor.contribute(owner, saleId, contributionTokenIndex, new BN(amount));
|
||||
for (const [tokenIndex, contributionAmounts] of contributions) {
|
||||
for (const amount of contributionAmounts) {
|
||||
const tx = await contributor.contribute(orchestrator, saleId, tokenIndex, new BN(amount));
|
||||
}
|
||||
}
|
||||
|
||||
// check buyer state
|
||||
{
|
||||
const saleId = dummyConductor.getSaleId();
|
||||
const buyerState = await contributor.getBuyer(saleId, owner.publicKey);
|
||||
expect(buyerState.status).has.key("active");
|
||||
|
||||
const expectedContributedValues = [
|
||||
totalContributionAmount,
|
||||
new BN(0),
|
||||
new BN(0),
|
||||
new BN(0),
|
||||
new BN(0),
|
||||
totalContributions[0],
|
||||
new BN(0),
|
||||
new BN(0),
|
||||
totalContributions[1],
|
||||
new BN(0),
|
||||
new BN(0),
|
||||
new BN(0),
|
||||
new BN(0),
|
||||
];
|
||||
const contributed = buyerState.contributed;
|
||||
expect(contributed.length).to.equal(10);
|
||||
for (let i = 0; i < 10; ++i) {
|
||||
expect(contributed[i].toString()).to.equal(expectedContributedValues[i].toString());
|
||||
|
||||
// check buyer state
|
||||
{
|
||||
const buyerState = await contributor.getBuyer(saleId, orchestrator.publicKey);
|
||||
expect(buyerState.status).has.key("active");
|
||||
|
||||
const contributed = buyerState.contributed;
|
||||
for (let i = 0; i < expectedContributedValues.length; ++i) {
|
||||
expect(contributed[i].toString()).to.equal(expectedContributedValues[i].toString());
|
||||
}
|
||||
}
|
||||
|
||||
// check sale state
|
||||
{
|
||||
const saleState = await contributor.getSale(saleId);
|
||||
|
||||
// check totals
|
||||
const totals: any = saleState.totals;
|
||||
|
||||
for (let i = 0; i < expectedContributedValues.length; ++i) {
|
||||
const total = totals[i];
|
||||
expect(total.contributions.toString()).to.equal(expectedContributedValues[i].toString());
|
||||
expect(total.allocations.toString()).to.equal("0");
|
||||
expect(total.excessContributions.toString()).to.equal("0");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,7 +267,7 @@ describe("anchor-contributor", () => {
|
|||
|
||||
let caughtError = false;
|
||||
try {
|
||||
const tx = await contributor.contribute(owner, saleId, tokenIndex, amount);
|
||||
const tx = await contributor.contribute(orchestrator, saleId, tokenIndex, amount);
|
||||
} catch (e) {
|
||||
caughtError = e.error.errorCode.code == "InvalidTokenIndex";
|
||||
}
|
||||
|
@ -247,7 +307,7 @@ describe("anchor-contributor", () => {
|
|||
|
||||
let caughtError = false;
|
||||
try {
|
||||
const tx = await contributor.contribute(owner, saleId, tokenIndex, amount);
|
||||
const tx = await contributor.contribute(orchestrator, saleId, tokenIndex, amount);
|
||||
} catch (e) {
|
||||
caughtError = e.error.errorCode.code == "SaleEnded";
|
||||
}
|
||||
|
@ -255,18 +315,12 @@ describe("anchor-contributor", () => {
|
|||
if (!caughtError) {
|
||||
throw Error("did not catch expected error");
|
||||
}
|
||||
// check buyer state
|
||||
{
|
||||
const saleId = dummyConductor.getSaleId();
|
||||
//const buyerState = await contributor.getBuyer(saleId, owner.publicKey);
|
||||
}
|
||||
|
||||
// TODO: check balances on contract and buyer
|
||||
});
|
||||
|
||||
// TODO
|
||||
it("Orchestrator Seals Sale with Signed VAA", async () => {
|
||||
expect(false).to.be.true;
|
||||
//const saleSealedVaa = dummyConductor.sealSale();
|
||||
//const tx = await contributor.sealSale(orchestrator, saleSealedVaa);
|
||||
});
|
||||
|
||||
// TODO
|
||||
|
@ -292,24 +346,32 @@ describe("anchor-contributor", () => {
|
|||
|
||||
describe("Conduct Aborted Sale", () => {
|
||||
// contributor info
|
||||
const contributionTokenIndex = 2;
|
||||
const contributionAmounts = ["2000000000", "3000000000"];
|
||||
const totalContributionAmount = contributionAmounts.map((x) => new BN(x)).reduce((prev, curr) => prev.add(curr));
|
||||
const contributions = new Map<number, string[]>();
|
||||
contributions.set(2, ["8700000000", "6500000000"]);
|
||||
contributions.set(8, ["4300000000", "2100000000"]);
|
||||
|
||||
const totalContributions: BN[] = [];
|
||||
contributions.forEach((amounts) => {
|
||||
totalContributions.push(amounts.map((x) => new BN(x)).reduce((prev, curr) => prev.add(curr)));
|
||||
});
|
||||
|
||||
// squirrel away associated sale token account
|
||||
let saleTokenAccount: AssociatedTokenAccount;
|
||||
|
||||
it("Create ATA for Sale Token if Non-Existent", async () => {
|
||||
saleTokenAccount = await getOrCreateAssociatedTokenAccount(
|
||||
connection,
|
||||
orchestrator,
|
||||
dummyConductor.getSaleTokenOnSolana(),
|
||||
program.programId
|
||||
);
|
||||
});
|
||||
|
||||
it("Orchestrator Initialize Sale with Signed VAA", async () => {
|
||||
// set up saleInit vaa
|
||||
const tokenAccountKey = tryHexToNativeString(
|
||||
"00000000000000000000000083752ecafebf4707258dedffbd9c7443148169db",
|
||||
CHAIN_ID_SOLANA
|
||||
); // placeholder
|
||||
|
||||
const startTime = 10 + (await getBlockTime(connection));
|
||||
const duration = 5; // seconds
|
||||
const initSaleVaa = dummyConductor.createSale(
|
||||
await getBlockTime(connection),
|
||||
duration,
|
||||
new web3.PublicKey(tokenAccountKey)
|
||||
);
|
||||
const tx = await contributor.initSale(owner, initSaleVaa);
|
||||
const initSaleVaa = dummyConductor.createSale(startTime, duration, saleTokenAccount.address);
|
||||
const tx = await contributor.initSale(orchestrator, initSaleVaa);
|
||||
|
||||
{
|
||||
const saleId = dummyConductor.getSaleId();
|
||||
|
@ -352,16 +414,19 @@ describe("anchor-contributor", () => {
|
|||
}
|
||||
|
||||
// now go about your business
|
||||
// contribute multiple times
|
||||
const saleId = dummyConductor.getSaleId();
|
||||
for (const amount of contributionAmounts) {
|
||||
const tx = await contributor.contribute(owner, saleId, contributionTokenIndex, new BN(amount));
|
||||
for (const [tokenIndex, contributionAmounts] of contributions) {
|
||||
for (const amount of contributionAmounts) {
|
||||
const tx = await contributor.contribute(orchestrator, saleId, tokenIndex, new BN(amount));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it("Orchestrator Aborts Sale with Signed VAA", async () => {
|
||||
// TODO: need to abort sale
|
||||
const saleAbortedVaa = dummyConductor.abortSale(await getBlockTime(connection));
|
||||
const tx = await contributor.abortSale(owner, saleAbortedVaa);
|
||||
const tx = await contributor.abortSale(orchestrator, saleAbortedVaa);
|
||||
|
||||
{
|
||||
const saleId = dummyConductor.getSaleId();
|
||||
|
@ -376,7 +441,7 @@ describe("anchor-contributor", () => {
|
|||
|
||||
let caughtError = false;
|
||||
try {
|
||||
const tx = await contributor.abortSale(owner, saleAbortedVaa);
|
||||
const tx = await contributor.abortSale(orchestrator, saleAbortedVaa);
|
||||
} catch (e) {
|
||||
caughtError = e.error.errorCode.code == "SaleEnded";
|
||||
}
|
||||
|
@ -401,23 +466,4 @@ describe("anchor-contributor", () => {
|
|||
expect(false).to.be.true;
|
||||
});
|
||||
});
|
||||
/*
|
||||
|
||||
it("creates custody accounts for given token", async () => {
|
||||
setDefaultWasm("node");
|
||||
const { parse_vaa } = await importCoreWasm();
|
||||
const parsedVaa = parse_vaa(initSaleVaa);
|
||||
|
||||
const parsedPayload = await parseSaleInit(parsedVaa.payload);
|
||||
console.log(parsedPayload);
|
||||
|
||||
//Iterate through all accepted tokens on Solana
|
||||
let solanaTokenAddresses = [];
|
||||
|
||||
for(let addr of solanaTokenAddresses) {
|
||||
await createAssociatedTokenAccount(connection, owner, addr, program.programId);
|
||||
}
|
||||
});
|
||||
*/
|
||||
});
|
||||
|
|
@ -1,11 +1,14 @@
|
|||
import { web3 } from "@project-serum/anchor";
|
||||
import { CHAIN_ID_ETH, CHAIN_ID_SOLANA, tryNativeToHexString } from "@certusone/wormhole-sdk";
|
||||
import { createMint, getOrCreateAssociatedTokenAccount, mintTo } from "@solana/spl-token";
|
||||
import { BigNumber } from "ethers";
|
||||
|
||||
import { toBigNumberHex } from "./utils";
|
||||
import { CONDUCTOR_ADDRESS, CONDUCTOR_CHAIN } from "./consts";
|
||||
import { signAndEncodeVaa } from "./wormhole";
|
||||
import { web3 } from "@project-serum/anchor";
|
||||
|
||||
// sale struct info
|
||||
export const MAX_ACCEPTED_TOKENS = 8;
|
||||
const NUM_BYTES_ACCEPTED_TOKEN = 33;
|
||||
const NUM_BYTES_ALLOCATION = 65;
|
||||
|
||||
|
@ -18,6 +21,9 @@ export class DummyConductor {
|
|||
|
||||
initSaleVaa: Buffer;
|
||||
|
||||
saleTokenOnSolana: string;
|
||||
acceptedTokens: AcceptedToken[];
|
||||
|
||||
constructor() {
|
||||
this.saleId = 0;
|
||||
this.wormholeSequence = 0;
|
||||
|
@ -26,30 +32,50 @@ export class DummyConductor {
|
|||
this.saleEnd = 0;
|
||||
|
||||
this.acceptedTokens = [];
|
||||
this.acceptedTokens.push(makeAcceptedToken(2, "So11111111111111111111111111111111111111112"));
|
||||
}
|
||||
|
||||
async attestSaleToken(connection: web3.Connection, payer: web3.Keypair): Promise<void> {
|
||||
const mint = await createMint(connection, payer, payer.publicKey, payer.publicKey, 9);
|
||||
this.saleTokenOnSolana = mint.toBase58();
|
||||
return;
|
||||
}
|
||||
|
||||
getSaleTokenOnSolana(): web3.PublicKey {
|
||||
return new web3.PublicKey(this.saleTokenOnSolana);
|
||||
}
|
||||
|
||||
async createAcceptedTokens(connection: web3.Connection, payer: web3.Keypair): Promise<AcceptedToken[]> {
|
||||
const tokenIndices = [2, 3, 5, 8, 13, 21, 34, 55];
|
||||
for (let i = 0; i < MAX_ACCEPTED_TOKENS; ++i) {
|
||||
// just make everything the same number of decimals (9)
|
||||
const mint = await createMint(connection, payer, payer.publicKey, payer.publicKey, 9);
|
||||
const acceptedToken = makeAcceptedToken(tokenIndices[i], mint.toBase58());
|
||||
this.acceptedTokens.push(acceptedToken);
|
||||
}
|
||||
return this.acceptedTokens;
|
||||
}
|
||||
|
||||
getSaleId(): Buffer {
|
||||
return Buffer.from(toBigNumberHex(this.saleId, 32), "hex");
|
||||
}
|
||||
|
||||
createSale(blockTime: number, duration: number, associatedTokenAddress: web3.PublicKey): Buffer {
|
||||
createSale(startTime: number, duration: number, associatedSaleTokenAddress: web3.PublicKey): Buffer {
|
||||
// uptick saleId for every new sale
|
||||
++this.saleId;
|
||||
|
||||
// set up sale time based on block time
|
||||
this.saleStart = blockTime + 5;
|
||||
this.saleStart = startTime;
|
||||
this.saleEnd = this.saleStart + duration;
|
||||
|
||||
this.initSaleVaa = signAndEncodeVaa(
|
||||
blockTime,
|
||||
startTime,
|
||||
this.nonce,
|
||||
CONDUCTOR_CHAIN,
|
||||
Buffer.from(CONDUCTOR_ADDRESS).toString("hex"),
|
||||
this.wormholeSequence,
|
||||
encodeSaleInit(
|
||||
this.saleId,
|
||||
tryNativeToHexString(associatedTokenAddress.toString(), CHAIN_ID_SOLANA),
|
||||
tryNativeToHexString(associatedSaleTokenAddress.toString(), CHAIN_ID_SOLANA),
|
||||
this.tokenChain,
|
||||
this.tokenDecimals,
|
||||
this.saleStart,
|
||||
|
@ -76,7 +102,6 @@ export class DummyConductor {
|
|||
//associatedTokenAddress = "00000000000000000000000083752ecafebf4707258dedffbd9c7443148169db";
|
||||
tokenChain = CHAIN_ID_ETH as number;
|
||||
tokenDecimals = 18;
|
||||
acceptedTokens: AcceptedToken[];
|
||||
recipient = tryNativeToHexString("0x22d491bde2303f2f43325b2108d26f1eaba1e32b", CHAIN_ID_ETH);
|
||||
|
||||
// wormhole nonce
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import { web3 } from "@project-serum/anchor";
|
||||
import { getAssociatedTokenAddress, getAccount } from "@solana/spl-token";
|
||||
import { tryHexToNativeString, CHAIN_ID_SOLANA } from "@certusone/wormhole-sdk";
|
||||
import { BigNumber, BigNumberish } from "ethers";
|
||||
|
||||
export function toBigNumberHex(value: BigNumberish, numBytes: number): string {
|
||||
|
@ -16,3 +18,13 @@ export async function getBlockTime(connection: web3.Connection): Promise<number>
|
|||
const slot = await connection.getSlot();
|
||||
return connection.getBlockTime(slot);
|
||||
}
|
||||
|
||||
export async function getSplBalance(connection: web3.Connection, mint: web3.PublicKey, owner: web3.PublicKey) {
|
||||
const tokenAccount = await getAssociatedTokenAddress(mint, owner);
|
||||
const account = await getAccount(connection, tokenAccount);
|
||||
return account.amount;
|
||||
}
|
||||
|
||||
export function hexToPublicKey(hexlified: string): web3.PublicKey {
|
||||
return new web3.PublicKey(tryHexToNativeString(hexlified, CHAIN_ID_SOLANA));
|
||||
}
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
[156,58,190,217,217,182,164,165,16,94,2,148,52,60,124,179,124,246,51,210,65,41,197,4,69,101,18,51,144,149,178,85,170,87,2,76,226,26,32,176,106,152,191,126,156,67,26,119,102,204,192,42,216,85,108,243,227,56,255,208,45,59,124,205]
|
|
@ -2,9 +2,9 @@
|
|||
"compilerOptions": {
|
||||
"types": ["mocha", "chai"],
|
||||
"typeRoots": ["./node_modules/@types"],
|
||||
"lib": ["es2015"],
|
||||
"lib": ["es2020"],
|
||||
"module": "commonjs",
|
||||
"target": "es6",
|
||||
"target": "es2020",
|
||||
"esModuleInterop": true,
|
||||
"moduleResolution": "node"
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue