fix tests

This commit is contained in:
Conner Gallagher 2022-11-28 19:58:33 -07:00
parent aa08dbef43
commit 271918602f
13 changed files with 331 additions and 285 deletions

View File

@ -64,5 +64,5 @@ jobs:
run: |
solana-keygen new --no-bip39-passphrase --outfile ~/.config/solana/id.json --silent
mkdir -p .anchor/test-ledger
solana-test-validator -q -r --ledger .anchor/test-ledger --mint $(solana-keygen pubkey ~/.config/solana/id.json) --bind-address 0.0.0.0 --url https://api.devnet.solana.com --rpc-port 8899 --clone 2TfB33aLaneQb5TNVwyDz3jSZXS6jdW2ARw1Dgf84XCG --clone J4CArpsbrZqu1axqQ4AnrqREs3jwoyA1M5LMiQQmAzB9 --clone CKwZcshn4XDvhaWVH9EXnk3iu19t6t5xP2Sy2pD6TRDp & sleep 15
solana-test-validator -q -r --ledger .anchor/test-ledger --mint $(solana-keygen pubkey ~/.config/solana/id.json) --bind-address 0.0.0.0 --url https://api.devnet.solana.com --rpc-port 8899 --clone 2TfB33aLaneQb5TNVwyDz3jSZXS6jdW2ARw1Dgf84XCG --clone J4CArpsbrZqu1axqQ4AnrqREs3jwoyA1M5LMiQQmAzB9 --clone CKwZcshn4XDvhaWVH9EXnk3iu19t6t5xP2Sy2pD6TRDp --clone BYM81n8HvTJuqZU1PmTVcwZ9G8uoji7FKM6EaPkwphPt --clone FVLfR6C2ckZhbSwBzZY4CX7YBcddUSge5BNeGQv5eKhy & sleep 15
npm run test:localnet

View File

@ -5,6 +5,7 @@ import * as errors from '../errors';
import Big from 'big.js';
import { SwitchboardProgram } from '../program';
import {
AccountMeta,
Keypair,
PublicKey,
SystemProgram,
@ -20,6 +21,7 @@ import { LeaseAccount } from './leaseAccount';
import { PermissionAccount } from './permissionAccount';
import * as spl from '@solana/spl-token';
import { TransactionObject } from '../transaction';
import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
export class AggregatorAccount extends Account<types.AggregatorAccountData> {
static accountName = 'AggregatorAccountData';
@ -716,62 +718,20 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
return txnSignature;
}
public openRoundInstruction(
public async openRoundInstruction(
payer: PublicKey,
params: {
queueAccount: QueueAccount;
queueAuthority: PublicKey;
queueDataBuffer: PublicKey;
mint: PublicKey;
payoutWallet: PublicKey;
lease: [LeaseAccount, number];
leaseEscrow: PublicKey;
permission: [PermissionAccount, number];
}
): TransactionInstruction {
const [leaseAccount, leaseBump] = params.lease;
const [permissionAccount, permissionBump] = params.permission;
return types.aggregatorOpenRound(
this.program,
{
params: {
stateBump: this.program.programState.bump,
leaseBump: leaseBump,
permissionBump: permissionBump,
jitter: 0, // what is this for?
},
},
{
aggregator: this.publicKey,
lease: leaseAccount.publicKey,
oracleQueue: params.queueAccount.publicKey,
queueAuthority: params.queueAuthority,
permission: permissionAccount.publicKey,
escrow: params.leaseEscrow,
programState: this.program.programState.publicKey,
payoutWallet: params.payoutWallet,
tokenProgram: spl.TOKEN_PROGRAM_ID,
dataBuffer: params.queueDataBuffer,
mint: params.mint,
}
);
}
public async openRound(
params: Partial<{
aggregator: types.AggregatorAccountData;
queueAccount: QueueAccount;
queueAuthority: PublicKey;
queueDataBuffer: PublicKey;
mint: PublicKey;
payoutWallet: PublicKey;
lease: [LeaseAccount, number];
leaseEscrow: PublicKey;
permission: [PermissionAccount, number];
aggregator?: types.AggregatorAccountData;
queueAccount?: QueueAccount;
queue?: types.OracleQueueAccountData;
queueAuthority?: PublicKey;
queueDataBuffer?: PublicKey;
payoutWallet?: PublicKey;
lease?: [LeaseAccount, number];
leaseEscrow?: PublicKey;
permission?: [PermissionAccount, number];
}>
): Promise<TransactionSignature> {
const payer = this.program.walletPubkey;
): Promise<TransactionObject> {
const aggregator = params.aggregator ?? (await this.loadData());
const queueAccount =
params.queueAccount ??
@ -779,12 +739,16 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
let queueAuthority = params.queueAuthority;
let queueDataBuffer = params.queueDataBuffer;
let mint = params.mint;
if (!queueAuthority || !queueDataBuffer || !mint) {
const queue = await queueAccount.loadData();
let queue = params.queue;
if (params.queue) {
queueAuthority = params.queue.authority;
queueDataBuffer = params.queue.dataBuffer;
}
if (!queueAuthority || !queueDataBuffer) {
queue = await queueAccount.loadData();
queueAuthority = queue.authority;
queueDataBuffer = queue.dataBuffer;
mint = mint ?? queue.mint ?? spl.NATIVE_MINT;
}
const [leaseAccount, leaseBump] =
@ -794,18 +758,23 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
queueAccount.publicKey,
this.publicKey
);
let lease: types.LeaseAccountData;
try {
await leaseAccount.loadData();
lease = await leaseAccount.loadData();
} catch (_) {
throw new Error(
'A requested lease pda account has not been initialized.'
);
}
const leaseEscrow = spl.getAssociatedTokenAddressSync(
mint,
leaseAccount.publicKey,
true
);
const leaseEscrow =
params.leaseEscrow ??
lease.escrow ??
spl.getAssociatedTokenAddressSync(
this.program.mint.address,
leaseAccount.publicKey,
true
);
const [permissionAccount, permissionBump] =
params.permission ??
@ -815,44 +784,76 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
queueAccount.publicKey,
this.publicKey
);
let permission: types.PermissionAccountData;
try {
await permissionAccount.loadData();
permission = await permissionAccount.loadData();
} catch (_) {
throw new Error(
'A requested aggregator permission pda account has not been initialized.'
);
}
const preInstructions: Array<TransactionInstruction> = [];
const ixns: Array<TransactionInstruction> = [];
const payoutWallet = spl.getAssociatedTokenAddressSync(mint, payer, true);
try {
await spl.getAccount(this.program.connection, payoutWallet);
} catch (error) {
// TODO: Catch error and make sure it matches account doesnt exist
preInstructions.push(
spl.createAssociatedTokenAccountInstruction(
payer,
payoutWallet,
payer,
mint
)
);
const payoutWallet =
params.payoutWallet ?? this.program.mint.getAssociatedAddress(payer);
const payoutWalletAccountInfo =
await this.program.connection.getAccountInfo(payoutWallet);
if (payoutWalletAccountInfo === null) {
const [createTokenAccountTxn] =
this.program.mint.createAssocatedUserInstruction(payer);
ixns.push(...createTokenAccountTxn.ixns);
}
return await this.program.signAndSendTransaction([
...preInstructions,
this.openRoundInstruction(this.program.walletPubkey, {
queueAccount,
queueAuthority,
queueDataBuffer,
mint,
lease: [leaseAccount, leaseBump],
permission: [permissionAccount, permissionBump],
payoutWallet: payoutWallet,
leaseEscrow: leaseEscrow,
}),
]);
ixns.push(
types.aggregatorOpenRound(
this.program,
{
params: {
stateBump: this.program.programState.bump,
leaseBump,
permissionBump,
jitter: 0,
},
},
{
aggregator: this.publicKey,
lease: leaseAccount.publicKey,
oracleQueue: queueAccount.publicKey,
queueAuthority: queueAuthority,
permission: permissionAccount.publicKey,
escrow: leaseEscrow,
programState: this.program.programState.publicKey,
payoutWallet: payoutWallet,
tokenProgram: TOKEN_PROGRAM_ID,
dataBuffer: queueDataBuffer,
mint: this.program.mint.address,
}
)
);
return new TransactionObject(payer, ixns, []);
}
public async openRound(
params: Partial<{
aggregator?: types.AggregatorAccountData;
queueAccount?: QueueAccount;
queue?: types.OracleQueueAccountData;
queueAuthority?: PublicKey;
queueDataBuffer?: PublicKey;
payoutWallet?: PublicKey;
lease?: [LeaseAccount, number];
leaseEscrow?: PublicKey;
permission?: [PermissionAccount, number];
}>
): Promise<TransactionSignature> {
const openRoundTxn = await this.openRoundInstruction(
this.program.walletPubkey,
params
);
const txnSignature = await this.program.signAndSend(openRoundTxn);
return txnSignature;
}
public saveResultInstruction(
@ -877,6 +878,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
} & Partial<{
error?: boolean;
historyBuffer?: PublicKey;
oracles: Array<types.OracleAccountData>;
}>
): TransactionInstruction {
const [leaseAccount, leaseBump] = params.lease;
@ -944,11 +946,26 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
payoutWallet: PublicKey;
lease: [LeaseAccount, number];
leaseEscrow: PublicKey;
oracles: Array<types.OracleAccountData>;
}>
): Promise<TransactionSignature> {
const payer = this.program.walletPubkey;
const aggregator = params.aggregator ?? (await this.loadData());
const remainingAccounts: Array<PublicKey> = [];
for (let i = 0; i < aggregator.oracleRequestBatchSize; ++i) {
remainingAccounts.push(aggregator.currentRound.oraclePubkeysData[i]);
}
for (const oracle of params?.oracles ?? []) {
remainingAccounts.push(oracle.tokenAccount);
}
remainingAccounts.push(
anchor.utils.publicKey.findProgramAddressSync(
[Buffer.from('SlidingResultAccountData'), this.publicKey.toBytes()],
this.program.programId
)[0]
);
const oracleIdx =
params.oracleIdx ??
aggregator.currentRound.oraclePubkeysData
@ -959,6 +976,18 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
throw new Error('Failed to find oracle in current round');
}
const ixns: Array<TransactionInstruction> = [];
const payoutWallet =
params.payoutWallet ?? this.program.mint.getAssociatedAddress(payer);
const payoutWalletAccountInfo =
await this.program.connection.getAccountInfo(payoutWallet);
if (payoutWalletAccountInfo === null) {
const [createTokenAccountTxn] =
this.program.mint.createAssocatedUserInstruction(payer);
ixns.push(...createTokenAccountTxn.ixns);
}
const queueAccount =
params.queueAccount ??
new QueueAccount(this.program, aggregator.queuePubkey);
@ -1023,49 +1052,41 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
);
}
const preInstructions: Array<TransactionInstruction> = [];
const payoutWallet = spl.getAssociatedTokenAddressSync(mint, payer, true);
try {
await spl.getAccount(this.program.connection, payoutWallet);
} catch (error) {
// TODO: Catch error and make sure it matches account doesnt exist
preInstructions.push(
spl.createAssociatedTokenAccountInstruction(
payer,
payoutWallet,
payer,
mint
)
);
}
const historyBuffer = params.historyBuffer ?? aggregator.historyBuffer;
// TODO: Add SlidingWindow account to remainingAccounts
const saveResultIxn = this.saveResultInstruction({
queueAccount,
queueAuthority,
feedPermission: [feedPermissionAccount, feedPermissionBump],
jobs: params.jobs,
historyBuffer: historyBuffer.equals(PublicKey.default)
? undefined
: historyBuffer,
oracleAccount: params.oracleAccount,
oracleIdx,
oraclePermission: [oraclePermissionAccount, oraclePermissionBump],
value: params.value,
minResponse: params.minResponse,
maxResponse: params.maxResponse,
error: params.error ?? false,
mint,
payoutWallet: payoutWallet,
lease: [leaseAccount, leaseBump],
leaseEscrow: leaseEscrow,
});
saveResultIxn.keys.push(
...remainingAccounts.map((pubkey): AccountMeta => {
return { isSigner: false, isWritable: true, pubkey };
})
);
ixns.push(saveResultIxn);
return await this.program.signAndSendTransaction([
...preInstructions,
this.saveResultInstruction({
queueAccount,
queueAuthority,
feedPermission: [feedPermissionAccount, feedPermissionBump],
jobs: params.jobs,
historyBuffer: historyBuffer.equals(PublicKey.default)
? undefined
: historyBuffer,
oracleAccount: params.oracleAccount,
oracleIdx,
oraclePermission: [oraclePermissionAccount, oraclePermissionBump],
value: params.value,
minResponse: params.minResponse,
maxResponse: params.maxResponse,
error: params.error ?? false,
mint,
payoutWallet: payoutWallet,
lease: [leaseAccount, leaseBump],
leaseEscrow: leaseEscrow,
}),
]);
const saveResultTxn = new TransactionObject(
this.program.walletPubkey,
ixns,
[]
);
const txnSignature = await this.program.signAndSend(saveResultTxn);
return txnSignature;
}
}

