solana.js: added aggregator queue transfer method
This commit is contained in:
parent
2c8e676c9b
commit
9620ce3bc9
|
@ -19,11 +19,13 @@ import crypto from 'crypto';
|
|||
import { JobAccount } from './jobAccount';
|
||||
import { QueueAccount } from './queueAccount';
|
||||
import { LeaseAccount } from './leaseAccount';
|
||||
import { PermissionAccount } from './permissionAccount';
|
||||
import { PermissionAccount, PermissionSetParams } from './permissionAccount';
|
||||
import * as spl from '@solana/spl-token';
|
||||
import { TransactionObject } from '../transaction';
|
||||
import { TOKEN_PROGRAM_ID } from '@solana/spl-token';
|
||||
import { AggregatorHistoryBuffer } from './aggregatorHistoryBuffer';
|
||||
import { PermitOracleQueueUsage } from '../generated/types/SwitchboardPermission';
|
||||
import { CrankAccount } from './crankAccount';
|
||||
|
||||
/**
|
||||
* Account type holding a data feed's update configuration, job accounts, and its current result.
|
||||
|
@ -233,6 +235,172 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
|
|||
return [account, txnSignature];
|
||||
}
|
||||
|
||||
async transferInstruction(
|
||||
payer: PublicKey,
|
||||
params: {
|
||||
newQueue: QueueAccount;
|
||||
authority?: Keypair;
|
||||
crankPubkey?: PublicKey;
|
||||
} & Partial<PermissionSetParams>
|
||||
): Promise<Array<TransactionObject>> {
|
||||
const txns: Array<TransactionObject> = [];
|
||||
|
||||
const aggregator = await this.loadData();
|
||||
const newQueue = await params.newQueue.loadData();
|
||||
|
||||
const authorityPubkey = params.authority
|
||||
? params.authority.publicKey
|
||||
: payer;
|
||||
|
||||
if (!aggregator.authority.equals(authorityPubkey)) {
|
||||
throw new errors.IncorrectAuthority(
|
||||
aggregator.authority,
|
||||
authorityPubkey
|
||||
);
|
||||
}
|
||||
|
||||
const jobs = await this.loadJobs(aggregator);
|
||||
const jobAuthorities = jobs.map(j => j.state.authority);
|
||||
// const jobAuthorities = Array.from(
|
||||
// jobs.reduce((set, job) => {
|
||||
// set.add(job.state.authority);
|
||||
// return set;
|
||||
// }, new Set<PublicKey>())
|
||||
// );
|
||||
|
||||
const [oldLeaseAccount] = LeaseAccount.fromSeed(
|
||||
this.program,
|
||||
aggregator.queuePubkey,
|
||||
this.publicKey
|
||||
);
|
||||
|
||||
const setQueueTxn = new TransactionObject(
|
||||
payer,
|
||||
[
|
||||
types.aggregatorSetQueue(
|
||||
this.program,
|
||||
{ params: {} },
|
||||
{
|
||||
aggregator: this.publicKey,
|
||||
authority: authorityPubkey,
|
||||
queue: params.newQueue.publicKey,
|
||||
}
|
||||
),
|
||||
],
|
||||
params.authority ? [params.authority] : []
|
||||
);
|
||||
txns.push(setQueueTxn);
|
||||
|
||||
// create and set permissions
|
||||
const [newPermissionAccount, permissionInitTxn] =
|
||||
PermissionAccount.createInstruction(this.program, payer, {
|
||||
authority: newQueue.authority,
|
||||
granter: params.newQueue.publicKey,
|
||||
grantee: this.publicKey,
|
||||
});
|
||||
if (params.enable) {
|
||||
if (
|
||||
params.queueAuthority &&
|
||||
!params.queueAuthority.publicKey.equals(newQueue.authority)
|
||||
) {
|
||||
throw new errors.IncorrectAuthority(
|
||||
newQueue.authority,
|
||||
params.queueAuthority.publicKey
|
||||
);
|
||||
}
|
||||
const permissionSetTxn = newPermissionAccount.setInstruction(payer, {
|
||||
enable: true,
|
||||
queueAuthority: params.queueAuthority ?? undefined,
|
||||
permission: new PermitOracleQueueUsage(),
|
||||
});
|
||||
permissionInitTxn.combine(permissionSetTxn);
|
||||
}
|
||||
txns.push(permissionInitTxn);
|
||||
|
||||
// create payer token account if we need to
|
||||
const payerTokenAccount = this.program.mint.getAssociatedAddress(payer);
|
||||
const payerTokenAccountInfo = await this.program.connection.getAccountInfo(
|
||||
payerTokenAccount
|
||||
);
|
||||
if (payerTokenAccountInfo === null) {
|
||||
const [payerTokenAddress, payerTokenInitTxn] =
|
||||
await this.program.mint.getOrCreateWrappedUserInstructions(payer, {
|
||||
amount: 0,
|
||||
});
|
||||
txns.unshift(payerTokenInitTxn);
|
||||
}
|
||||
|
||||
// withdraw from lease
|
||||
let oldLeaseWithdrawAuthority = payer;
|
||||
let oldLeaseBalance = 0;
|
||||
try {
|
||||
const oldLease = await oldLeaseAccount.loadData();
|
||||
oldLeaseBalance = await oldLeaseAccount.getBalance(oldLease.escrow);
|
||||
oldLeaseWithdrawAuthority = oldLease.withdrawAuthority;
|
||||
const withdrawTxn = await oldLeaseAccount.withdrawInstruction(payer, {
|
||||
amount: oldLeaseBalance,
|
||||
withdrawWallet: payerTokenAccount,
|
||||
unwrap: false,
|
||||
});
|
||||
txns.push(withdrawTxn);
|
||||
} catch {
|
||||
// failed to get old lease balance, skipping
|
||||
}
|
||||
|
||||
// create lease for the new queue and transfer existing balance
|
||||
const [leaseAccount, leaseInitTxn] = await LeaseAccount.createInstructions(
|
||||
this.program,
|
||||
payer,
|
||||
{
|
||||
aggregatorAccount: this,
|
||||
queueAccount: params.newQueue,
|
||||
jobAuthorities,
|
||||
loadAmount: oldLeaseBalance ?? 0,
|
||||
withdrawAuthority: oldLeaseWithdrawAuthority,
|
||||
jobPubkeys: aggregator.jobPubkeysData.slice(
|
||||
0,
|
||||
aggregator.jobPubkeysSize
|
||||
),
|
||||
}
|
||||
);
|
||||
txns.push(leaseInitTxn);
|
||||
|
||||
// push onto crank
|
||||
if (params.crankPubkey) {
|
||||
const crankAccount = new CrankAccount(this.program, params.crankPubkey);
|
||||
const crank = await crankAccount.loadData();
|
||||
if (!params.newQueue.publicKey.equals(crank.queuePubkey)) {
|
||||
throw new Error(
|
||||
`Desired crank does not belong to new queue, expected ${params.newQueue.publicKey}, received ${crank.queuePubkey}`
|
||||
);
|
||||
}
|
||||
const crankPush = await crankAccount.pushInstruction(payer, {
|
||||
aggregatorAccount: this,
|
||||
});
|
||||
|
||||
txns.push(crankPush);
|
||||
}
|
||||
|
||||
return TransactionObject.pack(txns);
|
||||
}
|
||||
|
||||
async transfer(
|
||||
params: {
|
||||
newQueue: QueueAccount;
|
||||
authority?: Keypair;
|
||||
crankPubkey?: PublicKey;
|
||||
} & Partial<PermissionSetParams>
|
||||
): Promise<Array<TransactionSignature>> {
|
||||
const transactions = await this.transferInstruction(
|
||||
this.program.walletPubkey,
|
||||
params
|
||||
);
|
||||
const txnSignatures = await this.program.signAndSendAll(transactions, {
|
||||
skipPreflight: true,
|
||||
});
|
||||
return txnSignatures;
|
||||
}
|
||||
|
||||
public getAccounts(params: {
|
||||
queueAccount: QueueAccount;
|
||||
queueAuthority: PublicKey;
|
||||
|
@ -439,7 +607,15 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
|
|||
* @throws {AggregatorConfigError} if minUpdateDelaySeconds < 5, if batchSize > queueSize, if minOracleResults > batchSize, if minJobResults > aggregator.jobPubkeysSize
|
||||
*/
|
||||
public verifyConfig(
|
||||
aggregator: types.AggregatorAccountData,
|
||||
aggregator:
|
||||
| types.AggregatorAccountData
|
||||
| {
|
||||
oracleRequestBatchSize: number;
|
||||
minOracleResults: number;
|
||||
minJobResults: number;
|
||||
minUpdateDelaySeconds: number;
|
||||
jobPubkeysSize: number;
|
||||
},
|
||||
queue: types.OracleQueueAccountData,
|
||||
target: {
|
||||
batchSize?: number;
|
||||
|
|
|
@ -5,6 +5,7 @@ import { SwitchboardProgram } from '../program';
|
|||
import { Account } from './account';
|
||||
import * as spl from '@solana/spl-token';
|
||||
import {
|
||||
AccountMeta,
|
||||
Keypair,
|
||||
PublicKey,
|
||||
SystemProgram,
|
||||
|
@ -78,31 +79,25 @@ export class LeaseAccount extends Account<types.LeaseAccountData> {
|
|||
static getWallets(
|
||||
jobAuthorities: Array<PublicKey>,
|
||||
mint: PublicKey
|
||||
): {
|
||||
wallets: Array<{ publicKey: PublicKey; bump: number }>;
|
||||
walletBumps: Uint8Array;
|
||||
} {
|
||||
): Array<{ publicKey: PublicKey; bump: number }> {
|
||||
const wallets: Array<{ publicKey: PublicKey; bump: number }> = [];
|
||||
const walletBumps: Array<number> = [];
|
||||
|
||||
for (const jobAuthority in jobAuthorities) {
|
||||
const authority = new PublicKey(jobAuthority);
|
||||
if (!jobAuthority || PublicKey.default.equals(authority)) {
|
||||
for (const jobAuthority of jobAuthorities) {
|
||||
if (!jobAuthority || PublicKey.default.equals(jobAuthority)) {
|
||||
continue;
|
||||
}
|
||||
const [jobWallet, bump] = anchor.utils.publicKey.findProgramAddressSync(
|
||||
[
|
||||
authority.toBuffer(),
|
||||
jobAuthority.toBuffer(),
|
||||
spl.TOKEN_PROGRAM_ID.toBuffer(),
|
||||
mint.toBuffer(),
|
||||
],
|
||||
spl.ASSOCIATED_TOKEN_PROGRAM_ID
|
||||
);
|
||||
wallets.push({ publicKey: jobWallet, bump });
|
||||
walletBumps.push(bump);
|
||||
}
|
||||
|
||||
return { wallets, walletBumps: new Uint8Array(walletBumps) };
|
||||
return wallets;
|
||||
}
|
||||
|
||||
static async createInstructions(
|
||||
|
@ -111,11 +106,12 @@ export class LeaseAccount extends Account<types.LeaseAccountData> {
|
|||
params: {
|
||||
aggregatorAccount: AggregatorAccount;
|
||||
queueAccount: QueueAccount;
|
||||
jobAuthorities?: Array<PublicKey>;
|
||||
jobPubkeys?: Array<PublicKey>;
|
||||
loadAmount?: number;
|
||||
funderTokenAccount?: PublicKey;
|
||||
funderAuthority?: Keypair;
|
||||
withdrawAuthority?: PublicKey;
|
||||
jobAuthorities: Array<PublicKey>;
|
||||
}
|
||||
): Promise<[LeaseAccount, TransactionObject]> {
|
||||
const loadAmount = params.loadAmount ?? 0;
|
||||
|
@ -152,46 +148,68 @@ export class LeaseAccount extends Account<types.LeaseAccountData> {
|
|||
spl.ASSOCIATED_TOKEN_PROGRAM_ID
|
||||
);
|
||||
|
||||
const { walletBumps } = LeaseAccount.getWallets(
|
||||
params.jobAuthorities,
|
||||
// load jobPubkeys and authorities ONLY if undefined
|
||||
// we need to allow empty arrays for initial job creation or else loading aggregator will fail
|
||||
let jobPubkeys = params.jobPubkeys;
|
||||
let jobAuthorities = params.jobAuthorities;
|
||||
if (jobPubkeys === undefined || jobAuthorities === undefined) {
|
||||
const aggregator = await params.aggregatorAccount.loadData();
|
||||
jobPubkeys = aggregator.jobPubkeysData.slice(
|
||||
0,
|
||||
aggregator.jobPubkeysSize
|
||||
);
|
||||
const jobs = await params.aggregatorAccount.loadJobs(aggregator);
|
||||
jobAuthorities = jobs.map(j => j.state.authority);
|
||||
}
|
||||
|
||||
const wallets = LeaseAccount.getWallets(
|
||||
jobAuthorities ?? [],
|
||||
program.mint.address
|
||||
);
|
||||
const walletBumps = new Uint8Array(wallets.map(w => w.bump));
|
||||
|
||||
const remainingAccounts: Array<AccountMeta> = (jobPubkeys ?? [])
|
||||
.concat(wallets.map(w => w.publicKey))
|
||||
.map(pubkey => {
|
||||
return { isSigner: false, isWritable: true, pubkey };
|
||||
});
|
||||
|
||||
const createTokenAccountIxn = spl.createAssociatedTokenAccountInstruction(
|
||||
payer,
|
||||
escrow,
|
||||
leaseAccount.publicKey,
|
||||
program.mint.address
|
||||
);
|
||||
const leaseInitIxn = types.leaseInit(
|
||||
program,
|
||||
{
|
||||
params: {
|
||||
loadAmount: loadTokenAmountBN,
|
||||
withdrawAuthority: params.withdrawAuthority ?? payer,
|
||||
leaseBump: leaseBump,
|
||||
stateBump: program.programState.bump,
|
||||
walletBumps: walletBumps,
|
||||
},
|
||||
},
|
||||
{
|
||||
lease: leaseAccount.publicKey,
|
||||
queue: params.queueAccount.publicKey,
|
||||
aggregator: params.aggregatorAccount.publicKey,
|
||||
payer: payer,
|
||||
systemProgram: SystemProgram.programId,
|
||||
tokenProgram: spl.TOKEN_PROGRAM_ID,
|
||||
funder: funderTokenAccount,
|
||||
owner: funderAuthority,
|
||||
escrow: escrow,
|
||||
programState: program.programState.publicKey,
|
||||
mint: program.mint.address,
|
||||
}
|
||||
);
|
||||
leaseInitIxn.keys.push(...remainingAccounts);
|
||||
|
||||
const leaseInitTxn = new TransactionObject(
|
||||
payer,
|
||||
[
|
||||
spl.createAssociatedTokenAccountInstruction(
|
||||
payer,
|
||||
escrow,
|
||||
leaseAccount.publicKey,
|
||||
program.mint.address
|
||||
),
|
||||
types.leaseInit(
|
||||
program,
|
||||
{
|
||||
params: {
|
||||
loadAmount: loadTokenAmountBN,
|
||||
withdrawAuthority: params.withdrawAuthority ?? payer,
|
||||
leaseBump: leaseBump,
|
||||
stateBump: program.programState.bump,
|
||||
walletBumps: walletBumps,
|
||||
},
|
||||
},
|
||||
{
|
||||
lease: leaseAccount.publicKey,
|
||||
queue: params.queueAccount.publicKey,
|
||||
aggregator: params.aggregatorAccount.publicKey,
|
||||
payer: payer,
|
||||
systemProgram: SystemProgram.programId,
|
||||
tokenProgram: spl.TOKEN_PROGRAM_ID,
|
||||
funder: funderTokenAccount,
|
||||
owner: funderAuthority,
|
||||
escrow: escrow,
|
||||
programState: program.programState.publicKey,
|
||||
mint: program.mint.address,
|
||||
}
|
||||
),
|
||||
],
|
||||
[createTokenAccountIxn, leaseInitIxn],
|
||||
params.funderAuthority ? [params.funderAuthority] : []
|
||||
);
|
||||
|
||||
|
@ -208,11 +226,12 @@ export class LeaseAccount extends Account<types.LeaseAccountData> {
|
|||
params: {
|
||||
aggregatorAccount: AggregatorAccount;
|
||||
queueAccount: QueueAccount;
|
||||
jobAuthorities?: Array<PublicKey>;
|
||||
jobPubkeys?: Array<PublicKey>;
|
||||
loadAmount?: number;
|
||||
funderTokenAccount?: PublicKey;
|
||||
funderAuthority?: Keypair;
|
||||
withdrawAuthority?: PublicKey;
|
||||
jobAuthorities: Array<PublicKey>;
|
||||
}
|
||||
): Promise<[LeaseAccount, TransactionSignature]> {
|
||||
const [leaseAccount, transaction] = await LeaseAccount.createInstructions(
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import * as anchor from '@project-serum/anchor';
|
||||
import { ACCOUNT_DISCRIMINATOR_SIZE } from '@project-serum/anchor';
|
||||
import {
|
||||
AccountInfo,
|
||||
Keypair,
|
||||
PublicKey,
|
||||
SystemProgram,
|
||||
|
@ -49,8 +51,6 @@ export class PermitNone {
|
|||
}
|
||||
|
||||
export interface PermissionSetParams {
|
||||
/** The {@linkcode types.SwitchboardPermission} to set for the grantee. */
|
||||
permission: types.SwitchboardPermissionKind;
|
||||
/** Whether to enable PERMIT_ORACLE_HEARTBEAT permissions. **Note:** Requires a provided queueAuthority keypair or payer to be the assigned queue authority. */
|
||||
enable: boolean;
|
||||
/** Keypair used to enable heartbeat permissions if payer is not the queue authority. */
|
||||
|
@ -196,7 +196,12 @@ export class PermissionAccount extends Account<types.PermissionAccountData> {
|
|||
/**
|
||||
* Sets the permission in the PermissionAccount
|
||||
*/
|
||||
public async set(params: PermissionSetParams): Promise<string> {
|
||||
public async set(
|
||||
params: PermissionSetParams & {
|
||||
/** The {@linkcode types.SwitchboardPermission} to set for the grantee. */
|
||||
permission: types.SwitchboardPermissionKind;
|
||||
}
|
||||
): Promise<string> {
|
||||
const setTxn = this.setInstruction(this.program.walletPubkey, params);
|
||||
const txnSignature = await this.program.signAndSend(setTxn);
|
||||
return txnSignature;
|
||||
|
@ -207,7 +212,10 @@ export class PermissionAccount extends Account<types.PermissionAccountData> {
|
|||
*/
|
||||
public setInstruction(
|
||||
payer: PublicKey,
|
||||
params: PermissionSetParams
|
||||
params: PermissionSetParams & {
|
||||
/** The {@linkcode types.SwitchboardPermission} to set for the grantee. */
|
||||
permission: types.SwitchboardPermissionKind;
|
||||
}
|
||||
): TransactionObject {
|
||||
return new TransactionObject(
|
||||
payer,
|
||||
|
@ -231,4 +239,37 @@ export class PermissionAccount extends Account<types.PermissionAccountData> {
|
|||
params.queueAuthority ? [params.queueAuthority] : []
|
||||
);
|
||||
}
|
||||
|
||||
static getGranteePermissions(
|
||||
grantee: AccountInfo<Buffer>
|
||||
): types.SwitchboardPermissionKind {
|
||||
if (grantee.data.byteLength < ACCOUNT_DISCRIMINATOR_SIZE) {
|
||||
throw new Error(`Cannot assign permissions to grantee`);
|
||||
}
|
||||
const discriminator = grantee.data.slice(0, ACCOUNT_DISCRIMINATOR_SIZE);
|
||||
|
||||
// check oracle
|
||||
if (types.OracleAccountData.discriminator.compare(discriminator) === 0) {
|
||||
return new PermitOracleHeartbeat();
|
||||
}
|
||||
|
||||
// check aggregator and buffer relayer
|
||||
if (
|
||||
types.AggregatorAccountData.discriminator.compare(discriminator) === 0 ||
|
||||
types.BufferRelayerAccountData.discriminator.compare(discriminator)
|
||||
) {
|
||||
return new PermitOracleQueueUsage();
|
||||
}
|
||||
|
||||
// check vrf
|
||||
if (types.VrfAccountData.discriminator.compare(discriminator) === 0) {
|
||||
return new PermitVrfRequests();
|
||||
}
|
||||
|
||||
throw new Error(
|
||||
`Cannot find permissions to assign for account with discriminator of [${discriminator.join(
|
||||
', '
|
||||
)}]`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -296,7 +296,7 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
|
|||
payer: PublicKey,
|
||||
params: OracleInitParams &
|
||||
OracleStakeParams &
|
||||
Partial<Omit<PermissionSetParams, 'permission'>> & {
|
||||
Partial<PermissionSetParams> & {
|
||||
queueAuthorityPubkey?: PublicKey;
|
||||
}
|
||||
): Promise<[OracleAccount, Array<TransactionObject>]> {
|
||||
|
@ -355,9 +355,7 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
|
|||
* ```
|
||||
*/
|
||||
public async createOracle(
|
||||
params: OracleInitParams &
|
||||
OracleStakeParams &
|
||||
Partial<Omit<PermissionSetParams, 'permission'>>
|
||||
params: OracleInitParams & OracleStakeParams & Partial<PermissionSetParams>
|
||||
): Promise<[OracleAccount, Array<TransactionSignature>]> {
|
||||
const signers: Keypair[] = [];
|
||||
|
||||
|
@ -438,7 +436,7 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
|
|||
fundAmount?: number;
|
||||
funderAuthority?: Keypair;
|
||||
funderTokenAccount?: PublicKey;
|
||||
} & Partial<Omit<PermissionSetParams, 'permission'>> & {
|
||||
} & Partial<PermissionSetParams> & {
|
||||
// job params
|
||||
jobs?: Array<{ pubkey: PublicKey; weight?: number } | JobInitParams>;
|
||||
} & {
|
||||
|
@ -512,7 +510,8 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
|
|||
funderAuthority: params.funderAuthority,
|
||||
aggregatorAccount: aggregatorAccount,
|
||||
queueAccount: this,
|
||||
jobAuthorities: [],
|
||||
jobAuthorities: [], // create lease before adding jobs to skip this step
|
||||
jobPubkeys: [],
|
||||
})
|
||||
)[1];
|
||||
txns.push(leaseInit);
|
||||
|
@ -626,7 +625,7 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
|
|||
fundAmount?: number;
|
||||
funderAuthority?: Keypair;
|
||||
funderTokenAccount?: PublicKey;
|
||||
} & Partial<Omit<PermissionSetParams, 'permission'>> & {
|
||||
} & Partial<PermissionSetParams> & {
|
||||
// job params
|
||||
jobs?: Array<{ pubkey: PublicKey; weight?: number } | JobInitParams>;
|
||||
}
|
||||
|
@ -745,8 +744,7 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
|
|||
*/
|
||||
public async createVrfInstructions(
|
||||
payer: PublicKey,
|
||||
params: Omit<VrfInitParams, 'queueAccount'> &
|
||||
Partial<Omit<PermissionSetParams, 'permission'>>
|
||||
params: Omit<VrfInitParams, 'queueAccount'> & Partial<PermissionSetParams>
|
||||
): Promise<[VrfAccount, TransactionObject]> {
|
||||
const queue = await this.loadData();
|
||||
|
||||
|
@ -808,8 +806,7 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
|
|||
* ```
|
||||
*/
|
||||
public async createVrf(
|
||||
params: Omit<VrfInitParams, 'queueAccount'> &
|
||||
Partial<Omit<PermissionSetParams, 'permission'>>
|
||||
params: Omit<VrfInitParams, 'queueAccount'> & Partial<PermissionSetParams>
|
||||
): Promise<[VrfAccount, TransactionSignature]> {
|
||||
const [vrfAccount, txn] = await this.createVrfInstructions(
|
||||
this.program.walletPubkey,
|
||||
|
@ -845,7 +842,7 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
|
|||
public async createBufferRelayerInstructions(
|
||||
payer: PublicKey,
|
||||
params: Omit<Omit<BufferRelayerInit, 'jobAccount'>, 'queueAccount'> &
|
||||
Partial<Omit<PermissionSetParams, 'permission'>> & {
|
||||
Partial<PermissionSetParams> & {
|
||||
// job params
|
||||
job: JobAccount | PublicKey | Omit<JobInitParams, 'weight'>;
|
||||
}
|
||||
|
@ -947,7 +944,7 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
|
|||
*/
|
||||
public async createBufferRelayer(
|
||||
params: Omit<Omit<BufferRelayerInit, 'jobAccount'>, 'queueAccount'> &
|
||||
Partial<Omit<PermissionSetParams, 'permission'>> & {
|
||||
Partial<PermissionSetParams> & {
|
||||
// job params
|
||||
job: JobAccount | PublicKey | Omit<JobInitParams, 'weight'>;
|
||||
}
|
||||
|
@ -1166,7 +1163,7 @@ export interface QueueInitParams {
|
|||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* Buffer for queue metadata
|
||||
* Metadata for the queue for easier identification.
|
||||
*/
|
||||
metadata?: string;
|
||||
/**
|
||||
|
@ -1233,18 +1230,58 @@ export interface QueueInitParams {
|
|||
dataBufferKeypair?: Keypair;
|
||||
}
|
||||
|
||||
export type QueueSetConfigParams = Partial<{
|
||||
export interface QueueSetConfigParams {
|
||||
/** Alternative keypair that is the queue authority and is permitted to make account changes. Defaults to the payer if not provided. */
|
||||
authority?: anchor.web3.Keypair;
|
||||
name: string;
|
||||
metadata: string;
|
||||
unpermissionedFeedsEnabled: boolean;
|
||||
unpermissionedVrfEnabled: boolean;
|
||||
enableBufferRelayers: boolean;
|
||||
slashingEnabled: boolean;
|
||||
varianceToleranceMultiplier: number;
|
||||
oracleTimeout: number;
|
||||
reward: number;
|
||||
minStake: number;
|
||||
consecutiveFeedFailureLimit: number;
|
||||
consecutiveOracleFailureLimit: number;
|
||||
}>;
|
||||
/**
|
||||
* A name to assign to this {@linkcode QueueAccount}
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* Metadata for the queue for easier identification.
|
||||
*/
|
||||
metadata?: string;
|
||||
/**
|
||||
* Enabling this setting means data feeds do not need explicit permission to join the queue.
|
||||
*/
|
||||
unpermissionedFeedsEnabled?: boolean;
|
||||
/**
|
||||
* Enabling this setting means data feeds do not need explicit permission
|
||||
* to request VRF proofs and verifications from this queue.
|
||||
*/
|
||||
unpermissionedVrfEnabled?: boolean;
|
||||
/**
|
||||
* Enabling this setting will allow buffer relayer accounts to call openRound.
|
||||
*/
|
||||
enableBufferRelayers?: boolean;
|
||||
/**
|
||||
* Whether slashing is enabled on this queue.
|
||||
*/
|
||||
slashingEnabled?: boolean;
|
||||
/**
|
||||
* The tolerated variance amount oracle results can have from the accepted round result
|
||||
* before being slashed.
|
||||
* slashBound = varianceToleranceMultiplier * stdDeviation
|
||||
*/
|
||||
varianceToleranceMultiplier?: number;
|
||||
/**
|
||||
* Time period (in seconds) we should remove an oracle after if no response.
|
||||
*/
|
||||
oracleTimeout?: number;
|
||||
/**
|
||||
* Rewards to provide oracles and round openers on this queue.
|
||||
*/
|
||||
reward?: number;
|
||||
/**
|
||||
* The minimum amount of stake oracles must present to remain on the queue.
|
||||
*/
|
||||
minStake?: number;
|
||||
/**
|
||||
* Consecutive failure limit for a feed before feed permission is revoked.
|
||||
*/
|
||||
consecutiveFeedFailureLimit?: number;
|
||||
/**
|
||||
* Consecutive failure limit for an oracle before oracle permission is revoked.
|
||||
*/
|
||||
consecutiveOracleFailureLimit?: number;
|
||||
}
|
||||
|
|
|
@ -109,6 +109,11 @@ export class TransactionObject implements ITransactionObject {
|
|||
throw new errors.SwitchboardProgramReadOnlyError();
|
||||
}
|
||||
|
||||
// if empty object, return
|
||||
if (ixns.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// verify num ixns
|
||||
if (ixns.length > 10) {
|
||||
throw new errors.TransactionInstructionOverflowError(ixns.length);
|
||||
|
|
|
@ -8,9 +8,12 @@ import {
|
|||
AggregatorAccount,
|
||||
JobAccount,
|
||||
LeaseAccount,
|
||||
PermissionAccount,
|
||||
QueueAccount,
|
||||
} from '../src';
|
||||
import { OracleJob } from '@switchboard-xyz/common';
|
||||
import { assert } from 'console';
|
||||
import { PermitOracleQueueUsage } from '../src/generated/types/SwitchboardPermission';
|
||||
|
||||
describe('Aggregator Tests', () => {
|
||||
let ctx: TestContext;
|
||||
|
@ -248,4 +251,86 @@ describe('Aggregator Tests', () => {
|
|||
);
|
||||
}
|
||||
});
|
||||
|
||||
it('Transfers aggregator to a new queue', async () => {
|
||||
const newQueueAuthority = Keypair.generate();
|
||||
|
||||
const [newQueue] = await sbv2.QueueAccount.create(ctx.program, {
|
||||
name: 'new-queue',
|
||||
metadata: '',
|
||||
authority: newQueueAuthority.publicKey,
|
||||
queueSize: 1,
|
||||
reward: 0,
|
||||
minStake: 0,
|
||||
oracleTimeout: 86400,
|
||||
slashingEnabled: false,
|
||||
unpermissionedFeeds: true,
|
||||
unpermissionedVrf: true,
|
||||
enableBufferRelayers: false,
|
||||
});
|
||||
|
||||
const [aggregatorAccount] = await queueAccount.createFeed({
|
||||
queueAuthority: queueAuthority,
|
||||
batchSize: 1,
|
||||
minRequiredOracleResults: 1,
|
||||
minRequiredJobResults: 1,
|
||||
minUpdateDelaySeconds: 60,
|
||||
fundAmount: 1.25,
|
||||
enable: true,
|
||||
jobs: [
|
||||
{
|
||||
weight: 1,
|
||||
data: OracleJob.encodeDelimited(
|
||||
OracleJob.fromObject({
|
||||
tasks: [
|
||||
{
|
||||
valueTask: {
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
).finish(),
|
||||
},
|
||||
],
|
||||
});
|
||||
await aggregatorAccount.loadData();
|
||||
|
||||
await aggregatorAccount.transfer({
|
||||
newQueue,
|
||||
enable: true,
|
||||
queueAuthority: newQueueAuthority,
|
||||
});
|
||||
|
||||
const aggregator = await aggregatorAccount.loadData();
|
||||
assert(
|
||||
aggregator.queuePubkey.equals(newQueue.publicKey),
|
||||
`Aggregator queue mismatch, expected ${newQueue.publicKey}, received ${aggregator.queuePubkey}`
|
||||
);
|
||||
|
||||
const [newLeaseAccount] = LeaseAccount.fromSeed(
|
||||
ctx.program,
|
||||
newQueue.publicKey,
|
||||
aggregatorAccount.publicKey
|
||||
);
|
||||
const balance = await newLeaseAccount.getBalance();
|
||||
assert(
|
||||
balance === 1.25,
|
||||
`Aggregator did not transfer full lease balance, expected 1.25, received ${balance}`
|
||||
);
|
||||
|
||||
const [newPermissionAccount] = PermissionAccount.fromSeed(
|
||||
ctx.program,
|
||||
newQueueAuthority.publicKey,
|
||||
newQueue.publicKey,
|
||||
aggregatorAccount.publicKey
|
||||
);
|
||||
const newPermission = await newPermissionAccount.loadData();
|
||||
assert(
|
||||
newPermission.permissions === PermitOracleQueueUsage.discriminator + 1,
|
||||
`Aggregator permission mismatch, expected ${
|
||||
PermitOracleQueueUsage.discriminator + 1
|
||||
}, received ${newPermission.permissions}`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue