working generate script

This commit is contained in:
Conner Gallagher 2023-05-25 12:56:28 -06:00
parent 371106f6fb
commit 0697a59469
37 changed files with 3960 additions and 125 deletions

View File

@ -29,7 +29,7 @@
"localnet:down": "kill -9 $(pgrep command solana-test-validator) || exit 0",
"local:validator": "shx mkdir -p .anchor/test-ledger || true; 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 SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f `# programId` --clone 7nYabs9dUhvxYwdTnrWVBL9MYviKSfrEbdWCUbcnwkpF `# programDataAddress` --clone Fi8vncGpNKbq62gPo56G4toCehWNy77GgqGkTaAF5Lkk `# idlAddress` --clone CyZuD7RPDcrqCGbNvLCyqk6Py9cEZTKmNKujfPi3ynDd `# programState` --clone 7hkp1xfPBcD2t1vZMoWWQPzipHVcXeLAAaiGXdPSfDie `# switchboardVault`",
"local:validator:mainnet": "solana-test-validator -q -r --ledger .anchor/test-ledger --mint $(solana-keygen pubkey ~/.config/solana/id.json) --bind-address 0.0.0.0 --rpc-port 8899 --url https://api.mainnet-beta.solana.com --clone SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f --clone 7nYabs9dUhvxYwdTnrWVBL9MYviKSfrEbdWCUbcnwkpF --clone Fi8vncGpNKbq62gPo56G4toCehWNy77GgqGkTaAF5Lkk --clone CyZuD7RPDcrqCGbNvLCyqk6Py9cEZTKmNKujfPi3ynDd --clone J7nSEX8ADf3pVVicd6yKy2Skvg8iLePEmkLUisAAaioD",
"generate": "node generate-client.js",
"generate": "node ./generate-client.js",
"build": "shx rm -rf lib || true; tsc -p tsconfig.cjs.json && tsc",
"watch": "tsc -p tsconfig.cjs.json --watch",
"test": "node ./node_modules/mocha/bin/mocha --loader=ts-node/esm --extension ts --timeout 60000 --exit",

View File