View File

@ -90,7 +90,6 @@ export class LeaseAccount extends Account<types.LeaseAccountData> {
payer: PublicKey,
params: {
loadAmount?: number;
mint: PublicKey;
funder?: PublicKey;
funderAuthority?: Keypair;
queuePubkey: PublicKey;
@ -111,11 +110,11 @@ export class LeaseAccount extends Account<types.LeaseAccountData> {
const funder = params.funder
? params.funder
: program.mint.getAssociatedAddress(funderAuthority);
const funderBalance = await program.mint.getBalance(funderAuthority);
const funderBalance = (await program.mint.getBalance(funderAuthority)) ?? 0;
if (loadAmount && funderBalance < loadAmount) {
const wrapIxns = await program.mint.unwrapInstruction(
const wrapIxns = await program.mint.wrapInstruction(
payer,
params.loadAmount,
{ amount: loadAmount },
params.funderAuthority
);
ixns.push(...wrapIxns.ixns);
@ -132,14 +131,14 @@ export class LeaseAccount extends Account<types.LeaseAccountData> {
[
leaseAccount.publicKey.toBuffer(),
spl.TOKEN_PROGRAM_ID.toBuffer(),
params.mint.toBuffer(),
program.mint.address.toBuffer(),
],
spl.ASSOCIATED_TOKEN_PROGRAM_ID
);
const { walletBumps } = LeaseAccount.getWallets(
params.jobAuthorities,
params.mint
program.mint.address
);
ixns.push(
@ -147,7 +146,7 @@ export class LeaseAccount extends Account<types.LeaseAccountData> {
payer,
escrow,
leaseAccount.publicKey,
params.mint
program.mint.address
),
types.leaseInit(
program,
@ -171,7 +170,7 @@ export class LeaseAccount extends Account<types.LeaseAccountData> {
owner: funderAuthority,
escrow: escrow,
programState: program.programState.publicKey,
mint: params.mint,
mint: program.mint.address,
}
)
);
@ -348,7 +347,8 @@ export class LeaseAccount extends Account<types.LeaseAccountData> {
const funder = params.funder
? params.funder
: this.program.mint.getAssociatedAddress(funderAuthority);
const funderBalance = await this.program.mint.getBalance(funderAuthority);
const funderBalance =
(await this.program.mint.getBalance(funderAuthority)) ?? 0;
if (funderBalance < params.loadAmount) {
const wrapIxns = await this.program.mint.unwrapInstruction(
payer,

View File

@ -253,7 +253,8 @@ export class OracleAccount extends Account<types.OracleAccountData> {
);
}
return await this.program.signAndSendTransaction(
const heartbeatTxn = new TransactionObject(
this.program.walletPubkey,
[
this.heartbeatInstruction(this.program.walletPubkey, {
tokenWallet: tokenWallet,
@ -266,6 +267,9 @@ export class OracleAccount extends Account<types.OracleAccountData> {
],
params.authority ? [params.authority] : []
);
const txnSignature = await this.program.signAndSend(heartbeatTxn);
return txnSignature;
}
withdrawInstruction(
@ -343,7 +347,8 @@ export class OracleAccount extends Account<types.OracleAccountData> {
permissionBump = permission[1];
}
return await this.program.signAndSendTransaction(
const withdrawTxn = new TransactionObject(
this.program.walletPubkey,
[
this.withdrawInstruction(this.program.walletPubkey, {
amount: params.amount,
@ -355,5 +360,8 @@ export class OracleAccount extends Account<types.OracleAccountData> {
],
params.authority ? [params.authority] : []
);
const txnSignature = await this.program.signAndSend(withdrawTxn);
return txnSignature;
}
}

View File

@ -1,5 +1,5 @@
import * as anchor from '@project-serum/anchor';
import { SwitchboardProgram } from '../';
import { SwitchboardProgram } from '../program';
import * as types from '../generated';
import { Account } from './account';
import * as spl from '@solana/spl-token';
@ -10,6 +10,7 @@ import {
SystemProgram,
TransactionSignature,
} from '@solana/web3.js';
import { TransactionObject } from '../transaction';
/**
* Account type representing Switchboard global program state.
@ -68,21 +69,28 @@ export class ProgramStateAccount extends Account<types.SbState> {
];
}
})();
const instruction = types.programInit(
program,
{ params: { stateBump: bump } },
{
state: account.publicKey,
authority: program.wallet.publicKey,
payer: program.wallet.publicKey,
tokenMint: mint,
vault: vault,
systemProgram: SystemProgram.programId,
tokenProgram: spl.TOKEN_PROGRAM_ID,
daoMint: params.daoMint ?? mint,
}
const programInit = new TransactionObject(
program.walletPubkey,
[
types.programInit(
program,
{ params: { stateBump: bump } },
{
state: account.publicKey,
authority: program.wallet.publicKey,
payer: program.wallet.publicKey,
tokenMint: mint,
vault: vault,
systemProgram: SystemProgram.programId,
tokenProgram: spl.TOKEN_PROGRAM_ID,
daoMint: params.daoMint ?? mint,
}
),
],
[]
);
await program.signAndSendTransaction([instruction]);
await program.signAndSend(programInit);
} catch {} // eslint-disable-line no-empty
}
return [account, bump];
@ -143,18 +151,26 @@ export class ProgramStateAccount extends Account<types.SbState> {
): Promise<TransactionSignature> {
const [account, bump] = ProgramStateAccount.fromSeed(program);
const vault = (await account.loadData()).tokenVault;
const instruction = types.vaultTransfer(
program,
{ params: { stateBump: bump, amount: params.amount } },
{
state: account.publicKey,
to,
vault,
authority: authority.publicKey,
tokenProgram: spl.TOKEN_PROGRAM_ID,
}
const vaultTransfer = new TransactionObject(
program.walletPubkey,
[
types.vaultTransfer(
program,
{ params: { stateBump: bump, amount: params.amount } },
{
state: account.publicKey,
to,
vault,
authority: authority.publicKey,
tokenProgram: spl.TOKEN_PROGRAM_ID,
}
),
],
[]
);
return program.signAndSendTransaction([instruction]);
const txnSignature = await program.signAndSend(vaultTransfer);
return txnSignature;
}
/**
* @return account size of the global {@linkcode ProgramStateAccount}.

View File

@ -405,7 +405,20 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
): Promise<[TransactionObject[], AggregatorAccount]> {
const queue = await this.loadData();
const pre: TransactionObject[] = [];
const txns: TransactionObject[] = [];
const post: TransactionObject[] = [];
// getOrCreate token account for
const userTokenAddress = this.program.mint.getAssociatedAddress(payer);
const userTokenAccountInfo = await this.program.connection.getAccountInfo(
userTokenAddress
);
if (userTokenAccountInfo === null) {
const [createTokenAccount] =
this.program.mint.createAssocatedUserInstruction(payer);
pre.push(createTokenAccount);
}
// create / load jobs
const jobs: { job: JobAccount; weight: number }[] = [];
@ -424,7 +437,7 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
jobKeypair: job.jobKeypair,
}
);
txns.push(...jobInit);
pre.push(...jobInit);
jobs.push({ job: jobAccount, weight: job.weight ?? 1 });
} else if ('pubkey' in job) {
const jobAccount = new JobAccount(this.program, job.pubkey);
@ -435,16 +448,6 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
}
}
}
// getOrCreate token account for
const userTokenAddress = this.program.mint.getAssociatedAddress(payer);
const userTokenAccountInfo = await this.program.connection.getAccountInfo(
userTokenAddress
);
if (userTokenAccountInfo === null) {
const [createTokenAccount] =
this.program.mint.createAssocatedUserInstruction(payer);
txns.push(createTokenAccount);
}
const [aggregatorInit, aggregatorAccount] =
await AggregatorAccount.createInstruction(this.program, payer, {
@ -465,14 +468,14 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
loadAmount: params.loadAmount,
funder: params.funder,
funderAuthority: params.funderAuthority,
mint: this.program.mint.address,
aggregatorPubkey: aggregatorAccount.publicKey,
queuePubkey: this.publicKey,
jobAuthorities: [],
}
);
txns.push(leaseInit);
// // create permission account
// create permission account
const [permissionInit, permissionAccount] =
PermissionAccount.createInstruction(this.program, payer, {
granter: this.publicKey,
@ -498,10 +501,14 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
weight: weight,
authority: params.authority,
});
txns.push(addJobTxn);
post.push(addJobTxn);
}
const packed = TransactionObject.pack(txns);
const packed = TransactionObject.pack([
...TransactionObject.pack(pre),
...TransactionObject.pack(txns),
...TransactionObject.pack(post),
]);
return [packed, aggregatorAccount];
}

View File

@ -4,6 +4,7 @@ import { PublicKey, SystemProgram } from '@solana/web3.js';
import * as errors from '../errors';
import * as types from '../generated';
import { SwitchboardProgram } from '../program';
import { TransactionObject } from '../transaction';
import { Account, OnAccountChangeCallback } from './account';
import { QueueAccount } from './queueAccount';
@ -48,15 +49,13 @@ export class VrfAccount extends Account<types.VrfAccountData> {
program: SwitchboardProgram,
params: VrfInitParams
): Promise<[string, VrfAccount]> {
return this.createInstructions(program, {
...params,
payerKeypair: program.wallet.payer,
}).then(async ([instructions, account]) => {
const txSignature = await program.signAndSendTransaction(instructions, [
params.vrfKeypair,
]);
return [txSignature, account];
});
const [createTxn, vrfAccount] = await VrfAccount.createInstructions(
program,
program.walletPubkey,
params
);
const txnSignature = await program.signAndSend(createTxn);
return [txnSignature, vrfAccount];
}
/**
@ -67,9 +66,9 @@ export class VrfAccount extends Account<types.VrfAccountData> {
*/
public static async createInstructions(
program: SwitchboardProgram,
params: VrfInitParams & { payerKeypair: anchor.web3.Keypair },
payer: PublicKey = program.walletPubkey
): Promise<[anchor.web3.TransactionInstruction[], VrfAccount]> {
payer: PublicKey,
params: VrfInitParams
): Promise<[TransactionObject, VrfAccount]> {
const vrfAccount = new VrfAccount(program, params.vrfKeypair.publicKey);
const size = program.account.vrfAccountData.size;
const switchTokenMint = await params.queue.loadMint();
@ -78,50 +77,50 @@ export class VrfAccount extends Account<types.VrfAccountData> {
params.vrfKeypair.publicKey,
true
);
return [
[
spl.createAssociatedTokenAccountInstruction(
program.wallet.payer.publicKey,
escrow,
params.vrfKeypair.publicKey,
switchTokenMint.address
const ixns = [
spl.createAssociatedTokenAccountInstruction(
program.wallet.payer.publicKey,
escrow,
params.vrfKeypair.publicKey,
switchTokenMint.address
),
spl.createSetAuthorityInstruction(
escrow,
params.vrfKeypair.publicKey,
spl.AuthorityType.AccountOwner,
program.programState.publicKey,
[program.wallet.payer, params.vrfKeypair]
),
SystemProgram.createAccount({
fromPubkey: program.wallet.payer.publicKey,
newAccountPubkey: params.vrfKeypair.publicKey,
space: size,
lamports: await program.connection.getMinimumBalanceForRentExemption(
size
),
spl.createSetAuthorityInstruction(
escrow,
params.vrfKeypair.publicKey,
spl.AuthorityType.AccountOwner,
program.programState.publicKey,
[program.wallet.payer, params.vrfKeypair]
),
SystemProgram.createAccount({
fromPubkey: program.wallet.payer.publicKey,
newAccountPubkey: params.vrfKeypair.publicKey,
space: size,
lamports: await program.connection.getMinimumBalanceForRentExemption(
size
),
programId: program.programId,
}),
types.vrfInit(
program,
{
params: {
stateBump: program.programState.bump,
callback: params.callback,
},
programId: program.programId,
}),
types.vrfInit(
program,
{
params: {
stateBump: program.programState.bump,
callback: params.callback,
},
{
vrf: params.vrfKeypair.publicKey,
authority: params.authority ?? params.vrfKeypair.publicKey,
escrow,
oracleQueue: params.queue.publicKey,
programState: program.programState.publicKey,
tokenProgram: spl.TOKEN_PROGRAM_ID,
}
),
],
vrfAccount,
},
{
vrf: params.vrfKeypair.publicKey,
authority: params.authority ?? params.vrfKeypair.publicKey,
escrow,
oracleQueue: params.queue.publicKey,
programState: program.programState.publicKey,
tokenProgram: spl.TOKEN_PROGRAM_ID,
}
),
];
const txn = new TransactionObject(payer, ixns, [params.vrfKeypair]);
return [txn, vrfAccount];
}
/**

View File

@ -55,14 +55,23 @@ export class Mint {
return swbDecimal.toBig().toNumber();
}
public async getAccount(user: PublicKey): Promise<spl.Account> {
public async getAccount(user: PublicKey): Promise<spl.Account | null> {
const userTokenAddress = Mint.getAssociatedAddress(user);
const account = await spl.getAccount(this.connection, userTokenAddress);
const userTokenAccountInfo = await this.provider.connection.getAccountInfo(
userTokenAddress
);
if (userTokenAccountInfo === null) {
return null;
}
const account = spl.unpackAccount(userTokenAddress, userTokenAccountInfo);
return account;
}
public async getBalance(user: PublicKey): Promise<number> {
public async getBalance(user: PublicKey): Promise<number | null> {
const userAccount = await this.getAccount(user);
if (userAccount === null) {
return null;
}
return this.fromTokenAmount(userAccount.amount);
}
@ -147,7 +156,7 @@ export class Mint {
Mint.native,
owner
);
return [account, new TransactionObject(payer, [ixn], user ? [user] : [])];
return [account, new TransactionObject(payer, [ixn], [])];
}
public createUserInstruction(
@ -179,6 +188,8 @@ export class Mint {
throw new NativeMintOnlyError();
}
const ixns: TransactionInstruction[] = [];
const owner = user ? user.publicKey : payer;
const ownerBalance = new Big(await this.connection.getBalance(owner));
@ -189,6 +200,16 @@ export class Mint {
userAccountInfo === null
? null
: spl.unpackAccount(userAddress, userAccountInfo);
// if (userAccount === null) {
// ixns.push(
// spl.createAssociatedTokenAccountInstruction(
// payer,
// userAddress,
// owner,
// Mint.native
// )
// );
// }
const balance = userAccount
? new Big(this.fromTokenAmount(userAccount.amount))
@ -219,7 +240,7 @@ export class Mint {
const wrapAmountLamports = this.toTokenAmount(wrapAmount.toNumber());
const ixns = [
ixns.push(
spl.createAssociatedTokenAccountInstruction(
payer,
ephemeralWallet,
@ -242,8 +263,8 @@ export class Mint {
ephemeralWallet,
owner,
ephemeralAccount.publicKey
),
];
)
);
return new TransactionObject(
payer,
@ -286,7 +307,7 @@ export class Mint {
const signers: Keypair[] = user ? [user] : [];
const userAddress = this.getAssociatedAddress(owner);
const userBalance = await this.getBalance(owner);
const userBalance = (await this.getBalance(owner)) ?? 0;
if (amount) {
if (amount >= userBalance) {

View File

@ -376,27 +376,6 @@ export class SwitchboardProgram {
return txnSignature;
}
public async signAndSendTransaction(
instructions: TransactionInstruction[],
signers?: Signer[]
): Promise<TransactionSignature> {
if (isBrowser) throw new errors.SwitchboardProgramIsBrowserError();
if (this.isReadOnly) throw new errors.SwitchboardProgramReadOnlyError();
const txnSignature = await this.provider.sendAndConfirm(
await this.provider.wallet.signTransaction(
new Transaction({
feePayer: this.provider.wallet.publicKey,
...(await this.connection.getLatestBlockhash()),
}).add(...instructions)
),
signers,
{ skipPreflight: false, maxRetries: 10 }
);
return txnSignature;
}
}
export class AnchorWallet implements anchor.Wallet {

View File

@ -50,6 +50,8 @@ describe('Aggregator Tests', () => {
queueAccount = oracleQueue;
await ctx.program.mint.getOrCreateAssociatedUser(ctx.program.walletPubkey);
// add a single oracle for open round calls
await queueAccount.createOracle({
name: 'oracle-1',
@ -222,9 +224,8 @@ describe('Aggregator Tests', () => {
);
}
const finalUserTokenBalance = await ctx.program.mint.getBalance(
ctx.payer.publicKey
);
const finalUserTokenBalance =
(await ctx.program.mint.getBalance(ctx.payer.publicKey)) ?? 0;
if (initialUserTokenBalance !== finalUserTokenBalance) {
throw new Error(
`User token balance has incorrect funds, expected ${initialUserTokenBalance} wSOL, received ${finalUserTokenBalance}`

View File

@ -27,10 +27,8 @@ describe('Mint Tests', () => {
await ctx.program.mint.createAssocatedUser(ctx.payer.publicKey, user);
userTokenAddress = tokenAddress;
const userTokenAccount = await ctx.program.mint.getAccount(user.publicKey);
const userTokenBalance = ctx.program.mint.fromTokenAmount(
userTokenAccount.amount
);
const userTokenBalance =
(await ctx.program.mint.getBalance(user.publicKey)) ?? 0;
if (userTokenBalance !== 0) {
throw new Error(
@ -50,10 +48,8 @@ describe('Mint Tests', () => {
user
);
const userTokenAccount = await ctx.program.mint.getAccount(user.publicKey);
const userTokenBalance = ctx.program.mint.fromTokenAmount(
userTokenAccount.amount
);
const userTokenBalance =
(await ctx.program.mint.getBalance(user.publicKey)) ?? 0;
if (userTokenBalance !== 0.25) {
throw new Error(
`Incorrect user token balance, expected 0.25, received ${userTokenBalance}`
@ -66,12 +62,8 @@ describe('Mint Tests', () => {
throw new Error(`User token address does not exist`);
}
const initialUserTokenAccount = await ctx.program.mint.getAccount(
user.publicKey
);
const initialUserTokenBalance = ctx.program.mint.fromTokenAmount(
initialUserTokenAccount.amount
);
const initialUserTokenBalance =
(await ctx.program.mint.getBalance(user.publicKey)) ?? 0;
const expectedFinalBalance = initialUserTokenBalance - 0.1;
if (expectedFinalBalance < 0) {
throw new Error(`Final user token address would be negative`);

View File

@ -74,6 +74,8 @@ export async function setupTest(): Promise<TestContext> {
console.error(e);
}
await program.mint.getOrCreateAssociatedUser(program.walletPubkey);
return {
cluster,
program,

View File

@ -1426,7 +1426,7 @@ export class AggregatorAccount {
mint: params.tokenMint,
})
.remainingAccounts(
remainingAccounts.map((pubkey: PublicKey) => {
remainingAccounts.map((pubkey: PublicKey): AccountMeta => {
return { isSigner: false, isWritable: true, pubkey };
})
)