solana.js: save result fixes

This commit is contained in:
Conner Gallagher 2022-12-22 17:04:50 -07:00
parent 3309e086c1
commit bee8ef1d24
1 changed files with 119 additions and 143 deletions

View File

@ -23,7 +23,10 @@ import { QueueAccount } from './queueAccount';
import { LeaseAccount, LeaseExtendParams } from './leaseAccount'; import { LeaseAccount, LeaseExtendParams } from './leaseAccount';
import { PermissionAccount } from './permissionAccount'; import { PermissionAccount } from './permissionAccount';
import * as spl from '@solana/spl-token'; import * as spl from '@solana/spl-token';
import { TransactionObject } from '../TransactionObject'; import {
TransactionObject,
TransactionObjectOptions,
} from '../TransactionObject';
import { TOKEN_PROGRAM_ID } from '@solana/spl-token'; import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
import { AggregatorHistoryBuffer } from './aggregatorHistoryBuffer'; import { AggregatorHistoryBuffer } from './aggregatorHistoryBuffer';
import { CrankAccount } from './crankAccount'; import { CrankAccount } from './crankAccount';
@ -1306,42 +1309,19 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
return txnSignature; return txnSignature;
} }
public saveResultInstruction( public saveResultInstructionSync(
params: { payer: PublicKey,
queueAccount: QueueAccount; params: AggregatorSaveResultSyncParams,
queueAuthority: PublicKey; options?: TransactionObjectOptions
feedPermission: [PermissionAccount, number]; ): TransactionObject {
jobs: Array<OracleJob>;
// oracle
oracleAccount: OracleAccount;
oracleAuthority: PublicKey;
oracleIdx: number;
oraclePermission: [PermissionAccount, number];
// response
value: Big;
minResponse: Big;
maxResponse: Big;
// token
mint: PublicKey;
payoutWallet: PublicKey;
lease: [LeaseAccount, number];
leaseEscrow: PublicKey;
} & Partial<{
error?: boolean;
historyBuffer?: PublicKey;
oracles: Array<types.OracleAccountData>;
}>
): TransactionInstruction {
const [leaseAccount, leaseBump] = params.lease;
const [feedPermissionAccount, feedPermissionBump] = params.feedPermission;
const [oraclePermissionAccount, oraclePermissionBump] = const [oraclePermissionAccount, oraclePermissionBump] =
params.oraclePermission; params.oraclePermission;
if (params.oracleIdx < 0) { if (params.oracleIdx < 0 || params.oracleIdx > params.oracles.length - 1) {
throw new Error('Failed to find oracle in current round'); throw new Error('Failed to find oracle in current round');
} }
return types.aggregatorSaveResult( const saveResultIxn = types.aggregatorSaveResult(
this.program, this.program,
{ {
params: { params: {
@ -1353,108 +1333,73 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
.borsh, .borsh,
maxResponse: types.SwitchboardDecimal.fromBig(params.maxResponse) maxResponse: types.SwitchboardDecimal.fromBig(params.maxResponse)
.borsh, .borsh,
feedPermissionBump: feedPermissionBump, feedPermissionBump: params.permissionBump,
oraclePermissionBump: oraclePermissionBump, oraclePermissionBump: oraclePermissionBump,
leaseBump: leaseBump, leaseBump: params.leaseBump,
stateBump: this.program.programState.bump, stateBump: this.program.programState.bump,
}, },
}, },
{ {
aggregator: this.publicKey, aggregator: this.publicKey,
oracle: params.oracleAccount.publicKey, oracle: params.oracles[params.oracleIdx].account.publicKey,
oracleAuthority: params.oracleAuthority, oracleAuthority: params.oracles[params.oracleIdx].state.oracleAuthority,
oracleQueue: params.queueAccount.publicKey, oracleQueue: params.queueAccount.publicKey,
queueAuthority: params.queueAuthority, queueAuthority: params.queueAuthority,
feedPermission: feedPermissionAccount.publicKey, feedPermission: params.permissionAccount.publicKey,
oraclePermission: oraclePermissionAccount.publicKey, oraclePermission: oraclePermissionAccount.publicKey,
lease: leaseAccount.publicKey, lease: params.leaseAccount.publicKey,
escrow: params.leaseEscrow, escrow: params.leaseEscrow,
tokenProgram: spl.TOKEN_PROGRAM_ID, tokenProgram: spl.TOKEN_PROGRAM_ID,
programState: this.program.programState.publicKey, programState: this.program.programState.publicKey,
historyBuffer: params.historyBuffer ?? this.publicKey, historyBuffer: params.historyBuffer ?? this.publicKey,
mint: params.mint, mint: this.program.mint.address,
} }
); );
}
public async saveResult(
params: {
jobs: Array<OracleJob>;
oracleAccount: OracleAccount;
value: Big;
minResponse: Big;
maxResponse: Big;
} & Partial<{
queueAccount: QueueAccount;
queueAuthority: PublicKey;
aggregator: types.AggregatorAccountData;
feedPermission: [PermissionAccount, number];
historyBuffer: PublicKey;
oracleIdx: number;
oracleAuthority: PublicKey;
oraclePermission: [PermissionAccount, number];
error: boolean;
mint: PublicKey;
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> = []; const remainingAccounts: Array<PublicKey> = [];
for (let i = 0; i < aggregator.oracleRequestBatchSize; ++i) { params.oracles.forEach(oracle =>
remainingAccounts.push(aggregator.currentRound.oraclePubkeysData[i]); remainingAccounts.push(oracle.account.publicKey)
} );
for (const oracle of params?.oracles ?? params.oracles.forEach(oracle =>
(await this.loadCurrentRoundOracles(aggregator)).map(a => a.state)) { remainingAccounts.push(oracle.state.tokenAccount)
remainingAccounts.push(oracle.tokenAccount); );
}
remainingAccounts.push(this.slidingWindowKey); remainingAccounts.push(this.slidingWindowKey);
saveResultIxn.keys.push(
...remainingAccounts.map((pubkey): AccountMeta => {
return { isSigner: false, isWritable: true, pubkey };
})
);
return new TransactionObject(payer, [saveResultIxn], [], options);
}
public async saveResultInstruction(
payer: PublicKey,
params: AggregatorSaveResultAsyncParams,
options?: TransactionObjectOptions
): Promise<TransactionObject> {
const aggregator = params.aggregator ?? (await this.loadData());
const oracles =
params.oracles ?? (await this.loadCurrentRoundOracles(aggregator));
const oracleIdx = const oracleIdx =
params.oracleIdx ?? params.oracleIdx ??
aggregator.currentRound.oraclePubkeysData oracles.findIndex(o =>
.slice(0, aggregator.oracleRequestBatchSize) o.account.publicKey.equals(params.oracleAccount.publicKey)
.findIndex(o => o.equals(params.oracleAccount.publicKey)); );
if (oracleIdx < 0) { if (oracleIdx < 0 || oracleIdx > oracles.length - 1) {
throw new Error('Failed to find oracle in current round'); 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 = const queueAccount =
params.queueAccount ?? params.queueAccount ??
new QueueAccount(this.program, aggregator.queuePubkey); new QueueAccount(this.program, aggregator.queuePubkey);
let queueAuthority = params.queueAuthority; const queueAuthority =
let mint = params.mint; params.queueAuthority ?? (await queueAccount.loadData()).authority;
if (!queueAuthority || !mint) {
const queue = await queueAccount.loadData();
queueAuthority = queue.authority;
mint = mint ?? queue.mint ?? spl.NATIVE_MINT;
}
const {
permissionAccount,
permissionBump,
leaseAccount,
leaseBump,
leaseEscrow,
} = this.getAccounts(queueAccount, queueAuthority);
const [oraclePermissionAccount, oraclePermissionBump] = const [oraclePermissionAccount, oraclePermissionBump] =
params.oraclePermission ?? params.oraclePermission ??
@ -1464,50 +1409,54 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
queueAccount.publicKey, queueAccount.publicKey,
params.oracleAccount.publicKey params.oracleAccount.publicKey
); );
try {
await oraclePermissionAccount.loadData();
} catch (_) {
throw new Error(
'A requested oracle permission pda account has not been initialized.'
);
}
const historyBuffer = params.historyBuffer ?? aggregator.historyBuffer; const accounts: AggregatorPdaAccounts =
params.permissionAccount === undefined ||
params.leaseAccount === undefined ||
params.leaseEscrow === undefined ||
params.permissionBump === undefined ||
params.leaseBump === undefined
? this.getAccounts(queueAccount, queueAuthority)
: {
permissionAccount: params.permissionAccount,
permissionBump: params.permissionBump,
leaseAccount: params.leaseAccount,
leaseBump: params.leaseBump,
leaseEscrow: params.leaseEscrow,
};
const saveResultIxn = this.saveResultInstruction({ const saveResultTxn = this.saveResultInstructionSync(
queueAccount, payer,
queueAuthority, {
feedPermission: [permissionAccount, permissionBump], ...accounts,
jobs: params.jobs, queueAccount,
historyBuffer: historyBuffer.equals(PublicKey.default) queueAuthority,
? undefined jobs: params.jobs,
: historyBuffer, historyBuffer: aggregator.historyBuffer.equals(PublicKey.default)
oracleAccount: params.oracleAccount, ? undefined
oracleAuthority: (await params.oracleAccount.loadData()).oracleAuthority, : aggregator.historyBuffer,
oracleIdx, oracleIdx,
oraclePermission: [oraclePermissionAccount, oraclePermissionBump], oraclePermission: [oraclePermissionAccount, oraclePermissionBump],
value: params.value, value: params.value,
minResponse: params.minResponse, minResponse: params.minResponse,
maxResponse: params.maxResponse, maxResponse: params.maxResponse,
error: params.error ?? false, error: params.error ?? false,
mint, aggregator: aggregator,
payoutWallet: payoutWallet, oracles: oracles,
lease: [leaseAccount, leaseBump], },
leaseEscrow: leaseEscrow, options
});
// add remaining accounts
saveResultIxn.keys.push(
...remainingAccounts.map((pubkey): AccountMeta => {
return { isSigner: false, isWritable: true, pubkey };
})
); );
return saveResultTxn;
}
ixns.push(saveResultIxn); public async saveResult(
const saveResultTxn = new TransactionObject( params: AggregatorSaveResultAsyncParams,
options?: TransactionObjectOptions
): Promise<TransactionSignature> {
const saveResultTxn = await this.saveResultInstruction(
this.program.walletPubkey, this.program.walletPubkey,
ixns, params,
[] options
); );
const txnSignature = await this.program.signAndSend(saveResultTxn); const txnSignature = await this.program.signAndSend(saveResultTxn);
return txnSignature; return txnSignature;
@ -2054,3 +2003,30 @@ export type AggregatorPdaAccounts = {
leaseBump: number; leaseBump: number;
leaseEscrow: PublicKey; leaseEscrow: PublicKey;
}; };
export type SaveResultResponse = {
jobs: Array<OracleJob>;
// oracleAccount: OracleAccount;
value: Big;
minResponse: Big;
maxResponse: Big;
error?: boolean;
};
export type SaveResultAccounts = AggregatorPdaAccounts & {
aggregator: types.AggregatorAccountData;
// queue
queueAccount: QueueAccount;
queueAuthority: PublicKey;
// oracle
oraclePermission: [PermissionAccount, number];
oracles: Array<{ account: OracleAccount; state: types.OracleAccountData }>;
oracleIdx: number;
// history
historyBuffer?: PublicKey;
};
export type AggregatorSaveResultSyncParams = SaveResultResponse &
SaveResultAccounts;
export type AggregatorSaveResultAsyncParams = SaveResultResponse &
(Partial<SaveResultAccounts> & { oracleAccount: OracleAccount });