From 46e68b8f20a5e7bec52638126c88d4824414b009 Mon Sep 17 00:00:00 2001 From: Conner Gallagher Date: Wed, 30 Nov 2022 17:18:09 -0700 Subject: [PATCH] doc comments --- .../src/accounts/aggregatorAccount.ts | 23 +++- .../src/accounts/bufferRelayAccount.ts | 17 ++- .../solana.js/src/accounts/crankAccount.ts | 15 +- .../solana.js/src/accounts/jobAccount.ts | 4 + .../solana.js/src/accounts/leaseAccount.ts | 4 + .../solana.js/src/accounts/oracleAccount.ts | 6 + .../src/accounts/permissionAccount.ts | 7 + .../src/accounts/programStateAccount.ts | 1 + .../solana.js/src/accounts/queueAccount.ts | 129 ++++++++++++++++-- .../solana.js/src/accounts/vrfAccount.ts | 7 + 10 files changed, 198 insertions(+), 15 deletions(-) diff --git a/javascript/solana.js/src/accounts/aggregatorAccount.ts b/javascript/solana.js/src/accounts/aggregatorAccount.ts index 935a6b5..21f5421 100644 --- a/javascript/solana.js/src/accounts/aggregatorAccount.ts +++ b/javascript/solana.js/src/accounts/aggregatorAccount.ts @@ -7,6 +7,7 @@ import { SwitchboardProgram } from '../program'; import { AccountInfo, AccountMeta, + Commitment, Keypair, PublicKey, SystemProgram, @@ -24,6 +25,16 @@ import * as spl from '@solana/spl-token'; import { TransactionObject } from '../transaction'; import { TOKEN_PROGRAM_ID } from '@solana/spl-token'; +/** + * @class AggregatorAccount + * Account type holding a data feed's update configuration, job accounts, and its current result. + * + * An aggregator account belongs to a single {@linkcode QueueAccount} but can later be transferred by the aggregator's authority. In order for an {@linkcode OracleAccount} to respond to an aggregator's update request, the aggregator must initialize a {@linkcode PermissionAccount} and {@linkcode LeaseAccount}. These will need to be recreated when transferring queues. + * + * Optionally, An aggregator can be pushed onto a {@linkcode CrankAccount} in order to be updated + * + * Optionally, an aggregator can add a history buffer to store the last N historical samples along with their update timestamp. + */ export class AggregatorAccount extends Account { static accountName = 'AggregatorAccountData'; @@ -55,14 +66,22 @@ export class AggregatorAccount extends Account { } } + /** + * Invoke a callback each time an AggregatorAccount's data has changed on-chain. + * @param callback - the callback invoked when the aggregator state changes + * @param commitment - optional, the desired transaction finality. defaults to 'confirmed' + * @returns the websocket subscription id + */ public onChange( - callback: OnAccountChangeCallback + callback: OnAccountChangeCallback, + commitment: Commitment = 'confirmed' ): number { return this.program.connection.onAccountChange( this.publicKey, accountInfo => { callback(this.decode(accountInfo.data)); - } + }, + commitment ); } diff --git a/javascript/solana.js/src/accounts/bufferRelayAccount.ts b/javascript/solana.js/src/accounts/bufferRelayAccount.ts index 5947f81..c9e32cd 100644 --- a/javascript/solana.js/src/accounts/bufferRelayAccount.ts +++ b/javascript/solana.js/src/accounts/bufferRelayAccount.ts @@ -5,6 +5,7 @@ import { TOKEN_PROGRAM_ID, } from '@solana/spl-token'; import { + Commitment, Keypair, PublicKey, SystemProgram, @@ -23,6 +24,10 @@ import { JobAccount } from './jobAccount'; import { PermissionAccount } from './permissionAccount'; import { QueueAccount } from './queueAccount'; +/** + * @class BufferRelayerAccount + * Account type holding a buffer of data sourced from the buffers sole {@linkcode JobAccount}. A buffer relayer has no consensus mechanism and relies on trusting an {@linkcode OracleAccount} to respond honestly. A buffer relayer has a max capacity of 500 bytes. + */ export class BufferRelayerAccount extends Account { static accountName = 'BufferRelayerAccountData'; @@ -44,14 +49,22 @@ export class BufferRelayerAccount extends Account + callback: OnAccountChangeCallback, + commitment: Commitment = 'confirmed' ): number { return this.program.connection.onAccountChange( this.publicKey, accountInfo => { callback(this.decode(accountInfo.data)); - } + }, + commitment ); } diff --git a/javascript/solana.js/src/accounts/crankAccount.ts b/javascript/solana.js/src/accounts/crankAccount.ts index 408497d..618c065 100644 --- a/javascript/solana.js/src/accounts/crankAccount.ts +++ b/javascript/solana.js/src/accounts/crankAccount.ts @@ -18,7 +18,8 @@ import { AggregatorAccount } from './aggregatorAccount'; import { QueueAccount } from './queueAccount'; /** - * A Switchboard account representing a crank of aggregators ordered by next update time. + * @class CrankAccount + * Account holding a priority queue of aggregators and their next available update time. This is a scheduling mechanism to ensure {@linkcode AggregatorAccount}'s are updated as close as possible to their specified update interval. */ export class CrankAccount extends Account { static accountName = 'CrankAccountData'; @@ -31,6 +32,12 @@ export class CrankAccount extends Account { */ public size = this.program.account.crankAccountData.size; + /** + * Invoke a callback each time a CrankAccount's data has changed on-chain. + * @param callback - the callback invoked when the cranks state changes + * @param commitment - optional, the desired transaction finality. defaults to 'confirmed' + * @returns the websocket subscription id + */ onChange( callback: OnAccountChangeCallback, commitment: Commitment = 'confirmed' @@ -42,6 +49,12 @@ export class CrankAccount extends Account { ); } + /** + * Invoke a callback each time a crank's buffer has changed on-chain. The buffer stores a list of {@linkcode AggregatorAccount} public keys along with their next available update time. + * @param callback - the callback invoked when the crank's buffer changes + * @param commitment - optional, the desired transaction finality. defaults to 'confirmed' + * @returns the websocket subscription id + */ onBufferChange( callback: OnAccountChangeCallback>, _dataBuffer?: PublicKey, diff --git a/javascript/solana.js/src/accounts/jobAccount.ts b/javascript/solana.js/src/accounts/jobAccount.ts index d740191..6688f7e 100644 --- a/javascript/solana.js/src/accounts/jobAccount.ts +++ b/javascript/solana.js/src/accounts/jobAccount.ts @@ -13,6 +13,10 @@ import { SwitchboardProgram } from '../program'; import { Account } from './account'; import { TransactionObject } from '../transaction'; +/** + * @class JobAccount + * Account type storing a list of SwitchboardTasks {@linkcode OracleJob.ITask} dictating how to source data off-chain. + */ export class JobAccount extends Account { static accountName = 'JobAccountData'; diff --git a/javascript/solana.js/src/accounts/leaseAccount.ts b/javascript/solana.js/src/accounts/leaseAccount.ts index ccf2e71..a8107e0 100644 --- a/javascript/solana.js/src/accounts/leaseAccount.ts +++ b/javascript/solana.js/src/accounts/leaseAccount.ts @@ -16,6 +16,10 @@ import { QueueAccount } from './queueAccount'; import { TransactionObject } from '../transaction'; import { BN } from 'bn.js'; +/** + * @class LeaseAccount + * Account type representing an {@linkcode AggregatorAccount}'s pre-funded escrow used to reward {@linkcode OracleAccount}'s for responding to open round requests. + */ export class LeaseAccount extends Account { static accountName = 'LeaseAccountData'; diff --git a/javascript/solana.js/src/accounts/oracleAccount.ts b/javascript/solana.js/src/accounts/oracleAccount.ts index f4f7842..8be7c50 100644 --- a/javascript/solana.js/src/accounts/oracleAccount.ts +++ b/javascript/solana.js/src/accounts/oracleAccount.ts @@ -15,6 +15,12 @@ import { QueueAccount } from './queueAccount'; import * as spl from '@solana/spl-token'; import { TransactionObject } from '../transaction'; +/** + * @class OracleAccount + * Account type holding an oracle's configuration including the authority and the reward/slashing wallet along with a set of metrics tracking its reliability. + * + * An oracle is a server that sits between the internet and a blockchain and facilitates the flow of information and is rewarded for responding with the honest majority. + */ export class OracleAccount extends Account { static accountName = 'OracleAccountData'; diff --git a/javascript/solana.js/src/accounts/permissionAccount.ts b/javascript/solana.js/src/accounts/permissionAccount.ts index db098f0..7c90273 100644 --- a/javascript/solana.js/src/accounts/permissionAccount.ts +++ b/javascript/solana.js/src/accounts/permissionAccount.ts @@ -14,6 +14,13 @@ export interface PermissionAccountInitParams { grantee: PublicKey; authority: PublicKey; } + +/** + * @class PermissionAccount + * Account type dictating the level of permissions between a granter and a grantee. + * + * A {@linkcode QueueAccount} acts as the granter where the queue authority assigns or revokes a grantee's {@linkcode types.SwitchboardPermission}. A grantee can be one of the following: {@linkcode AggregatorAccount}, {@linkcode BufferRelayerAccount}, or {@linkcode VrfAccount}. + */ export class PermissionAccount extends Account { static accountName = 'PermissionAccountData'; diff --git a/javascript/solana.js/src/accounts/programStateAccount.ts b/javascript/solana.js/src/accounts/programStateAccount.ts index 05eb0fd..4b376c7 100644 --- a/javascript/solana.js/src/accounts/programStateAccount.ts +++ b/javascript/solana.js/src/accounts/programStateAccount.ts @@ -13,6 +13,7 @@ import { import { TransactionObject } from '../transaction'; /** + * @class ProgramStateAccount * Account type representing Switchboard global program state. */ export class ProgramStateAccount extends Account { diff --git a/javascript/solana.js/src/accounts/queueAccount.ts b/javascript/solana.js/src/accounts/queueAccount.ts index 472e33f..a66f95e 100644 --- a/javascript/solana.js/src/accounts/queueAccount.ts +++ b/javascript/solana.js/src/accounts/queueAccount.ts @@ -28,6 +28,12 @@ import { OracleAccount } from './oracleAccount'; import { PermissionAccount } from './permissionAccount'; import { VrfAccount, VrfInitParams } from './vrfAccount'; +/** + * @class QueueAccount + * Account type representing an oracle queue's configuration along with a buffer account holding a list of oracles that are actively heartbeating. + * + * A QueueAccount is responsible for allocating update requests to it's round robin queue of {@linkcode OracleAccount}'s. + */ export class QueueAccount extends Account { static accountName = 'OracleQueueAccountData'; @@ -51,6 +57,12 @@ export class QueueAccount extends Account { public static getMetadata = (queue: types.OracleQueueAccountData) => Buffer.from(queue.metadata).toString('utf8').replace(/u0000/g, ''); + /** + * Invoke a callback each time a QueueAccount's data has changed on-chain. + * @param callback - the callback invoked when the queues state changes + * @param commitment - optional, the desired transaction finality. defaults to 'confirmed' + * @returns the websocket subscription id + */ onChange( callback: OnAccountChangeCallback, commitment: Commitment = 'confirmed' @@ -63,6 +75,12 @@ export class QueueAccount extends Account { ); } + /** + * Invoke a callback each time a QueueAccount's oracle queue buffer has changed on-chain. The buffer stores a list of oracle's and their last heartbeat timestamp. + * @param callback - the callback invoked when the queues buffer changes + * @param commitment - optional, the desired transaction finality. defaults to 'confirmed' + * @returns the websocket subscription id + */ onBufferChange( callback: OnAccountChangeCallback>, _dataBuffer?: PublicKey, @@ -101,6 +119,9 @@ export class QueueAccount extends Account { return this.program.mint.mint; } + /** + * Create a new QueueAccount. + */ public static async create( program: SwitchboardProgram, params: QueueInitParams @@ -114,6 +135,9 @@ export class QueueAccount extends Account { return [txnSignature, account]; } + /** + * Create a {@linkcode TransactionObject} that contains the Solana TransactionInstructions and signers required to create a new QueueAccount on-chain. + */ public static async createInstructions( program: SwitchboardProgram, payer: PublicKey, @@ -191,6 +215,9 @@ export class QueueAccount extends Account { ]; } + /** + * Create a new {@linkcode OracleAccount} for the queue. + */ public async createOracle(params: { name?: string; metadata?: string; @@ -219,6 +246,9 @@ export class QueueAccount extends Account { return [signature, oracleAccount]; } + /** + * Create a {@linkcode TransactionObject} that can then be used to create a new {@linkcode OracleAccount} for the queue. + */ public async createOracleInstructions( payer: PublicKey, params: { @@ -259,6 +289,45 @@ export class QueueAccount extends Account { ]; } + /** + * Create a new {@linkcode AggregatorAccount} for the queue, along with its {@linkcode PermissionAccount} and {@linkcode LeaseAccount}. + * + * Optionally, specify a crankPubkey in order to push it onto an existing {@linkcode CrankAccount}. + * + * Optionally, enable the permissions by setting a queueAuthority keypair along with the enable boolean set to true. + * + * ```ts + * import {QueueAccount} from '@switchboard-xyz/solana.js'; + * const queueAccount = new QueueAccount(program, queuePubkey); + * const [aggregatorInitSignatures, aggregatorAccount] = + await queueAccount.createFeed({ + enable: true, // not needed if queue has unpermissionedFeedsEnabled + queueAuthority: queueAuthority, // not needed if queue has unpermissionedFeedsEnabled + batchSize: 1, + minRequiredOracleResults: 1, + minRequiredJobResults: 1, + minUpdateDelaySeconds: 60, + fundAmount: 2.5, // deposit 2.5 wSOL into the leaseAccount escrow + jobs: [ + { pubkey: jobAccount.publicKey }, + { + weight: 2, + data: OracleJob.encodeDelimited( + OracleJob.fromObject({ + tasks: [ + { + valueTask: { + value: 1, + }, + }, + ], + }) + ).finish(), + }, + ], + }); + * ``` + */ public async createFeed( params: Omit< Omit, 'queueAuthority'>, @@ -302,6 +371,46 @@ export class QueueAccount extends Account { return [signatures, aggregatorAccount]; } + /** + * Create a new {@linkcode TransactionObject} containing the instructions and signers needed to create a new {@linkcode AggregatorAccount} for the queue along with its {@linkcode PermissionAccount} and {@linkcode LeaseAccount}. + * + * Optionally, specify a crankPubkey in order to push it onto an existing {@linkcode CrankAccount}. + * + * Optionally, enable the permissions by setting a queueAuthority keypair along with the enable boolean set to true. + * + * ```ts + * import {QueueAccount} from '@switchboard-xyz/solana.js'; + * const queueAccount = new QueueAccount(program, queuePubkey); + * const [aggregatorInitTxnObject, aggregatorAccount] = + await queueAccount.createFeedInstructions({ + enable: true, // not needed if queue has unpermissionedFeedsEnabled + queueAuthority: queueAuthority, // not needed if queue has unpermissionedFeedsEnabled + batchSize: 1, + minRequiredOracleResults: 1, + minRequiredJobResults: 1, + minUpdateDelaySeconds: 60, + fundAmount: 2.5, // deposit 2.5 wSOL into the leaseAccount escrow + jobs: [ + { pubkey: jobAccount.publicKey }, + { + weight: 2, + data: OracleJob.encodeDelimited( + OracleJob.fromObject({ + tasks: [ + { + valueTask: { + value: 1, + }, + }, + ], + }) + ).finish(), + }, + ], + }); + const aggregatorInitSignatures = await this.program.signAndSendAll(txns); + * ``` + */ public async createFeedInstructions( payer: PublicKey, params: Omit< @@ -455,16 +564,6 @@ export class QueueAccount extends Account { return [packed, aggregatorAccount]; } - public async createCrankInstructions( - payer: PublicKey, - params: Omit - ): Promise<[TransactionObject, CrankAccount]> { - return await CrankAccount.createInstructions(this.program, payer, { - ...params, - queueAccount: this, - }); - } - public async createCrank( params: Omit ): Promise<[TransactionSignature, CrankAccount]> { @@ -476,6 +575,16 @@ export class QueueAccount extends Account { return [txnSignature, crankAccount]; } + public async createCrankInstructions( + payer: PublicKey, + params: Omit + ): Promise<[TransactionObject, CrankAccount]> { + return await CrankAccount.createInstructions(this.program, payer, { + ...params, + queueAccount: this, + }); + } + public async createBufferRelayerInstructions( payer: PublicKey, params: Omit, 'queueAccount'> & { diff --git a/javascript/solana.js/src/accounts/vrfAccount.ts b/javascript/solana.js/src/accounts/vrfAccount.ts index 46535f4..461cb35 100644 --- a/javascript/solana.js/src/accounts/vrfAccount.ts +++ b/javascript/solana.js/src/accounts/vrfAccount.ts @@ -22,6 +22,7 @@ import { QueueAccount } from './queueAccount'; /** * @class VrfAccount + * Account holding a Verifiable Random Function result with a callback instruction for consuming on-chain pseudo-randomness. */ export class VrfAccount extends Account { static accountName = 'VrfAccountData'; @@ -31,6 +32,12 @@ export class VrfAccount extends Account { */ public readonly size = this.program.account.vrfAccountData.size; + /** + * Invoke a callback each time a VrfAccount's data has changed on-chain. + * @param callback - the callback invoked when the vrf state changes + * @param commitment - optional, the desired transaction finality. defaults to 'confirmed' + * @returns the websocket subscription id + */ onChange( callback: OnAccountChangeCallback, commitment: Commitment = 'confirmed'