@ -265,6 +265,7 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
unpermissionedFeeds: params.unpermissionedFeeds ?? false,
unpermissionedVrf: params.unpermissionedVrf ?? false,
enableBufferRelayers: params.enableBufferRelayers ?? false,
enableTeeOnly: params.enableTeeOnly ?? false,
},
},
{
@ -1321,6 +1322,7 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
? new anchor.BN(params.consecutiveOracleFailureLimit)
: null,
varianceToleranceMultiplier: multiplier,
enableTeeOnly: params.enableTeeOnly ?? false,
},
},
{
@ -1459,6 +1461,7 @@ export interface QueueInitParams {
keypair?: Keypair;
dataBufferKeypair?: Keypair;
enableTeeOnly?: boolean;
}
export interface QueueSetConfigParams {
@ -1515,6 +1518,7 @@ export interface QueueSetConfigParams {
* Consecutive failure limit for an oracle before oracle permission is revoked.
*/
consecutiveOracleFailureLimit?: number;
enableTeeOnly?: boolean;
}
export type QueueAccountsJSON = Omit<

View File

@ -12,7 +12,7 @@ import { Account, OnAccountChangeCallback } from './account';
import { OracleAccount } from './oracleAccount';
import { PermissionAccount } from './permissionAccount';
import { QueueAccount } from './queueAccount';
import { Callback } from './vrfAccount';
import { Callback, VrfResult } from './vrfAccount';
import {
ASSOCIATED_TOKEN_PROGRAM_ID,
@ -22,6 +22,7 @@ import {
import {
Commitment,
Keypair,
ParsedTransactionWithMeta,
PublicKey,
SystemProgram,
SYSVAR_INSTRUCTIONS_PUBKEY,
@ -417,4 +418,115 @@ export class VrfLiteAccount extends Account<types.VrfLiteAccountData> {
public getEscrow(): PublicKey {
return this.program.mint.getAssociatedAddress(this.publicKey);
}
/**
* Await for the next vrf result
*
* @param roundId - optional, the id associated with the VRF round to watch. If not provided the current round Id will be used.
* @param timeout - the number of milliseconds to wait for the round to close
*
* @throws {string} when the timeout interval is exceeded or when the latestConfirmedRound.roundOpenSlot exceeds the target roundOpenSlot
*/
public async nextResult(roundId?: BN, timeout = 30000): Promise<VrfResult> {
let id: BN;
if (roundId) {
id = roundId;
} else {
const vrf = await this.loadData();
if (vrf.status.kind === 'StatusVerifying') {
id = vrf.counter;
} else {
// wait for the next round
id = vrf.counter.add(new BN(1));
}
}
let ws: number | undefined;
const closeWebsocket = async () => {
if (ws !== undefined) {
await this.program.connection.removeAccountChangeListener(ws);
ws = undefined;
}
};
let result: VrfResult;
try {
result = await promiseWithTimeout(
timeout,
new Promise(
(
resolve: (result: VrfResult) => void,
reject: (reason: string) => void
) => {
ws = this.onChange(vrf => {
if (vrf.counter.gt(id)) {
reject(`Current counter is higher than requested roundId`);
}
if (vrf.counter.eq(id)) {
switch (vrf.status.kind) {
case 'StatusCallbackSuccess': {
resolve({
success: true,
result: new Uint8Array(vrf.result),
status: vrf.status,
});
break;
}
case 'StatusVerifyFailure': {
resolve({
success: false,
result: new Uint8Array(),
status: vrf.status,
});
break;
}
}
}
});
}
)
);
} finally {
await closeWebsocket();
}
await closeWebsocket();
return result;
}
/** Return parsed transactions for a VRF request */
public async getCallbackTransactions(
requestSlot?: BN,
txnLimit = 50
): Promise<Array<ParsedTransactionWithMeta>> {
const slot = requestSlot ?? (await this.loadData()).requestSlot;
// TODO: Add options and allow getting signatures by slot
const transactions = await this.program.connection.getSignaturesForAddress(
this.publicKey,
{ limit: txnLimit, minContextSlot: slot.toNumber() },
'confirmed'
);
const signatures = transactions.map(txn => txn.signature);
const parsedTransactions =
await this.program.connection.getParsedTransactions(
signatures,
'confirmed'
);
const callbackTransactions: ParsedTransactionWithMeta[] = [];
for (const txn of parsedTransactions) {
if (txn === null) {
continue;
}
const logs = txn.meta?.logMessages?.join('\n') ?? '';
if (logs.includes('Invoking callback')) {
callbackTransactions.push(txn);
}
}
return callbackTransactions;
}
}

View File

@ -54,6 +54,7 @@ export interface OracleQueueAccountDataFields {
mint: PublicKey;
/** Whether oracles are permitted to fulfill buffer relayer update request. */
enableBufferRelayers: boolean;
enableTeeOnly: boolean;
/** Reserved for future info. */
ebuf: Array<number>;
/** Maximum number of oracles a queue can support. */
@ -112,6 +113,7 @@ export interface OracleQueueAccountDataJSON {
mint: string;
/** Whether oracles are permitted to fulfill buffer relayer update request. */
enableBufferRelayers: boolean;
enableTeeOnly: boolean;
/** Reserved for future info. */
ebuf: Array<number>;
/** Maximum number of oracles a queue can support. */
@ -170,6 +172,7 @@ export class OracleQueueAccountData {
readonly mint: PublicKey;
/** Whether oracles are permitted to fulfill buffer relayer update request. */
readonly enableBufferRelayers: boolean;
readonly enableTeeOnly: boolean;
/** Reserved for future info. */
readonly ebuf: Array<number>;
/** Maximum number of oracles a queue can support. */
@ -202,7 +205,8 @@ export class OracleQueueAccountData {
borsh.bool('lockLeaseFunding'),
borsh.publicKey('mint'),
borsh.bool('enableBufferRelayers'),
borsh.array(borsh.u8(), 968, 'ebuf'),
borsh.bool('enableTeeOnly'),
borsh.array(borsh.u8(), 967, 'ebuf'),
borsh.u32('maxSize'),
borsh.publicKey('dataBuffer'),
]);
@ -232,6 +236,7 @@ export class OracleQueueAccountData {
this.lockLeaseFunding = fields.lockLeaseFunding;
this.mint = fields.mint;
this.enableBufferRelayers = fields.enableBufferRelayers;
this.enableTeeOnly = fields.enableTeeOnly;
this.ebuf = fields.ebuf;
this.maxSize = fields.maxSize;
this.dataBuffer = fields.dataBuffer;
@ -303,6 +308,7 @@ export class OracleQueueAccountData {
lockLeaseFunding: dec.lockLeaseFunding,
mint: dec.mint,
enableBufferRelayers: dec.enableBufferRelayers,
enableTeeOnly: dec.enableTeeOnly,
ebuf: dec.ebuf,
maxSize: dec.maxSize,
dataBuffer: dec.dataBuffer,
@ -332,6 +338,7 @@ export class OracleQueueAccountData {
lockLeaseFunding: this.lockLeaseFunding,
mint: this.mint.toString(),
enableBufferRelayers: this.enableBufferRelayers,
enableTeeOnly: this.enableTeeOnly,
ebuf: this.ebuf,
maxSize: this.maxSize,
dataBuffer: this.dataBuffer.toString(),
@ -362,6 +369,7 @@ export class OracleQueueAccountData {
lockLeaseFunding: obj.lockLeaseFunding,
mint: new PublicKey(obj.mint),
enableBufferRelayers: obj.enableBufferRelayers,
enableTeeOnly: obj.enableTeeOnly,
ebuf: obj.ebuf,
maxSize: obj.maxSize,
dataBuffer: new PublicKey(obj.dataBuffer),

View File

@ -0,0 +1,190 @@
import { SwitchboardProgram } from '../../SwitchboardProgram';
import { PublicKey, Connection } from '@solana/web3.js';
import { BN } from '@switchboard-xyz/common'; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from '@coral-xyz/borsh'; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as types from '../types'; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface QuoteAccountDataFields {
delegatedSecuredSigner: PublicKey;
bump: number;
/** TODO: Add description */
quoteRegistry: Array<number>;
/** Key to lookup the buffer data on IPFS or an alternative decentralized storage solution. */
registryKey: Array<number>;
/** Queue used for attestation to verify a MRENCLAVE measurement. */
attestationQueue: PublicKey;
/** The quotes MRENCLAVE measurement dictating the contents of the secure enclave. */
mrEnclave: Array<number>;
verificationStatus: number;
verificationTimestamp: BN;
validUntil: BN;
isOnQueue: boolean;
/** The last time the quote heartbeated. */
lastHeartbeat: BN;
ebuf: Array<number>;
}
export interface QuoteAccountDataJSON {
delegatedSecuredSigner: string;
bump: number;
/** TODO: Add description */
quoteRegistry: Array<number>;
/** Key to lookup the buffer data on IPFS or an alternative decentralized storage solution. */
registryKey: Array<number>;
/** Queue used for attestation to verify a MRENCLAVE measurement. */
attestationQueue: string;
/** The quotes MRENCLAVE measurement dictating the contents of the secure enclave. */
mrEnclave: Array<number>;
verificationStatus: number;
verificationTimestamp: string;
validUntil: string;
isOnQueue: boolean;
/** The last time the quote heartbeated. */
lastHeartbeat: string;
ebuf: Array<number>;
}
export class QuoteAccountData {
readonly delegatedSecuredSigner: PublicKey;
readonly bump: number;
/** TODO: Add description */
readonly quoteRegistry: Array<number>;
/** Key to lookup the buffer data on IPFS or an alternative decentralized storage solution. */
readonly registryKey: Array<number>;
/** Queue used for attestation to verify a MRENCLAVE measurement. */
readonly attestationQueue: PublicKey;
/** The quotes MRENCLAVE measurement dictating the contents of the secure enclave. */
readonly mrEnclave: Array<number>;
readonly verificationStatus: number;
readonly verificationTimestamp: BN;
readonly validUntil: BN;
readonly isOnQueue: boolean;
/** The last time the quote heartbeated. */
readonly lastHeartbeat: BN;
readonly ebuf: Array<number>;
static readonly discriminator = Buffer.from([
205, 205, 167, 232, 0, 74, 44, 160,
]);
static readonly layout = borsh.struct([
borsh.publicKey('delegatedSecuredSigner'),
borsh.u8('bump'),
borsh.array(borsh.u8(), 32, 'quoteRegistry'),
borsh.array(borsh.u8(), 64, 'registryKey'),
borsh.publicKey('attestationQueue'),
borsh.array(borsh.u8(), 32, 'mrEnclave'),
borsh.u8('verificationStatus'),
borsh.i64('verificationTimestamp'),
borsh.i64('validUntil'),
borsh.bool('isOnQueue'),
borsh.i64('lastHeartbeat'),
borsh.array(borsh.u8(), 1024, 'ebuf'),
]);
constructor(fields: QuoteAccountDataFields) {
this.delegatedSecuredSigner = fields.delegatedSecuredSigner;
this.bump = fields.bump;
this.quoteRegistry = fields.quoteRegistry;
this.registryKey = fields.registryKey;
this.attestationQueue = fields.attestationQueue;
this.mrEnclave = fields.mrEnclave;
this.verificationStatus = fields.verificationStatus;
this.verificationTimestamp = fields.verificationTimestamp;
this.validUntil = fields.validUntil;
this.isOnQueue = fields.isOnQueue;
this.lastHeartbeat = fields.lastHeartbeat;
this.ebuf = fields.ebuf;
}
static async fetch(
program: SwitchboardProgram,
address: PublicKey
): Promise<QuoteAccountData | null> {
const info = await program.connection.getAccountInfo(address);
if (info === null) {
return null;
}
if (!info.owner.equals(program.programId)) {
throw new Error("account doesn't belong to this program");
}
return this.decode(info.data);
}
static async fetchMultiple(
program: SwitchboardProgram,
addresses: PublicKey[]
): Promise<Array<QuoteAccountData | null>> {
const infos = await program.connection.getMultipleAccountsInfo(addresses);
return infos.map(info => {
if (info === null) {
return null;
}
if (!info.owner.equals(program.programId)) {
throw new Error("account doesn't belong to this program");
}
return this.decode(info.data);
});
}
static decode(data: Buffer): QuoteAccountData {
if (!data.slice(0, 8).equals(QuoteAccountData.discriminator)) {
throw new Error('invalid account discriminator');
}
const dec = QuoteAccountData.layout.decode(data.slice(8));
return new QuoteAccountData({
delegatedSecuredSigner: dec.delegatedSecuredSigner,
bump: dec.bump,
quoteRegistry: dec.quoteRegistry,
registryKey: dec.registryKey,
attestationQueue: dec.attestationQueue,
mrEnclave: dec.mrEnclave,
verificationStatus: dec.verificationStatus,
verificationTimestamp: dec.verificationTimestamp,
validUntil: dec.validUntil,
isOnQueue: dec.isOnQueue,
lastHeartbeat: dec.lastHeartbeat,
ebuf: dec.ebuf,
});
}
toJSON(): QuoteAccountDataJSON {
return {
delegatedSecuredSigner: this.delegatedSecuredSigner.toString(),
bump: this.bump,
quoteRegistry: this.quoteRegistry,
registryKey: this.registryKey,
attestationQueue: this.attestationQueue.toString(),
mrEnclave: this.mrEnclave,
verificationStatus: this.verificationStatus,
verificationTimestamp: this.verificationTimestamp.toString(),
validUntil: this.validUntil.toString(),
isOnQueue: this.isOnQueue,
lastHeartbeat: this.lastHeartbeat.toString(),
ebuf: this.ebuf,
};
}
static fromJSON(obj: QuoteAccountDataJSON): QuoteAccountData {
return new QuoteAccountData({
delegatedSecuredSigner: new PublicKey(obj.delegatedSecuredSigner),
bump: obj.bump,
quoteRegistry: obj.quoteRegistry,
registryKey: obj.registryKey,
attestationQueue: new PublicKey(obj.attestationQueue),
mrEnclave: obj.mrEnclave,
verificationStatus: obj.verificationStatus,
verificationTimestamp: new BN(obj.verificationTimestamp),
validUntil: new BN(obj.validUntil),
isOnQueue: obj.isOnQueue,
lastHeartbeat: new BN(obj.lastHeartbeat),
ebuf: obj.ebuf,
});
}
}

View File

@ -15,6 +15,8 @@ export interface SbStateFields {
daoMint: PublicKey;
/** The PDA bump to derive the pubkey. */
bump: number;
/** Permitted enclave measurements */
mrEnclaves: Array<Array<number>>;
/** Reserved for future info. */
ebuf: Array<number>;
}
@ -30,6 +32,8 @@ export interface SbStateJSON {
daoMint: string;
/** The PDA bump to derive the pubkey. */
bump: number;
/** Permitted enclave measurements */
mrEnclaves: Array<Array<number>>;
/** Reserved for future info. */
ebuf: Array<number>;
}
@ -45,6 +49,8 @@ export class SbState {
readonly daoMint: PublicKey;
/** The PDA bump to derive the pubkey. */
readonly bump: number;
/** Permitted enclave measurements */
readonly mrEnclaves: Array<Array<number>>;
/** Reserved for future info. */
readonly ebuf: Array<number>;
@ -58,7 +64,8 @@ export class SbState {
borsh.publicKey('tokenVault'),
borsh.publicKey('daoMint'),
borsh.u8('bump'),
borsh.array(borsh.u8(), 991, 'ebuf'),
borsh.array(borsh.array(borsh.u8(), 32), 6, 'mrEnclaves'),
borsh.array(borsh.u8(), 799, 'ebuf'),
]);
constructor(fields: SbStateFields) {
@ -67,6 +74,7 @@ export class SbState {
this.tokenVault = fields.tokenVault;
this.daoMint = fields.daoMint;
this.bump = fields.bump;
this.mrEnclaves = fields.mrEnclaves;
this.ebuf = fields.ebuf;
}
@ -117,6 +125,7 @@ export class SbState {
tokenVault: dec.tokenVault,
daoMint: dec.daoMint,
bump: dec.bump,
mrEnclaves: dec.mrEnclaves,
ebuf: dec.ebuf,
});
}
@ -128,6 +137,7 @@ export class SbState {
tokenVault: this.tokenVault.toString(),
daoMint: this.daoMint.toString(),
bump: this.bump,
mrEnclaves: this.mrEnclaves,
ebuf: this.ebuf,
};
}
@ -139,6 +149,7 @@ export class SbState {
tokenVault: new PublicKey(obj.tokenVault),
daoMint: new PublicKey(obj.daoMint),
bump: obj.bump,
mrEnclaves: obj.mrEnclaves,
ebuf: obj.ebuf,
});
}

View File

@ -1,3 +1,8 @@
export { QuoteAccountData } from './QuoteAccountData';
export type {
QuoteAccountDataFields,
QuoteAccountDataJSON,
} from './QuoteAccountData';
export { SbState } from './SbState';
export type { SbStateFields, SbStateJSON } from './SbState';
export { TaskSpecRecord } from './TaskSpecRecord';

View File

@ -99,7 +99,10 @@ export type CustomError =
| VrfPoolRequestTooSoon
| VrfPoolMiss
| VrfLiteOwnedByPool
| InsufficientTokenBalance;
| InsufficientTokenBalance
| InvalidQuoteError
| InvalidHistoryAccountError
| GenericError;
export class ArrayOperationError extends Error {
static readonly code = 6000;
@ -1235,6 +1238,37 @@ export class InsufficientTokenBalance extends Error {
}
}
export class InvalidQuoteError extends Error {
static readonly code = 6100;
readonly code = 6100;
readonly name = 'InvalidQuoteError';
readonly msg = 'Invalid SAS quote account';
constructor(readonly logs?: string[]) {
super('6100: Invalid SAS quote account');
}
}
export class InvalidHistoryAccountError extends Error {
static readonly code = 6101;
readonly code = 6101;
readonly name = 'InvalidHistoryAccountError';
constructor(readonly logs?: string[]) {
super('6101: ');
}
}
export class GenericError extends Error {
static readonly code = 6102;
readonly code = 6102;
readonly name = 'GenericError';
constructor(readonly logs?: string[]) {
super('6102: ');
}
}
export function fromCode(code: number, logs?: string[]): CustomError | null {
switch (code) {
case 6000:
@ -1437,6 +1471,12 @@ export function fromCode(code: number, logs?: string[]): CustomError | null {
return new VrfLiteOwnedByPool(logs);
case 6099:
return new InsufficientTokenBalance(logs);
case 6100:
return new InvalidQuoteError(logs);
case 6101:
return new InvalidHistoryAccountError(logs);
case 6102:
return new GenericError(logs);
}
return null;

View File

@ -1,4 +1,3 @@
import { SBV2_DEVNET_PID, SBV2_MAINNET_PID } from '../../SwitchboardProgram';
import { PROGRAM_ID } from '../programId';
import * as anchor from './anchor';
import * as custom from './custom';
@ -46,10 +45,7 @@ export function fromTxError(
}
const [programIdRaw, codeRaw] = firstMatch.slice(1);
if (
programIdRaw !== SBV2_DEVNET_PID.toString() &&
programIdRaw !== SBV2_MAINNET_PID.toString()
) {
if (programIdRaw !== PROGRAM_ID.toString()) {
return null;
}

View File

@ -0,0 +1,80 @@
import { SwitchboardProgram } from '../../SwitchboardProgram';
import {
TransactionInstruction,
PublicKey,
AccountMeta,
} from '@solana/web3.js'; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from '@switchboard-xyz/common'; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from '@coral-xyz/borsh'; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as types from '../types'; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface AggregatorTeeSaveResultArgs {
params: types.AggregatorTeeSaveResultParamsFields;
}
export interface AggregatorTeeSaveResultAccounts {
aggregator: PublicKey;
oracle: PublicKey;
oracleAuthority: PublicKey;
oracleQueue: PublicKey;
queueAuthority: PublicKey;
feedPermission: PublicKey;
oraclePermission: PublicKey;
lease: PublicKey;
escrow: PublicKey;
tokenProgram: PublicKey;
programState: PublicKey;
historyBuffer: PublicKey;
mint: PublicKey;
slider: PublicKey;
quote: PublicKey;
rewardWallet: PublicKey;
payer: PublicKey;
systemProgram: PublicKey;
}
export const layout = borsh.struct([
types.AggregatorTeeSaveResultParams.layout('params'),
]);
export function aggregatorTeeSaveResult(
program: SwitchboardProgram,
args: AggregatorTeeSaveResultArgs,
accounts: AggregatorTeeSaveResultAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.aggregator, isSigner: false, isWritable: true },
{ pubkey: accounts.oracle, isSigner: false, isWritable: true },
{ pubkey: accounts.oracleAuthority, isSigner: true, isWritable: false },
{ pubkey: accounts.oracleQueue, isSigner: false, isWritable: false },
{ pubkey: accounts.queueAuthority, isSigner: false, isWritable: false },
{ pubkey: accounts.feedPermission, isSigner: false, isWritable: true },
{ pubkey: accounts.oraclePermission, isSigner: false, isWritable: false },
{ pubkey: accounts.lease, isSigner: false, isWritable: true },
{ pubkey: accounts.escrow, isSigner: false, isWritable: true },
{ pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
{ pubkey: accounts.programState, isSigner: false, isWritable: false },
{ pubkey: accounts.historyBuffer, isSigner: false, isWritable: true },
{ pubkey: accounts.mint, isSigner: false, isWritable: false },
{ pubkey: accounts.slider, isSigner: false, isWritable: true },
{ pubkey: accounts.quote, isSigner: false, isWritable: false },
{ pubkey: accounts.rewardWallet, isSigner: false, isWritable: true },
{ pubkey: accounts.payer, isSigner: true, isWritable: true },
{ pubkey: accounts.systemProgram, isSigner: false, isWritable: false },
];
const identifier = Buffer.from([43, 192, 193, 209, 121, 90, 186, 135]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.AggregatorTeeSaveResultParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.programId,
data,
});
return ix;
}

View File

@ -40,6 +40,11 @@ export type {
AggregatorSaveResultV2Args,
AggregatorSaveResultV2Accounts,
} from './aggregatorSaveResultV2';
export { aggregatorTeeSaveResult } from './aggregatorTeeSaveResult';
export type {
AggregatorTeeSaveResultArgs,
AggregatorTeeSaveResultAccounts,
} from './aggregatorTeeSaveResult';
export { aggregatorSetAuthority } from './aggregatorSetAuthority';
export type {
AggregatorSetAuthorityArgs,
@ -108,6 +113,11 @@ export type {
OracleHeartbeatArgs,
OracleHeartbeatAccounts,
} from './oracleHeartbeat';
export { oracleTeeHeartbeat } from './oracleTeeHeartbeat';
export type {
OracleTeeHeartbeatArgs,
OracleTeeHeartbeatAccounts,
} from './oracleTeeHeartbeat';
export { oracleInit } from './oracleInit';
export type { OracleInitArgs, OracleInitAccounts } from './oracleInit';
export { oracleQueueInit } from './oracleQueueInit';

View File

@ -0,0 +1,62 @@
import { SwitchboardProgram } from '../../SwitchboardProgram';
import {
TransactionInstruction,
PublicKey,
AccountMeta,
} from '@solana/web3.js'; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from '@switchboard-xyz/common'; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from '@coral-xyz/borsh'; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as types from '../types'; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface OracleTeeHeartbeatArgs {
params: types.OracleTeeHeartbeatParamsFields;
}
export interface OracleTeeHeartbeatAccounts {
oracle: PublicKey;
oracleAuthority: PublicKey;
tokenAccount: PublicKey;
gcOracle: PublicKey;
oracleQueue: PublicKey;
permission: PublicKey;
dataBuffer: PublicKey;
quote: PublicKey;
programState: PublicKey;
}
export const layout = borsh.struct([
types.OracleTeeHeartbeatParams.layout('params'),
]);
export function oracleTeeHeartbeat(
program: SwitchboardProgram,
args: OracleTeeHeartbeatArgs,
accounts: OracleTeeHeartbeatAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.oracle, isSigner: false, isWritable: true },
{ pubkey: accounts.oracleAuthority, isSigner: true, isWritable: false },
{ pubkey: accounts.tokenAccount, isSigner: false, isWritable: false },
{ pubkey: accounts.gcOracle, isSigner: false, isWritable: true },
{ pubkey: accounts.oracleQueue, isSigner: false, isWritable: true },
{ pubkey: accounts.permission, isSigner: false, isWritable: false },
{ pubkey: accounts.dataBuffer, isSigner: false, isWritable: true },
{ pubkey: accounts.quote, isSigner: false, isWritable: false },
{ pubkey: accounts.programState, isSigner: false, isWritable: false },
];
const identifier = Buffer.from([92, 64, 133, 138, 16, 62, 245, 251]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.OracleTeeHeartbeatParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.programId,
data,
});
return ix;
}

View File

@ -0,0 +1,124 @@
import { SwitchboardProgram } from '../../SwitchboardProgram';
import { PublicKey } from '@solana/web3.js'; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from '@switchboard-xyz/common'; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as types from '../types'; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from '@coral-xyz/borsh';
export interface AggregatorTeeSaveResultParamsFields {
value: types.BorshDecimalFields;
jobsChecksum: Array<number>;
minResponse: types.BorshDecimalFields;
maxResponse: types.BorshDecimalFields;
feedPermissionBump: number;
oraclePermissionBump: number;
leaseBump: number;
stateBump: number;
}
export interface AggregatorTeeSaveResultParamsJSON {
value: types.BorshDecimalJSON;
jobsChecksum: Array<number>;
minResponse: types.BorshDecimalJSON;
maxResponse: types.BorshDecimalJSON;
feedPermissionBump: number;
oraclePermissionBump: number;
leaseBump: number;
stateBump: number;
}
export class AggregatorTeeSaveResultParams {
readonly value: types.BorshDecimal;
readonly jobsChecksum: Array<number>;
readonly minResponse: types.BorshDecimal;
readonly maxResponse: types.BorshDecimal;
readonly feedPermissionBump: number;
readonly oraclePermissionBump: number;
readonly leaseBump: number;
readonly stateBump: number;
constructor(fields: AggregatorTeeSaveResultParamsFields) {
this.value = new types.BorshDecimal({ ...fields.value });
this.jobsChecksum = fields.jobsChecksum;
this.minResponse = new types.BorshDecimal({ ...fields.minResponse });
this.maxResponse = new types.BorshDecimal({ ...fields.maxResponse });
this.feedPermissionBump = fields.feedPermissionBump;
this.oraclePermissionBump = fields.oraclePermissionBump;
this.leaseBump = fields.leaseBump;
this.stateBump = fields.stateBump;
}
static layout(property?: string) {
return borsh.struct(
[
types.BorshDecimal.layout('value'),
borsh.array(borsh.u8(), 32, 'jobsChecksum'),
types.BorshDecimal.layout('minResponse'),
types.BorshDecimal.layout('maxResponse'),
borsh.u8('feedPermissionBump'),
borsh.u8('oraclePermissionBump'),
borsh.u8('leaseBump'),
borsh.u8('stateBump'),
],
property
);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new AggregatorTeeSaveResultParams({
value: types.BorshDecimal.fromDecoded(obj.value),
jobsChecksum: obj.jobsChecksum,
minResponse: types.BorshDecimal.fromDecoded(obj.minResponse),
maxResponse: types.BorshDecimal.fromDecoded(obj.maxResponse),
feedPermissionBump: obj.feedPermissionBump,
oraclePermissionBump: obj.oraclePermissionBump,
leaseBump: obj.leaseBump,
stateBump: obj.stateBump,
});
}
static toEncodable(fields: AggregatorTeeSaveResultParamsFields) {
return {
value: types.BorshDecimal.toEncodable(fields.value),
jobsChecksum: fields.jobsChecksum,
minResponse: types.BorshDecimal.toEncodable(fields.minResponse),
maxResponse: types.BorshDecimal.toEncodable(fields.maxResponse),
feedPermissionBump: fields.feedPermissionBump,
oraclePermissionBump: fields.oraclePermissionBump,
leaseBump: fields.leaseBump,
stateBump: fields.stateBump,
};
}
toJSON(): AggregatorTeeSaveResultParamsJSON {
return {
value: this.value.toJSON(),
jobsChecksum: this.jobsChecksum,
minResponse: this.minResponse.toJSON(),
maxResponse: this.maxResponse.toJSON(),
feedPermissionBump: this.feedPermissionBump,
oraclePermissionBump: this.oraclePermissionBump,
leaseBump: this.leaseBump,
stateBump: this.stateBump,
};
}
static fromJSON(
obj: AggregatorTeeSaveResultParamsJSON
): AggregatorTeeSaveResultParams {
return new AggregatorTeeSaveResultParams({
value: types.BorshDecimal.fromJSON(obj.value),
jobsChecksum: obj.jobsChecksum,
minResponse: types.BorshDecimal.fromJSON(obj.minResponse),
maxResponse: types.BorshDecimal.fromJSON(obj.maxResponse),
feedPermissionBump: obj.feedPermissionBump,
oraclePermissionBump: obj.oraclePermissionBump,
leaseBump: obj.leaseBump,
stateBump: obj.stateBump,
});
}
toEncodable() {
return AggregatorTeeSaveResultParams.toEncodable(this);
}
}

View File

@ -1,6 +1,7 @@
import * as borsh from '@coral-xyz/borsh';
import * as types from '../types'; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from '@coral-xyz/borsh';
export interface DJSON {
kind: 'D';
}

View File

@ -19,6 +19,7 @@ export interface OracleQueueInitParamsFields {
unpermissionedFeeds: boolean;
unpermissionedVrf: boolean;
enableBufferRelayers: boolean;
enableTeeOnly: boolean;
}
export interface OracleQueueInitParamsJSON {
@ -36,6 +37,7 @@ export interface OracleQueueInitParamsJSON {
unpermissionedFeeds: boolean;
unpermissionedVrf: boolean;
enableBufferRelayers: boolean;
enableTeeOnly: boolean;
}
export class OracleQueueInitParams {
@ -53,6 +55,7 @@ export class OracleQueueInitParams {
readonly unpermissionedFeeds: boolean;
readonly unpermissionedVrf: boolean;
readonly enableBufferRelayers: boolean;
readonly enableTeeOnly: boolean;
constructor(fields: OracleQueueInitParamsFields) {
this.name = fields.name;
@ -71,6 +74,7 @@ export class OracleQueueInitParams {
this.unpermissionedFeeds = fields.unpermissionedFeeds;
this.unpermissionedVrf = fields.unpermissionedVrf;
this.enableBufferRelayers = fields.enableBufferRelayers;
this.enableTeeOnly = fields.enableTeeOnly;
}
static layout(property?: string) {
@ -90,6 +94,7 @@ export class OracleQueueInitParams {
borsh.bool('unpermissionedFeeds'),
borsh.bool('unpermissionedVrf'),
borsh.bool('enableBufferRelayers'),
borsh.bool('enableTeeOnly'),
],
property
);
@ -114,6 +119,7 @@ export class OracleQueueInitParams {
unpermissionedFeeds: obj.unpermissionedFeeds,
unpermissionedVrf: obj.unpermissionedVrf,
enableBufferRelayers: obj.enableBufferRelayers,
enableTeeOnly: obj.enableTeeOnly,
});
}
@ -135,6 +141,7 @@ export class OracleQueueInitParams {
unpermissionedFeeds: fields.unpermissionedFeeds,
unpermissionedVrf: fields.unpermissionedVrf,
enableBufferRelayers: fields.enableBufferRelayers,
enableTeeOnly: fields.enableTeeOnly,
};
}
@ -155,6 +162,7 @@ export class OracleQueueInitParams {
unpermissionedFeeds: this.unpermissionedFeeds,
unpermissionedVrf: this.unpermissionedVrf,
enableBufferRelayers: this.enableBufferRelayers,
enableTeeOnly: this.enableTeeOnly,
};
}
@ -176,6 +184,7 @@ export class OracleQueueInitParams {
unpermissionedFeeds: obj.unpermissionedFeeds,
unpermissionedVrf: obj.unpermissionedVrf,
enableBufferRelayers: obj.enableBufferRelayers,
enableTeeOnly: obj.enableTeeOnly,
});
}

View File

@ -17,6 +17,7 @@ export interface OracleQueueSetConfigParamsFields {
oracleTimeout: number | null;
consecutiveFeedFailureLimit: BN | null;
consecutiveOracleFailureLimit: BN | null;
enableTeeOnly: boolean | null;
}
export interface OracleQueueSetConfigParamsJSON {
@ -32,6 +33,7 @@ export interface OracleQueueSetConfigParamsJSON {
oracleTimeout: number | null;
consecutiveFeedFailureLimit: string | null;
consecutiveOracleFailureLimit: string | null;
enableTeeOnly: boolean | null;
}
export class OracleQueueSetConfigParams {
@ -47,6 +49,7 @@ export class OracleQueueSetConfigParams {
readonly oracleTimeout: number | null;
readonly consecutiveFeedFailureLimit: BN | null;
readonly consecutiveOracleFailureLimit: BN | null;
readonly enableTeeOnly: boolean | null;
constructor(fields: OracleQueueSetConfigParamsFields) {
this.name = fields.name;
@ -64,6 +67,7 @@ export class OracleQueueSetConfigParams {
this.oracleTimeout = fields.oracleTimeout;
this.consecutiveFeedFailureLimit = fields.consecutiveFeedFailureLimit;
this.consecutiveOracleFailureLimit = fields.consecutiveOracleFailureLimit;
this.enableTeeOnly = fields.enableTeeOnly;
}
static layout(property?: string) {
@ -84,6 +88,7 @@ export class OracleQueueSetConfigParams {
borsh.option(borsh.u32(), 'oracleTimeout'),
borsh.option(borsh.u64(), 'consecutiveFeedFailureLimit'),
borsh.option(borsh.u64(), 'consecutiveOracleFailureLimit'),
borsh.option(borsh.bool(), 'enableTeeOnly'),
],
property
);
@ -107,6 +112,7 @@ export class OracleQueueSetConfigParams {
oracleTimeout: obj.oracleTimeout,
consecutiveFeedFailureLimit: obj.consecutiveFeedFailureLimit,
consecutiveOracleFailureLimit: obj.consecutiveOracleFailureLimit,
enableTeeOnly: obj.enableTeeOnly,
});
}
@ -127,6 +133,7 @@ export class OracleQueueSetConfigParams {
oracleTimeout: fields.oracleTimeout,
consecutiveFeedFailureLimit: fields.consecutiveFeedFailureLimit,
consecutiveOracleFailureLimit: fields.consecutiveOracleFailureLimit,
enableTeeOnly: fields.enableTeeOnly,
};
}
@ -153,6 +160,7 @@ export class OracleQueueSetConfigParams {
(this.consecutiveOracleFailureLimit &&
this.consecutiveOracleFailureLimit.toString()) ||
null,
enableTeeOnly: this.enableTeeOnly,
};
}
@ -181,6 +189,7 @@ export class OracleQueueSetConfigParams {
(obj.consecutiveOracleFailureLimit &&
new BN(obj.consecutiveOracleFailureLimit)) ||
null,
enableTeeOnly: obj.enableTeeOnly,
});
}

View File

@ -0,0 +1,54 @@
import { SwitchboardProgram } from '../../SwitchboardProgram';
import { PublicKey } from '@solana/web3.js'; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from '@switchboard-xyz/common'; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as types from '../types'; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from '@coral-xyz/borsh';
export interface OracleTeeHeartbeatParamsFields {
permissionBump: number;
}
export interface OracleTeeHeartbeatParamsJSON {
permissionBump: number;
}
export class OracleTeeHeartbeatParams {
readonly permissionBump: number;
constructor(fields: OracleTeeHeartbeatParamsFields) {
this.permissionBump = fields.permissionBump;
}
static layout(property?: string) {
return borsh.struct([borsh.u8('permissionBump')], property);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new OracleTeeHeartbeatParams({
permissionBump: obj.permissionBump,
});
}
static toEncodable(fields: OracleTeeHeartbeatParamsFields) {
return {
permissionBump: fields.permissionBump,
};
}
toJSON(): OracleTeeHeartbeatParamsJSON {
return {
permissionBump: this.permissionBump,
};
}
static fromJSON(obj: OracleTeeHeartbeatParamsJSON): OracleTeeHeartbeatParams {
return new OracleTeeHeartbeatParams({
permissionBump: obj.permissionBump,
});
}
toEncodable() {
return OracleTeeHeartbeatParams.toEncodable(this);
}
}

View File

@ -8,28 +8,42 @@ export interface ProgramConfigParamsFields {
token: PublicKey;
bump: number;
daoMint: PublicKey;
addEnclaves: Array<Array<number>>;
rmEnclaves: Array<Array<number>>;
}
export interface ProgramConfigParamsJSON {
token: string;
bump: number;
daoMint: string;
addEnclaves: Array<Array<number>>;
rmEnclaves: Array<Array<number>>;
}
export class ProgramConfigParams {
readonly token: PublicKey;
readonly bump: number;
readonly daoMint: PublicKey;
readonly addEnclaves: Array<Array<number>>;
readonly rmEnclaves: Array<Array<number>>;
constructor(fields: ProgramConfigParamsFields) {
this.token = fields.token;
this.bump = fields.bump;
this.daoMint = fields.daoMint;
this.addEnclaves = fields.addEnclaves;
this.rmEnclaves = fields.rmEnclaves;
}
static layout(property?: string) {
return borsh.struct(
[borsh.publicKey('token'), borsh.u8('bump'), borsh.publicKey('daoMint')],
[
borsh.publicKey('token'),
borsh.u8('bump'),
borsh.publicKey('daoMint'),
borsh.vec(borsh.array(borsh.u8(), 32), 'addEnclaves'),
borsh.vec(borsh.array(borsh.u8(), 32), 'rmEnclaves'),
],
property
);
}
@ -40,6 +54,8 @@ export class ProgramConfigParams {
token: obj.token,
bump: obj.bump,
daoMint: obj.daoMint,
addEnclaves: obj.addEnclaves,
rmEnclaves: obj.rmEnclaves,
});
}
@ -48,6 +64,8 @@ export class ProgramConfigParams {
token: fields.token,
bump: fields.bump,
daoMint: fields.daoMint,
addEnclaves: fields.addEnclaves,
rmEnclaves: fields.rmEnclaves,
};
}
@ -56,6 +74,8 @@ export class ProgramConfigParams {
token: this.token.toString(),
bump: this.bump,
daoMint: this.daoMint.toString(),
addEnclaves: this.addEnclaves,
rmEnclaves: this.rmEnclaves,
};
}
@ -64,6 +84,8 @@ export class ProgramConfigParams {
token: new PublicKey(obj.token),
bump: obj.bump,
daoMint: new PublicKey(obj.daoMint),
addEnclaves: obj.addEnclaves,
rmEnclaves: obj.rmEnclaves,
});
}

View File

@ -0,0 +1,151 @@
import { SwitchboardProgram } from '../../SwitchboardProgram';
import { PublicKey } from '@solana/web3.js'; // eslint-disable-line @typescript-eslint/no-unused-vars
import { BN } from '@switchboard-xyz/common'; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as types from '../types'; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from '@coral-xyz/borsh';
export interface VerificationPendingJSON {
kind: 'VerificationPending';
}
export class VerificationPending {
static readonly discriminator = 0;
static readonly kind = 'VerificationPending';
readonly discriminator = 0;
readonly kind = 'VerificationPending';
toJSON(): VerificationPendingJSON {
return {
kind: 'VerificationPending',
};
}
toEncodable() {
return {
VerificationPending: {},
};
}
}
export interface VerificationFailureJSON {
kind: 'VerificationFailure';
}
export class VerificationFailure {
static readonly discriminator = 1;
static readonly kind = 'VerificationFailure';
readonly discriminator = 1;
readonly kind = 'VerificationFailure';
toJSON(): VerificationFailureJSON {
return {
kind: 'VerificationFailure',
};
}
toEncodable() {
return {
VerificationFailure: {},
};
}
}
export interface VerificationSuccessJSON {
kind: 'VerificationSuccess';
}
export class VerificationSuccess {
static readonly discriminator = 2;
static readonly kind = 'VerificationSuccess';
readonly discriminator = 2;
readonly kind = 'VerificationSuccess';
toJSON(): VerificationSuccessJSON {
return {
kind: 'VerificationSuccess',
};
}
toEncodable() {
return {
VerificationSuccess: {},
};
}
}
export interface VerificationOverrideJSON {
kind: 'VerificationOverride';
}
export class VerificationOverride {
static readonly discriminator = 3;
static readonly kind = 'VerificationOverride';
readonly discriminator = 3;
readonly kind = 'VerificationOverride';
toJSON(): VerificationOverrideJSON {
return {
kind: 'VerificationOverride',
};
}
toEncodable() {
return {
VerificationOverride: {},
};
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function fromDecoded(obj: any): types.VerificationStatusKind {
if (typeof obj !== 'object') {
throw new Error('Invalid enum object');
}
if ('VerificationPending' in obj) {
return new VerificationPending();
}
if ('VerificationFailure' in obj) {
return new VerificationFailure();
}
if ('VerificationSuccess' in obj) {
return new VerificationSuccess();
}
if ('VerificationOverride' in obj) {
return new VerificationOverride();
}
throw new Error('Invalid enum object');
}
export function fromJSON(
obj: types.VerificationStatusJSON
): types.VerificationStatusKind {
switch (obj.kind) {
case 'VerificationPending': {
return new VerificationPending();
}
case 'VerificationFailure': {
return new VerificationFailure();
}
case 'VerificationSuccess': {
return new VerificationSuccess();
}
case 'VerificationOverride': {
return new VerificationOverride();
}
}
}
export function layout(property?: string) {
const ret = borsh.rustEnum([
borsh.struct([], 'VerificationPending'),
borsh.struct([], 'VerificationFailure'),
borsh.struct([], 'VerificationSuccess'),
borsh.struct([], 'VerificationOverride'),
]);
if (property !== undefined) {
return ret.replicate(property);
}
return ret;
}

View File

@ -4,400 +4,384 @@ import * as Lanes from './Lanes';
import * as OracleResponseType from './OracleResponseType';
import * as Shuffle from './Shuffle';
import * as SwitchboardPermission from './SwitchboardPermission';
import * as VerificationStatus from './VerificationStatus';
import * as VrfStatus from './VrfStatus';
export { AccountMetaBorsh } from './AccountMetaBorsh';
export type {
AccountMetaBorshFields,
AccountMetaBorshJSON,
} from './AccountMetaBorsh';
export { AccountMetaZC } from './AccountMetaZC';
export { AccountMetaBorsh } from './AccountMetaBorsh';
export type { AccountMetaZCFields, AccountMetaZCJSON } from './AccountMetaZC';
export { AggregatorAddJobParams } from './AggregatorAddJobParams';
export { AccountMetaZC } from './AccountMetaZC';
export type {
AggregatorAddJobParamsFields,
AggregatorAddJobParamsJSON,
} from './AggregatorAddJobParams';
export { AggregatorCloseParams } from './AggregatorCloseParams';
export { AggregatorAddJobParams } from './AggregatorAddJobParams';
export type {
AggregatorCloseParamsFields,
AggregatorCloseParamsJSON,
} from './AggregatorCloseParams';
export { AggregatorHistoryRow } from './AggregatorHistoryRow';
export { AggregatorCloseParams } from './AggregatorCloseParams';
export type {
AggregatorHistoryRowFields,
AggregatorHistoryRowJSON,
} from './AggregatorHistoryRow';
export { AggregatorInitParams } from './AggregatorInitParams';
export { AggregatorHistoryRow } from './AggregatorHistoryRow';
export type {
AggregatorInitParamsFields,
AggregatorInitParamsJSON,
} from './AggregatorInitParams';
export { AggregatorLockParams } from './AggregatorLockParams';
export { AggregatorInitParams } from './AggregatorInitParams';
export type {
AggregatorLockParamsFields,
AggregatorLockParamsJSON,
} from './AggregatorLockParams';
export { AggregatorOpenRoundParams } from './AggregatorOpenRoundParams';
export { AggregatorLockParams } from './AggregatorLockParams';
export type {
AggregatorOpenRoundParamsFields,
AggregatorOpenRoundParamsJSON,
} from './AggregatorOpenRoundParams';
export { AggregatorRemoveJobParams } from './AggregatorRemoveJobParams';
export { AggregatorOpenRoundParams } from './AggregatorOpenRoundParams';
export type {
AggregatorRemoveJobParamsFields,
AggregatorRemoveJobParamsJSON,
} from './AggregatorRemoveJobParams';
export { AggregatorRound } from './AggregatorRound';
export { AggregatorRemoveJobParams } from './AggregatorRemoveJobParams';
export type {
AggregatorRoundFields,
AggregatorRoundJSON,
} from './AggregatorRound';
export { AggregatorSaveResultParams } from './AggregatorSaveResultParams';
export { AggregatorRound } from './AggregatorRound';
export type {
AggregatorSaveResultParamsFields,
AggregatorSaveResultParamsJSON,
} from './AggregatorSaveResultParams';
export { AggregatorSaveResultParamsV2 } from './AggregatorSaveResultParamsV2';
export { AggregatorSaveResultParams } from './AggregatorSaveResultParams';
export type {
AggregatorSaveResultParamsV2Fields,
AggregatorSaveResultParamsV2JSON,
} from './AggregatorSaveResultParamsV2';
export { AggregatorSetAuthorityParams } from './AggregatorSetAuthorityParams';
export { AggregatorSaveResultParamsV2 } from './AggregatorSaveResultParamsV2';
export type {
AggregatorSetAuthorityParamsFields,
AggregatorSetAuthorityParamsJSON,
} from './AggregatorSetAuthorityParams';
export { AggregatorSetBatchSizeParams } from './AggregatorSetBatchSizeParams';
export { AggregatorSetAuthorityParams } from './AggregatorSetAuthorityParams';
export type {
AggregatorSetBatchSizeParamsFields,
AggregatorSetBatchSizeParamsJSON,
} from './AggregatorSetBatchSizeParams';
export { AggregatorSetConfigParams } from './AggregatorSetConfigParams';
export { AggregatorSetBatchSizeParams } from './AggregatorSetBatchSizeParams';
export type {
AggregatorSetConfigParamsFields,
AggregatorSetConfigParamsJSON,
} from './AggregatorSetConfigParams';
export { AggregatorSetForceReportPeriodParams } from './AggregatorSetForceReportPeriodParams';
export { AggregatorSetConfigParams } from './AggregatorSetConfigParams';
export type {
AggregatorSetForceReportPeriodParamsFields,
AggregatorSetForceReportPeriodParamsJSON,
} from './AggregatorSetForceReportPeriodParams';
export { AggregatorSetHistoryBufferParams } from './AggregatorSetHistoryBufferParams';
export { AggregatorSetForceReportPeriodParams } from './AggregatorSetForceReportPeriodParams';
export type {
AggregatorSetHistoryBufferParamsFields,
AggregatorSetHistoryBufferParamsJSON,
} from './AggregatorSetHistoryBufferParams';
export { AggregatorSetMinJobsParams } from './AggregatorSetMinJobsParams';
export { AggregatorSetHistoryBufferParams } from './AggregatorSetHistoryBufferParams';
export type {
AggregatorSetMinJobsParamsFields,
AggregatorSetMinJobsParamsJSON,
} from './AggregatorSetMinJobsParams';
export { AggregatorSetMinOraclesParams } from './AggregatorSetMinOraclesParams';
export { AggregatorSetMinJobsParams } from './AggregatorSetMinJobsParams';
export type {
AggregatorSetMinOraclesParamsFields,
AggregatorSetMinOraclesParamsJSON,
} from './AggregatorSetMinOraclesParams';
export { AggregatorSetQueueParams } from './AggregatorSetQueueParams';
export { AggregatorSetMinOraclesParams } from './AggregatorSetMinOraclesParams';
export type {
AggregatorSetQueueParamsFields,
AggregatorSetQueueParamsJSON,
} from './AggregatorSetQueueParams';
export { AggregatorSetResolutionModeParams } from './AggregatorSetResolutionModeParams';
export { AggregatorSetQueueParams } from './AggregatorSetQueueParams';
export type {
AggregatorSetResolutionModeParamsFields,
AggregatorSetResolutionModeParamsJSON,
} from './AggregatorSetResolutionModeParams';
export { AggregatorSetUpdateIntervalParams } from './AggregatorSetUpdateIntervalParams';
export { AggregatorSetResolutionModeParams } from './AggregatorSetResolutionModeParams';
export type {
AggregatorSetUpdateIntervalParamsFields,
AggregatorSetUpdateIntervalParamsJSON,
} from './AggregatorSetUpdateIntervalParams';
export { AggregatorSetVarianceThresholdParams } from './AggregatorSetVarianceThresholdParams';
export { AggregatorSetUpdateIntervalParams } from './AggregatorSetUpdateIntervalParams';
export type {
AggregatorSetVarianceThresholdParamsFields,
AggregatorSetVarianceThresholdParamsJSON,
} from './AggregatorSetVarianceThresholdParams';
export { BorshDecimal } from './BorshDecimal';
export { AggregatorSetVarianceThresholdParams } from './AggregatorSetVarianceThresholdParams';
export type {
AggregatorTeeSaveResultParamsFields,
AggregatorTeeSaveResultParamsJSON,
} from './AggregatorTeeSaveResultParams';
export { AggregatorTeeSaveResultParams } from './AggregatorTeeSaveResultParams';
export type { BorshDecimalFields, BorshDecimalJSON } from './BorshDecimal';
export { BufferRelayerInitParams } from './BufferRelayerInitParams';
export { BorshDecimal } from './BorshDecimal';
export type {
BufferRelayerInitParamsFields,
BufferRelayerInitParamsJSON,
} from './BufferRelayerInitParams';
export { BufferRelayerOpenRoundParams } from './BufferRelayerOpenRoundParams';
export { BufferRelayerInitParams } from './BufferRelayerInitParams';
export type {
BufferRelayerOpenRoundParamsFields,
BufferRelayerOpenRoundParamsJSON,
} from './BufferRelayerOpenRoundParams';
export { BufferRelayerRound } from './BufferRelayerRound';
export { BufferRelayerOpenRoundParams } from './BufferRelayerOpenRoundParams';
export type {
BufferRelayerRoundFields,
BufferRelayerRoundJSON,
} from './BufferRelayerRound';
export { BufferRelayerSaveResultParams } from './BufferRelayerSaveResultParams';
export { BufferRelayerRound } from './BufferRelayerRound';
export type {
BufferRelayerSaveResultParamsFields,
BufferRelayerSaveResultParamsJSON,
} from './BufferRelayerSaveResultParams';
export { Callback } from './Callback';
export { BufferRelayerSaveResultParams } from './BufferRelayerSaveResultParams';
export type { CallbackFields, CallbackJSON } from './Callback';
export { CallbackZC } from './CallbackZC';
export { Callback } from './Callback';
export type { CallbackZCFields, CallbackZCJSON } from './CallbackZC';
export { CompletedPointZC } from './CompletedPointZC';
export { CallbackZC } from './CallbackZC';
export type {
CompletedPointZCFields,
CompletedPointZCJSON,
} from './CompletedPointZC';
export { CrankInitParams } from './CrankInitParams';
export { CompletedPointZC } from './CompletedPointZC';
export type {
CrankInitParamsFields,
CrankInitParamsJSON,
} from './CrankInitParams';
export { CrankPopParams } from './CrankPopParams';
export { CrankInitParams } from './CrankInitParams';
export type {
CrankPopParamsFields,
CrankPopParamsJSON,
} from './CrankPopParams';
export { CrankPopParamsV2 } from './CrankPopParamsV2';
export { CrankPopParams } from './CrankPopParams';
export type {
CrankPopParamsV2Fields,
CrankPopParamsV2JSON,
} from './CrankPopParamsV2';
export { CrankPushParams } from './CrankPushParams';
export { CrankPopParamsV2 } from './CrankPopParamsV2';
export type {
CrankPushParamsFields,
CrankPushParamsJSON,
} from './CrankPushParams';
export { CrankRow } from './CrankRow';
export { CrankPushParams } from './CrankPushParams';
export type { CrankRowFields, CrankRowJSON } from './CrankRow';
export { EcvrfIntermediate } from './EcvrfIntermediate';
export { CrankRow } from './CrankRow';
export type {
EcvrfIntermediateFields,
EcvrfIntermediateJSON,
} from './EcvrfIntermediate';
export { EcvrfProofZC } from './EcvrfProofZC';
export { EcvrfIntermediate } from './EcvrfIntermediate';
export type { EcvrfProofZCFields, EcvrfProofZCJSON } from './EcvrfProofZC';
export { EdwardsPointZC } from './EdwardsPointZC';
export { EcvrfProofZC } from './EcvrfProofZC';
export type {
EdwardsPointZCFields,
EdwardsPointZCJSON,
} from './EdwardsPointZC';
export { FieldElementZC } from './FieldElementZC';
export { EdwardsPointZC } from './EdwardsPointZC';
export type {
FieldElementZCFields,
FieldElementZCJSON,
} from './FieldElementZC';
export { Hash } from './Hash';
export { FieldElementZC } from './FieldElementZC';
export type { HashFields, HashJSON } from './Hash';
export { JobInitParams } from './JobInitParams';
export { Hash } from './Hash';
export type { JobInitParamsFields, JobInitParamsJSON } from './JobInitParams';
export { JobSetDataParams } from './JobSetDataParams';
export { JobInitParams } from './JobInitParams';
export type {
JobSetDataParamsFields,
JobSetDataParamsJSON,
} from './JobSetDataParams';
export { LeaseExtendParams } from './LeaseExtendParams';
export { JobSetDataParams } from './JobSetDataParams';
export type {
LeaseExtendParamsFields,
LeaseExtendParamsJSON,
} from './LeaseExtendParams';
export { LeaseInitParams } from './LeaseInitParams';
export { LeaseExtendParams } from './LeaseExtendParams';
export type {
LeaseInitParamsFields,
LeaseInitParamsJSON,
} from './LeaseInitParams';
export { LeaseSetAuthorityParams } from './LeaseSetAuthorityParams';
export { LeaseInitParams } from './LeaseInitParams';
export type {
LeaseSetAuthorityParamsFields,
LeaseSetAuthorityParamsJSON,
} from './LeaseSetAuthorityParams';
export { LeaseWithdrawParams } from './LeaseWithdrawParams';
export { LeaseSetAuthorityParams } from './LeaseSetAuthorityParams';
export type {
LeaseWithdrawParamsFields,
LeaseWithdrawParamsJSON,
} from './LeaseWithdrawParams';
export { OracleHeartbeatParams } from './OracleHeartbeatParams';
export { LeaseWithdrawParams } from './LeaseWithdrawParams';
export type {
OracleHeartbeatParamsFields,
OracleHeartbeatParamsJSON,
} from './OracleHeartbeatParams';
export { OracleInitParams } from './OracleInitParams';
export { OracleHeartbeatParams } from './OracleHeartbeatParams';
export type {
OracleInitParamsFields,
OracleInitParamsJSON,
} from './OracleInitParams';
export { OracleMetrics } from './OracleMetrics';
export { OracleInitParams } from './OracleInitParams';
export type { OracleMetricsFields, OracleMetricsJSON } from './OracleMetrics';
export { OracleQueueInitParams } from './OracleQueueInitParams';
export { OracleMetrics } from './OracleMetrics';
export type {
OracleQueueInitParamsFields,
OracleQueueInitParamsJSON,
} from './OracleQueueInitParams';
export { OracleQueueSetConfigParams } from './OracleQueueSetConfigParams';
export { OracleQueueInitParams } from './OracleQueueInitParams';
export type {
OracleQueueSetConfigParamsFields,
OracleQueueSetConfigParamsJSON,
} from './OracleQueueSetConfigParams';
export { OracleQueueSetRewardsParams } from './OracleQueueSetRewardsParams';
export { OracleQueueSetConfigParams } from './OracleQueueSetConfigParams';
export type {
OracleQueueSetRewardsParamsFields,
OracleQueueSetRewardsParamsJSON,
} from './OracleQueueSetRewardsParams';
export { OracleWithdrawParams } from './OracleWithdrawParams';
export { OracleQueueSetRewardsParams } from './OracleQueueSetRewardsParams';
export type {
OracleTeeHeartbeatParamsFields,
OracleTeeHeartbeatParamsJSON,
} from './OracleTeeHeartbeatParams';
export { OracleTeeHeartbeatParams } from './OracleTeeHeartbeatParams';
export type {
OracleWithdrawParamsFields,
OracleWithdrawParamsJSON,
} from './OracleWithdrawParams';
export { PermissionInitParams } from './PermissionInitParams';
export { OracleWithdrawParams } from './OracleWithdrawParams';
export type {
PermissionInitParamsFields,
PermissionInitParamsJSON,
} from './PermissionInitParams';
export { PermissionSetParams } from './PermissionSetParams';
export { PermissionInitParams } from './PermissionInitParams';
export type {
PermissionSetParamsFields,
PermissionSetParamsJSON,
} from './PermissionSetParams';
export { ProgramConfigParams } from './ProgramConfigParams';
export { PermissionSetParams } from './PermissionSetParams';
export type {
ProgramConfigParamsFields,
ProgramConfigParamsJSON,
} from './ProgramConfigParams';
export { ProgramInitParams } from './ProgramInitParams';
export { ProgramConfigParams } from './ProgramConfigParams';
export type {
ProgramInitParamsFields,
ProgramInitParamsJSON,
} from './ProgramInitParams';
export { ProjectivePointZC } from './ProjectivePointZC';
export { ProgramInitParams } from './ProgramInitParams';
export type {
ProjectivePointZCFields,
ProjectivePointZCJSON,
} from './ProjectivePointZC';
export { Scalar } from './Scalar';
export { ProjectivePointZC } from './ProjectivePointZC';
export type { ScalarFields, ScalarJSON } from './Scalar';
export { SetBumpsParams } from './SetBumpsParams';
export { Scalar } from './Scalar';
export type {
SetBumpsParamsFields,
SetBumpsParamsJSON,
} from './SetBumpsParams';
export { SlidingWindowElement } from './SlidingWindowElement';
export { SetBumpsParams } from './SetBumpsParams';
export type {
SlidingWindowElementFields,
SlidingWindowElementJSON,
} from './SlidingWindowElement';
export { SwitchboardDecimal } from './SwitchboardDecimal';
export { SlidingWindowElement } from './SlidingWindowElement';
export type {
SwitchboardDecimalFields,
SwitchboardDecimalJSON,
} from './SwitchboardDecimal';
export {
PermitNone,
PermitOracleHeartbeat,
PermitOracleQueueUsage,
PermitVrfRequests,
} from './SwitchboardPermission';
export { VaultTransferParams } from './VaultTransferParams';
export { SwitchboardDecimal } from './SwitchboardDecimal';
export type {
VaultTransferParamsFields,
VaultTransferParamsJSON,
} from './VaultTransferParams';
export { VrfBuilder } from './VrfBuilder';
export { VaultTransferParams } from './VaultTransferParams';
export type { VrfBuilderFields, VrfBuilderJSON } from './VrfBuilder';
export { VrfCloseParams } from './VrfCloseParams';
export { VrfBuilder } from './VrfBuilder';
export type {
VrfCloseParamsFields,
VrfCloseParamsJSON,
} from './VrfCloseParams';
export { VrfInitParams } from './VrfInitParams';
export { VrfCloseParams } from './VrfCloseParams';
export type { VrfInitParamsFields, VrfInitParamsJSON } from './VrfInitParams';
export { VrfLiteCloseParams } from './VrfLiteCloseParams';
export { VrfInitParams } from './VrfInitParams';
export type {
VrfLiteCloseParamsFields,
VrfLiteCloseParamsJSON,
} from './VrfLiteCloseParams';
export { VrfLiteInitParams } from './VrfLiteInitParams';
export { VrfLiteCloseParams } from './VrfLiteCloseParams';
export type {
VrfLiteInitParamsFields,
VrfLiteInitParamsJSON,
} from './VrfLiteInitParams';
export { VrfLiteProveAndVerifyParams } from './VrfLiteProveAndVerifyParams';
export { VrfLiteInitParams } from './VrfLiteInitParams';
export type {
VrfLiteProveAndVerifyParamsFields,
VrfLiteProveAndVerifyParamsJSON,
} from './VrfLiteProveAndVerifyParams';
export { VrfLiteRequestRandomnessParams } from './VrfLiteRequestRandomnessParams';
export { VrfLiteProveAndVerifyParams } from './VrfLiteProveAndVerifyParams';
export type {
VrfLiteRequestRandomnessParamsFields,
VrfLiteRequestRandomnessParamsJSON,
} from './VrfLiteRequestRandomnessParams';
export { VrfPoolAddParams } from './VrfPoolAddParams';
export { VrfLiteRequestRandomnessParams } from './VrfLiteRequestRandomnessParams';
export type {
VrfPoolAddParamsFields,
VrfPoolAddParamsJSON,
} from './VrfPoolAddParams';
export { VrfPoolInitParams } from './VrfPoolInitParams';
export { VrfPoolAddParams } from './VrfPoolAddParams';
export type {
VrfPoolInitParamsFields,
VrfPoolInitParamsJSON,
} from './VrfPoolInitParams';
export { VrfPoolRemoveParams } from './VrfPoolRemoveParams';
export { VrfPoolInitParams } from './VrfPoolInitParams';
export type {
VrfPoolRemoveParamsFields,
VrfPoolRemoveParamsJSON,
} from './VrfPoolRemoveParams';
export { VrfPoolRequestParams } from './VrfPoolRequestParams';
export { VrfPoolRemoveParams } from './VrfPoolRemoveParams';
export type {
VrfPoolRequestParamsFields,
VrfPoolRequestParamsJSON,
} from './VrfPoolRequestParams';
export { VrfPoolRow } from './VrfPoolRow';
export { VrfPoolRequestParams } from './VrfPoolRequestParams';
export type { VrfPoolRowFields, VrfPoolRowJSON } from './VrfPoolRow';
export { VrfProveAndVerifyParams } from './VrfProveAndVerifyParams';
export { VrfPoolRow } from './VrfPoolRow';
export type {
VrfProveAndVerifyParamsFields,
VrfProveAndVerifyParamsJSON,
} from './VrfProveAndVerifyParams';
export { VrfProveParams } from './VrfProveParams';
export { VrfProveAndVerifyParams } from './VrfProveAndVerifyParams';
export type {
VrfProveParamsFields,
VrfProveParamsJSON,
} from './VrfProveParams';
export { VrfRequestRandomnessParams } from './VrfRequestRandomnessParams';
export { VrfProveParams } from './VrfProveParams';
export type {
VrfRequestRandomnessParamsFields,
VrfRequestRandomnessParamsJSON,
} from './VrfRequestRandomnessParams';
export { VrfRound } from './VrfRound';
export { VrfRequestRandomnessParams } from './VrfRequestRandomnessParams';
export type { VrfRoundFields, VrfRoundJSON } from './VrfRound';
export { VrfSetCallbackParams } from './VrfSetCallbackParams';
export { VrfRound } from './VrfRound';
export type {
VrfSetCallbackParamsFields,
VrfSetCallbackParamsJSON,
} from './VrfSetCallbackParams';
export { Lanes };
export { Shuffle };
export { Error };
export { AggregatorResolutionMode };
export { SwitchboardPermission };
export { OracleResponseType };
export { VrfStatus };
export { VrfSetCallbackParams } from './VrfSetCallbackParams';
/**
* The `Lanes` enum represents a subset of the lanes `A,B,C,D` of a
* `FieldElement2625x4`.
*
* It's used to specify blend operations without
* having to know details about the data layout of the
* `FieldElement2625x4`.
*/
export type LanesKind = Lanes.C | Lanes.D | Lanes.AB | Lanes.AC | Lanes.AD;
export type LanesJSON =
| Lanes.CJSON
| Lanes.DJSON
| Lanes.ABJSON
| Lanes.ACJSON
| Lanes.ADJSON;
export { Shuffle };
/**
* The `Shuffle` enum represents a shuffle of a `FieldElement2625x4`.
@ -429,6 +413,26 @@ export type ShuffleJSON =
| Shuffle.BACDJSON
| Shuffle.ABDCJSON;
export { Lanes };
/**
* The `Lanes` enum represents a subset of the lanes `A,B,C,D` of a
* `FieldElement2625x4`.
*
* It's used to specify blend operations without
* having to know details about the data layout of the
* `FieldElement2625x4`.
*/
export type LanesKind = Lanes.C | Lanes.D | Lanes.AB | Lanes.AC | Lanes.AD;
export type LanesJSON =
| Lanes.CJSON
| Lanes.DJSON
| Lanes.ABJSON
| Lanes.ACJSON
| Lanes.ADJSON;
export { Error };
export type ErrorKind =
| Error.InvalidPublicKey
| Error.SerializationError
@ -440,6 +444,21 @@ export type ErrorJSON =
| Error.DeserializationErrorJSON
| Error.InvalidDataErrorJSON;
export { VerificationStatus };
export type VerificationStatusKind =
| VerificationStatus.VerificationPending
| VerificationStatus.VerificationFailure
| VerificationStatus.VerificationSuccess
| VerificationStatus.VerificationOverride;
export type VerificationStatusJSON =
| VerificationStatus.VerificationPendingJSON
| VerificationStatus.VerificationFailureJSON
| VerificationStatus.VerificationSuccessJSON
| VerificationStatus.VerificationOverrideJSON;
export { AggregatorResolutionMode };
export type AggregatorResolutionModeKind =
| AggregatorResolutionMode.ModeRoundResolution
| AggregatorResolutionMode.ModeSlidingResolution;
@ -447,6 +466,8 @@ export type AggregatorResolutionModeJSON =
| AggregatorResolutionMode.ModeRoundResolutionJSON
| AggregatorResolutionMode.ModeSlidingResolutionJSON;
export { SwitchboardPermission };
export type SwitchboardPermissionKind =
| SwitchboardPermission.PermitNone
| SwitchboardPermission.PermitOracleHeartbeat
@ -458,6 +479,8 @@ export type SwitchboardPermissionJSON =
| SwitchboardPermission.PermitOracleQueueUsageJSON
| SwitchboardPermission.PermitVrfRequestsJSON;
export { OracleResponseType };
export type OracleResponseTypeKind =
| OracleResponseType.TypeSuccess
| OracleResponseType.TypeError
@ -469,6 +492,8 @@ export type OracleResponseTypeJSON =
| OracleResponseType.TypeDisagreementJSON
| OracleResponseType.TypeNoResponseJSON;
export { VrfStatus };
export type VrfStatusKind =
| VrfStatus.StatusNone
| VrfStatus.StatusRequesting

File diff suppressed because it is too large Load Diff

View File

@ -445,6 +445,109 @@
}
]
},
{
"name": "aggregatorTeeSaveResult",
"accounts": [
{
"name": "aggregator",
"isMut": true,
"isSigner": false
},
{
"name": "oracle",
"isMut": true,
"isSigner": false
},
{
"name": "oracleAuthority",
"isMut": false,
"isSigner": true
},
{
"name": "oracleQueue",
"isMut": false,
"isSigner": false
},
{
"name": "queueAuthority",
"isMut": false,
"isSigner": false
},
{
"name": "feedPermission",
"isMut": true,
"isSigner": false
},
{
"name": "oraclePermission",
"isMut": false,
"isSigner": false
},
{
"name": "lease",
"isMut": true,
"isSigner": false
},
{
"name": "escrow",
"isMut": true,
"isSigner": false
},
{
"name": "tokenProgram",
"isMut": false,
"isSigner": false
},
{
"name": "programState",
"isMut": false,
"isSigner": false
},
{
"name": "historyBuffer",
"isMut": true,
"isSigner": false
},
{
"name": "mint",
"isMut": false,
"isSigner": false
},
{
"name": "slider",
"isMut": true,
"isSigner": false
},
{
"name": "quote",
"isMut": false,
"isSigner": false
},
{
"name": "rewardWallet",
"isMut": true,
"isSigner": false
},
{
"name": "payer",
"isMut": true,
"isSigner": true
},
{
"name": "systemProgram",
"isMut": false,
"isSigner": false
}
],
"args": [
{
"name": "params",
"type": {
"defined": "AggregatorTeeSaveResultParams"
}
}
]
},
{
"name": "aggregatorSetAuthority",
"accounts": [
@ -1307,6 +1410,64 @@
}
]
},
{
"name": "oracleTeeHeartbeat",
"accounts": [
{
"name": "oracle",
"isMut": true,
"isSigner": false
},
{
"name": "oracleAuthority",
"isMut": false,
"isSigner": true
},
{
"name": "tokenAccount",
"isMut": false,
"isSigner": false
},
{
"name": "gcOracle",
"isMut": true,
"isSigner": false
},
{
"name": "oracleQueue",
"isMut": true,
"isSigner": false
},
{
"name": "permission",
"isMut": false,
"isSigner": false
},
{
"name": "dataBuffer",
"isMut": true,
"isSigner": false
},
{
"name": "quote",
"isMut": false,
"isSigner": false
},
{
"name": "programState",
"isMut": false,
"isSigner": false
}
],
"args": [
{
"name": "params",
"type": {
"defined": "OracleTeeHeartbeatParams"
}
}
]
},
{
"name": "oracleInit",
"accounts": [
@ -2390,6 +2551,97 @@
}
],
"accounts": [
{
"name": "QuoteAccountData",
"type": {
"kind": "struct",
"fields": [
{
"name": "delegatedSecuredSigner",
"type": "publicKey"
},
{
"name": "bump",
"type": "u8"
},
{
"name": "quoteRegistry",
"docs": [
"TODO: Add description"
],
"type": {
"array": [
"u8",
32
]
}
},
{
"name": "registryKey",
"docs": [
"Key to lookup the buffer data on IPFS or an alternative decentralized storage solution."
],
"type": {
"array": [
"u8",
64
]
}
},
{
"name": "attestationQueue",
"docs": [
"Queue used for attestation to verify a MRENCLAVE measurement."
],
"type": "publicKey"
},
{
"name": "mrEnclave",
"docs": [
"The quotes MRENCLAVE measurement dictating the contents of the secure enclave."
],
"type": {
"array": [
"u8",
32
]
}
},
{
"name": "verificationStatus",
"type": "u8"
},
{
"name": "verificationTimestamp",
"type": "i64"
},
{
"name": "validUntil",
"type": "i64"
},
{
"name": "isOnQueue",
"type": "bool"
},
{
"name": "lastHeartbeat",
"docs": [
"The last time the quote heartbeated."
],
"type": "i64"
},
{
"name": "ebuf",
"type": {
"array": [
"u8",
1024
]
}
}
]
}
},
{
"name": "SbState",
"type": {
@ -2430,6 +2682,23 @@
],
"type": "u8"
},
{
"name": "mrEnclaves",
"docs": [
"Permitted enclave measurements"
],
"type": {
"array": [
{
"array": [
"u8",
32
]
},
6
]
}
},
{
"name": "ebuf",
"docs": [
@ -2438,7 +2707,7 @@
"type": {
"array": [
"u8",
991
799
]
}
}
@ -3119,6 +3388,10 @@
],
"type": "bool"
},
{
"name": "enableTeeOnly",
"type": "bool"
},
{
"name": "ebuf",
"docs": [
@ -3127,7 +3400,7 @@
"type": {
"array": [
"u8",
968
967
]
}
},
@ -4292,6 +4565,57 @@
]
}
},
{
"name": "AggregatorTeeSaveResultParams",
"type": {
"kind": "struct",
"fields": [
{
"name": "value",
"type": {
"defined": "BorshDecimal"
}
},
{
"name": "jobsChecksum",
"type": {
"array": [
"u8",
32
]
}
},
{
"name": "minResponse",
"type": {
"defined": "BorshDecimal"
}
},
{
"name": "maxResponse",
"type": {
"defined": "BorshDecimal"
}
},
{
"name": "feedPermissionBump",
"type": "u8"
},
{
"name": "oraclePermissionBump",
"type": "u8"
},
{
"name": "leaseBump",
"type": "u8"
},
{
"name": "stateBump",
"type": "u8"
}
]
}
},
{
"name": "BufferRelayerInitParams",
"type": {
@ -4712,6 +5036,10 @@
{
"name": "enableBufferRelayers",
"type": "bool"
},
{
"name": "enableTeeOnly",
"type": "bool"
}
]
}
@ -4804,6 +5132,12 @@
"type": {
"option": "u64"
}
},
{
"name": "enableTeeOnly",
"type": {
"option": "bool"
}
}
]
}
@ -4820,6 +5154,18 @@
]
}
},
{
"name": "OracleTeeHeartbeatParams",
"type": {
"kind": "struct",
"fields": [
{
"name": "permissionBump",
"type": "u8"
}
]
}
},
{
"name": "OracleWithdrawParams",
"type": {
@ -4881,6 +5227,28 @@
{
"name": "daoMint",
"type": "publicKey"
},
{
"name": "addEnclaves",
"type": {
"vec": {
"array": [
"u8",
32
]
}
}
},
{
"name": "rmEnclaves",
"type": {
"vec": {
"array": [
"u8",
32
]
}
}
}
]
}
@ -6396,6 +6764,26 @@
]
}
},
{
"name": "VerificationStatus",
"type": {
"kind": "enum",
"variants": [
{
"name": "VerificationPending"
},
{
"name": "VerificationFailure"
},
{
"name": "VerificationSuccess"
},
{
"name": "VerificationOverride"
}
]
}
},
{
"name": "AggregatorResolutionMode",
"type": {
@ -6671,6 +7059,38 @@
}
]
},
{
"name": "AggregatorTeeSaveResultEvent",
"fields": [
{
"name": "feedPubkey",
"type": "publicKey",
"index": false
},
{
"name": "value",
"type": {
"defined": "BorshDecimal"
},
"index": false
},
{
"name": "slot",
"type": "u64",
"index": false
},
{
"name": "timestamp",
"type": "i64",
"index": false
},
{
"name": "oraclePubkey",
"type": "publicKey",
"index": false
}
]
},
{
"name": "AggregatorValueUpdateEvent",
"fields": [
@ -7224,6 +7644,16 @@
"index": false
}
]
},
{
"name": "QuoteVerifyRequestEvent",
"fields": [
{
"name": "quotePubkey",
"type": "publicKey",
"index": false
}
]
}
],
"errors": [
@ -7726,6 +8156,21 @@
"code": 6099,
"name": "InsufficientTokenBalance",
"msg": "Escrow has insufficient funds to perform this action."
},
{
"code": 6100,
"name": "InvalidQuoteError",
"msg": "Invalid SAS quote account"
},
{
"code": 6101,
"name": "InvalidHistoryAccountError",
"msg": ""
},
{
"code": 6102,
"name": "GenericError",
"msg": ""
}
]
}

View File

@ -0,0 +1,8 @@
.anchor
.DS_Store
target
**/*.rs.bk
node_modules
test-ledger
client/

View File

@ -0,0 +1,38 @@
[workspace]
members = ["."]
[provider]
# cluster = "devnet"
cluster = "localnet"
wallet = "~/.config/solana/id.json"
[programs.localnet]
anchor_vrf_lite_parser = "5Hhm5xKDiThfidbpqjJpKmMJEcKmjj5tEUNFpi2DzSvb"
[programs.devnet]
anchor_vrf_lite_parser = "5Hhm5xKDiThfidbpqjJpKmMJEcKmjj5tEUNFpi2DzSvb"
[registry]
url = "https://anchor.projectserum.com"
[scripts]
test = "yarn run ts-mocha -p ./tsconfig.json -t 60000 ./tests/*.test.ts --exit"
"test:devnet" = "USE_SWITCHBOARD_DEVNET_QUEUE=true yarn run ts-mocha -p ./tsconfig.json -t 60000 ./tests/*.test.ts --exit"
[test.validator]
url = "https://api.devnet.solana.com"
[test]
startup_wait = 15000
[[test.validator.clone]] # sbv2 devnet programID
address = "SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f"
[[test.validator.clone]] # sbv2 devnet IDL
address = "Fi8vncGpNKbq62gPo56G4toCehWNy77GgqGkTaAF5Lkk"
[[test.validator.clone]] # sbv2 devnet SbState
address = "CyZuD7RPDcrqCGbNvLCyqk6Py9cEZTKmNKujfPi3ynDd"
[[test.validator.clone]] # sbv2 devnet tokenVault
address = "7hkp1xfPBcD2t1vZMoWWQPzipHVcXeLAAaiGXdPSfDie"

View File

@ -0,0 +1,24 @@
[package]
name = "anchor-vrf-lite-parser"
version = "0.1.0"
description = "Created with Anchor"
edition = "2021"
[lib]
crate-type = ["cdylib", "lib"]
name = "anchor_vrf_lite_parser"
[features]
default = []
no-entrypoint = []
no-idl = []
no-log-ix-name = []
cpi = ["no-entrypoint"]
[dependencies]
switchboard-v2 = { path = "../../rust/switchboard-v2" }
# switchboard-v2 = { version = "^0.1.23" }
anchor-lang = "^0.27.0"
anchor-spl = "^0.27.0"
solana-program = "~1.14.0"
bytemuck = "1.7.2"

View File

@ -0,0 +1,38 @@
<div align="center">
![Switchboard Logo](https://github.com/switchboard-xyz/sbv2-core/raw/main/website/static/img/icons/switchboard/avatar.png)
# anchor-vrf-parser
> An example program written in Anchor demonstrating how to deserialize and read
> a Switchboard VRF account on Solana.
[![Anchor Test Status](https://github.com/switchboard-xyz/sbv2-solana/actions/workflows/anchor-test.yml/badge.svg)](https://github.com/switchboard-xyz/sbv2-solana/actions/workflows/anchor-test.yml)
</div>
<!-- install -->
<!-- installstop -->
## Usage
Build the example program
```bash
anchor build
```
Get your program ID and update `Anchor.toml` and `src/lib.rs` with your pubkey
```bash
export ANCHOR_VRF_PARSER_PUBKEY=$(solana-keygen pubkey target/deploy/anchor_vrf_parser-keypair.json)
sed -i '' s/4wTeTACfwiXqqvy44bNBB3V2rFjmSTXVoEr4ZAYamJEN/"$ANCHOR_VRF_PARSER_PUBKEY"/g Anchor.toml
sed -i '' s/4wTeTACfwiXqqvy44bNBB3V2rFjmSTXVoEr4ZAYamJEN/"$ANCHOR_VRF_PARSER_PUBKEY"/g src/lib.rs
```
Then run Anchor test
```bash
anchor test
```

View File

@ -0,0 +1,2 @@
[target.bpfel-unknown-unknown.dependencies.std]
features = []

View File

@ -0,0 +1,46 @@
{
"name": "anchor-vrf-lite-parser",
"version": "1.0.0",
"private": true,
"repository": {
"type": "git",
"url": "https://github.com/switchboard-xyz/sbv2-solana",
"directory": "programs/anchor-vrf-lite-parser"
},
"scripts": {
"lint": "eslint --ext .js,.json,.ts 'src/**' --fix",
"build": "node ../build.js anchor-vrf-parser 5Hhm5xKDiThfidbpqjJpKmMJEcKmjj5tEUNFpi2DzSvb",
"test": "npm run localnet && npm run network:create && npm run network:start & sleep 60 && anchor test --skip-local-validator",
"test:dev": "npm run localnet && npm run network:create && npm run network:start:dev & sleep 15 && anchor test --skip-local-validator"
},
"dependencies": {
"@coral-xyz/anchor": "^0.27.0",
"@coral-xyz/borsh": "^0.27.0",
"@project-serum/borsh": "^0.2.5",
"@solana/spl-token": "^0.3.6",
"@solana/web3.js": "^1.73.3",
"@switchboard-xyz/common": "^2.2.0",
"@switchboard-xyz/oracle": "^2.1.13",
"@switchboard-xyz/solana.js": "workspace:*",
"chalk": "^4.1.2",
"dotenv": "^16.0.1",
"yargs": "^17.5.1"
},
"devDependencies": {
"@types/chai": "^4.3.0",
"@types/mocha": "^9.0.0",
"@types/node": "^17.0.45",
"@typescript-eslint/eslint-plugin": "^5.44.0",
"@typescript-eslint/parser": "^5.44.0",
"chai": "^4.3.6",
"eslint": "^8.28.0",
"mocha": "^9.0.3",
"npm-run-all": "^4.1.5",
"prettier": "^2.4.1",
"prettier-plugin-organize-imports": "^2.3.4",
"shx": "^0.3.4",
"ts-mocha": "^9.0.2",
"ts-node": "^10.9.1",
"typescript": "^4.9.3"
}
}

View File

@ -0,0 +1,143 @@
use crate::*;
use anchor_lang::prelude::*;
use anchor_lang::solana_program::clock;
use anchor_spl::token::Token;
pub use switchboard_v2::{VrfLiteAccountData, VrfLiteClose, VrfCloseParams, PERMISSION_SEED};
#[derive(Accounts)]
#[instruction(params: CloseStateParams)]
pub struct CloseState<'info> {
#[account(
mut,
close = sol_dest,
seeds = [
STATE_SEED,
vrf.key().as_ref(),
authority.key().as_ref(),
],
bump = state.load()?.bump,
has_one = vrf
)]
pub state: AccountLoader<'info, VrfClient>,
/// CHECK:
#[account(signer)]
pub authority: AccountInfo<'info>,
/// CHECK:
#[account(mut, signer)]
pub payer: AccountInfo<'info>,
#[account(mut)]
pub vrf: AccountLoader<'info, VrfLiteAccountData>,
#[account(
mut,
constraint = escrow.mint == escrow_dest.mint && escrow.owner == program_state.key()
)]
pub escrow: Account<'info, TokenAccount>,
/// SWITCHBOARD ACCOUNTS
#[account(
mut,
seeds = [
PERMISSION_SEED,
queue_authority.key().as_ref(),
oracle_queue.key().as_ref(),
vrf.key().as_ref()
],
bump = state.load()?.permission_bump,
seeds::program = switchboard_program.key()
)]
pub permission: AccountLoader<'info, PermissionAccountData>,
#[account(
constraint = oracle_queue.load()?.authority == queue_authority.key()
)]
pub oracle_queue: AccountLoader<'info, OracleQueueAccountData>,
/// CHECK:
pub queue_authority: AccountInfo<'info>,
#[account(
seeds = [STATE_SEED],
bump = state.load()?.switchboard_state_bump,
seeds::program = switchboard_program.key()
)]
pub program_state: AccountLoader<'info, SbState>,
/// CHECK:
pub sol_dest: SystemAccount<'info>,
/// CHECK:
#[account(mut)]
pub escrow_dest: Account<'info, TokenAccount>,
/// CHECK:
#[account(
constraint =
switchboard_program.executable == true
&& *switchboard_program.key == SWITCHBOARD_PROGRAM_ID @ VrfErrorCode::InvalidSwitchboardAccount
)]
pub switchboard_program: AccountInfo<'info>,
/// SYSTEM ACCOUNTS
#[account(address = anchor_spl::token::ID)]
pub token_program: Program<'info, Token>,
}
#[derive(Clone, AnchorSerialize, AnchorDeserialize)]
pub struct CloseStateParams {}
impl CloseState<'_> {
pub fn validate(&self, ctx: &Context<Self>, params: &CloseStateParams) -> Result<()> {
msg!("Validate init");
// TODO: Validate the current user doesnt have an open request
// 1500 slots, 400ms/slot = about 10min
if ctx.accounts.vrf.load()?.request_slot != 0 && ctx.accounts.vrf.load()?.request_slot + 1500 > clock::Clock::get()?.slot {
return Err(error!(VrfErrorCode::VrfCloseNotReady));
}
Ok(())
}
pub fn actuate(ctx: &Context<Self>, params: &CloseStateParams) -> Result<()> {
msg!("Actuate init");
let client_state = ctx.accounts.state.load()?;
let bump = client_state.bump.clone();
let max_result = client_state.max_result;
let permission_bump = client_state.permission_bump.clone();
let switchboard_state_bump = client_state.switchboard_state_bump.clone();
drop(client_state);
// get pda seeds
let vrf_key = ctx.accounts.vrf.key();
let authority_key = ctx.accounts.authority.key.clone();
msg!("bump: {}", bump);
msg!("authority: {}", authority_key);
msg!("vrf: {}", vrf_key);
let state_seeds: &[&[&[u8]]] = &[&[
&STATE_SEED,
vrf_key.as_ref(),
authority_key.as_ref(),
&[bump],
]];
let vrf_close = VrfLiteClose {
authority: ctx.accounts.state.to_account_info(),
vrf_lite: ctx.accounts.vrf.to_account_info(),
permission: ctx.accounts.permission.to_account_info(),
queue: ctx.accounts.oracle_queue.to_account_info(),
queue_authority: ctx.accounts.queue_authority.to_account_info(),
program_state: ctx.accounts.program_state.to_account_info(),
escrow: ctx.accounts.escrow.clone(),
sol_dest: ctx.accounts.sol_dest.to_account_info(),
escrow_dest: ctx.accounts.escrow_dest.clone(),
token_program: ctx.accounts.token_program.to_account_info(),
};
msg!("closing VRF account");
vrf_close.invoke_signed(
ctx.accounts.switchboard_program.to_account_info(),
state_seeds,
)?;
msg!("VRF account closed!");
Ok(())
}
}

View File

@ -0,0 +1,81 @@
use crate::*;
use anchor_lang::prelude::*;
pub use switchboard_v2::VrfLiteAccountData;
#[derive(Accounts)]
#[instruction(params: InitStateParams)]
pub struct InitState<'info> {
#[account(
init,
seeds = [
STATE_SEED,
vrf.key().as_ref(),
authority.key().as_ref(),
],
payer = payer,
space = 8 + std::mem::size_of::<VrfClient>(),
bump,
)]
pub state: AccountLoader<'info, VrfClient>,
/// CHECK:
pub authority: AccountInfo<'info>,
/// CHECK:
#[account(mut, signer)]
/// CHECK:
pub payer: AccountInfo<'info>,
#[account(
constraint =
*vrf.to_account_info().owner == SWITCHBOARD_PROGRAM_ID @ VrfErrorCode::InvalidSwitchboardAccount
)]
pub vrf: AccountLoader<'info, VrfLiteAccountData>,
#[account(address = solana_program::system_program::ID)]
pub system_program: Program<'info, System>,
}
#[derive(Clone, AnchorSerialize, AnchorDeserialize)]
pub struct InitStateParams {
pub max_result: u64,
pub permission_bump: u8,
pub switchboard_state_bump: u8,
}
impl InitState<'_> {
pub fn validate(&self, _ctx: &Context<Self>, params: &InitStateParams) -> Result<()> {
msg!("Validate init");
if params.max_result > MAX_RESULT {
return Err(error!(VrfErrorCode::MaxResultExceedsMaximum));
}
Ok(())
}
pub fn actuate(ctx: &Context<Self>, params: &InitStateParams) -> Result<()> {
msg!("Actuate init");
msg!("Checking VRF Account");
let vrf = ctx.accounts.vrf.load()?;
// client state needs to be authority in order to sign request randomness instruction
if vrf.authority != ctx.accounts.state.key() {
return Err(error!(VrfErrorCode::InvalidAuthorityError));
}
drop(vrf);
msg!("Setting VrfClient state");
let mut state = ctx.accounts.state.load_init()?;
*state = VrfClient::default();
state.bump = ctx.bumps.get("state").unwrap().clone();
state.authority = ctx.accounts.authority.key.clone();
state.vrf = ctx.accounts.vrf.key();
state.permission_bump = params.permission_bump;
state.switchboard_state_bump = params.switchboard_state_bump;
msg!("Setting VrfClient max_result");
if params.max_result == 0 {
state.max_result = MAX_RESULT;
} else {
state.max_result = params.max_result;
}
Ok(())
}
}

View File

@ -0,0 +1,11 @@
pub mod init_state;
pub use init_state::*;
pub mod update_result;
pub use update_result::*;
pub mod request_result;
pub use request_result::*;
pub mod close_state;
pub use close_state::*;

View File

@ -0,0 +1,161 @@
use crate::*;
use anchor_lang::prelude::*;
use anchor_lang::solana_program::clock;
use anchor_spl::token::Token;
pub use switchboard_v2::{
OracleQueueAccountData, PermissionAccountData, SbState, VrfLiteAccountData, VrfLiteRequestRandomness,
VrfSetCallback,
};
#[derive(Accounts)]
#[instruction(params: RequestResultParams)] // rpc parameters hint
pub struct RequestResult<'info> {
#[account(
mut,
seeds = [
STATE_SEED,
vrf.key().as_ref(),
authority.key().as_ref(),
],
bump = state.load()?.bump,
has_one = vrf @ VrfErrorCode::InvalidVrfAccount,
has_one = authority @ VrfErrorCode::InvalidAuthorityError
)]
pub state: AccountLoader<'info, VrfClient>,
/// CHECK:
#[account(signer)]
pub authority: AccountInfo<'info>,
// SWITCHBOARD ACCOUNTS
#[account(mut,
has_one = escrow,
constraint =
*vrf.to_account_info().owner == SWITCHBOARD_PROGRAM_ID @ VrfErrorCode::InvalidSwitchboardAccount
)]
pub vrf: AccountLoader<'info, VrfLiteAccountData>,
/// CHECK
#[account(mut,
has_one = data_buffer,
constraint =
oracle_queue.load()?.authority == queue_authority.key()
&& *oracle_queue.to_account_info().owner == SWITCHBOARD_PROGRAM_ID @ VrfErrorCode::InvalidSwitchboardAccount
)]
pub oracle_queue: AccountLoader<'info, OracleQueueAccountData>,
/// CHECK: Will be checked in the CPI instruction
pub queue_authority: UncheckedAccount<'info>,
/// CHECK
#[account(mut,
constraint =
*data_buffer.owner == SWITCHBOARD_PROGRAM_ID @ VrfErrorCode::InvalidSwitchboardAccount
)]
pub data_buffer: AccountInfo<'info>,
/// CHECK
#[account(mut,
constraint =
*permission.to_account_info().owner == SWITCHBOARD_PROGRAM_ID @ VrfErrorCode::InvalidSwitchboardAccount
)]
pub permission: AccountLoader<'info, PermissionAccountData>,
#[account(mut,
constraint =
escrow.owner == program_state.key()
&& escrow.mint == program_state.load()?.token_mint
)]
pub escrow: Account<'info, TokenAccount>,
/// CHECK: Will be checked in the CPI instruction
#[account(mut,
constraint =
*program_state.to_account_info().owner == SWITCHBOARD_PROGRAM_ID @ VrfErrorCode::InvalidSwitchboardAccount
)]
pub program_state: AccountLoader<'info, SbState>,
/// CHECK:
#[account(
constraint =
switchboard_program.executable == true
&& *switchboard_program.key == SWITCHBOARD_PROGRAM_ID @ VrfErrorCode::InvalidSwitchboardAccount
)]
pub switchboard_program: AccountInfo<'info>,
// SYSTEM ACCOUNTS
/// CHECK:
#[account(address = solana_program::sysvar::recent_blockhashes::ID)]
pub recent_blockhashes: AccountInfo<'info>,
#[account(address = anchor_spl::token::ID)]
pub token_program: Program<'info, Token>,
}
#[derive(Clone, AnchorSerialize, AnchorDeserialize)]
pub struct RequestResultParams {
}
impl RequestResult<'_> {
pub fn validate(&self, _ctx: &Context<Self>, _params: &RequestResultParams) -> Result<()> {
Ok(())
}
pub fn actuate(ctx: &Context<Self>, _params: &RequestResultParams) -> Result<()> {
let client_state = ctx.accounts.state.load()?;
let bump = client_state.bump.clone();
let max_result = client_state.max_result;
let permission_bump = client_state.permission_bump.clone();
let switchboard_state_bump = client_state.switchboard_state_bump.clone();
drop(client_state);
// get pda seeds
let vrf_key = ctx.accounts.vrf.key();
let authority_key = ctx.accounts.authority.key.clone();
msg!("bump: {}", bump);
msg!("authority: {}", authority_key);
msg!("vrf: {}", vrf_key);
let state_seeds: &[&[&[u8]]] = &[&[
&STATE_SEED,
vrf_key.as_ref(),
authority_key.as_ref(),
&[bump],
]];
// first set callback
let vrf_set_callback = VrfSetCallback {
authority: ctx.accounts.state.to_account_info(),
vrf: ctx.accounts.vrf.to_account_info(),
};
let callback = UpdateResult::to_callback(
&vrf_set_callback.authority,
&vrf_set_callback.vrf.key(),
&UpdateResultParams {},
)?;
// then request randomness
let vrf_request_randomness = VrfLiteRequestRandomness {
authority: ctx.accounts.state.to_account_info(),
vrf_lite: ctx.accounts.vrf.to_account_info(),
queue: ctx.accounts.oracle_queue.to_account_info(),
queue_authority: ctx.accounts.queue_authority.to_account_info(),
data_buffer: ctx.accounts.data_buffer.to_account_info(),
permission: ctx.accounts.permission.to_account_info(),
escrow: ctx.accounts.escrow.clone(),
recent_blockhashes: ctx.accounts.recent_blockhashes.to_account_info(),
program_state: ctx.accounts.program_state.to_account_info(),
token_program: ctx.accounts.token_program.to_account_info(),
};
msg!("requesting randomness");
vrf_request_randomness.invoke_signed(
ctx.accounts.switchboard_program.to_account_info(),
Some(callback),
state_seeds,
)?;
let mut client_state = ctx.accounts.state.load_mut()?;
client_state.result = 0;
emit!(RequestingRandomness {
vrf_client: ctx.accounts.state.key(),
max_result: max_result,
timestamp: clock::Clock::get().unwrap().unix_timestamp
});
msg!("randomness requested successfully");
Ok(())
}
}

View File

@ -0,0 +1,111 @@
use crate::*;
use anchor_lang::prelude::*;
use anchor_lang::solana_program::clock;
use anchor_lang::{Discriminator};
#[derive(Accounts)]
#[instruction(params: UpdateResultParams)] // rpc parameters hint
pub struct UpdateResult<'info> {
#[account(mut,
has_one = vrf @ VrfErrorCode::InvalidVrfAccount
)]
pub state: AccountLoader<'info, VrfClient>,
#[account(
constraint =
*vrf.to_account_info().owner == SWITCHBOARD_PROGRAM_ID @ VrfErrorCode::InvalidSwitchboardAccount
)]
pub vrf: AccountLoader<'info, VrfLiteAccountData>,
}
#[derive(Clone, AnchorSerialize, AnchorDeserialize)]
pub struct UpdateResultParams {}
impl Discriminator for UpdateResult<'_> {
const DISCRIMINATOR: [u8; 8] = [145, 72, 9, 94, 61, 97, 126, 106];
}
impl UpdateResult<'_> {
pub fn try_to_vec(params: &UpdateResultParams) -> Result<Vec<u8>> {
let ix_data = params.try_to_vec()?;
let data: Vec<u8> = UpdateResult::discriminator().into_iter().chain(ix_data.into_iter()).collect();
assert_eq!(data.len(), 8 + std::mem::size_of::<UpdateResultParams>());
Ok(data)
}
pub fn to_callback(
client_state: &AccountInfo,
vrf: &Pubkey,
params: &UpdateResultParams,
) -> Result<Callback> {
let program_id = client_state.owner.clone();
let accounts: Vec<switchboard_v2::AccountMetaBorsh> = vec![
switchboard_v2::AccountMetaBorsh {
pubkey: client_state.key.clone(),
is_signer: false,
is_writable: true,
},
switchboard_v2::AccountMetaBorsh {
pubkey: vrf.clone(),
is_signer: false,
is_writable: false,
},
];
let ix_data = UpdateResult::try_to_vec(params)?;
let callback = Callback {
program_id,
accounts,
ix_data
};
Ok(callback)
}
pub fn validate(&self, _ctx: &Context<Self>, _params: &UpdateResultParams) -> Result<()> {
// We should check VRF account passed is equal to the pubkey stored in our client state
// But skipping so we can re-use this program instruction for CI testing
Ok(())
}
pub fn actuate(ctx: &Context<Self>, _params: &UpdateResultParams) -> Result<()> {
let clock = clock::Clock::get().unwrap();
emit!(VrfClientInvoked {
vrf_client: ctx.accounts.state.key(),
timestamp: clock.unix_timestamp,
});
let vrf = ctx.accounts.vrf.load()?;
let result_buffer = vrf.get_result()?;
if result_buffer == [0u8; 32] {
msg!("vrf buffer empty");
return Ok(());
}
let state = &mut ctx.accounts.state.load_mut()?;
let max_result = state.max_result;
if result_buffer == state.result_buffer {
msg!("existing result_buffer");
return Ok(());
}
msg!("Result buffer is {:?}", result_buffer);
let value: &[u128] = bytemuck::cast_slice(&result_buffer[..]);
msg!("u128 buffer {:?}", value);
let result = value[0] % max_result as u128 + 1;
msg!("Current VRF Value [1 - {}) = {}!", max_result, result);
if state.result != result {
state.result_buffer = result_buffer;
state.result = result;
state.last_timestamp = clock.unix_timestamp;
emit!(VrfClientResultUpdated {
vrf_client: ctx.accounts.state.key(),
result: state.result,
result_buffer: result_buffer,
timestamp: clock.unix_timestamp,
});
}
Ok(())
}
}

View File

@ -0,0 +1,99 @@
pub mod actions;
pub use actions::*;
pub use anchor_lang::prelude::*;
use anchor_spl::token::TokenAccount;
pub use switchboard_v2::SWITCHBOARD_PROGRAM_ID;
pub use switchboard_v2::Callback;
declare_id!("5Hhm5xKDiThfidbpqjJpKmMJEcKmjj5tEUNFpi2DzSvb");
const MAX_RESULT: u64 = u64::MAX;
const STATE_SEED: &[u8] = b"STATE";
#[program]
pub mod anchor_vrf_lite_parser {
use super::*;
#[access_control(ctx.accounts.validate(&ctx, &params))]
pub fn init_state(ctx: Context<InitState>, params: InitStateParams) -> Result<()> {
InitState::actuate(&ctx, &params)
}
#[access_control(ctx.accounts.validate(&ctx, &params))]
pub fn update_result(ctx: Context<UpdateResult>, params: UpdateResultParams) -> Result<()> {
UpdateResult::actuate(&ctx, &params)
}
#[access_control(ctx.accounts.validate(&ctx, &params))]
pub fn request_result(ctx: Context<RequestResult>, params: RequestResultParams) -> Result<()> {
RequestResult::actuate(&ctx, &params)
}
#[access_control(ctx.accounts.validate(&ctx, &params))]
pub fn close_state(ctx: Context<CloseState>, params: CloseStateParams) -> Result<()> {
CloseState::actuate(&ctx, &params)
}
}
#[repr(packed)]
#[account(zero_copy(unsafe))]
pub struct VrfClient {
pub bump: u8,
pub max_result: u64,
pub result_buffer: [u8; 32],
pub result: u128,
pub last_timestamp: i64,
pub authority: Pubkey,
pub vrf: Pubkey,
pub permission_bump: u8,
pub switchboard_state_bump: u8,
}
impl Default for VrfClient {
fn default() -> Self {
unsafe { std::mem::zeroed() }
}
}
#[event]
pub struct RequestingRandomness {
pub vrf_client: Pubkey,
pub max_result: u64,
pub timestamp: i64,
}
#[event]
pub struct VrfClientInvoked {
pub vrf_client: Pubkey,
pub timestamp: i64,
}
#[event]
pub struct VrfClientResultUpdated {
pub vrf_client: Pubkey,
pub result: u128,
pub result_buffer: [u8; 32],
pub timestamp: i64,
}
#[error_code]
#[derive(Eq, PartialEq)]
pub enum VrfErrorCode {
#[msg("Not a valid Switchboard account")]
InvalidSwitchboardAccount,
#[msg("The max result must not exceed u64")]
MaxResultExceedsMaximum,
#[msg("Current round result is empty")]
EmptyCurrentRoundResult,
#[msg("Invalid authority account provided.")]
InvalidAuthorityError,
#[msg("Invalid VRF account provided.")]
InvalidVrfAccount,
#[msg("VRF client is not ready to be closed.")]
VrfClientCloseNotReady,
#[msg("VRF account is not ready to be closed.")]
VrfCloseNotReady,
}

View File

@ -0,0 +1,368 @@
import assert from "assert";
import "mocha";
import * as anchor from "@coral-xyz/anchor";
import { AnchorProvider } from "@coral-xyz/anchor";
import {
PublicKey,
SystemProgram,
SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
} from "@solana/web3.js";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
import { sleep } from "@switchboard-xyz/common";
import {
AnchorWallet,
Callback,
PermissionAccount,
QueueAccount,
SwitchboardProgram,
SwitchboardTestContext,
SWITCHBOARD_LABS_DEVNET_PERMISSIONLESS_QUEUE,
types,
} from "@switchboard-xyz/solana.js";
import { AnchorVrfLiteParser } from "../target/types/anchor_vrf_lite_parser";
import { NodeOracle } from "@switchboard-xyz/oracle";
describe("anchor-vrf-lite-parser test", () => {
const provider = AnchorProvider.env();
anchor.setProvider(provider);
const vrfClientProgram: anchor.Program<AnchorVrfLiteParser> =
anchor.workspace.AnchorVrfLiteParser;
const payer = (provider.wallet as AnchorWallet).payer;
const vrfSecret = anchor.web3.Keypair.generate();
console.log(`VRF Account: ${vrfSecret.publicKey}`);
const [vrfClientKey, vrfClientBump] = PublicKey.findProgramAddressSync(
[
Buffer.from("STATE"),
vrfSecret.publicKey.toBytes(),
payer.publicKey.toBytes(),
],
vrfClientProgram.programId
);
const vrfIxCoder = new anchor.BorshInstructionCoder(vrfClientProgram.idl);
const vrfClientCallback: Callback = {
programId: vrfClientProgram.programId,
accounts: [
// ensure all accounts in updateResult are populated
{ pubkey: vrfClientKey, isSigner: false, isWritable: true },
{ pubkey: vrfSecret.publicKey, isSigner: false, isWritable: false },
],
ixData: vrfIxCoder.encode("updateResult", ""), // pass any params for instruction here
};
let switchboard: SwitchboardTestContext;
let oracle: NodeOracle;
let queueAccount: QueueAccount;
let queue: types.OracleQueueAccountData;
before(async () => {
if (process.env.USE_SWITCHBOARD_DEVNET_QUEUE) {
const switchboardProgram = await SwitchboardProgram.fromProvider(
vrfClientProgram.provider as anchor.AnchorProvider
);
[queueAccount, queue] = await QueueAccount.load(
switchboardProgram,
SWITCHBOARD_LABS_DEVNET_PERMISSIONLESS_QUEUE
);
} else {
switchboard = await SwitchboardTestContext.loadFromProvider(provider, {
// You can provide a keypair to so the PDA schemes dont change between test runs
name: "Test Queue",
keypair: SwitchboardTestContext.loadKeypair("~/.keypairs/queue.json"),
queueSize: 10,
reward: 0,
minStake: 0,
oracleTimeout: 900,
unpermissionedFeeds: true,
unpermissionedVrf: true,
enableBufferRelayers: true,
oracle: {
name: "Test Oracle",
enable: true,
stakingWalletKeypair: SwitchboardTestContext.loadKeypair(
"~/.keypairs/oracleWallet.json"
),
},
});
queueAccount = switchboard.queue;
queue = await queueAccount.loadData();
oracle = await NodeOracle.fromReleaseChannel({
chain: "solana",
releaseChannel: "testnet",
network: "localnet", // disables production capabilities like monitoring and alerts
rpcUrl: switchboard.program.connection.rpcEndpoint,
oracleKey: switchboard.oracle.publicKey.toBase58(),
secretPath: switchboard.walletPath,
silent: false, // set to true to suppress oracle logs in the console
envVariables: {
VERBOSE: "1",
DEBUG: "1",
DISABLE_NONCE_QUEUE: "1",
DISABLE_METRICS: "1",
},
});
await oracle.startAndAwait();
}
});
after(() => {
oracle?.stop();
});
it("Creates a vrfClient account", async () => {
const { unpermissionedVrfEnabled, authority, dataBuffer } = queue;
console.log("creating vrfLite");
// Create Switchboard VRF and Permission account
const [vrfAccount] = await queueAccount.createVrfLite({
callback: vrfClientCallback,
authority: vrfClientKey, // vrf authority
keypair: vrfSecret,
enable: false,
});
console.log(`Created VRF Account: ${vrfAccount.publicKey}`);
const [permissionAccount, permissionBump] = PermissionAccount.fromSeed(
queueAccount.program,
authority,
queueAccount.publicKey,
vrfAccount.publicKey
);
console.log(`Created Permission Account: ${permissionAccount.publicKey}`);
// If queue requires permissions to use VRF, check the correct authority was provided
if (!unpermissionedVrfEnabled) {
if (!payer.publicKey.equals(authority)) {
throw new Error(
`queue requires PERMIT_VRF_REQUESTS and wrong queue authority provided`
);
}
await permissionAccount.set({
queueAuthority: payer,
permission: new types.SwitchboardPermission.PermitVrfRequests(),
enable: true,
});
console.log(`Set VRF Permissions`);
}
// Create VRF Client account
await vrfClientProgram.methods
.initState({
maxResult: new anchor.BN(1337000),
permissionBump: permissionBump,
switchboardStateBump: queueAccount.program.programState.bump,
})
.accounts({
state: vrfClientKey,
vrf: vrfAccount.publicKey,
payer: payer.publicKey,
authority: payer.publicKey,
systemProgram: SystemProgram.programId,
})
.rpc();
console.log(`Created VrfClient Account: ${vrfClientKey}`);
const [payerTokenWallet] =
await queueAccount.program.mint.getOrCreateWrappedUser(
queueAccount.program.walletPubkey,
{ fundUpTo: 0.002 }
);
const vrf = await vrfAccount.loadData();
// give account time to propagate to oracle RPCs
await sleep(2000);
try {
// Request randomness
await vrfClientProgram.methods.requestResult!({})
.accounts({
state: vrfClientKey,
authority: payer.publicKey,
switchboardProgram: queueAccount.program.programId,
vrf: vrfAccount.publicKey,
oracleQueue: queueAccount.publicKey,
queueAuthority: authority,
dataBuffer,
permission: permissionAccount.publicKey,
escrow: vrf.escrow,
recentBlockhashes: SYSVAR_RECENT_BLOCKHASHES_PUBKEY,
programState: queueAccount.program.programState.publicKey,
tokenProgram: TOKEN_PROGRAM_ID,
})
.rpc();
const result = await vrfAccount.nextResult(
new anchor.BN(vrf.counter.toNumber() + 1),
45_000
);
if (!result.success) {
throw new Error(`Failed to get VRF Result: ${result.status}`);
}
const vrfClient = await vrfClientProgram.account.vrfClient.fetch(
vrfClientKey
);
console.log(`VrfClient Result: ${vrfClient.result}`);
} catch (error) {
const callbackTxn = await vrfAccount.getCallbackTransactions();
if (callbackTxn.length && callbackTxn[0].meta?.logMessages?.length) {
console.log(
JSON.stringify(callbackTxn[0].meta.logMessages, undefined, 2)
);
}
throw error;
}
});
it("Creates and closes a vrfClient account", async () => {
// we create a new client & VRF because a VRF must wait at least 1500 slots
// after a request before it can be closed
const newVrfSecret = anchor.web3.Keypair.generate();
const [newVrfClientKey, newVrfClientBump] =
PublicKey.findProgramAddressSync(
[
Buffer.from("STATE"),
newVrfSecret.publicKey.toBytes(),
payer.publicKey.toBytes(),
],
vrfClientProgram.programId
);
const vrfIxCoder = new anchor.BorshInstructionCoder(vrfClientProgram.idl);
const vrfClientCallback: Callback = {
programId: vrfClientProgram.programId,
accounts: [
// ensure all accounts in updateResult are populated
{ pubkey: newVrfClientKey, isSigner: false, isWritable: true },
{ pubkey: newVrfSecret.publicKey, isSigner: false, isWritable: false },
],
ixData: vrfIxCoder.encode("updateResult", ""), // pass any params for instruction here
};
const { unpermissionedVrfEnabled, authority, dataBuffer } = queue;
// Create Switchboard VRF and Permission account
const [newVrfAccount] = await queueAccount.createVrf({
callback: vrfClientCallback,
authority: newVrfClientKey, // vrf authority
vrfKeypair: newVrfSecret,
enable: false,
});
console.log(`Created New VRF Account: ${newVrfAccount.publicKey}`);
const [permissionAccount, permissionBump] = PermissionAccount.fromSeed(
queueAccount.program,
authority,
queueAccount.publicKey,
newVrfAccount.publicKey
);
console.log(
`Created New Permission Account: ${permissionAccount.publicKey}`
);
// If queue requires permissions to use VRF, check the correct authority was provided
if (!unpermissionedVrfEnabled) {
if (!payer.publicKey.equals(authority)) {
throw new Error(
`queue requires PERMIT_VRF_REQUESTS and wrong queue authority provided`
);
}
await permissionAccount.set({
queueAuthority: payer,
permission: new types.SwitchboardPermission.PermitVrfRequests(),
enable: true,
});
console.log(`Set New VRF Permissions`);
}
// Create VRF Client account
await vrfClientProgram.methods
.initState({
maxResult: new anchor.BN(1337000),
permissionBump: permissionBump,
switchboardStateBump: queueAccount.program.programState.bump,
})
.accounts({
state: newVrfClientKey,
vrf: newVrfAccount.publicKey,
payer: payer.publicKey,
authority: payer.publicKey,
systemProgram: SystemProgram.programId,
})
.rpc();
console.log(`Created New VrfClient Account: ${newVrfClientKey}`);
await sleep(5000);
const newVrfClientState = await vrfClientProgram.account.vrfClient.fetch(
newVrfClientKey
);
assert(
newVrfClientState.vrf.equals(newVrfAccount.publicKey),
`Vrf Client VRF account mismatch, expected ${newVrfAccount.publicKey}, received ${newVrfClientState.vrf}`
);
const newVrfInitialState = await newVrfAccount.loadData();
// send any wrapped SOL to the payers associated wSOL wallet
const [payerTokenAccount] =
await queueAccount.program.mint.getOrCreateWrappedUser(payer.publicKey, {
fundUpTo: 0,
});
// close the client and VRF account
await vrfClientProgram.methods
.closeState({})
.accounts({
state: newVrfClientKey,
authority: payer.publicKey,
payer: payer.publicKey,
vrf: newVrfAccount.publicKey,
escrow: newVrfInitialState.escrow,
permission: permissionAccount.publicKey,
oracleQueue: queueAccount.publicKey,
queueAuthority: queue.authority,
programState: queueAccount.program.programState.publicKey,
solDest: payer.publicKey,
escrowDest: payerTokenAccount,
switchboardProgram: queueAccount.program.programId,
tokenProgram: TOKEN_PROGRAM_ID,
})
.rpc();
const vrfClientAccountInfo =
await vrfClientProgram.provider.connection.getAccountInfo(
newVrfClientKey,
"processed"
);
assert(vrfClientAccountInfo === null, "VrfClientNotClosed");
const vrfAccountInfo =
await vrfClientProgram.provider.connection.getAccountInfo(
newVrfAccount.publicKey,
"processed"
);
assert(vrfAccountInfo === null, "VrfAccountNotClosed");
});
});

View File

@ -0,0 +1,23 @@
{
"ts-node": {
"compilerOptions": {
"module": "commonjs"
}
},
"compilerOptions": {
"types": ["mocha", "chai", "node"],
"typeRoots": ["./node_modules/@types"],
"module": "commonjs",
"noEmit": true,
"esModuleInterop": true,
"strict": false,
"strictNullChecks": false,
"target": "es6",
"paths": {
"@switchboard-xyz/solana.js": ["../../javascript/solana.js"]
}
},
"include": ["tests/**/*", "./cli.ts", "./client/**/*"],
"exclude": ["target", "lib"],
"references": [{ "path": "../../javascript/solana.js" }]
}

View File

@ -304,6 +304,8 @@ pub struct VrfLiteClose<'info> {
#[account(mut)]
pub queue: AccountInfo<'info>,
pub queue_authority: AccountInfo<'info>,
// #[account(seeds = [b"STATE"], bump = params.state_bump)]
/// CHECK:
pub program_state: AccountInfo<'info>,
@ -314,8 +316,6 @@ pub struct VrfLiteClose<'info> {
#[account(mut, constraint = escrow.mint == escrow_dest.mint )]
pub escrow_dest: Account<'info, TokenAccount>,
pub recent_blockhashes: AccountInfo<'info>,
// #[account(seeds = [b"STATE"], bump = params.state_bump)]
pub token_program: AccountInfo<'info>,
}