Add V3 SGX Program to solana.js (#102)

This commit is contained in:
gallynaut 2023-06-12 12:19:25 -04:00 committed by GitHub
parent 0cddfe378a
commit dffd9def99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
320 changed files with 19744 additions and 1648 deletions

View File

@ -25,7 +25,7 @@ jobs:
- name: Setup Workspace
uses: ./.github/actions/setup-workspace
with:
solanaVersion: "v1.14.10"
solanaVersion: "v1.14.18"
anchorVersion: "0.26.0"
nodeVersion: ${{ matrix.nodeVersion }}
@ -68,7 +68,7 @@ jobs:
- name: Setup Workspace
uses: ./.github/actions/setup-workspace
with:
solanaVersion: "v1.14.10"
solanaVersion: "v1.14.18"
anchorVersion: "0.26.0"
nodeVersion: ${{ matrix.nodeVersion }}

View File

@ -44,9 +44,7 @@ jobs:
id: cache-solana-sdk-build
uses: actions/cache@v3
with:
key:
${{ runner.os }}-Solana.js-${{
hashFiles('javascript/solana.js/src/**') }}
key: ${{ runner.os }}-Solana.js-${{ hashFiles('javascript/solana.js/src/**') }}
path: |
javascript/solana.js/lib
- name: Build solana.js
@ -90,9 +88,7 @@ jobs:
id: cache-solana-sdk-build
uses: actions/cache@v3
with:
key:
${{ runner.os }}-Solana.js-${{
hashFiles('javascript/solana.js/src/**') }}
key: ${{ runner.os }}-Solana.js-${{ hashFiles('javascript/solana.js/src/**') }}
path: |
javascript/solana.js/lib
- name: Build solana.js
@ -104,11 +100,13 @@ jobs:
with:
solana-version: v1.14.10
cluster: devnet
args:
"--url ${{ secrets.DEVNET_RPC_URL }} --clone
args: "--url ${{ secrets.DEVNET_RPC_URL }} --clone
SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f --clone
7nYabs9dUhvxYwdTnrWVBL9MYviKSfrEbdWCUbcnwkpF --clone
Fi8vncGpNKbq62gPo56G4toCehWNy77GgqGkTaAF5Lkk --clone
2No5FVKPAAYqytpkEoq93tVh33fo4p6DgAnm4S6oZHo7 --clone
BNrpbCMbBFiCEqGdWaDMqjQmwqtGdgmoFFzGJnUexSbj --clone
th1SbXMTX3SrWJ1kbiSKqMDpTBaXkESxpcehXRa12T4 --clone
CyZuD7RPDcrqCGbNvLCyqk6Py9cEZTKmNKujfPi3ynDd"
- name: Run Tests
working-directory: javascript/solana.js
@ -154,9 +152,7 @@ jobs:
id: cache-solana-sdk-build
uses: actions/cache@v3
with:
key:
${{ runner.os }}-Solana.js-${{
hashFiles('javascript/solana.js/src/**') }}
key: ${{ runner.os }}-Solana.js-${{ hashFiles('javascript/solana.js/src/**') }}
path: |
javascript/solana.js/lib
- name: Build solana.js
@ -168,11 +164,13 @@ jobs:
with:
solana-version: v1.14.10
cluster: mainnet
args:
"--url ${{ secrets.MAINNET_RPC_URL }} --clone
args: "--url ${{ secrets.MAINNET_RPC_URL }} --clone
SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f --clone
7nYabs9dUhvxYwdTnrWVBL9MYviKSfrEbdWCUbcnwkpF --clone
Fi8vncGpNKbq62gPo56G4toCehWNy77GgqGkTaAF5Lkk --clone
2No5FVKPAAYqytpkEoq93tVh33fo4p6DgAnm4S6oZHo7 --clone
BNrpbCMbBFiCEqGdWaDMqjQmwqtGdgmoFFzGJnUexSbj --clone
th1SbXMTX3SrWJ1kbiSKqMDpTBaXkESxpcehXRa12T4 --clone
CyZuD7RPDcrqCGbNvLCyqk6Py9cEZTKmNKujfPi3ynDd"
- name: Run Tests
working-directory: javascript/solana.js

View File

@ -1,3 +1,2 @@
build/
node_modules/
src/generated

View File

@ -1,6 +1,9 @@
{
"extends": "@switchboard-xyz",
"rules": {
"quotes": "off"
"quotes": "off",
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-empty-interface": "off"
}
}

View File

@ -1,12 +1,48 @@
index.cjs
index.js
index.d.ts
SwitchboardProgram.cjs
SwitchboardProgram.js
SwitchboardProgram.d.ts
TransactionObject.cjs
TransactionObject.js
TransactionObject.d.ts
AggregatorAccount.cjs
AggregatorAccount.js
AggregatorAccount.d.ts
generated.cjs
generated.js
generated.d.ts
accounts.cjs
accounts.js
accounts.d.ts
program.cjs
program.js
program.d.ts
generated/accounts.cjs
generated/accounts.js
generated/accounts.d.ts
generated/instructions.cjs
generated/instructions.js
generated/instructions.d.ts
generated/types.cjs
generated/types.js
generated/types.d.ts
generated/oracle.cjs
generated/oracle.js
generated/oracle.d.ts
generated/oracle/accounts.cjs
generated/oracle/accounts.js
generated/oracle/accounts.d.ts
generated/oracle/instructions.cjs
generated/oracle/instructions.js
generated/oracle/instructions.d.ts
generated/oracle/types.cjs
generated/oracle/types.js
generated/oracle/types.d.ts
generated/attestation.cjs
generated/attestation.js
generated/attestation.d.ts
generated/attestation/accounts.cjs
generated/attestation/accounts.js
generated/attestation/accounts.d.ts
generated/attestation/instructions.cjs
generated/attestation/instructions.js
generated/attestation/instructions.d.ts
generated/attestation/types.cjs
generated/attestation/types.js
generated/attestation/types.d.ts

View File

@ -37,9 +37,24 @@ const commonOptions = {
const entrypoints = {
index: "index",
SwitchboardProgram: "SwitchboardProgram",
TransactionObject: "TransactionObject",
AggregatorAccount: "accounts/AggregatorAccount",
generated: "generated/index",
accounts: "accounts/index",
program: "SwitchboardProgram",
"generated/accounts": "generated/accounts",
"generated/instructions": "generated/instructions",
"generated/types": "generated/types",
"generated/oracle": "generated/oracle-program/index",
"generated/oracle/accounts": "generated/oracle-program/accounts/index",
"generated/oracle/instructions":
"generated/oracle-program/instructions/index",
"generated/oracle/types": "generated/oracle-program/types/index",
"generated/attestation": "generated/attestation-program/index",
"generated/attestation/accounts":
"generated/attestation-program/accounts/index",
"generated/attestation/instructions":
"generated/attestation-program/instructions/index",
"generated/attestation/types": "generated/attestation-program/types/index",
};
const updateJsonFile = (relativePath, updateFunction) => {

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "@switchboard-xyz/solana.js",
"version": "2.2.0",
"version": "2.3.0-beta.5",
"author": "",
"license": "MIT",
"description": "A Typescript client to interact with Switchboard on Solana.",
@ -13,15 +13,51 @@
"index.cjs",
"index.js",
"index.d.ts",
"SwitchboardProgram.cjs",
"SwitchboardProgram.js",
"SwitchboardProgram.d.ts",
"TransactionObject.cjs",
"TransactionObject.js",
"TransactionObject.d.ts",
"AggregatorAccount.cjs",
"AggregatorAccount.js",
"AggregatorAccount.d.ts",
"generated.cjs",
"generated.js",
"generated.d.ts",
"accounts.cjs",
"accounts.js",
"accounts.d.ts",
"program.cjs",
"program.js",
"program.d.ts"
"generated/accounts.cjs",
"generated/accounts.js",
"generated/accounts.d.ts",
"generated/instructions.cjs",
"generated/instructions.js",
"generated/instructions.d.ts",
"generated/types.cjs",
"generated/types.js",
"generated/types.d.ts",
"generated/oracle.cjs",
"generated/oracle.js",
"generated/oracle.d.ts",
"generated/oracle/accounts.cjs",
"generated/oracle/accounts.js",
"generated/oracle/accounts.d.ts",
"generated/oracle/instructions.cjs",
"generated/oracle/instructions.js",
"generated/oracle/instructions.d.ts",
"generated/oracle/types.cjs",
"generated/oracle/types.js",
"generated/oracle/types.d.ts",
"generated/attestation.cjs",
"generated/attestation.js",
"generated/attestation.d.ts",
"generated/attestation/accounts.cjs",
"generated/attestation/accounts.js",
"generated/attestation/accounts.d.ts",
"generated/attestation/instructions.cjs",
"generated/attestation/instructions.js",
"generated/attestation/instructions.d.ts",
"generated/attestation/types.cjs",
"generated/attestation/types.js",
"generated/attestation/types.d.ts"
],
"exports": {
".": {
@ -29,29 +65,90 @@
"import": "./index.js",
"require": "./index.cjs"
},
"./SwitchboardProgram": {
"types": "./SwitchboardProgram.d.ts",
"import": "./SwitchboardProgram.js",
"require": "./SwitchboardProgram.cjs"
},
"./TransactionObject": {
"types": "./TransactionObject.d.ts",
"import": "./TransactionObject.js",
"require": "./TransactionObject.cjs"
},
"./AggregatorAccount": {
"types": "./AggregatorAccount.d.ts",
"import": "./AggregatorAccount.js",
"require": "./AggregatorAccount.cjs"
},
"./generated": {
"types": "./generated.d.ts",
"import": "./generated.js",
"require": "./generated.cjs"
},
"./accounts": {
"types": "./accounts.d.ts",
"import": "./accounts.js",
"require": "./accounts.cjs"
"./generated/accounts": {
"types": "./generated/accounts.d.ts",
"import": "./generated/accounts.js",
"require": "./generated/accounts.cjs"
},
"./program": {
"types": "./program.d.ts",
"import": "./program.js",
"require": "./program.cjs"
"./generated/instructions": {
"types": "./generated/instructions.d.ts",
"import": "./generated/instructions.js",
"require": "./generated/instructions.cjs"
},
"./generated/types": {
"types": "./generated/types.d.ts",
"import": "./generated/types.js",
"require": "./generated/types.cjs"
},
"./generated/oracle": {
"types": "./generated/oracle.d.ts",
"import": "./generated/oracle.js",
"require": "./generated/oracle.cjs"
},
"./generated/oracle/accounts": {
"types": "./generated/oracle/accounts.d.ts",
"import": "./generated/oracle/accounts.js",
"require": "./generated/oracle/accounts.cjs"
},
"./generated/oracle/instructions": {
"types": "./generated/oracle/instructions.d.ts",
"import": "./generated/oracle/instructions.js",
"require": "./generated/oracle/instructions.cjs"
},
"./generated/oracle/types": {
"types": "./generated/oracle/types.d.ts",
"import": "./generated/oracle/types.js",
"require": "./generated/oracle/types.cjs"
},
"./generated/attestation": {
"types": "./generated/attestation.d.ts",
"import": "./generated/attestation.js",
"require": "./generated/attestation.cjs"
},
"./generated/attestation/accounts": {
"types": "./generated/attestation/accounts.d.ts",
"import": "./generated/attestation/accounts.js",
"require": "./generated/attestation/accounts.cjs"
},
"./generated/attestation/instructions": {
"types": "./generated/attestation/instructions.d.ts",
"import": "./generated/attestation/instructions.js",
"require": "./generated/attestation/instructions.cjs"
},
"./generated/attestation/types": {
"types": "./generated/attestation/types.d.ts",
"import": "./generated/attestation/types.js",
"require": "./generated/attestation/types.cjs"
},
"./package.json": "./package.json"
},
"scripts": {
"keypair:create": "shx find ~/.config/solana/id.json || solana-keygen new -s --no-bip39-passphrase --outfile ~/.config/solana/id.json",
"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 ./scripts/generate-client.js",
"localnet": "tsx ./scripts/localnet.ts",
"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 2No5FVKPAAYqytpkEoq93tVh33fo4p6DgAnm4S6oZHo7 `# sgxProgramId` --clone BNrpbCMbBFiCEqGdWaDMqjQmwqtGdgmoFFzGJnUexSbj `# sgxProgramDataAddress` --clone th1SbXMTX3SrWJ1kbiSKqMDpTBaXkESxpcehXRa12T4 `# sgxIdlAddress` --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 2No5FVKPAAYqytpkEoq93tVh33fo4p6DgAnm4S6oZHo7 --clone BNrpbCMbBFiCEqGdWaDMqjQmwqtGdgmoFFzGJnUexSbj --clone th1SbXMTX3SrWJ1kbiSKqMDpTBaXkESxpcehXRa12T4 --clone CyZuD7RPDcrqCGbNvLCyqk6Py9cEZTKmNKujfPi3ynDd --clone J7nSEX8ADf3pVVicd6yKy2Skvg8iLePEmkLUisAAaioD",
"generate": "tsx ./scripts/generate-client.ts",
"build:old": "shx rm -rf lib || true; tsc -p tsconfig.cjs.json && tsc",
"build": "node esbuild.js",
"watch": "tsc -p tsconfig.cjs.json --watch",
@ -68,7 +165,8 @@
"@coral-xyz/borsh": "^0.27.0",
"@solana/spl-token": "^0.3.6",
"@solana/web3.js": "^1.73.0",
"@switchboard-xyz/common": "^2.2.3",
"@switchboard-xyz/common": "^2.1.46",
"cron-validator": "^1.3.1",
"dotenv": "^16.0.3",
"lodash": "^4.17.21"
},
@ -79,6 +177,8 @@
"@types/lodash": "^4.14.191",
"@types/mocha": "^10.0.0",
"@types/node": "^18.11.18",
"@types/shelljs": "^0.8.12",
"@typescript-eslint/eslint-plugin": "^5.44.0",
"chai": "^4.3.7",
"chalk": "^4.1.2",
"esbuild": "^0.17.19",
@ -89,6 +189,7 @@
"shx": "^0.3.4",
"ts-mocha": "^10.0.0",
"ts-node": "^10.9.1",
"tsx": "^3.12.7",
"typedoc": "^0.23.23",
"typescript": "^4.9.4"
},

View File

@ -1,5 +1,8 @@
import * as sbv2 from '../src';
import { AggregatorAccount, CrankAccount, QueueAccount } from '../src';
#!/usr/bin/env tsx
import * as sbv2 from "../src";
import { AggregatorAccount, CrankAccount, QueueAccount } from "../src";
import {
Aggregator,
CHECK_ICON,
@ -8,21 +11,21 @@ import {
jsonReplacers,
PLUS_ICON,
setupOutputDir,
} from './utils';
} from "./utils.js";
import { clusterApiUrl, Connection, Keypair, PublicKey } from '@solana/web3.js';
import { OracleJob, sleep, toUtf8 } from '@switchboard-xyz/common';
import assert from 'assert';
import { clusterApiUrl, Connection, Keypair, PublicKey } from "@solana/web3.js";
import { OracleJob, sleep, toUtf8 } from "@switchboard-xyz/common";
import assert from "assert";
// import { backOff } from 'exponential-backoff';
import fs from 'fs';
import os from 'os';
import path from 'path';
import fs from "fs";
import os from "os";
import path from "path";
const VERBOSE = process.env.VERBOSE || false;
// expects a directory of keypairs that corresponds to
// aggregatorAccount pubkeys and also the feed authority
const keypairDirectory = path.join(os.homedir(), 'aggregator-keypairs');
const keypairDirectory = path.join(os.homedir(), "aggregator-keypairs");
const DEFAULT_FEED_OPTIONS = {
slidingWindow: true,
@ -36,26 +39,26 @@ const DEFAULT_FEED_OPTIONS = {
const aggregatorMapPath = path.join(
os.homedir(),
'devnet-migration',
sbv2.SBV2_MAINNET_PID.toBase58(),
'aggregator_map.csv'
"devnet-migration",
sbv2.SB_V2_PID.toBase58(),
"aggregator_map.csv"
);
async function main() {
const [oldDirPath, oldFeedDirPath, oldJobDirPath] = setupOutputDir(
'2TfB33aLaneQb5TNVwyDz3jSZXS6jdW2ARw1Dgf84XCG'
"2TfB33aLaneQb5TNVwyDz3jSZXS6jdW2ARw1Dgf84XCG"
);
const [newDirPath, newFeedDirPath, newJobDirPath] = setupOutputDir(
sbv2.SBV2_MAINNET_PID.toBase58()
sbv2.SB_V2_PID.toBase58()
);
const keypairs = new Map<string, Keypair>();
// first find all keypairs in directory
for (const file of fs.readdirSync(keypairDirectory)) {
if (!file.endsWith('.json')) {
if (!file.endsWith(".json")) {
continue;
}
const fileName = path.basename(file).replace('.json', '');
const fileName = path.basename(file).replace(".json", "");
const keypair = sbv2.SwitchboardTestContextV2.loadKeypair(
path.join(keypairDirectory, file)
);
@ -73,36 +76,36 @@ async function main() {
console.log(`Found ${keypairs.size} keypairs`);
const devnetConnection = new Connection(
process.env.SOLANA_DEVNET_RPC ?? clusterApiUrl('devnet')
process.env.SOLANA_DEVNET_RPC ?? clusterApiUrl("devnet")
);
console.log(`rpcUrl: ${devnetConnection.rpcEndpoint}`);
const payer = sbv2.SwitchboardTestContextV2.loadKeypair(
'~/switchboard_environments_v2/devnet/upgrade_authority/upgrade_authority.json'
"~/switchboard_environments_v2/devnet/upgrade_authority/upgrade_authority.json"
);
console.log(`payer: ${payer.publicKey.toBase58()}`);
const oldProgram = await sbv2.SwitchboardProgram.load(
'devnet',
"devnet",
devnetConnection,
payer,
new PublicKey('2TfB33aLaneQb5TNVwyDz3jSZXS6jdW2ARw1Dgf84XCG')
new PublicKey("2TfB33aLaneQb5TNVwyDz3jSZXS6jdW2ARw1Dgf84XCG")
);
const newProgram = await sbv2.SwitchboardProgram.load(
'devnet',
"devnet",
devnetConnection,
payer,
sbv2.SBV2_MAINNET_PID
sbv2.SB_V2_PID
);
const [oldQueueAccount, oldQueue] = await QueueAccount.load(
oldProgram,
'GhYg3R1V6DmJbwuc57qZeoYG6gUuvCotUF1zU3WCj98U'
"GhYg3R1V6DmJbwuc57qZeoYG6gUuvCotUF1zU3WCj98U"
);
const [oldCrankAccount, oldCrank] = await CrankAccount.load(
oldProgram,
'85L2cFUvXaeGQ4HrzP8RJEVCL7WvRrXM2msvEmQ82AVr'
"85L2cFUvXaeGQ4HrzP8RJEVCL7WvRrXM2msvEmQ82AVr"
);
const [newQueueAccount, newQueue] = await QueueAccount.load(
@ -128,16 +131,16 @@ async function main() {
keypair.publicKey
);
const programType: 'old' | 'new' | undefined =
const programType: "old" | "new" | undefined =
aggregatorAccountInfo &&
aggregatorAccountInfo.owner.equals(oldProgram.programId)
? 'old'
? "old"
: aggregatorAccountInfo &&
aggregatorAccountInfo.owner.equals(newProgram.programId)
? 'new'
? "new"
: undefined;
if (programType === 'new') {
if (programType === "new") {
console.log(`Aggregator ${pubkey} has already been migrated`);
continue;
}
@ -150,7 +153,7 @@ async function main() {
feedPath
);
if (programType === 'old') {
if (programType === "old") {
await closeAggregator(aggregatorAccount, keypair);
console.log(`\t${CHECK_ICON} feed closed`);
}
@ -226,14 +229,14 @@ async function main() {
feedDefPath: string
): Promise<Aggregator> {
let feedDefinition: Aggregator | undefined = fs.existsSync(feedDefPath)
? JSON.parse(fs.readFileSync(feedDefPath, 'utf-8'))
? JSON.parse(fs.readFileSync(feedDefPath, "utf-8"))
: undefined;
if (feedDefinition) {
console.log(
`\t${CHECK_ICON} feed definition loaded from ${feedDefPath
.replace(process.cwd(), '.')
.replace(os.homedir(), '~')}`
.replace(process.cwd(), ".")
.replace(os.homedir(), "~")}`
);
} else {
const aggregator = await aggregatorAccount.loadData();
@ -304,7 +307,7 @@ async function main() {
},
lease: lease.toJSON(),
balance: leaseBalance,
jobs: jobs.map(j => {
jobs: jobs.map((j) => {
return {
account: {
publicKey: j.account.publicKey.toBase58(),
@ -343,7 +346,7 @@ async function main() {
pushCrank: true,
disableCrank: false,
authority: payer.publicKey.toBase58(),
jobs: aggregatorDefinition.jobs.map(j => {
jobs: aggregatorDefinition.jobs.map((j) => {
return {
pubkey: j.account.publicKey,
weight: 1,
@ -359,8 +362,8 @@ async function main() {
);
console.log(
`\t${CHECK_ICON} feed definition fetched and saved to ${feedDefPath
.replace(process.cwd(), '.')
.replace(os.homedir(), '~')}`
.replace(process.cwd(), ".")
.replace(os.homedir(), "~")}`
);
}
@ -382,7 +385,7 @@ async function main() {
const [aggregatorAccount] = await queueAccount.createFeed({
...DEFAULT_FEED_OPTIONS,
keypair: keypair,
authority: queueAuthority, // make queueAuthority the authority
authority: queueAuthority.publicKey, // make queueAuthority the authority
enable: true,
queueAuthority: queueAuthority,
name: aggregator.definition.name,
@ -391,7 +394,7 @@ async function main() {
minRequiredOracleResults: aggregator.definition.minRequiredOracleResults,
minRequiredJobResults: aggregator.definition.minRequiredJobResults,
minUpdateDelaySeconds: aggregator.definition.minUpdateDelaySeconds,
jobs: aggregator.data.jobs.map(j => {
jobs: aggregator.data.jobs.map((j) => {
return {
data: OracleJob.encodeDelimited(
OracleJob.fromObject(j.oracleJob)
@ -414,7 +417,7 @@ async function main() {
console.log(
`${CHECK_ICON} ${aggregator.publicKey.padEnd(
44,
' '
" "
)} -> ${aggregatorAccount.publicKey.toBase58()}`
);
@ -423,7 +426,7 @@ async function main() {
undefined,
queueAccount,
queue,
'processed'
"processed"
);
fs.writeFileSync(
newFeedPath,
@ -461,14 +464,14 @@ async function main() {
}
}
main().catch(error => {
main().catch((error) => {
console.error(error);
});
function writeAggregatorMap(map: Map<string, string>) {
const fileString = `oldPubkey, newPubkey\n${Array.from(map.entries())
.map(r => r.join(', '))
.join('\n')}`;
.map((r) => r.join(", "))
.join("\n")}`;
fs.writeFileSync(aggregatorMapPath, fileString);
}
@ -478,10 +481,10 @@ function loadAggregatorMap(): Map<string, string> {
}
const map = new Map();
const fileString = fs.readFileSync(aggregatorMapPath, 'utf-8');
const fileLines = fileString.split('\n').slice(1);
fileLines.forEach(r => {
const [oldPubkey, newPubkey] = r.split(', ');
const fileString = fs.readFileSync(aggregatorMapPath, "utf-8");
const fileLines = fileString.split("\n").slice(1);
fileLines.forEach((r) => {
const [oldPubkey, newPubkey] = r.split(", ");
map.set(oldPubkey, newPubkey);
});

View File

@ -1,175 +0,0 @@
import shell from "shelljs";
import path from "path";
import fs from "fs";
import { execSync } from "child_process";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const projectRoot = path.join(__dirname, "..");
// Super hacky. Some files need to be reset to the previous git state and will be manually managed
const ignoreFiles = [
"./src/generated/types/SwitchboardPermission.ts", // we manually added NONE enumeration
"./src/generated/types/SwitchboardDecimal.ts", // added toBig methods
"./src/generated/types/Lanes.ts", // anchor-client-gen struggles with dual exports
"./src/generated/types/index.ts", // TODO: Need a better way to handle this. anchor-client-gen adds multiple, broken exports (for VRF builder)
"./src/generated/errors/index.ts", // need to revert the program ID check
];
/**
* Fetch a list of filepaths for a given directory and desired file extension
* @param [dirPath] Filesystem path to a directory to search.
* @param [arrayOfFiles] An array of existing file paths for recursive calls
* @param [extensions] Optional, an array of desired extensions with the leading separator '.'
* @throws {String}
* @returns {string[]}
*/
const getAllFiles = (dirPath, arrayOfFiles, extensions) => {
const files = fs.readdirSync(dirPath, "utf8");
arrayOfFiles = arrayOfFiles || [];
files.forEach((file) => {
if (fs.statSync(dirPath + "/" + file).isDirectory()) {
arrayOfFiles = getAllFiles(
dirPath + "/" + file,
arrayOfFiles,
extensions
);
} else {
const ext = path.extname(file);
if (extensions && Array.isArray(extensions) && extensions.includes(ext)) {
arrayOfFiles.push(path.join(dirPath, "/", file));
} else {
arrayOfFiles.push(path.join(dirPath, "/", file));
}
// if (!(extensions === undefined) || extensions.includes(ext)) {
// arrayOfFiles.push(path.join(dirPath, '/', file));
// }
}
});
return arrayOfFiles;
};
async function main() {
shell.cd(projectRoot);
const isDev = process.argv.includes("--dev");
if (!shell.which("anchor")) {
shell.echo(
"Sorry, this script requires 'anchor' to be installed in your $PATH"
);
shell.exit(1);
}
fs.rmSync("idl", { recursive: true });
fs.mkdirSync("idl", { recursive: true });
execSync(
"anchor idl fetch -o ./idl/mainnet.json SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f --provider.cluster mainnet"
);
execSync(
"anchor idl fetch -o ./idl/devnet.json SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f --provider.cluster devnet"
);
if (isDev) {
execSync(
"rm -rf ./src/generated && npx anchor-client-gen --program-id SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f ../../../switchboard-core/switchboard_v2/target/idl/switchboard_v2.json ./src/generated"
);
} else {
execSync(
"rm -rf ./src/generated && npx anchor-client-gen --program-id SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f ./idl/mainnet.json ./src/generated"
);
}
fs.writeFileSync(
"./src/generated/index.ts",
[
"export * from './accounts/index.js';",
"export * from './errors/index.js';",
"export * from './instructions/index.js';",
"export * from './types/index.js';",
].join("\n")
);
// loop through directory and run regex replaces
for await (const file of [
...getAllFiles("./src/generated/accounts"),
...getAllFiles("./src/generated/errors"),
...getAllFiles("./src/generated/instructions"),
...getAllFiles("./src/generated/types"),
]) {
if (file.includes("index.ts")) {
continue;
}
const fileString = fs.readFileSync(file, "utf-8");
fs.writeFileSync(
file,
`import { SwitchboardProgram } from "../../SwitchboardProgram.js"\n${fileString}`
);
console.log(file);
// replace BN import
shell.sed(
"-i",
'import BN from "bn.js"',
'import { BN } from "@switchboard-xyz/common"',
file
);
// update types import
shell.sed(
"-i",
'import * as types from "../types"',
'import * as types from "../types/index.js"',
file
);
// replace borsh import
shell.sed("-i", "@project-serum", "@coral-xyz", file);
// remove PROGRAM_ID import, we will use SwitchboardProgram instead
shell.sed("-i", 'import { PROGRAM_ID } from "../programId"', "", file);
// replace PROGRAM_ID with program.programId
shell.sed("-i", "PROGRAM_ID", "program.programId", file);
// replace Connection with SwitchboardProgram
shell.sed("-i", "c: Connection,", "program: SwitchboardProgram,", file);
// replace c.getAccountInfo with the SwitchboardProgram connection
shell.sed(
"-i",
"c.getAccountInfo",
"program.connection.getAccountInfo",
file
);
// replace c.getMultipleAccountsInfo with the SwitchboardProgram connection
shell.sed(
"-i",
"c.getMultipleAccountsInfo",
"program.connection.getMultipleAccountsInfo",
file
);
// add program as first arguement to instructions
if (file.includes("/instructions/")) {
shell.sed("-i", "args:", "program: SwitchboardProgram, args:", file);
}
}
execSync("npx prettier ./src/generated --write");
// reset files
for (const file of ignoreFiles) {
execSync(`git restore ${file}`);
}
}
main()
.then(() => {
// console.log("Executed successfully");
})
.catch((err) => {
console.error(err);
});

View File

@ -0,0 +1,370 @@
#!/usr/bin/env tsx
import { exec, execSync } from "child_process";
import fsSync from "fs";
import fs from "fs/promises";
import _ from "lodash";
import path from "path";
import shell from "shelljs";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const projectRoot = path.join(__dirname, "..");
// const shx = path.join(projectRoot, 'node_modules', '.bin', 'shx');
const v2DevnetIdlPath = path.join(projectRoot, "./idl/devnet.json");
const v2MainnetIdlPath = path.join(projectRoot, "./idl/mainnet.json");
const v2GeneratedPath = path.join(
projectRoot,
"./src/generated/oracle-program"
);
const attestationDevnetIdlPath = path.join(
projectRoot,
"./idl/attestation-devnet.json"
);
const attestationGeneratedPath = path.join(
projectRoot,
"./src/generated/attestation-program"
);
const switchboardCoreDir = path.join(
projectRoot,
"../../../switchboard-core/switchboard_v2"
);
const switchboardV2IdlPath = path.join(
switchboardCoreDir,
"target/idl/switchboard_v2.json"
);
const switchboardAttestationIdlPath = path.join(
switchboardCoreDir,
"target/idl/switchboard_attestation_program.json"
);
// Super hacky. Some files need to be reset to the previous git state and will be manually managed
const ignoreFiles = [
`${v2GeneratedPath}/types/SwitchboardPermission.ts`, // we manually added NONE enumeration
`${v2GeneratedPath}/types/SwitchboardDecimal.ts`, // added toBig methods
`${v2GeneratedPath}/types/Lanes.ts`, // anchor-client-gen struggles with dual exports
`${v2GeneratedPath}/types/index.ts`, // TODO: Need a better way to handle this. anchor-client-gen adds multiple, broken exports (for VRF builder)
`${v2GeneratedPath}/errors/index.ts`, // need to revert the program ID check,
`${attestationGeneratedPath}/types/VerificationStatus.ts`,
`${attestationGeneratedPath}/errors/index.ts`,
`${attestationGeneratedPath}/types/SwitchboardAttestationPermission.ts`,
// `${v2GeneratedPath}/types/VerificationStatus.ts`,
];
/**
* Fetch a list of filepaths for a given directory and desired file extension
* @param [dirPath] Filesystem path to a directory to search.
* @param [arrayOfFiles] An array of existing file paths for recursive calls
* @param [extensions] Optional, an array of desired extensions with the leading separator '.'
* @throws {String}
* @returns {string[]}
*/
const getAllFiles = async (
dirPath: string,
arrayOfFiles: string[] = [],
extensions: string[] = []
): Promise<string[]> => {
const files = await fs.readdir(dirPath, "utf8");
arrayOfFiles = arrayOfFiles || [];
for await (const file of files) {
if (fsSync.statSync(dirPath + "/" + file).isDirectory()) {
arrayOfFiles = await getAllFiles(
dirPath + "/" + file,
arrayOfFiles,
extensions
);
} else {
const ext = path.extname(file);
if (extensions && Array.isArray(extensions) && extensions.includes(ext)) {
arrayOfFiles.push(path.join(dirPath, "/", file));
} else {
arrayOfFiles.push(path.join(dirPath, "/", file));
}
// if (!(extensions === undefined) || extensions.includes(ext)) {
// arrayOfFiles.push(path.join(dirPath, '/', file));
// }
}
}
return arrayOfFiles;
};
async function main() {
shell.cd(projectRoot);
// generate IDL types from local directory
let devMode = false;
if (process.argv.slice(2).includes("--dev")) {
devMode = true;
}
if (!shell.which("anchor")) {
shell.echo(
"Sorry, this script requires 'anchor' to be installed in your $PATH"
);
shell.exit(1);
}
// Fetch IDLs and cleaning generated directories
console.log(`Fetching anchor IDLs ...`);
await Promise.all([
runCommandAsync(
`anchor idl fetch -o ${v2MainnetIdlPath} SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f --provider.cluster mainnet`,
{
encoding: "utf-8",
}
),
runCommandAsync(
`anchor idl fetch -o ${v2DevnetIdlPath} SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f --provider.cluster devnet`,
{
encoding: "utf-8",
}
),
runCommandAsync(
`anchor idl fetch -o ${attestationDevnetIdlPath} 2No5FVKPAAYqytpkEoq93tVh33fo4p6DgAnm4S6oZHo7 --provider.cluster devnet`,
{
encoding: "utf-8",
}
),
fsSync.existsSync(v2GeneratedPath)
? fs.rm(v2GeneratedPath, { recursive: true })
: Promise.resolve(),
fsSync.existsSync(attestationGeneratedPath)
? fs.rm(attestationGeneratedPath, { recursive: true })
: Promise.resolve(),
]);
console.log(`Running anchor-client-gen ...`);
if (devMode) {
await Promise.all([
runCommandAsync(
`npx anchor-client-gen --program-id SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f ${switchboardV2IdlPath} ${v2GeneratedPath}`,
{ encoding: "utf-8" }
),
runCommandAsync(
`npx anchor-client-gen --program-id 2No5FVKPAAYqytpkEoq93tVh33fo4p6DgAnm4S6oZHo7 ${switchboardAttestationIdlPath} ${attestationGeneratedPath}`,
{ encoding: "utf-8" }
),
]);
} else {
await Promise.all([
runCommandAsync(
`npx anchor-client-gen --program-id SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f ${v2DevnetIdlPath} ${v2GeneratedPath}`,
{ encoding: "utf-8" }
),
runCommandAsync(
`npx anchor-client-gen --program-id 2No5FVKPAAYqytpkEoq93tVh33fo4p6DgAnm4S6oZHo7 ${attestationDevnetIdlPath} ${attestationGeneratedPath}`,
{ encoding: "utf-8" }
),
]);
}
await Promise.all([
fs.writeFile(
`${v2GeneratedPath}/index.ts`,
[
"export * from './accounts/index.js';",
"export * from './errors/index.js';",
"export * from './instructions/index.js';",
"export * from './types/index.js';",
].join("\n")
),
fs.writeFile(
`${attestationGeneratedPath}/index.ts`,
[
"export * from './accounts/index.js';",
"export * from './errors/index.js';",
"export * from './instructions/index.js';",
"export * from './types/index.js';",
].join("\n")
),
]);
// loop through directory and run regex replaces
const allGeneratedFiles = _.flatten(
await Promise.all([
getAllFiles(`${v2GeneratedPath}/accounts`),
getAllFiles(`${v2GeneratedPath}/errors`),
getAllFiles(`${v2GeneratedPath}/instructions`),
getAllFiles(`${v2GeneratedPath}/types`),
getAllFiles(`${attestationGeneratedPath}/accounts`),
getAllFiles(`${attestationGeneratedPath}/errors`),
getAllFiles(`${attestationGeneratedPath}/instructions`),
getAllFiles(`${attestationGeneratedPath}/types`),
])
);
console.log(`Processing ${allGeneratedFiles.length} files ...`);
await Promise.all(allGeneratedFiles.map((f) => processFile(f)));
console.log(`Formatting generated files ...`);
await Promise.all([
runCommandAsync(`npx prettier ${v2GeneratedPath} --write`, {
encoding: "utf-8",
}),
runCommandAsync(`npx prettier ${attestationGeneratedPath} --write`, {
encoding: "utf-8",
}),
]);
// reset ignored files
for (const file of ignoreFiles) {
execSync(`git restore ${file}`, { encoding: "utf-8" });
}
// delete the extra QuoteAccountData
await fs.rm(path.join(v2GeneratedPath, "accounts", "QuoteAccountData.ts"));
// delete the extra VerificationStatus
await fs.rm(path.join(v2GeneratedPath, "types", "VerificationStatus.ts"));
// run auto fix for import ordering
execSync(`pnpm fix`, { encoding: "utf-8" });
}
main()
.then(() => {
// console.log("Executed successfully");
})
.catch((err) => {
console.error(err);
});
/**
* Process the generated file and add the SwitchboardProgram class
*/
const processFile = async (file: string) => {
return await fs
.readFile(file, "utf-8")
.then(async (fileString: string): Promise<string> => {
let updatedFileString = fileString;
if (file.endsWith("errors/index.ts")) {
return updatedFileString
.replace(
`import { PROGRAM_ID } from "../programId"`,
`import { PROGRAM_ID } from "../programId.js"`
)
.replace(
`import * as anchor from "./anchor"`,
`import * as anchor from "./anchor.js"`
)
.replace(
`import * as custom from "./custom"`,
`import * as custom from "./custom.js"`
);
}
if (file.includes("index.ts")) {
if (file === path.join(v2GeneratedPath, "accounts", "index.ts")) {
updatedFileString = updatedFileString.replace(
`export { QuoteAccountData } from "./QuoteAccountData"
export type {
QuoteAccountDataFields,
QuoteAccountDataJSON,
} from "./QuoteAccountData"
`,
``
);
}
// add the .js extension to all local import/export paths
return updatedFileString.replace(
/((import|export)((\s\w+)?([^'"]*))from\s['"])([^'"]+)(['"])/gm,
"$1$6.js$7"
);
}
updatedFileString =
`import { SwitchboardProgram } from "../../../SwitchboardProgram.js"` +
"\n" +
fileString;
// update the types import
updatedFileString = updatedFileString
// use full path
.replace(
`import * as types from "../types"`,
`import * as types from "../types/index.js"`
)
// use our library to avoid version conflicts
.replace(
`import BN from "bn.js"`,
`import { BN } from "@switchboard-xyz/common"`
)
// better
.replace(
`import * as borsh from "@project-serum/borsh"`,
`import * as borsh from "@coral-xyz/borsh"`
)
// remove this import, using SwitchboardProgram
.replace(`import { PROGRAM_ID } from "../programId"`, ``)
.replaceAll(`PROGRAM_ID`, `program.programId`)
.replaceAll(`c: Connection,`, `program: SwitchboardProgram,`)
.replaceAll(`c.getAccountInfo`, `program.connection.getAccountInfo`)
.replaceAll(
`c.getMultipleAccountsInfo`,
`program.connection.getMultipleAccountsInfo`
);
if (file.includes("/instructions/")) {
updatedFileString = updatedFileString.replaceAll(
`args:`,
`program: SwitchboardProgram, args:`
);
}
if (file.includes("/attestation-program/")) {
updatedFileString = updatedFileString.replaceAll(
`program.programId`,
`program.attestationProgramId`
);
}
return updatedFileString;
})
.then(async (updatedFileString: string) => {
return await fs.writeFile(file, updatedFileString, "utf-8");
});
};
async function runCommandAsync(
command: string,
options: Record<string, any>
): Promise<void> {
return new Promise((resolve, reject) => {
const cmd = exec(command, options);
// cmd.stdout.on('data', data => {
// console.log(data.toString());
// });
cmd?.stderr?.on("data", (data) => {
console.error(data.toString());
});
// cmd.on("message", (data) => {
// console.info(data.toString());
// });
cmd.on("error", (error) => {
reject(error);
});
cmd.on("close", (code) => {
if (code !== 0) {
reject(new Error(`Command exited with code ${code}`));
} else {
resolve(undefined);
}
});
});
}

View File

@ -0,0 +1,338 @@
#!/usr/bin/env tsx
import { clusterApiUrl, Connection, Keypair, PublicKey } from "@solana/web3.js";
import { sleep } from "@switchboard-xyz/common";
import { exec, execSync, spawn } from "child_process";
import fsSync from "fs";
import fs from "fs/promises";
import _ from "lodash";
import os from "os";
import path from "path";
import { fileURLToPath } from "url";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const getProgramDataAddress = (programId) => {
return PublicKey.findProgramAddressSync(
[programId.toBytes()],
new PublicKey("BPFLoaderUpgradeab1e11111111111111111111111")
)[0];
};
const getIdlAddress = (programId) => {
const base = PublicKey.findProgramAddressSync([], programId)[0];
// const buffer = Buffer.concat([
// base.toBuffer(),
// Buffer.from('anchor:idl'),
// programId.toBuffer(),
// ]);
// const publicKeyBytes = sha256(buffer);
// return new PublicKey(publicKeyBytes);
return PublicKey.createWithSeed(base, "anchor:idl", new PublicKey(programId));
};
const SWITCHBOARD_PROGRAM_ID = new PublicKey(
"SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f"
);
// const SWITCHBOARD_PROGRAM_ACCOUNTS = [
// SWITCHBOARD_PROGRAM_ID,
// getProgramDataAddress(SWITCHBOARD_PROGRAM_ID),
// await getIdlAddress(SWITCHBOARD_PROGRAM_ID),
// ];
const SWITCHBOARD_ATTESTATION_PROGRAM_ID = new PublicKey(
"2No5FVKPAAYqytpkEoq93tVh33fo4p6DgAnm4S6oZHo7"
);
// const SWITCHBOARD_ATTESTATION_PROGRAM_ACCOUNTS = [
// SWITCHBOARD_ATTESTATION_PROGRAM_ID,
// getProgramDataAddress(SWITCHBOARD_ATTESTATION_PROGRAM_ID),
// await getIdlAddress(SWITCHBOARD_ATTESTATION_PROGRAM_ID),
// ];
const jsSdkRoot = path.join(__dirname, "..");
const solanaSdkRoot = path.join(jsSdkRoot, "..", "..");
const devSwitchboard = path.join(
solanaSdkRoot,
"..",
"switchboard-core",
"switchboard_v2"
);
const defaultPubkeyPath = path.join(
os.homedir(),
".config",
"solana",
"id.json"
);
function killPort(port) {
execSync(`lsof -t -i :${port} | xargs kill -9 || exit 0`, {
encoding: "utf-8",
});
}
async function main() {
// if dev, clone the local program version
const isDev = process.argv.slice(2).includes("--dev");
if (isDev) {
console.log(`Using local switchboard programs`);
}
const isMainnet = process.argv.slice(2).includes("--mainnet");
const shouldBuild = process.argv.slice(2).includes("--build");
try {
killPort(8899);
killPort(8900);
} catch (error) {
console.error(`Failed to kill port 8899`);
console.error(error);
}
if (!fsSync.existsSync(defaultPubkeyPath)) {
await fs.writeFile(defaultPubkeyPath, `[${Keypair.generate().secretKey}]`);
}
const payerPubkey = Keypair.fromSecretKey(
new Uint8Array(JSON.parse(await fs.readFile(defaultPubkeyPath, "utf-8")))
).publicKey;
await fs.mkdir(".anchor/test-ledger", { recursive: true });
let rpcUrl = clusterApiUrl(isMainnet ? "mainnet-beta" : "devnet");
if (isMainnet && process.env.SOLANA_MAINNET_RPC_URL) {
rpcUrl = process.env.SOLANA_MAINNET_RPC_URL;
} else if (!isMainnet && process.env.SOLANA_DEVNET_RPC_URL) {
rpcUrl = process.env.SOLANA_DEVNET_RPC_URL;
}
if (shouldBuild && isDev) {
console.log(`rebuilding anchor programs ...`);
execSync(`anchor build`, { cwd: devSwitchboard });
}
if (isDev) {
spawn(
"solana-test-validator",
[
"-q",
"-r",
"--mint",
payerPubkey.toBase58(),
"--ledger",
".anchor/test-ledger",
// '--url',
// rpcUrl,
// ...cloneAccounts,
],
{ cwd: jsSdkRoot, stdio: "pipe" }
);
await awaitValidator();
await Promise.all([
programDeploy(
devSwitchboard,
defaultPubkeyPath,
"switchboard_v2",
"SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f"
),
programDeploy(
devSwitchboard,
defaultPubkeyPath,
"switchboard_attestation_program",
"2No5FVKPAAYqytpkEoq93tVh33fo4p6DgAnm4S6oZHo7"
),
]);
} else {
const cloneAccounts = [
SWITCHBOARD_PROGRAM_ID,
getProgramDataAddress(SWITCHBOARD_PROGRAM_ID),
await getIdlAddress(SWITCHBOARD_PROGRAM_ID),
SWITCHBOARD_ATTESTATION_PROGRAM_ID,
getProgramDataAddress(SWITCHBOARD_ATTESTATION_PROGRAM_ID),
await getIdlAddress(SWITCHBOARD_ATTESTATION_PROGRAM_ID),
]
.map((a) => `--clone ${a.toBase58()}`)
.join(" ")
.split(" ");
spawn(
"solana-test-validator",
[
"-q",
"-r",
"--mint",
payerPubkey.toBase58(),
"--ledger",
".anchor/test-ledger",
"--url",
rpcUrl,
...cloneAccounts,
],
{ cwd: jsSdkRoot }
);
await awaitValidator();
}
console.log(`\n\nLocal solana validator started ... `);
}
main()
.then()
.catch((error) => {
console.error(error);
process.exit(1);
});
async function awaitValidator(timeout = 60) {
const connection = new Connection("http://127.0.0.1:8899");
let myError;
let numRetries = timeout * 2;
while (numRetries) {
try {
const id = await connection.getBlockHeight();
if (id) {
return;
}
} catch (error) {
myError = error;
// console.error(error);
}
--numRetries;
await sleep(500);
}
throw new Error(
`Failed to start Solana local validator in ${timeout} seconds${
myError ? ": " + myError : undefined
}`
);
}
async function programDeploy(
switchboardDir,
defaultPubkeyPath,
programName,
programId
) {
const sbProgramPath = path.join(
switchboardDir,
"target",
"deploy",
`${programName}.so`
);
if (!fsSync.existsSync(sbProgramPath)) {
throw new Error(
`Failed to find BPF program ${programName}.so in ${switchboardDir}`
);
}
const programKeypairPath = path.join(
switchboardDir,
"target",
"deploy",
`${programName}-keypair.json`
);
if (!fsSync.existsSync(programKeypairPath)) {
throw new Error(
`Failed to find program keypair for ${programName} in ${switchboardDir}`
);
}
const programKeypair = Keypair.fromSecretKey(
new Uint8Array(JSON.parse(await fs.readFile(programKeypairPath, "utf-8")))
);
if (programKeypair.publicKey.toBase58() !== programId) {
throw new Error(
`Program ID mismatch for program ${programName}, expected ${programId}, received ${programKeypair.publicKey.toBase58()}`
);
}
const idlPath = path.join(
switchboardDir,
"target",
"idl",
`${programName}.json`
);
if (!fsSync.existsSync(idlPath)) {
throw new Error(
`Failed to find IDL ${programName}.json in ${switchboardDir}`
);
}
console.log(`Starting program deploy for ${programName} ...`);
await runCommandAsync(
`solana ${[
"program",
"deploy",
"-u",
"l",
"-k",
"~/.config/solana/id.json",
"--program-id",
programKeypairPath,
"--upgrade-authority",
defaultPubkeyPath,
sbProgramPath,
].join(" ")}`,
{
cwd: switchboardDir,
encoding: "utf8",
// stdio: 'pipe',
shell: "/bin/zsh",
}
);
console.log(`Starting IDL deploy for ${programName} ...`);
await runCommandAsync(
`anchor ${[
"idl",
"init",
"--provider.cluster",
"localnet",
"--provider.wallet",
defaultPubkeyPath,
"-f",
idlPath,
programId,
].join(" ")}`,
{
cwd: switchboardDir,
encoding: "utf8",
// stdio: 'pipe',
shell: "/bin/zsh",
}
);
}
async function runCommandAsync(command, options) {
return new Promise((resolve, reject) => {
const cmd = spawn(command, options);
cmd.stdout.on("data", (data) => {
console.log(data.toString());
});
cmd.stderr.on("data", (data) => {
console.error(data.toString());
});
cmd.on("error", (error) => {
reject(error);
});
cmd.on("close", (code) => {
if (code !== 0) {
reject(new Error(`Command exited with code ${code}`));
} else {
resolve(undefined);
}
});
});
}

View File

@ -1,62 +1,63 @@
import * as sbv2 from './src';
import * as sbv2 from "../src/index.js";
import {
CrankAccount,
QueueAccount,
SWITCHBOARD_LABS_DEVNET_PERMISSIONLESS_CRANK,
SWITCHBOARD_LABS_DEVNET_PERMISSIONLESS_QUEUE,
} from './src';
} from "../src/index.js";
import {
Aggregator,
CHECK_ICON,
FAILED_ICON,
jsonReplacers,
setupOutputDir,
} from './utils';
} from "./utils.js";
import { clusterApiUrl, Connection, PublicKey } from '@solana/web3.js';
import { clusterApiUrl, Connection, PublicKey } from "@solana/web3.js";
// import { backOff } from 'exponential-backoff';
import fs from 'fs';
import os from 'os';
import path from 'path';
import fs from "fs";
import os from "os";
import path from "path";
const VERBOSE = process.env.VERBOSE || false;
const jobMapPath = path.join(
os.homedir(),
'devnet-migration',
sbv2.SBV2_MAINNET_PID.toBase58(),
'job_map.csv'
"devnet-migration",
sbv2.SB_V2_PID.toBase58(),
"job_map.csv"
);
const aggregatorMapPath = path.join(
os.homedir(),
'devnet-migration',
sbv2.SBV2_MAINNET_PID.toBase58(),
'aggregator_map.csv'
"devnet-migration",
sbv2.SB_V2_PID.toBase58(),
"aggregator_map.csv"
);
async function main() {
const [oldDirPath, oldFeedDirPath, oldJobDirPath] = setupOutputDir(
'2TfB33aLaneQb5TNVwyDz3jSZXS6jdW2ARw1Dgf84XCG'
"2TfB33aLaneQb5TNVwyDz3jSZXS6jdW2ARw1Dgf84XCG"
);
const [newDirPath, newFeedDirPath, newJobDirPath] = setupOutputDir(
sbv2.SBV2_MAINNET_PID.toBase58()
sbv2.SB_V2_PID.toBase58()
);
const devnetConnection = new Connection(
process.env.SOLANA_DEVNET_RPC ?? clusterApiUrl('devnet')
process.env.SOLANA_DEVNET_RPC ?? clusterApiUrl("devnet")
);
console.log(`rpcUrl: ${devnetConnection.rpcEndpoint}`);
const payer = sbv2.SwitchboardTestContextV2.loadKeypair(
'~/switchboard_environments_v2/devnet/upgrade_authority/upgrade_authority.json'
"~/switchboard_environments_v2/devnet/upgrade_authority/upgrade_authority.json"
);
console.log(`payer: ${payer.publicKey.toBase58()}`);
const newProgram = await sbv2.SwitchboardProgram.load(
'devnet',
"devnet",
devnetConnection,
payer,
sbv2.SBV2_MAINNET_PID
sbv2.SB_V2_PID
);
const [queueAccount, queue] = await QueueAccount.load(
@ -75,12 +76,12 @@ async function main() {
const aggregators = new Map<string, Aggregator>();
for (const file of fs.readdirSync(oldFeedDirPath)) {
if (!file.endsWith('.json')) {
if (!file.endsWith(".json")) {
continue;
}
const fileName = path.basename(file).replace('.json', '');
const fileName = path.basename(file).replace(".json", "");
const aggregatorDef: Aggregator = JSON.parse(
fs.readFileSync(path.join(oldFeedDirPath, file), 'utf-8')
fs.readFileSync(path.join(oldFeedDirPath, file), "utf-8")
);
aggregators.set(fileName, aggregatorDef);
}
@ -107,7 +108,7 @@ async function main() {
try {
// find job accounts
const jobs: Array<{ pubkey: PublicKey; weight: number }> =
aggregator.definition.jobs.map(j => {
aggregator.definition.jobs.map((j) => {
const newJobKey = jobMap.get(j.pubkey);
if (!newJobKey) {
throw new Error(`Job ${j.pubkey} was not migrated`);
@ -121,7 +122,7 @@ async function main() {
// create a feed but keep ourself as the authority until we do all final checks
const [aggregatorAccount] = await queueAccount.createFeed({
authority: payer,
authority: payer.publicKey,
name: aggregator.definition.name,
metadata: aggregator.definition.metadata,
batchSize: aggregator.definition.batchSize,
@ -162,7 +163,7 @@ async function main() {
console.log(
`${CHECK_ICON} ${aggregatorKey.padEnd(
44,
' '
" "
)} -> ${aggregatorAccount.publicKey.toBase58()}`
);
@ -171,7 +172,7 @@ async function main() {
undefined,
queueAccount,
queue,
'processed'
"processed"
);
fs.writeFileSync(
newFeedPath,
@ -212,14 +213,14 @@ async function main() {
}
}
main().catch(error => {
main().catch((error) => {
console.error(error);
});
function writeAggregatorMap(map: Map<string, string>) {
const fileString = `oldPubkey, newPubkey\n${Array.from(map.entries())
.map(r => r.join(', '))
.join('\n')}`;
.map((r) => r.join(", "))
.join("\n")}`;
fs.writeFileSync(aggregatorMapPath, fileString);
}
@ -229,10 +230,10 @@ function loadJobMap(): Map<string, string> {
}
const map = new Map();
const fileString = fs.readFileSync(jobMapPath, 'utf-8');
const fileLines = fileString.split('\n').slice(1);
fileLines.forEach(r => {
const [oldPubkey, newPubkey] = r.split(', ');
const fileString = fs.readFileSync(jobMapPath, "utf-8");
const fileLines = fileString.split("\n").slice(1);
fileLines.forEach((r) => {
const [oldPubkey, newPubkey] = r.split(", ");
map.set(oldPubkey, newPubkey);
});
@ -245,10 +246,10 @@ function loadAggregatorMap(): Map<string, string> {
}
const map = new Map();
const fileString = fs.readFileSync(aggregatorMapPath, 'utf-8');
const fileLines = fileString.split('\n').slice(1);
fileLines.forEach(r => {
const [oldPubkey, newPubkey] = r.split(', ');
const fileString = fs.readFileSync(aggregatorMapPath, "utf-8");
const fileLines = fileString.split("\n").slice(1);
fileLines.forEach((r) => {
const [oldPubkey, newPubkey] = r.split(", ");
map.set(oldPubkey, newPubkey);
});

View File

@ -12,7 +12,7 @@ const VERBOSE = process.env.VERBOSE || false;
const jobMapPath = path.join(
os.homedir(),
'devnet-migration',
sbv2.SBV2_MAINNET_PID.toBase58(),
sbv2.SB_V2_PID.toBase58(),
'job_map.csv'
);
@ -21,7 +21,7 @@ async function main() {
'2TfB33aLaneQb5TNVwyDz3jSZXS6jdW2ARw1Dgf84XCG'
);
const [newDirPath, newFeedDirPath, newJobDirPath] = setupOutputDir(
sbv2.SBV2_MAINNET_PID.toBase58()
sbv2.SB_V2_PID.toBase58()
);
const devnetConnection = new Connection(
@ -38,7 +38,7 @@ async function main() {
'devnet',
devnetConnection,
payer,
sbv2.SBV2_MAINNET_PID
sbv2.SB_V2_PID
);
const jobs = new Map<string, Job>();

View File

@ -14,7 +14,7 @@ import path from 'path';
const aggregatorMapPath = path.join(
os.homedir(),
'devnet-migration',
sbv2.SBV2_MAINNET_PID.toBase58(),
sbv2.SB_V2_PID.toBase58(),
'aggregator_map.csv'
);
@ -23,7 +23,7 @@ async function main() {
'2TfB33aLaneQb5TNVwyDz3jSZXS6jdW2ARw1Dgf84XCG'
);
const [newDirPath, newFeedDirPath, newJobDirPath] = setupOutputDir(
sbv2.SBV2_MAINNET_PID.toBase58()
sbv2.SB_V2_PID.toBase58()
);
const devnetConnection = new Connection(
@ -40,7 +40,7 @@ async function main() {
'devnet',
devnetConnection,
payer,
sbv2.SBV2_MAINNET_PID
sbv2.SB_V2_PID
);
const aggregatorMap = loadAggregatorMap();
@ -71,7 +71,7 @@ async function main() {
const aggregators = await fetchAggregators(
devnetConnection,
newAggregatorKeys,
sbv2.SBV2_MAINNET_PID,
sbv2.SB_V2_PID,
payer.publicKey
);

View File

@ -0,0 +1,13 @@
{
"extends": "../tsconfig.json",
"include": [
"**/*"
],
"compilerOptions": {
"rootDir": ".",
"noEmit": true,
"lib": [
"ES2022"
]
}
}

View File

@ -1,4 +1,5 @@
import {
AttestationProgramStateAccount,
BUFFER_DISCRIMINATOR,
CrankAccount,
DISCRIMINATOR_MAP,
@ -39,8 +40,16 @@ import { SwitchboardEvents } from "./SwitchboardEvents.js";
import { TransactionObject, TransactionOptions } from "./TransactionObject.js";
import { LoadedJobDefinition } from "./types.js";
import * as anchor from "@coral-xyz/anchor";
import { ACCOUNT_DISCRIMINATOR_SIZE } from "@coral-xyz/anchor";
import {
ACCOUNT_DISCRIMINATOR_SIZE,
AccountNamespace,
AnchorProvider,
BorshAccountsCoder,
Idl,
Program,
utils as AnchorUtils,
Wallet,
} from "@coral-xyz/anchor";
import {
AccountInfo,
Cluster,
@ -65,17 +74,17 @@ export const DEFAULT_SEND_TRANSACTION_OPTIONS: SendTransactionOptions = {
};
/**
* Switchboard Devnet Program ID
* Switchboard's V2 Program ID
*/
export const SBV2_DEVNET_PID = new PublicKey(
export const SB_V2_PID = new PublicKey(
"SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f"
);
/**
* Switchboard Mainnet Program ID
* Switchboard's Attestation Program ID
*/
export const SBV2_MAINNET_PID = new PublicKey(
"SW1TCH7qEPTdLsDHRgPuMQjbQxKdH2aBStViMFnt64f"
export const SB_ATTESTATION_PID = new PublicKey(
"2No5FVKPAAYqytpkEoq93tVh33fo4p6DgAnm4S6oZHo7"
);
/**
@ -92,12 +101,30 @@ export const getSwitchboardProgramId = (
case "localnet":
case "devnet":
case "mainnet-beta":
return SBV2_MAINNET_PID;
return SB_V2_PID;
case "testnet":
default:
throw new Error(`Switchboard PID not found for cluster (${cluster})`);
}
};
/**
* Returns the Program ID for the Switchboard Attestation Program for the specified Cluster.
*/
export const getSwitchboardAttestationProgramId = (
cluster: Cluster | "localnet"
): PublicKey => {
switch (cluster) {
case "localnet":
case "devnet":
case "mainnet-beta":
return SB_ATTESTATION_PID;
case "testnet":
default:
throw new Error(
`Switchboard Attestation PID not found for cluster (${cluster})`
);
}
};
/**
* Wrapper class for the Switchboard anchor Program.
@ -127,7 +154,10 @@ export class SwitchboardProgram {
private static readonly _readOnlyKeypair = READ_ONLY_KEYPAIR;
// The anchor program instance.
private readonly _program: anchor.Program;
private readonly _program: Program;
// The anchor program instance for Switchboard's attestation program.
private readonly _attestationProgram: Program | undefined;
/** The Solana cluster to load the Switchboard program for. */
readonly cluster: Cluster | "localnet";
@ -138,6 +168,12 @@ export class SwitchboardProgram {
bump: number;
};
// The pubkey and bump of the Switchboard quote verifier program state account.
readonly attestationProgramState: {
publicKey: PublicKey;
bump: number;
};
// The native mint for the Switchboard program.
readonly mint: NativeMint;
@ -149,11 +185,13 @@ export class SwitchboardProgram {
* @param mint - The native mint for the Switchboard program.
*/
constructor(
program: anchor.Program,
program: Program,
attestationProgram: Program | undefined,
cluster: Cluster | "localnet",
mint: NativeMint
) {
this._program = program;
this._attestationProgram = attestationProgram;
this.cluster = cluster;
// Derive the state account from the seed.
@ -162,6 +200,20 @@ export class SwitchboardProgram {
publicKey: stateAccount[0].publicKey,
bump: stateAccount[1],
};
this.programState = {
publicKey: stateAccount[0].publicKey,
bump: stateAccount[1],
};
// TODO: produce the attestation state account from the seed.
const attestationStateAccount =
AttestationProgramStateAccount.fromSeed(this);
this.attestationProgramState = {
publicKey: attestationStateAccount[0].publicKey,
bump: attestationStateAccount[1],
};
this.mint = mint;
}
@ -183,19 +235,19 @@ export class SwitchboardProgram {
connection: Connection,
payerKeypair: Keypair = READ_ONLY_KEYPAIR,
programId?: PublicKey
): Promise<anchor.Program> {
): Promise<Program> {
const pid = programId ?? getSwitchboardProgramId(cluster);
const provider = new anchor.AnchorProvider(
const provider = new AnchorProvider(
connection,
// If no keypair is provided, default to dummy keypair
new AnchorWallet(payerKeypair ?? SwitchboardProgram._readOnlyKeypair),
{ commitment: "confirmed" }
);
const anchorIdl = await anchor.Program.fetchIdl(pid, provider);
const anchorIdl = await Program.fetchIdl(pid, provider);
if (!anchorIdl) {
throw new Error(`Failed to find IDL for ${pid.toBase58()}`);
}
const program = new anchor.Program(anchorIdl, pid, provider);
const program = new Program(anchorIdl, pid, provider);
return program;
}
@ -232,21 +284,38 @@ export class SwitchboardProgram {
static load = async (
cluster: Cluster | "localnet",
connection: Connection,
payerKeypair: Keypair = READ_ONLY_KEYPAIR,
programId: PublicKey = getSwitchboardProgramId(cluster)
payerKeypair = READ_ONLY_KEYPAIR,
programId = getSwitchboardProgramId(cluster),
attestationProgramId = getSwitchboardAttestationProgramId(cluster)
): Promise<SwitchboardProgram> => {
const program = await SwitchboardProgram.loadAnchorProgram(
cluster,
connection,
payerKeypair,
programId
);
const mint = await NativeMint.load(
program.provider as anchor.AnchorProvider
);
return new SwitchboardProgram(program, cluster, mint);
const [program, attestationProgram] = await Promise.all([
SwitchboardProgram.loadAnchorProgram(
cluster,
connection,
payerKeypair,
programId
),
SwitchboardProgram.loadAnchorProgram(
cluster,
connection,
payerKeypair,
attestationProgramId
).catch((err) => {
console.error(`Failed to load AttestationProgram`);
console.error(err);
return undefined;
}),
]);
const mint = await NativeMint.load(program.provider as AnchorProvider);
return new SwitchboardProgram(program, attestationProgram, cluster, mint);
};
public verifyAttestation(): void {
if (this._attestationProgram === undefined) {
throw new Error(`Attestation Program is missing`);
}
}
/**
* Create and initialize a {@linkcode SwitchboardProgram} connection object.
*
@ -262,7 +331,7 @@ export class SwitchboardProgram {
* import { AnchorWallet, SwitchboardProgram, TransactionObject } from '@switchboard-xyz/solana.js';
*
* const connection = new Connection("https://api.mainnet-beta.solana.com");
* const provider = new anchor.AnchorProvider(
* const provider = new AnchorProvider(
connection,
new AnchorWallet(payerKeypair ?? SwitchboardProgram._readOnlyKeypair),
{ commitment: 'confirmed' }
@ -274,14 +343,16 @@ export class SwitchboardProgram {
* ```
*/
static fromProvider = async (
provider: anchor.AnchorProvider,
programId?: PublicKey
provider: AnchorProvider,
programId?: PublicKey,
attestationProgramId?: PublicKey
): Promise<SwitchboardProgram> => {
const payer = (provider.wallet as AnchorWallet).payer;
const program = await SwitchboardProgram.fromConnection(
provider.connection,
payer,
programId
programId,
attestationProgramId
);
return program;
};
@ -309,7 +380,8 @@ export class SwitchboardProgram {
static fromConnection = async (
connection: Connection,
payer = READ_ONLY_KEYPAIR,
programId?: PublicKey
programId?: PublicKey,
attestationProgramId?: PublicKey
): Promise<SwitchboardProgram> => {
const genesisHash = await connection.getGenesisHash();
const cluster =
@ -319,12 +391,21 @@ export class SwitchboardProgram {
? "devnet"
: "localnet";
const pid = programId ?? SBV2_MAINNET_PID;
const pid = programId ?? SB_V2_PID;
const programAccountInfo = await connection.getAccountInfo(pid);
if (programAccountInfo === null) {
throw new Error(
`Failed to load Switchboard at ${pid}, try manually providing a programId`
`Failed to load Switchboard V2 program at ${pid}, try manually providing a programId`
);
}
const attestationPid = attestationProgramId ?? SB_ATTESTATION_PID;
const attestationProgramAccountInfo = await connection.getAccountInfo(
attestationPid
);
if (attestationProgramAccountInfo === null) {
throw new Error(
`Failed to load Switchboard Attestation program at ${attestationPid}, try manually providing a programId`
);
}
@ -332,41 +413,66 @@ export class SwitchboardProgram {
cluster,
connection,
payer,
pid
pid,
attestationPid
);
return program;
};
/**
* Retrieves the Switchboard Program ID for the currently connected cluster.
* @return The PublicKey of the Switchboard Program ID.
* Retrieves the Switchboard V2 Program ID for the currently connected cluster.
* @return The PublicKey of the Switchboard V2 Program ID.
*/
public get programId(): PublicKey {
return this._program.programId;
}
/**
* Retrieves the Switchboard Program IDL.
* @return The IDL of the Switchboard Program.
* Retrieves the Switchboard Attestation Program ID for the currently connected cluster.
* @return The PublicKey of the Switchboard Attestation Program ID.
*/
public get idl(): anchor.Idl {
public get attestationProgramId(): PublicKey {
return this._attestationProgram.programId;
}
/**
* Retrieves the Switchboard V2 Program IDL.
* @return The IDL of the Switchboard V2 Program.
*/
public get idl(): Idl {
return this._program.idl;
}
/**
* Retrieves the Switchboard Borsh Accounts Coder.
* @return The BorshAccountsCoder for the Switchboard Program.
* Retrieves the Switchboard Attestation Program IDL.
* @return The IDL of the Switchboard Attestation Program.
*/
public get coder(): anchor.BorshAccountsCoder {
return new anchor.BorshAccountsCoder(this._program.idl);
public get attestationIdl(): Idl {
return this._program.idl;
}
/**
* Retrieves the Switchboard V2 Borsh Accounts Coder.
* @return The BorshAccountsCoder for the Switchboard V2 Program.
*/
public get coder(): BorshAccountsCoder {
return new BorshAccountsCoder(this._program.idl);
}
/**
* Retrieves the Switchboard Attestatio Borsh Accounts Coder.
* @return The BorshAccountsCoder for the Switchboard Attestation Program.
*/
public get attestationCoder(): BorshAccountsCoder {
return new BorshAccountsCoder(this._attestationProgram.idl);
}
/**
* Retrieves the anchor Provider used by this program to connect with the Solana cluster.
* @return The AnchorProvider instance for the Switchboard Program.
*/
public get provider(): anchor.AnchorProvider {
return this._program.provider as anchor.AnchorProvider;
public get provider(): AnchorProvider {
return this._program.provider as AnchorProvider;
}
/**
@ -374,7 +480,7 @@ export class SwitchboardProgram {
* @return The Connection instance for the Switchboard Program.
*/
public get connection(): Connection {
return this._program.provider.connection;
return this.provider.connection;
}
/**
@ -430,13 +536,21 @@ export class SwitchboardProgram {
}
/**
* Retrieves the account namespace for the Switchboard Program.
* @return The AccountNamespace instance for the Switchboard Program.
* Retrieves the account namespace for the Switchboard V2 Program.
* @return The AccountNamespace instance for the Switchboard V2 Program.
*/
public get account(): anchor.AccountNamespace {
public get account(): AccountNamespace {
return this._program.account;
}
/**
* Retrieves the account namespace for the Switchboard Attestation Program.
* @return The AccountNamespace instance for the Switchboard Attestation Program.
*/
public get attestationAccount(): AccountNamespace {
return this._attestationProgram.account;
}
/**
* Load the Switchboard Labs permissionless Queue for either devnet or mainnet. The permissionless queue has the following permissions:
* - unpermissionedFeedsEnabled: True
@ -556,6 +670,37 @@ export class SwitchboardProgram {
return await this._program.removeEventListener(listenerId);
}
/**
* Adds an event listener for the specified AnchorEvent, allowing consumers to monitor the chain for events
* emitted from Switchboard's attestation program.
*
* @param eventName - The name of the event to listen for.
* @param callback - A callback function to handle the event data, slot, and signature.
* @return A unique listener ID that can be used to remove the event listener.
*/
public addAttestationEventListener<EventName extends keyof SwitchboardEvents>(
eventName: EventName,
callback: (
data: SwitchboardEvents[EventName],
slot: number,
signature: string
) => void | Promise<void>
): number {
return this._attestationProgram.addEventListener(
eventName as string,
callback
);
}
/**
* Removes the event listener with the specified listener ID.
*
* @param listenerId - The unique ID of the event listener to be removed.
*/
public async removeAttestationEventListener(listenerId: number) {
return await this._attestationProgram.removeEventListener(listenerId);
}
public async signAndSendAll(
txns: Array<TransactionObject>,
opts: SendTransactionOptions = DEFAULT_SEND_TRANSACTION_OPTIONS,
@ -588,7 +733,7 @@ export class SwitchboardProgram {
{
memcmp: {
offset: 0,
bytes: anchor.utils.bytes.bs58.encode(
bytes: AnchorUtils.bytes.bs58.encode(
JobAccountData.discriminator
),
},
@ -801,7 +946,7 @@ export const isVersionedTransaction = (tx): tx is VersionedTransaction => {
return "version" in tx;
};
export class AnchorWallet implements anchor.Wallet {
export class AnchorWallet implements Wallet {
constructor(readonly payer: Keypair) {}
get publicKey(): PublicKey {
@ -835,6 +980,6 @@ export class AnchorWallet implements anchor.Wallet {
}
interface AccountInfoResponse {
pubkey: anchor.web3.PublicKey;
account: anchor.web3.AccountInfo<Buffer>;
pubkey: PublicKey;
account: AccountInfo<Buffer>;
}

View File

@ -1,4 +1,5 @@
import { fromTxError } from "./generated/index.js";
import * as attestationTypes from "./generated/attestation-program/index.js";
import { fromTxError } from "./generated/oracle-program/errors/index.js";
import { isBrowser } from "./browser.js";
import * as errors from "./errors.js";
import {
@ -628,11 +629,22 @@ export class TransactionObject implements ITransactionObject {
});
} catch (error) {
const err = fromTxError(error);
if (err === null) {
throw error;
if (err) {
if (err.logs) {
console.error(err.logs);
}
throw err;
}
throw err;
const attestationErr = attestationTypes.fromAttestationTxError(error);
if (attestationErr) {
if (attestationErr.logs) {
console.error(attestationErr.logs);
}
throw attestationErr;
}
throw error;
}
}
}

View File

@ -10,7 +10,7 @@ import {
SbState,
SlidingResultAccountData,
VrfAccountData,
} from "../generated/index.js";
} from "../generated/oracle-program/index.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import { AggregatorAccount } from "./aggregatorAccount.js";

View File

@ -1,5 +1,35 @@
import * as errors from "../errors.js";
import * as types from "../generated/index.js";
import {
AggregatorAccountData,
AggregatorAccountDataFields,
AggregatorAccountDataJSON,
} from "../generated/oracle-program/accounts/AggregatorAccountData.js";
import {
JobAccountData,
JobAccountDataJSON,
} from "../generated/oracle-program/accounts/JobAccountData.js";
import {
LeaseAccountData,
LeaseAccountDataJSON,
} from "../generated/oracle-program/accounts/LeaseAccountData.js";
import { OracleAccountData } from "../generated/oracle-program/accounts/OracleAccountData.js";
import {
OracleQueueAccountData,
OracleQueueAccountDataJSON,
} from "../generated/oracle-program/accounts/OracleQueueAccountData.js";
import {
PermissionAccountData,
PermissionAccountDataJSON,
} from "../generated/oracle-program/accounts/PermissionAccountData.js";
import * as ix from "../generated/oracle-program/instructions/index.js";
import {
AggregatorHistoryRow,
AggregatorResolutionMode,
AggregatorResolutionModeKind,
BorshDecimal,
} from "../generated/oracle-program/types/index.js";
import { SwitchboardDecimal } from "../generated/oracle-program/types/SwitchboardDecimal.js";
import { PermitOracleQueueUsage } from "../generated/oracle-program/types/SwitchboardPermission.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import {
SendTransactionObjectOptions,
@ -39,16 +69,16 @@ import {
toUtf8,
} from "@switchboard-xyz/common";
import assert from "assert";
import crypto from "crypto";
import crypto, { createHash } from "crypto";
/**
* Account type holding a data feed's update configuration, job accounts, and its current result.
*
* Data: {@linkcode types.AggregatorAccountData}
* Data: {@linkcode AggregatorAccountData}
*
* Result: {@linkcode types.SwitchboardDecimal}
* Result: {@linkcode SwitchboardDecimal}
*
* HistoryBuffer?: Array<{@linkcode types.AggregatorHistoryRow}>
* HistoryBuffer?: Array<{@linkcode AggregatorHistoryRow}>
*
* An aggregator account belongs to a single {@linkcode QueueAccount} but can later be transferred by the aggregator's authority. In order for an {@linkcode OracleAccount} to respond to an aggregator's update request, the aggregator must initialize a {@linkcode PermissionAccount} and {@linkcode LeaseAccount}. These will need to be recreated when transferring queues.
*
@ -56,7 +86,7 @@ import crypto from "crypto";
*
* Optionally, an aggregator can add a history buffer to store the last N historical samples along with their update timestamp.
*/
export class AggregatorAccount extends Account<types.AggregatorAccountData> {
export class AggregatorAccount extends Account<AggregatorAccountData> {
static accountName = "AggregatorAccountData";
public history?: AggregatorHistoryBuffer;
@ -64,12 +94,12 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
/**
* Returns the aggregator's name buffer in a stringified format.
*/
public static getName = (aggregator: types.AggregatorAccountData) =>
public static getName = (aggregator: AggregatorAccountData) =>
toUtf8(aggregator.name);
/**
* Returns the aggregator's metadata buffer in a stringified format.
*/
public static getMetadata = (aggregator: types.AggregatorAccountData) =>
public static getMetadata = (aggregator: AggregatorAccountData) =>
toUtf8(aggregator.metadata);
public static size = 3851;
@ -79,11 +109,11 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
*/
public size = this.program.account.aggregatorAccountData.size;
public decode(data: Buffer): types.AggregatorAccountData {
public decode(data: Buffer): AggregatorAccountData {
try {
return types.AggregatorAccountData.decode(data);
return AggregatorAccountData.decode(data);
} catch {
return this.program.coder.decode<types.AggregatorAccountData>(
return this.program.coder.decode<AggregatorAccountData>(
AggregatorAccount.accountName,
data
);
@ -93,10 +123,10 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
/**
* Return an aggregator account state initialized to the default values.
*/
public static default(): types.AggregatorAccountData {
public static default(): AggregatorAccountData {
const buffer = Buffer.alloc(AggregatorAccount.size, 0);
types.AggregatorAccountData.discriminator.copy(buffer, 0);
return types.AggregatorAccountData.decode(buffer);
AggregatorAccountData.discriminator.copy(buffer, 0);
return AggregatorAccountData.decode(buffer);
}
/**
@ -104,22 +134,22 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
*/
public static createMock(
programId: PublicKey,
data: Partial<types.AggregatorAccountData>,
data: Partial<AggregatorAccountData>,
options?: {
lamports?: number;
rentEpoch?: number;
}
): AccountInfo<Buffer> {
const fields: types.AggregatorAccountDataFields = {
const fields: AggregatorAccountDataFields = {
...AggregatorAccount.default(),
...data,
// any cleanup actions here
};
const state = new types.AggregatorAccountData(fields);
const state = new AggregatorAccountData(fields);
const buffer = Buffer.alloc(AggregatorAccount.size, 0);
types.AggregatorAccountData.discriminator.copy(buffer, 0);
types.AggregatorAccountData.layout.encode(state, buffer, 8);
AggregatorAccountData.discriminator.copy(buffer, 0);
AggregatorAccountData.layout.encode(state, buffer, 8);
return {
executable: false,
@ -137,7 +167,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
* @returns the websocket subscription id
*/
public onChange(
callback: OnAccountChangeCallback<types.AggregatorAccountData>,
callback: OnAccountChangeCallback<AggregatorAccountData>,
commitment: Commitment = "confirmed"
): number {
return this.program.connection.onAccountChange(
@ -150,10 +180,10 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
}
/**
* Retrieve and decode the {@linkcode types.AggregatorAccountData} stored in this account.
* Retrieve and decode the {@linkcode AggregatorAccountData} stored in this account.
*/
public async loadData(): Promise<types.AggregatorAccountData> {
const data = await types.AggregatorAccountData.fetch(
public async loadData(): Promise<AggregatorAccountData> {
const data = await AggregatorAccountData.fetch(
this.program,
this.publicKey
);
@ -174,7 +204,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
public static async load(
program: SwitchboardProgram,
publicKey: PublicKey | string
): Promise<[AggregatorAccount, types.AggregatorAccountData]> {
): Promise<[AggregatorAccount, AggregatorAccountData]> {
const account = new AggregatorAccount(
program,
typeof publicKey === "string" ? new PublicKey(publicKey) : publicKey
@ -244,7 +274,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
);
ixns.push(
types.aggregatorInit(
ix.aggregatorInit(
program,
{
params: {
@ -257,7 +287,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
minJobResults: params.minRequiredJobResults,
minUpdateDelaySeconds: params.minUpdateDelaySeconds,
startAfter: new BN(params.startAfter ?? 0),
varianceThreshold: types.SwitchboardDecimal.fromBig(
varianceThreshold: SwitchboardDecimal.fromBig(
new Big(params.varianceThreshold ?? 0)
).borsh,
forceReportPeriod: new BN(params.forceReportPeriod ?? 0),
@ -275,10 +305,15 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
)
);
const aggregatorInit = new TransactionObject(payer, ixns, signers, options);
const aggregatorInitTxn = new TransactionObject(
payer,
ixns,
signers,
options
);
const aggregatorAccount = new AggregatorAccount(program, keypair.publicKey);
return [aggregatorAccount, aggregatorInit];
return [aggregatorAccount, aggregatorInitTxn];
}
/**
@ -462,7 +497,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
const permissionSet = permissionAccount.setInstruction(payer, {
enable: params.enable,
queueAuthority: params.queueAuthority,
permission: new types.SwitchboardPermission.PermitOracleQueueUsage(),
permission: new PermitOracleQueueUsage(),
});
return [permissionSet, permissionAccount];
@ -547,7 +582,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
const setQueueTxn = new TransactionObject(
payer,
[
types.aggregatorSetQueue(
ix.aggregatorSetQueue(
this.program,
{ params: {} },
{
@ -763,7 +798,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
* ```
*/
public static decodeLatestValue(
aggregator: types.AggregatorAccountData
aggregator: AggregatorAccountData
): Big | null {
if ((aggregator.latestConfirmedRound?.numSuccess ?? 0) === 0) {
return null;
@ -805,9 +840,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
* console.log("Latest confirmed round timestamp:", latestTimestamp.toString());
* ```
*/
public static decodeLatestTimestamp(
aggregator: types.AggregatorAccountData
): BN {
public static decodeLatestTimestamp(aggregator: AggregatorAccountData): BN {
if ((aggregator.latestConfirmedRound?.numSuccess ?? 0) === 0) {
throw new Error("Aggregator currently holds no value.");
}
@ -831,7 +864,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
* ```
*/
public static decodeConfirmedRoundResults(
aggregator: types.AggregatorAccountData
aggregator: AggregatorAccountData
): Array<{ oraclePubkeys: PublicKey; value: Big }> {
if ((aggregator.latestConfirmedRound?.numSuccess ?? 0) === 0) {
throw new Error("Aggregator currently holds no value.");
@ -864,7 +897,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
* ```
*/
public getConfirmedRoundResults(
aggregator: types.AggregatorAccountData
aggregator: AggregatorAccountData
): Array<{ oracleAccount: OracleAccount; value: Big }> {
return AggregatorAccount.decodeConfirmedRoundResults(aggregator).map(
(o) => {
@ -902,7 +935,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
}
public static decodeCurrentRoundOracles(
aggregator: types.AggregatorAccountData
aggregator: AggregatorAccountData
): Array<PublicKey> {
return aggregator.currentRound.oraclePubkeysData.slice(
0,
@ -911,10 +944,8 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
}
public async loadCurrentRoundOracles(
aggregator: types.AggregatorAccountData
): Promise<
Array<{ account: OracleAccount; state: types.OracleAccountData }>
> {
aggregator: AggregatorAccountData
): Promise<Array<{ account: OracleAccount; state: OracleAccountData }>> {
return await Promise.all(
AggregatorAccount.decodeCurrentRoundOracles(aggregator).map(async (o) => {
const oracleAccount = new OracleAccount(this.program, o);
@ -927,15 +958,15 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
}
public static decodeJobPubkeys(
aggregator: types.AggregatorAccountData
aggregator: AggregatorAccountData
): Array<PublicKey> {
return aggregator.jobPubkeysData.slice(0, aggregator.jobPubkeysSize);
}
public async loadJobs(aggregator: types.AggregatorAccountData): Promise<
public async loadJobs(aggregator: AggregatorAccountData): Promise<
Array<{
account: JobAccount;
state: types.JobAccountData;
state: JobAccountData;
job: OracleJob;
weight: number;
}>
@ -959,7 +990,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
);
}
const jobAccount = new JobAccount(this.program, j.publicKey);
const jobState: types.JobAccountData = this.program.coder.decode(
const jobState: JobAccountData = this.program.coder.decode(
"JobAccountData",
j.account.data
);
@ -983,7 +1014,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
public getJobHashes(
jobs: Array<{
account: JobAccount;
state: types.JobAccountData;
state: JobAccountData;
}>
): Array<Buffer> {
return jobs.map((j) => Buffer.from(new Uint8Array(j.state.hash)));
@ -1020,7 +1051,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
*/
public static verifyConfig(
aggregator:
| types.AggregatorAccountData
| AggregatorAccountData
| {
oracleRequestBatchSize: number;
minOracleResults: number;
@ -1028,7 +1059,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
minUpdateDelaySeconds: number;
jobPubkeysSize: number;
},
queue: types.OracleQueueAccountData,
queue: OracleQueueAccountData,
target: {
batchSize?: number;
minOracleResults?: number;
@ -1119,7 +1150,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
*/
public verifyConfig(
aggregator:
| types.AggregatorAccountData
| AggregatorAccountData
| {
oracleRequestBatchSize: number;
minOracleResults: number;
@ -1127,7 +1158,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
minUpdateDelaySeconds: number;
jobPubkeysSize: number;
},
queue: types.OracleQueueAccountData,
queue: OracleQueueAccountData,
target: {
batchSize?: number;
minOracleResults?: number;
@ -1207,7 +1238,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
}
const varianceThreshold = params.varianceThreshold ?? 0;
const setConfigIxn = types.aggregatorSetConfig(
const setConfigIxn = ix.aggregatorSetConfig(
this.program,
{
params: {
@ -1228,8 +1259,8 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
forceReportPeriod: params.forceReportPeriod ?? null,
varianceThreshold:
varianceThreshold >= 0
? new types.BorshDecimal(
types.SwitchboardDecimal.fromBig(new Big(varianceThreshold))
? new BorshDecimal(
SwitchboardDecimal.fromBig(new Big(varianceThreshold))
)
: null,
basePriorityFee: params.basePriorityFee ?? null,
@ -1320,7 +1351,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
},
options?: TransactionObjectOptions
): TransactionObject {
const setQueueIxn = types.aggregatorSetQueue(
const setQueueIxn = ix.aggregatorSetQueue(
this.program,
{
params: {},
@ -1365,7 +1396,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
options?: TransactionObjectOptions
): TransactionObject {
const authority = params.authority ? params.authority.publicKey : payer;
const addJobIxn = types.aggregatorAddJob(
const addJobIxn = ix.aggregatorAddJob(
this.program,
{ params: { weight: params.weight ?? 1 } },
{
@ -1409,7 +1440,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
return new TransactionObject(
payer,
[
types.aggregatorLock(
ix.aggregatorLock(
this.program,
{ params: {} },
{
@ -1449,7 +1480,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
return new TransactionObject(
payer,
[
types.aggregatorSetAuthority(
ix.aggregatorSetAuthority(
this.program,
{ params: {} },
{
@ -1538,7 +1569,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
options?: TransactionObjectOptions
): TransactionObject {
const authority = params.authority ? params.authority.publicKey : payer;
const removeJobIxn = types.aggregatorRemoveJob(
const removeJobIxn = ix.aggregatorRemoveJob(
this.program,
{ params: { jobIdx: params.jobIdx } },
{
@ -1605,7 +1636,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
}
ixns.push(
types.aggregatorOpenRound(
ix.aggregatorOpenRound(
this.program,
{
params: {
@ -1649,6 +1680,92 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
return txnSignature;
}
public quoteKeypairFromSeed(seed: PublicKey): Keypair {
const hash = createHash("sha256");
hash.update(Buffer.from("QuoteAccountData"));
hash.update(seed.toBuffer());
const kp = Keypair.fromSeed(hash.digest());
return kp;
}
public teeSaveResultInstructionSync(
payer: PublicKey,
params: AggregatorSaveResultSyncParams & {
quotePubkey?: PublicKey;
authority: Keypair;
},
options?: TransactionObjectOptions
): TransactionObject {
const [oraclePermissionAccount, oraclePermissionBump] =
params.oraclePermission;
const quote =
params.quotePubkey ??
this.quoteKeypairFromSeed(
params.oracles[params.oracleIdx].state.oracleAuthority
).publicKey;
const saveResultIxn = ix.aggregatorTeeSaveResult(
this.program,
{
params: {
// oracleIdx: params.oracleIdx,
// error: params.error ?? false,
value: SwitchboardDecimal.fromBig(params.value).borsh,
jobsChecksum: [...this.produceJobsHash(params.jobs).digest()],
minResponse: SwitchboardDecimal.fromBig(params.minResponse).borsh,
maxResponse: SwitchboardDecimal.fromBig(params.maxResponse).borsh,
feedPermissionBump: params.permissionBump,
oraclePermissionBump: oraclePermissionBump,
leaseBump: params.leaseBump,
stateBump: this.program.programState.bump,
},
},
{
aggregator: this.publicKey,
oracle: params.oracles[params.oracleIdx].account.publicKey,
oracleAuthority: params.oracles[params.oracleIdx].state.oracleAuthority,
oracleQueue: params.queueAccount.publicKey,
queueAuthority: params.queueAuthority,
feedPermission: params.permissionAccount.publicKey,
oraclePermission: oraclePermissionAccount.publicKey,
lease: params.leaseAccount.publicKey,
escrow: params.leaseEscrow,
tokenProgram: spl.TOKEN_PROGRAM_ID,
programState: this.program.programState.publicKey,
historyBuffer: params.historyBuffer ?? this.publicKey,
mint: this.program.mint.address,
slider: this.slidingWindowKey,
quote: quote,
rewardWallet: this.program.mint.getAssociatedAddress(payer),
payer: payer,
systemProgram: SystemProgram.programId,
}
);
const remainingAccounts: Array<PublicKey> = [];
params.oracles.forEach((oracle) =>
remainingAccounts.push(oracle.account.publicKey)
);
params.oracles.forEach((oracle) =>
remainingAccounts.push(oracle.state.tokenAccount)
);
remainingAccounts.push(this.slidingWindowKey);
saveResultIxn.keys.push(
...remainingAccounts.map((pubkey): AccountMeta => {
return { isSigner: false, isWritable: true, pubkey };
})
);
return new TransactionObject(
payer,
[saveResultIxn],
[params.authority],
options
);
}
public saveResultInstructionSync(
payer: PublicKey,
params: AggregatorSaveResultSyncParams,
@ -1661,18 +1778,16 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
throw new Error("Failed to find oracle in current round");
}
const saveResultIxn = types.aggregatorSaveResult(
const saveResultIxn = ix.aggregatorSaveResult(
this.program,
{
params: {
oracleIdx: params.oracleIdx,
error: params.error ?? false,
value: types.SwitchboardDecimal.fromBig(params.value).borsh,
value: SwitchboardDecimal.fromBig(params.value).borsh,
jobsChecksum: [...this.produceJobsHash(params.jobs).digest()],
minResponse: types.SwitchboardDecimal.fromBig(params.minResponse)
.borsh,
maxResponse: types.SwitchboardDecimal.fromBig(params.maxResponse)
.borsh,
minResponse: SwitchboardDecimal.fromBig(params.minResponse).borsh,
maxResponse: SwitchboardDecimal.fromBig(params.maxResponse).borsh,
feedPermissionBump: params.permissionBump,
oraclePermissionBump: oraclePermissionBump,
leaseBump: params.leaseBump,
@ -1801,9 +1916,9 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
}
public async fetchAccounts(
_aggregator?: types.AggregatorAccountData,
_aggregator?: AggregatorAccountData,
_queueAccount?: QueueAccount,
_queue?: types.OracleQueueAccountData,
_queue?: OracleQueueAccountData,
commitment: Commitment = "confirmed"
): Promise<AggregatorAccounts> {
const aggregator = _aggregator ?? (await this.loadData());
@ -1841,7 +1956,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
`PermissionAccount has not been created yet for this aggregator`
);
}
const permission = types.PermissionAccountData.decode(
const permission = PermissionAccountData.decode(
permissionAccountInfo.account.data
);
@ -1851,7 +1966,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
`LeaseAccount has not been created yet for this aggregator`
);
}
const lease = types.LeaseAccountData.decode(leaseAccountInfo.account.data);
const lease = LeaseAccountData.decode(leaseAccountInfo.account.data);
const leaseEscrowAccountInfo = accountInfos.shift();
if (!leaseEscrowAccountInfo || !leaseEscrowAccountInfo.account) {
@ -1866,14 +1981,14 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
const jobs: Array<{
publicKey: PublicKey;
data: types.JobAccountData;
data: JobAccountData;
tasks: Array<OracleJob.ITask>;
}> = [];
accountInfos.map((accountInfo) => {
if (!accountInfo || !accountInfo.account) {
throw new Error(`Failed to fetch JobAccount`);
}
const job = types.JobAccountData.decode(accountInfo.account.data);
const job = JobAccountData.decode(accountInfo.account.data);
const oracleJob = OracleJob.decodeDelimited(job.data);
jobs.push({
publicKey: accountInfo.publicKey,
@ -1907,9 +2022,9 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
}
public async toAccountsJSON(
_aggregator?: types.AggregatorAccountData,
_aggregator?: AggregatorAccountData,
_queueAccount?: QueueAccount,
_queue?: types.OracleQueueAccountData
_queue?: OracleQueueAccountData
): Promise<AggregatorAccountsJSON> {
const accounts = await this.fetchAccounts(
_aggregator,
@ -1949,14 +2064,14 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
payer: PublicKey,
params: {
authority?: Keypair;
mode: types.AggregatorResolutionModeKind;
mode: AggregatorResolutionModeKind;
},
options?: TransactionObjectOptions
): TransactionObject {
return new TransactionObject(
payer,
[
types.aggregatorSetResolutionMode(
ix.aggregatorSetResolutionMode(
this.program,
{
params: { mode: params.mode.discriminator },
@ -1978,7 +2093,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
async setSlidingWindow(
params: {
authority?: Keypair;
mode: types.AggregatorResolutionModeKind;
mode: AggregatorResolutionModeKind;
},
options?: TransactionObjectOptions
): Promise<TransactionSignature> {
@ -1993,11 +2108,11 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
async openRoundAndAwaitResult(
params?: { payoutWallet?: PublicKey } & {
aggregator?: types.AggregatorAccountData;
aggregator?: AggregatorAccountData;
},
timeout = 30000,
options?: TransactionObjectOptions
): Promise<[types.AggregatorAccountData, TransactionSignature | undefined]> {
): Promise<[AggregatorAccountData, TransactionSignature | undefined]> {
const aggregator = params?.aggregator ?? (await this.loadData());
const currentRoundOpenSlot = aggregator.latestConfirmedRound.roundOpenSlot;
@ -2010,31 +2125,28 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
}
};
const statePromise: Promise<types.AggregatorAccountData> =
promiseWithTimeout(
timeout,
new Promise(
(resolve: (result: types.AggregatorAccountData) => void) => {
ws = this.onChange((aggregator) => {
// if confirmed round slot larger than last open slot
// AND sliding window mode or sufficient oracle results
if (
aggregator.latestConfirmedRound.roundOpenSlot.gt(
currentRoundOpenSlot
) &&
(aggregator.resolutionMode.kind ===
types.AggregatorResolutionMode.ModeSlidingResolution.kind ||
(aggregator.latestConfirmedRound.numSuccess ?? 0) >=
aggregator.minOracleResults)
) {
resolve(aggregator);
}
});
const statePromise: Promise<AggregatorAccountData> = promiseWithTimeout(
timeout,
new Promise((resolve: (result: AggregatorAccountData) => void) => {
ws = this.onChange((aggregator) => {
// if confirmed round slot larger than last open slot
// AND sliding window mode or sufficient oracle results
if (
aggregator.latestConfirmedRound.roundOpenSlot.gt(
currentRoundOpenSlot
) &&
(aggregator.resolutionMode.kind ===
AggregatorResolutionMode.ModeSlidingResolution.kind ||
(aggregator.latestConfirmedRound.numSuccess ?? 0) >=
aggregator.minOracleResults)
) {
resolve(aggregator);
}
)
).finally(async () => {
await closeWebsocket();
});
});
})
).finally(async () => {
await closeWebsocket();
});
const openRoundSignature = await this.openRound(params, options).catch(
async (error) => {
@ -2061,24 +2173,22 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
async nextRound(
roundOpenSlot?: BN,
timeout = 30000
): Promise<types.AggregatorAccountData> {
): Promise<AggregatorAccountData> {
const slot =
roundOpenSlot ?? (await this.loadData()).currentRound.roundOpenSlot;
let ws: number | undefined;
let result: types.AggregatorAccountData;
let result: AggregatorAccountData;
try {
result = await promiseWithTimeout(
timeout,
new Promise(
(resolve: (result: types.AggregatorAccountData) => void) => {
ws = this.onChange((aggregator) => {
if (aggregator.latestConfirmedRound.roundOpenSlot.eq(slot)) {
resolve(aggregator);
}
});
}
)
new Promise((resolve: (result: AggregatorAccountData) => void) => {
ws = this.onChange((aggregator) => {
if (aggregator.latestConfirmedRound.roundOpenSlot.eq(slot)) {
resolve(aggregator);
}
});
})
);
} finally {
if (ws) {
@ -2096,7 +2206,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
async loadHistory(
startTimestamp?: number,
endTimestamp?: number
): Promise<Array<types.AggregatorHistoryRow>> {
): Promise<Array<AggregatorHistoryRow>> {
if (!this.history) {
this.history = new AggregatorHistoryBuffer(
this.program,
@ -2116,12 +2226,12 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
): Promise<
Array<{
account: AggregatorAccount;
data: types.AggregatorAccountData;
data: AggregatorAccountData;
}>
> {
const aggregators: Array<{
account: AggregatorAccount;
data: types.AggregatorAccountData;
data: AggregatorAccountData;
}> = [];
const accountInfos = await anchor.utils.rpc.getMultipleAccounts(
@ -2136,9 +2246,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
}
try {
const account = new AggregatorAccount(program, accountInfo.publicKey);
const data = types.AggregatorAccountData.decode(
accountInfo.account.data
);
const data = AggregatorAccountData.decode(accountInfo.account.data);
aggregators.push({ account, data });
// eslint-disable-next-line no-empty
} catch {}
@ -2160,7 +2268,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
* @returns the solana priority fee to include in the save_result action
*/
public static calculatePriorityFee(
aggregator: types.AggregatorAccountData,
aggregator: AggregatorAccountData,
timestamp = Math.round(Date.now() / 1000),
baseFee = 0 // base compute unit price
): number {
@ -2586,21 +2694,21 @@ export interface AggregatorSaveResultParams {
/**
* List of parsed oracles.
*/
oracles: Array<types.OracleAccountData>;
oracles: Array<OracleAccountData>;
}
export type AggregatorAccountsJSON = types.AggregatorAccountDataJSON & {
export type AggregatorAccountsJSON = AggregatorAccountDataJSON & {
publicKey: PublicKey;
queue: types.OracleQueueAccountDataJSON & { publicKey: PublicKey };
permission: types.PermissionAccountDataJSON & {
queue: OracleQueueAccountDataJSON & { publicKey: PublicKey };
permission: PermissionAccountDataJSON & {
bump: number;
publicKey: PublicKey;
};
lease: types.LeaseAccountDataJSON & { bump: number; publicKey: PublicKey } & {
lease: LeaseAccountDataJSON & { bump: number; publicKey: PublicKey } & {
balance: number;
};
jobs: Array<
types.JobAccountDataJSON & {
JobAccountDataJSON & {
publicKey: PublicKey;
tasks: Array<OracleJob.ITask>;
}
@ -2609,26 +2717,26 @@ export type AggregatorAccountsJSON = types.AggregatorAccountDataJSON & {
export type AggregatorAccounts = {
aggregator: {
publicKey: PublicKey;
data: types.AggregatorAccountData;
data: AggregatorAccountData;
};
queue: {
publicKey: PublicKey;
data: types.OracleQueueAccountData;
data: OracleQueueAccountData;
};
permission: {
publicKey: PublicKey;
bump: number;
data: types.PermissionAccountData;
data: PermissionAccountData;
};
lease: {
publicKey: PublicKey;
bump: number;
balance: number;
data: types.LeaseAccountData;
data: LeaseAccountData;
};
jobs: Array<{
publicKey: PublicKey;
data: types.JobAccountData;
data: JobAccountData;
tasks: Array<OracleJob.ITask>;
}>;
};
@ -2651,13 +2759,13 @@ export type SaveResultResponse = {
};
export type SaveResultAccounts = AggregatorPdaAccounts & {
aggregator: types.AggregatorAccountData;
aggregator: AggregatorAccountData;
// queue
queueAccount: QueueAccount;
queueAuthority: PublicKey;
// oracle
oraclePermission: [PermissionAccount, number];
oracles: Array<{ account: OracleAccount; state: types.OracleAccountData }>;
oracles: Array<{ account: OracleAccount; state: OracleAccountData }>;
oracleIdx: number;
// history
historyBuffer?: PublicKey;

View File

@ -1,5 +1,5 @@
import * as errors from "../errors.js";
import * as types from "../generated/index.js";
import * as types from "../generated/oracle-program/index.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import {
SendTransactionObjectOptions,

View File

@ -0,0 +1,232 @@
import * as errors from "../errors.js";
import * as types from "../generated/attestation-program/index.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import {
SendTransactionObjectOptions,
TransactionObject,
TransactionObjectOptions,
} from "../TransactionObject.js";
import { Account } from "./account.js";
import {
Keypair,
PublicKey,
SystemProgram,
TransactionSignature,
} from "@solana/web3.js";
/**
* Parameters for initializing an {@linkcode AttestationPermissionAccount}
*/
export interface AttestationPermissionAccountInitParams {
granter: PublicKey;
grantee: PublicKey;
authority?: PublicKey;
}
/**
* Parameters for setting the permissions of a {@linkcode AttestationPermissionAccount}
*/
export interface AttestationPermissionSetParams {
enable: boolean;
/**
* The {@linkcode types.SwitchboardPermission} to set for the grantee.
*/
permission: types.SwitchboardAttestationPermissionKind;
/**
* The authority for the queue
*
* @default payer
*/
queueAuthority?: Keypair;
queue: PublicKey;
node: PublicKey;
}
/**
* Account type dictating the level of permissions between a granter and a grantee.
*
* Data: {@linkcode types.AttestationPermissionAccountData}
*/
export class AttestationPermissionAccount extends Account<types.AttestationPermissionAccountData> {
static accountName = "AttestationPermissionAccountData";
/**
* Load an existing PermissionAccount with its current on-chain state
*/
public static async load(
program: SwitchboardProgram,
authority: PublicKey | string,
granter: PublicKey | string,
grantee: PublicKey | string
): Promise<
[
AttestationPermissionAccount,
types.AttestationPermissionAccountData,
number
]
> {
program.verifyAttestation();
const [account, bump] = AttestationPermissionAccount.fromSeed(
program,
typeof authority === "string" ? new PublicKey(authority) : authority,
typeof granter === "string" ? new PublicKey(granter) : granter,
typeof grantee === "string" ? new PublicKey(grantee) : grantee
);
const state = await account.loadData();
return [account, state, bump];
}
/**
* Loads an AttestationPermissionAccount from the expected PDA seed format.
*
* @param program The Switchboard program for the current connection.
* @param authority The authority pubkey to be incorporated into the account seed.
* @param granter The granter pubkey to be incorporated into the account seed.
* @param grantee The grantee pubkey to be incorporated into the account seed.
*
* @return AttestationPermissionAccount and PDA bump.
*/
public static fromSeed(
program: SwitchboardProgram,
authority: PublicKey,
granter: PublicKey,
grantee: PublicKey
): [AttestationPermissionAccount, number] {
const [publicKey, bump] = PublicKey.findProgramAddressSync(
[
Buffer.from("PermissionAccountData"),
authority.toBytes(),
granter.toBytes(),
grantee.toBytes(),
],
program.attestationProgramId
);
return [new AttestationPermissionAccount(program, publicKey), bump];
}
public static createInstruction(
program: SwitchboardProgram,
payer: PublicKey,
params: AttestationPermissionAccountInitParams,
options?: TransactionObjectOptions
): [AttestationPermissionAccount, TransactionObject] {
program.verifyAttestation();
const authority = params.authority ?? payer;
const [account] = AttestationPermissionAccount.fromSeed(
program,
authority,
params.granter,
params.grantee
);
const instruction = types.attestationPermissionInit(
program,
{ params: {} },
{
permission: account.publicKey,
attestationQueue: params.granter,
node: params.grantee,
authority,
payer,
systemProgram: SystemProgram.programId,
}
);
return [account, new TransactionObject(payer, [instruction], [], options)];
}
public static async create(
program: SwitchboardProgram,
params: AttestationPermissionAccountInitParams,
options?: SendTransactionObjectOptions
): Promise<[AttestationPermissionAccount, TransactionSignature]> {
const [account, txnObject] = this.createInstruction(
program,
program.walletPubkey,
params,
options
);
const txSignature = await program.signAndSend(txnObject, options);
return [account, txSignature];
}
/**
* Returns the size of an on-chain {@linkcode AttestationPermissionAccount}.
*/
public readonly size =
this.program.attestationAccount.attestationPermissionAccountData.size;
/**
* Retrieve and decode the {@linkcode types.AttestationPermissionAccountData} stored in this account.
*/
public async loadData(): Promise<types.AttestationPermissionAccountData> {
this.program.verifyAttestation();
const data = await types.AttestationPermissionAccountData.fetch(
this.program,
this.publicKey
);
if (data) return data;
throw new errors.AccountNotFoundError(
"Permissions (Attestation)",
this.publicKey
);
}
/**
* Produces the instruction to set the permission in the AttestationPermissionAccount
*/
public setInstruction(
payer: PublicKey,
params: AttestationPermissionSetParams,
options?: TransactionObjectOptions
): TransactionObject {
this.program.verifyAttestation();
// const data = await this.loadData();
return new TransactionObject(
payer,
[
types.attestationPermissionSet(
this.program,
{
params: {
permission: params.permission.discriminator,
enable: params.enable,
},
},
{
permission: this.publicKey,
authority: params.queueAuthority
? params.queueAuthority.publicKey
: payer,
attestationQueue: params.queue,
node: params.node,
}
),
],
params.queueAuthority ? [params.queueAuthority] : [],
options
);
}
/**
* Sets the permission in the AttestationPermissionAccount
*/
public async set(
params: AttestationPermissionSetParams,
options?: SendTransactionObjectOptions
): Promise<string> {
const setTxn = await this.setInstruction(
this.program.walletPubkey,
params,
options
);
const txnSignature = await this.program.signAndSend(setTxn, options);
return txnSignature;
}
}

View File

@ -0,0 +1,160 @@
import * as errors from "../errors.js";
import * as types from "../generated/attestation-program/index.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import { TransactionObject } from "../TransactionObject.js";
import { Account } from "./account.js";
import {
AccountInfo,
LAMPORTS_PER_SOL,
PublicKey,
SystemProgram,
TransactionSignature,
} from "@solana/web3.js";
/**
* Account type representing Switchboard global program state.
*
* Data: {@linkcode types.State}
*/
export class AttestationProgramStateAccount extends Account<types.State> {
static accountName = "State";
public static size = 1128;
/**
* @return account size of the global {@linkcode AttestationProgramStateAccount}.
*/
public readonly size = this.program.account.sbState.size;
/**
* Return a program state account state initialized to the default values.
*/
public static default(): types.State {
const buffer = Buffer.alloc(AttestationProgramStateAccount.size, 0);
types.State.discriminator.copy(buffer, 0);
return types.State.decode(buffer);
}
/**
* Create a mock account info for a given program state config. Useful for test integrations.
*/
public static createMock(
programId: PublicKey,
data: Partial<types.State>,
options?: {
lamports?: number;
rentEpoch?: number;
}
): AccountInfo<Buffer> {
const fields: types.StateFields = {
...AttestationProgramStateAccount.default(),
...data,
// any cleanup actions here
};
const state = new types.State(fields);
const buffer = Buffer.alloc(AttestationProgramStateAccount.size, 0);
types.State.discriminator.copy(buffer, 0);
types.State.layout.encode(state, buffer, 8);
return {
executable: false,
owner: programId,
lamports: options?.lamports ?? 1 * LAMPORTS_PER_SOL,
data: buffer,
rentEpoch: options?.rentEpoch ?? 0,
};
}
/** Load the AttestationProgramStateAccount with its current on-chain state */
public static async load(
program: SwitchboardProgram,
publicKey: PublicKey | string
): Promise<[AttestationProgramStateAccount, types.State]> {
const account = new AttestationProgramStateAccount(
program,
typeof publicKey === "string" ? new PublicKey(publicKey) : publicKey
);
const state = await account.loadData();
return [account, state];
}
/**
* Retrieve and decode the {@linkcode types.State} stored in this account.
*/
public async loadData(): Promise<types.State> {
const data = await types.State.fetch(this.program, this.publicKey);
if (data === null)
throw new errors.AccountNotFoundError(
"Attestation Program State",
this.publicKey
);
return data;
}
/**
* Retrieves the {@linkcode AttestationProgramStateAccount}, creates it if it doesn't exist;
*/
static async getOrCreate(
program: SwitchboardProgram
): Promise<
[AttestationProgramStateAccount, number, TransactionSignature | undefined]
> {
const [account, bump, txn] =
await AttestationProgramStateAccount.getOrCreateInstructions(
program,
program.walletPubkey
);
if (txn) {
const txnSignature = await program.signAndSend(txn);
return [account, bump, txnSignature];
}
return [account, bump, undefined];
}
static async getOrCreateInstructions(
program: SwitchboardProgram,
payer: PublicKey
): Promise<
[AttestationProgramStateAccount, number, TransactionObject | undefined]
> {
const [account, bump] = AttestationProgramStateAccount.fromSeed(program);
try {
await account.loadData();
return [account, bump, undefined];
} catch (e) {
const stateInit = types.stateInit(
program,
{ params: {} },
{
state: account.publicKey,
payer: payer,
systemProgram: SystemProgram.programId,
}
);
const programInit = new TransactionObject(payer, [stateInit], []);
return [account, bump, programInit];
}
}
/**
* Finds the {@linkcode AttestationProgramStateAccount} from the static seed from which it was generated.
* @return AttestationProgramStateAccount and PDA bump tuple.
*/
public static fromSeed(
program: SwitchboardProgram
): [AttestationProgramStateAccount, number] {
const [publicKey, bump] = PublicKey.findProgramAddressSync(
[Buffer.from("STATE")],
program.attestationProgramId
);
return [new AttestationProgramStateAccount(program, publicKey), bump];
}
}

View File

@ -0,0 +1,536 @@
import * as errors from "../errors.js";
import * as types from "../generated/attestation-program/index.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import {
SendTransactionObjectOptions,
TransactionObject,
TransactionObjectOptions,
} from "../TransactionObject.js";
import { RawBuffer } from "../types.js";
import { parseMrEnclave, parseRawBuffer } from "../utils.js";
import { Account } from "./account.js";
import {
AttestationPermissionAccount,
AttestationPermissionSetParams,
} from "./attestationPermissionAccount.js";
import { QuoteAccount, QuoteAccountInitParams } from "./quoteAccount.js";
import {
Keypair,
PublicKey,
SystemProgram,
TransactionInstruction,
TransactionSignature,
} from "@solana/web3.js";
/**
* Parameters for initializing an {@linkcode QueueAccount}
*/
export interface AttestationQueueAccountInitParams {
/**
* Rewards to provide oracles and round openers on this queue.
*/
reward: number;
/**
* @TODO: document this param
*/
allowAuthorityOverrideAfter: number;
/**
* @TODO: document this param
*/
maxQuoteVerificationAge: number;
/**
* A flag indicating whether usage authority is required to heartbeat.
*
* @default false
*/
requireAuthorityHeartbeatPermission: boolean;
/**
* A flag indicating whether usage permissions are required.
*
* @default false
*/
requireUsagePermissions: boolean;
/**
* Time period (in seconds) we should remove an oracle after if no response.
*
* @default 180
*/
nodeTimeout?: number;
/**
* A keypair to be used to address this account
*
* @default Keypair.generate()
*/
keypair?: Keypair;
/**
* An authority to be used to control this account.
*
* @default payer
*/
authority?: Keypair;
}
/**
* Parameters for an {@linkcode types.queueAddMrEnclave} instruction.
*/
export interface AttestationQueueAddMrEnclaveParams {
mrEnclave: RawBuffer;
authority?: Keypair;
}
/**
* Parameters for an {@linkcode types.queueRemoveMrEnclave} instruction.
*/
export interface AttestationQueueRemoveMrEnclaveParams {
mrEnclave: RawBuffer;
authority?: Keypair;
}
export type CreateQueueQuoteParams = Omit<
QuoteAccountInitParams,
"queueAccount"
> &
Partial<AttestationPermissionSetParams> & {
queueAuthorityPubkey?: PublicKey;
} & { createPermissions?: boolean };
/**
* Account type representing an oracle queue's configuration along with a buffer account holding a
* list of oracles that are actively heartbeating.
*
* A QueueAccount is responsible for allocating update requests to it's round robin queue of
* {@linkcode OracleAccount}'s.
*
* Data: {@linkcode types.AttestationQueueAccountData}
*
* Buffer: {@linkcode QueueDataBuffer}
*/
export class AttestationQueueAccount extends Account<types.AttestationQueueAccountData> {
static accountName = "AttestationQueueAccountData";
/**
* Get the size of an {@linkcode QueueAccount} on-chain.
*/
public readonly size =
this.program.attestationAccount.attestationQueueAccountData.size;
/**
* Retrieve and decode the {@linkcode types.PermissionAccountData} stored in this account.
*/
public async loadData(): Promise<types.AttestationQueueAccountData> {
this.program.verifyAttestation();
const data = await types.AttestationQueueAccountData.fetch(
this.program,
this.publicKey
);
if (data) return data;
throw new errors.AccountNotFoundError("AttestationQueue", this.publicKey);
}
/**
* Load an existing {@linkcode AttestationQueueAccount} with its current on-chain state
*/
public static async load(
program: SwitchboardProgram,
address: PublicKey | string
): Promise<[AttestationQueueAccount, types.AttestationQueueAccountData]> {
program.verifyAttestation();
const queueAccount = new AttestationQueueAccount(program, address);
const state = await queueAccount.loadData();
return [queueAccount, state];
}
public static createInstruction(
program: SwitchboardProgram,
payer: PublicKey,
params: AttestationQueueAccountInitParams,
options?: TransactionObjectOptions
): [AttestationQueueAccount, TransactionObject] {
program.verifyAttestation();
const queueKeypair = params.keypair ?? Keypair.generate();
program.verifyNewKeypair(queueKeypair);
const instruction = types.attestationQueueInit(
program,
{
params: {
reward: params.reward,
allowAuthorityOverrideAfter: params.allowAuthorityOverrideAfter,
maxQuoteVerificationAge: params.maxQuoteVerificationAge,
nodeTimeout: params.nodeTimeout ?? 180,
requireAuthorityHeartbeatPermission:
params.requireAuthorityHeartbeatPermission ?? false,
requireUsagePermissions: params.requireUsagePermissions ?? false,
},
},
{
queue: queueKeypair.publicKey,
authority: params.authority ? params.authority.publicKey : payer,
payer: payer,
systemProgram: SystemProgram.programId,
}
);
return [
new AttestationQueueAccount(program, queueKeypair.publicKey),
new TransactionObject(payer, [instruction], [queueKeypair], options),
];
}
public static async create(
program: SwitchboardProgram,
params: AttestationQueueAccountInitParams,
options?: SendTransactionObjectOptions
): Promise<[AttestationQueueAccount, TransactionSignature]> {
const [account, txnObject] = this.createInstruction(
program,
program.walletPubkey,
params,
options
);
return [account, await program.signAndSend(txnObject, options)];
}
public async createQuoteInstruction(
payer: PublicKey,
params: CreateQueueQuoteParams,
options?: TransactionObjectOptions
): Promise<[QuoteAccount, TransactionObject]> {
this.program.verifyAttestation();
const authority = params.authority ?? payer;
const queueAuthority =
params.queueAuthorityPubkey ?? (await this.loadData()).authority;
const [quoteAccount, quoteInit] = await QuoteAccount.createInstruction(
this.program,
payer,
{ ...params, queueAccount: this, authority },
options
);
if (!params.createPermissions && !params.enable) {
return [quoteAccount, quoteInit];
}
const [permissionAccount, permissionInit] =
AttestationPermissionAccount.createInstruction(
this.program,
payer,
{
granter: this.publicKey,
grantee: quoteAccount.publicKey,
authority: queueAuthority,
},
options
);
if (params.enable) {
const permissionSet = permissionAccount.setInstruction(payer, {
enable: true,
permission:
new types.SwitchboardAttestationPermission.PermitNodeheartbeat(),
queue: this.publicKey,
node: quoteAccount.publicKey,
});
permissionInit.combine(permissionSet);
}
return [quoteAccount, quoteInit.combine(permissionInit)];
}
public async createQuote(
params: CreateQueueQuoteParams,
options?: SendTransactionObjectOptions
): Promise<[QuoteAccount, TransactionSignature]> {
const [account, txnObject] = await this.createQuoteInstruction(
this.program.walletPubkey,
params,
options
);
return [account, await this.program.signAndSend(txnObject, options)];
}
/**
* Find the index of an enclave in an array and return -1 if not found
*/
public static findEnclaveIdx(
enclaves: Array<Uint8Array>,
enclave: Uint8Array
): number {
for (const [n, e] of enclaves.entries()) {
if (Buffer.compare(e, enclave) === 0) {
return n;
}
}
return -1;
}
public async addMrEnclaveInstruction(
payer: PublicKey,
params: AttestationQueueAddMrEnclaveParams,
options?: TransactionObjectOptions
): Promise<TransactionObject> {
this.program.verifyAttestation();
const authority = params.authority?.publicKey ?? payer;
const signers = params.authority ? [params.authority] : [];
const instruction = types.attestationQueueAddMrEnclave(
this.program,
{ params: { mrEnclave: Array.from(parseMrEnclave(params.mrEnclave)) } },
{ authority, queue: this.publicKey }
);
return new TransactionObject(payer, [instruction], signers, options);
}
public async addMrEnclave(
params: AttestationQueueAddMrEnclaveParams,
options?: SendTransactionObjectOptions
): Promise<TransactionSignature> {
return await this.addMrEnclaveInstruction(
this.program.walletPubkey,
params,
options
).then((txn) => this.program.signAndSend(txn, options));
}
public async removeMrEnclaveInstruction(
payer: PublicKey,
params: AttestationQueueRemoveMrEnclaveParams,
options?: TransactionObjectOptions
): Promise<TransactionObject> {
this.program.verifyAttestation();
const authority = params.authority?.publicKey ?? payer;
const signers = params.authority ? [params.authority] : [];
const instruction = types.attestationQueueRemoveMrEnclave(
this.program,
{ params: { mrEnclave: Array.from(parseMrEnclave(params.mrEnclave)) } },
{ authority, queue: this.publicKey }
);
return new TransactionObject(payer, [instruction], signers, options);
}
public async removeMrEnclave(
params: AttestationQueueRemoveMrEnclaveParams,
options?: SendTransactionObjectOptions
): Promise<TransactionSignature> {
return await this.removeMrEnclaveInstruction(
this.program.walletPubkey,
params,
options
).then((txn) => this.program.signAndSend(txn, options));
}
/**
* Create a new attestation queue for internal testing
* - Creates AttestationQueue account
* - Creates a Quote verifier
* - Sets the quote verifier secured signer
* - Adds Quote verifier to the queue
*/
public static async bootstrapNewQueue(
program: SwitchboardProgram,
params?: CreateBootstrappedQueueParams,
options?: SendTransactionObjectOptions
): Promise<
BootstrappedAttestationQueue & { signatures?: Array<TransactionSignature> }
> {
const authority: Keypair = params?.authority ?? program.wallet.payer;
const attestationQueueKeypair = params?.keypair ?? Keypair.generate();
const verifierQuoteKeypair1 = Keypair.generate();
const verifierQuoteSigner1 = params?.securedSigner ?? Keypair.generate();
const ixns: Array<TransactionInstruction> = [];
const signers: Array<Keypair> = [
authority,
attestationQueueKeypair,
verifierQuoteKeypair1,
verifierQuoteSigner1,
];
// create attestation queue
ixns.push(
types.attestationQueueInit(
program,
{
params: {
reward: params?.reward ?? 0,
allowAuthorityOverrideAfter:
params?.allowAuthorityOverrideAfter ?? 300,
maxQuoteVerificationAge: params?.maxQuoteVerificationAge ?? 604800,
nodeTimeout: params?.nodeTimeout ?? 180,
requireAuthorityHeartbeatPermission:
params?.requireAuthorityHeartbeatPermission ?? false,
requireUsagePermissions: params?.requireUsagePermissions ?? false,
},
},
{
queue: attestationQueueKeypair.publicKey,
authority: authority.publicKey,
payer: authority.publicKey,
systemProgram: SystemProgram.programId,
}
)
);
// add mrEnclave
ixns.push(
types.attestationQueueAddMrEnclave(
program,
{
params: {
mrEnclave: Array.from(
parseMrEnclave(params?.quoteVerifierMrEnclave ?? "")
),
},
},
{
queue: attestationQueueKeypair.publicKey,
authority: authority.publicKey,
}
)
);
// create quote #1
ixns.push(
types.quoteInit(
program,
{
params: {
registryKey: parseRawBuffer(params?.registryKey ?? "", 64),
},
},
{
quote: verifierQuoteKeypair1.publicKey,
attestationQueue: attestationQueueKeypair.publicKey,
queueAuthority: authority.publicKey,
authority: authority.publicKey,
payer: authority.publicKey,
systemProgram: SystemProgram.programId,
}
)
);
// create & set quote #1 permissions
const [verifierQuotePermissions1] = AttestationPermissionAccount.fromSeed(
program,
authority.publicKey,
attestationQueueKeypair.publicKey,
verifierQuoteKeypair1.publicKey
);
ixns.push(
types.attestationPermissionInit(
program,
{ params: {} },
{
permission: verifierQuotePermissions1.publicKey,
attestationQueue: attestationQueueKeypair.publicKey,
node: verifierQuoteKeypair1.publicKey,
authority: authority.publicKey,
payer: authority.publicKey,
systemProgram: SystemProgram.programId,
}
)
);
ixns.push(
types.attestationPermissionSet(
program,
{
params: {
permission: 1, // Permit_Node_Heartbeat
enable: true,
},
},
{
permission: verifierQuotePermissions1.publicKey,
authority: authority.publicKey,
attestationQueue: attestationQueueKeypair.publicKey,
node: verifierQuoteKeypair1.publicKey,
}
)
);
// set quote #1 securedSigner
ixns.push(
types.quoteRotate(
program,
{
params: {
registryKey: Array.from(
parseRawBuffer(params?.registryKey ?? "", 64)
),
},
},
{
quote: verifierQuoteKeypair1.publicKey,
authority: authority.publicKey,
securedSigner: verifierQuoteSigner1.publicKey,
attestationQueue: attestationQueueKeypair.publicKey,
}
)
);
// quote #1 heartbeat
ixns.push(
types.quoteHeartbeat(
program,
{ params: {} },
{
quote: verifierQuoteKeypair1.publicKey,
securedSigner: verifierQuoteSigner1.publicKey,
attestationQueue: attestationQueueKeypair.publicKey,
queueAuthority: authority.publicKey,
gcNode: verifierQuoteKeypair1.publicKey,
permission: verifierQuotePermissions1.publicKey,
}
)
);
const txns = TransactionObject.packIxns(
program.walletPubkey,
ixns,
signers,
options
);
const signatures = await program.signAndSendAll(txns, options);
const attestationQueueAccount = new AttestationQueueAccount(
program,
attestationQueueKeypair.publicKey
);
return {
attestationQueueAccount,
signatures,
verifier: {
quoteAccount: new QuoteAccount(
program,
verifierQuoteKeypair1.publicKey
),
permissionAccount: verifierQuotePermissions1,
signer: verifierQuoteSigner1,
},
};
}
}
export type CreateBootstrappedQueueParams =
AttestationQueueAccountInitParams & {
quoteVerifierMrEnclave: RawBuffer;
registryKey: RawBuffer;
securedSigner?: Keypair;
};
type BootstrappedAttestationQueue = {
attestationQueueAccount: AttestationQueueAccount;
verifier: {
quoteAccount: QuoteAccount;
permissionAccount: AttestationPermissionAccount;
signer: Keypair;
};
};

View File

@ -1,6 +1,6 @@
import * as errors from "../errors.js";
import { bufferRelayerSaveResult } from "../generated/index.js";
import * as types from "../generated/index.js";
import { bufferRelayerSaveResult } from "../generated/oracle-program/index.js";
import * as types from "../generated/oracle-program/index.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import {
TransactionObject,

View File

@ -1,5 +1,5 @@
import * as errors from "../errors.js";
import * as types from "../generated/index.js";
import * as types from "../generated/oracle-program/index.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import {
SendTransactionObjectOptions,

View File

@ -1,5 +1,5 @@
import * as errors from "../errors.js";
import * as types from "../generated/index.js";
import * as types from "../generated/oracle-program/index.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import {

View File

@ -0,0 +1,654 @@
import { Account } from "../accounts/account.js";
import * as errors from "../errors.js";
import * as types from "../generated/attestation-program/index.js";
import {
SB_ATTESTATION_PID,
SB_V2_PID,
SwitchboardProgram,
} from "../SwitchboardProgram.js";
import {
SendTransactionObjectOptions,
TransactionObject,
TransactionObjectOptions,
} from "../TransactionObject.js";
import { parseCronSchedule, parseMrEnclave } from "../utils.js";
import {
AttestationPermissionAccount,
AttestationQueueAccount,
QuoteAccount,
} from "./index.js";
import * as anchor from "@coral-xyz/anchor";
import * as spl from "@solana/spl-token";
import {
ASSOCIATED_TOKEN_PROGRAM_ID,
TOKEN_PROGRAM_ID,
} from "@solana/spl-token";
import {
AddressLookupTableAccount,
Keypair,
PublicKey,
SystemProgram,
TransactionInstruction,
TransactionSignature,
} from "@solana/web3.js";
import { BN, toUtf8 } from "@switchboard-xyz/common";
/**
* Parameters for initializing an {@linkcode FunctionAccount}
*/
export interface FunctionAccountInitParams {
name?: string;
metadata?: string;
container: string;
version: string;
containerRegistry?: string;
schedule: string;
mrEnclave: Buffer | Uint8Array | number[];
attestationQueue: AttestationQueueAccount;
/**
* A keypair to be used to address this account.
*
* @default Keypair.generate()
*/
keypair?: Keypair;
/**
* An authority to be used to control this account.
*
* @default payer
*/
authority?: Keypair;
}
/**
* Parameters for an {@linkcode types.functionFund} instruction.
*/
export interface FunctionFundParams {
/**
* The amount to fund this function with.
*/
fundAmount: number;
/**
* _OPTIONAL_ The token account to fund the lease from. Defaults to payer's associated token account.
*/
funderTokenWallet?: PublicKey;
/**
* _OPTIONAL_ The funderTokenWallet authority if it differs from the provided payer.
*/
funderAuthority?: Keypair;
}
interface FunctionWithdrawBaseParams {
amount: number | "all";
unwrap: boolean;
}
export interface FunctionWithdrawUnwrapParams
extends FunctionWithdrawBaseParams {
unwrap: true;
}
export interface FunctionWithdrawWalletParams
extends FunctionWithdrawBaseParams {
unwrap: false;
withdrawWallet: PublicKey;
withdrawAuthority?: Keypair;
}
/**
* Parameters for an {@linkcode types.functionWithdraw} instruction.
*/
export type FunctionWithdrawParams =
| FunctionWithdrawUnwrapParams
| FunctionWithdrawWalletParams;
/**
* Parameters for an {@linkcode types.functionVerify} instruction.
*/
export interface FunctionVerifyParams {
observedTime: anchor.BN;
nextAllowedTimestamp: anchor.BN;
isFailure: boolean;
mrEnclave: Uint8Array;
verifier: QuoteAccount;
fnSigner: PublicKey;
}
/**
* Account type representing a Switchboard Function.
*
* Data: {@linkcode types.FunctionAccountData}
*/
export class FunctionAccount extends Account<types.FunctionAccountData> {
static accountName = "FunctionAccountData";
/**
* Returns the functions's name buffer in a stringified format.
*/
public static getName = (functionData: types.FunctionAccountData) =>
toUtf8(functionData.name);
/**
* Returns the functions's metadata buffer in a stringified format.
*/
public static getMetadata = (functionData: types.FunctionAccountData) =>
toUtf8(functionData.metadata);
/**
* Load an existing {@linkcode FunctionAccount} with its current on-chain state
*/
/**
* Get the size of an {@linkcode FunctionAccount} on-chain.
*/
public readonly size =
this.program.attestationAccount.functionAccountData.size;
/**
* Retrieve and decode the {@linkcode types.FunctionAccountData} stored in this account.
*/
public async loadData(): Promise<types.FunctionAccountData> {
const data = await types.FunctionAccountData.fetch(
this.program,
this.publicKey
);
if (data) return data;
throw new errors.AccountNotFoundError("Function", this.publicKey);
}
public static async load(
program: SwitchboardProgram,
address: PublicKey | string
): Promise<[FunctionAccount, types.FunctionAccountData]> {
program.verifyAttestation();
const functionAccount = new FunctionAccount(program, address);
const state = await functionAccount.loadData();
return [functionAccount, state];
}
public static async createInstruction(
program: SwitchboardProgram,
payer: PublicKey,
params: FunctionAccountInitParams,
options?: TransactionObjectOptions
): Promise<[FunctionAccount, TransactionObject]> {
program.verifyAttestation();
const functionKeypair = params.keypair ?? Keypair.generate();
program.verifyNewKeypair(functionKeypair);
const authority = params.authority ? params.authority.publicKey : payer;
const cronSchedule = parseCronSchedule(params.schedule);
const attestationQueueAccount = params.attestationQueue;
const attestationQueue = await attestationQueueAccount.loadData();
const recentSlot = new BN(
(
await program.connection.getLatestBlockhashAndContext({
commitment: "finalized",
})
).context.slot
);
const addressLookupProgram = new PublicKey(
"AddressLookupTab1e1111111111111111111111111"
);
const [addressLookupTable] = PublicKey.findProgramAddressSync(
[authority.toBuffer(), recentSlot.toBuffer("le", 8)],
addressLookupProgram
);
// get PDA accounts
const functionAccount = new FunctionAccount(
program,
functionKeypair.publicKey
);
const [permissionAccount] = functionAccount.getPermissionAccount(
attestationQueueAccount.publicKey,
attestationQueue.authority
);
const [quoteAccount] = functionAccount.getQuoteAccount();
const escrow = functionAccount.getEscrow();
const instruction = types.functionInit(
program,
{
params: {
name: new Uint8Array(Buffer.from(params.name ?? "", "utf8")),
metadata: new Uint8Array(Buffer.from(params.metadata ?? "", "utf8")),
schedule: new Uint8Array(Buffer.from(cronSchedule, "utf8")),
container: new Uint8Array(Buffer.from(params.container, "utf8")),
version: new Uint8Array(Buffer.from(params.version, "utf8")),
containerRegistry: new Uint8Array(
Buffer.from(params.containerRegistry ?? "", "utf8")
),
mrEnclave: Array.from(parseMrEnclave(params.mrEnclave)),
recentSlot: recentSlot,
},
},
{
function: functionAccount.publicKey,
addressLookupTable: addressLookupTable,
authority: authority,
quote: quoteAccount.publicKey,
attestationQueue: attestationQueueAccount.publicKey,
permission: permissionAccount.publicKey,
escrow,
state: program.attestationProgramState.publicKey,
mint: program.mint.address,
tokenProgram: TOKEN_PROGRAM_ID,
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
payer,
systemProgram: SystemProgram.programId,
addressLookupProgram: addressLookupProgram,
}
);
return [
functionAccount,
new TransactionObject(
payer,
[instruction],
params.authority
? [params.authority, functionKeypair]
: [functionKeypair],
options
),
];
}
public static async create(
program: SwitchboardProgram,
params: FunctionAccountInitParams,
options?: SendTransactionObjectOptions
): Promise<[FunctionAccount, TransactionSignature]> {
const [account, txnObject] = await this.createInstruction(
program,
program.walletPubkey,
params,
options
);
const txSignature = await program.signAndSend(txnObject, options);
return [account, txSignature];
}
public getPermissionAccount(
queuePubkey: PublicKey,
queueAuthority: PublicKey
): [AttestationPermissionAccount, number] {
return AttestationPermissionAccount.fromSeed(
this.program,
queueAuthority,
queuePubkey,
this.publicKey
);
}
public getQuoteAccount(): [QuoteAccount, number] {
return QuoteAccount.fromSeed(this.program, this.publicKey);
}
public getEscrow(): PublicKey {
return this.program.mint.getAssociatedAddress(this.publicKey);
}
public async fundInstruction(
payer: PublicKey,
params: FunctionFundParams,
options?: TransactionObjectOptions
): Promise<TransactionObject> {
this.program.verifyAttestation();
const fundTokenAmountBN = this.program.mint.toTokenAmountBN(
params.fundAmount
);
// TODO: Create funder token wallet if it doesnt exist
const funderAuthority = params.funderAuthority
? params.funderAuthority.publicKey
: payer;
const funderTokenWallet =
params.funderTokenWallet ??
this.program.mint.getAssociatedAddress(funderAuthority);
const functionData = await this.loadData();
const instruction = types.functionFund(
this.program,
{ params: { amount: fundTokenAmountBN } },
{
function: this.publicKey,
attestationQueue: functionData.attestationQueue,
escrow: this.getEscrow(),
funder: funderTokenWallet,
funderAuthority: funderAuthority,
state: this.program.attestationProgramState.publicKey,
tokenProgram: TOKEN_PROGRAM_ID,
associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID,
}
);
return new TransactionObject(payer, [instruction], [], options);
}
public async fund(
params: FunctionFundParams,
options?: SendTransactionObjectOptions
): Promise<TransactionSignature> {
return await this.fundInstruction(
this.program.walletPubkey,
params,
options
).then((txn) => this.program.signAndSend(txn, options));
}
public async withdrawInstruction(
payer: PublicKey,
params: FunctionWithdrawParams,
options?: TransactionObjectOptions
): Promise<TransactionObject> {
this.program.verifyAttestation();
const functionData = await this.loadData();
const [queueAccount, queueData] = await AttestationQueueAccount.load(
this.program,
functionData.attestationQueue
);
const withdrawAmount: number = await (async () => {
const minRequiredBalance = queueData.reward * 2;
const escrowBalance = await spl
.getAccount(this.program.connection, this.getEscrow())
.then((escrow) => this.program.mint.fromTokenAmount(escrow.amount));
const maxWithdrawAmount = escrowBalance - minRequiredBalance;
if (params.amount === "all") return maxWithdrawAmount;
return Math.min(params.amount, maxWithdrawAmount);
})();
if (params.unwrap) {
const ephemeralWallet = Keypair.generate();
const instructions: TransactionInstruction[] = [
// initialize space for ephemeral token account
SystemProgram.createAccount({
fromPubkey: payer,
newAccountPubkey: ephemeralWallet.publicKey,
lamports:
await this.program.connection.getMinimumBalanceForRentExemption(
spl.ACCOUNT_SIZE
),
space: spl.ACCOUNT_SIZE,
programId: spl.TOKEN_PROGRAM_ID,
}),
// initialize ephemeral token account
spl.createInitializeAccountInstruction(
ephemeralWallet.publicKey,
this.program.mint.address,
payer,
spl.TOKEN_PROGRAM_ID
),
// perform withdraw
types.functionWithdraw(
this.program,
{
params: {
amount: this.program.mint.toTokenAmountBN(withdrawAmount),
},
},
{
function: this.publicKey,
attestationQueue: queueAccount.publicKey,
escrow: this.getEscrow(),
authority: payer,
receiver: ephemeralWallet.publicKey,
state: this.program.attestationProgramState.publicKey,
tokenProgram: TOKEN_PROGRAM_ID,
}
),
// close ephemeral token account
spl.createCloseAccountInstruction(
ephemeralWallet.publicKey,
payer,
payer
),
];
return new TransactionObject(
payer,
instructions,
[ephemeralWallet],
options
);
} else {
return new TransactionObject(
payer,
[
types.functionWithdraw(
this.program,
{
params: {
amount: this.program.mint.toTokenAmountBN(withdrawAmount),
},
},
{
function: this.publicKey,
attestationQueue: queueAccount.publicKey,
escrow: this.getEscrow(),
authority:
"withdrawAuthority" in params && params.withdrawAuthority
? params.withdrawAuthority.publicKey
: payer,
receiver:
"withdrawWallet" in params && params.withdrawWallet
? params.withdrawWallet
: this.program.mint.getAssociatedAddress(payer),
state: this.program.attestationProgramState.publicKey,
tokenProgram: TOKEN_PROGRAM_ID,
}
),
],
"withdrawAuthority" in params && params.withdrawAuthority
? [params.withdrawAuthority]
: [],
options
);
}
}
public async withdraw(
params: FunctionWithdrawParams,
options?: SendTransactionObjectOptions
): Promise<TransactionSignature> {
return await this.withdrawInstruction(
this.program.walletPubkey,
params,
options
).then((txn) => this.program.signAndSend(txn, options));
}
public async getBalance(): Promise<number> {
const balance = await this.program.mint.getAssociatedBalance(
this.publicKey
);
if (balance === null) {
throw new errors.AccountNotFoundError(
`Function escrow`,
this.getEscrow()
);
}
return balance;
}
public async getBalanceBN(): Promise<BN> {
const balance = await this.getBalance();
return this.program.mint.toTokenAmountBN(balance);
}
public async verifyInstruction(
payer: PublicKey,
params: FunctionVerifyParams,
options?: TransactionObjectOptions
): Promise<TransactionObject> {
this.program.verifyAttestation();
const functionData = await this.loadData();
const attestationQueueAccount = new AttestationQueueAccount(
this.program,
functionData.attestationQueue
);
const attestationQueue = await attestationQueueAccount.loadData();
const fnPermissionAccount = this.getPermissionAccount(
attestationQueueAccount.publicKey,
attestationQueue.authority
)[0];
const fnQuoteAccount = this.getQuoteAccount()[0];
const verifierPermissionAccount = AttestationPermissionAccount.fromSeed(
this.program,
attestationQueue.authority,
attestationQueueAccount.publicKey,
payer
)[0];
const quoteVerifier = await params.verifier.loadData();
if (!quoteVerifier.authority.equals(payer)) {
throw new Error(
`The verifier owner must be the payer of this transaction, expected ${quoteVerifier.authority}, received ${payer}`
);
}
const receiver = await this.program.mint.getOrCreateAssociatedUser(payer);
const instruction = types.functionVerify(
this.program,
{
params: {
observedTime: params.observedTime,
nextAllowedTimestamp: params.nextAllowedTimestamp,
isFailure: params.isFailure,
mrEnclave: Array.from(params.mrEnclave),
},
},
{
function: this.publicKey,
fnSigner: params.fnSigner,
fnQuote: fnQuoteAccount.publicKey,
verifierQuote: params.verifier.publicKey,
attestationQueue: functionData.attestationQueue,
escrow: this.getEscrow(),
receiver: receiver,
verifierPermission: verifierPermissionAccount.publicKey,
fnPermission: fnPermissionAccount.publicKey,
state: this.program.attestationProgramState.publicKey,
tokenProgram: TOKEN_PROGRAM_ID,
payer,
systemProgram: SystemProgram.programId,
securedSigner: PublicKey.default, // TODO: update with correct account
}
);
return new TransactionObject(payer, [instruction], [], options);
}
public async verify(
params: FunctionVerifyParams,
options?: SendTransactionObjectOptions
): Promise<TransactionSignature> {
return await this.verifyInstruction(
this.program.walletPubkey,
params,
options
).then((txn) => this.program.signAndSend(txn, options));
}
public static decodeAddressLookup(lookupTable: AddressLookupTableAccount) {
const addresses = lookupTable.state.addresses;
if (addresses.length !== 16) {
throw new Error(`Failed to decode address lookup table`);
}
const systemProgram = addresses[0]!;
if (!systemProgram.equals(anchor.web3.SystemProgram.programId)) {
throw new Error("AddressLookupMismatch");
}
const tokenProgram = addresses[1]!;
if (!tokenProgram.equals(anchor.utils.token.TOKEN_PROGRAM_ID)) {
throw new Error("AddressLookupMismatch");
}
const assocatedTokenProgram = addresses[2]!;
if (
!assocatedTokenProgram.equals(anchor.utils.token.ASSOCIATED_PROGRAM_ID)
) {
throw new Error("AddressLookupMismatch");
}
const sysVarRent = addresses[3]!;
if (!sysVarRent.equals(anchor.web3.SYSVAR_RENT_PUBKEY)) {
throw new Error("AddressLookupMismatch");
}
const sysVarRecentBlockhashes = addresses[4]!;
if (
!sysVarRecentBlockhashes.equals(
anchor.web3.SYSVAR_RECENT_BLOCKHASHES_PUBKEY
)
) {
throw new Error("AddressLookupMismatch");
}
const sysVarInstructions = addresses[5]!;
if (!sysVarInstructions.equals(anchor.web3.SYSVAR_INSTRUCTIONS_PUBKEY)) {
throw new Error("AddressLookupMismatch");
}
const sysVarSlotHashes = addresses[6]!;
if (!sysVarSlotHashes.equals(anchor.web3.SYSVAR_SLOT_HASHES_PUBKEY)) {
throw new Error("AddressLookupMismatch");
}
const sysVarSlotHistory = addresses[7]!;
if (!sysVarSlotHistory.equals(anchor.web3.SYSVAR_SLOT_HISTORY_PUBKEY)) {
throw new Error("AddressLookupMismatch");
}
const switchboardProgram = addresses[8]!;
if (!switchboardProgram.equals(SB_V2_PID)) {
throw new Error("AddressLookupMismatch");
}
const attestationProgram = addresses[9]!;
if (!attestationProgram.equals(SB_ATTESTATION_PID)) {
throw new Error("AddressLookupMismatch");
}
// switchboard accounts, not worth the network calls
const statePubkey = addresses[10]!;
const attestationQueuePubkey = addresses[11]!;
const functionPubkey = addresses[12]!;
const escrowPubkey = addresses[13]!;
const fnPermission = addresses[14]!;
const fnQuote = addresses[15]!;
return {
systemProgram,
tokenProgram,
assocatedTokenProgram,
sysVarRent,
sysVarRecentBlockhashes,
sysVarInstructions,
sysVarSlotHashes,
sysVarSlotHistory,
switchboardProgram,
attestationProgram,
statePubkey,
attestationQueuePubkey,
functionPubkey,
escrowPubkey,
fnPermission,
fnQuote,
};
}
}

View File

@ -1,9 +1,13 @@
export * from "./account.js";
export * from "./aggregatorAccount.js";
export * from "./aggregatorHistoryBuffer.js";
export * from "./attestationPermissionAccount.js";
export * from "./attestationProgramStateAccount.js";
export * from "./attestationQueueAccount.js";
export * from "./bufferRelayAccount.js";
export * from "./crankAccount.js";
export * from "./crankDataBuffer.js";
export * from "./functionAccount.js";
export * from "./jobAccount.js";
export * from "./leaseAccount.js";
export * from "./oracleAccount.js";
@ -11,6 +15,7 @@ export * from "./permissionAccount.js";
export * from "./programStateAccount.js";
export * from "./queueAccount.js";
export * from "./queueDataBuffer.js";
export * from "./quoteAccount.js";
export * from "./vrfAccount.js";
export * from "./vrfLiteAccount.js";
export * from "./vrfPoolAccount.js";

View File

@ -1,5 +1,5 @@
import * as errors from "../errors.js";
import * as types from "../generated/index.js";
import * as types from "../generated/oracle-program/index.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import {
SendTransactionObjectOptions,

View File

@ -1,5 +1,5 @@
import * as errors from "../errors.js";
import * as types from "../generated/index.js";
import * as types from "../generated/oracle-program/index.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import {
SendTransactionObjectOptions,

View File

@ -1,5 +1,5 @@
import * as errors from "../errors.js";
import * as types from "../generated/index.js";
import * as types from "../generated/oracle-program/index.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import {
SendTransactionObjectOptions,
@ -20,6 +20,7 @@ import {
LAMPORTS_PER_SOL,
PublicKey,
SystemProgram,
TransactionInstruction,
TransactionSignature,
} from "@solana/web3.js";
import { BN } from "@switchboard-xyz/common";
@ -192,9 +193,7 @@ export class OracleAccount extends Account<types.OracleAccountData> {
public static async createInstructions(
program: SwitchboardProgram,
payer: PublicKey,
params: {
queueAccount: QueueAccount;
} & OracleInitParams &
params: { queueAccount: QueueAccount } & OracleInitParams &
Partial<OracleStakeParams>,
options?: TransactionObjectOptions
): Promise<[OracleAccount, Array<TransactionObject>]> {
@ -498,6 +497,97 @@ export class OracleAccount extends Account<types.OracleAccountData> {
return txnSignature;
}
teeHeartbeatInstruction(
params: OracleTeeHeartbeatSyncParams
): TransactionInstruction {
const [permissionAccount, permissionBump] = params.permission;
const instruction = types.oracleTeeHeartbeat(
this.program,
{ params: { permissionBump } },
{
oracle: this.publicKey,
oracleAuthority: params.authority,
tokenAccount: params.tokenWallet,
gcOracle: params.gcOracle ?? this.publicKey,
oracleQueue: params.oracleQueue,
permission: permissionAccount.publicKey,
dataBuffer: params.dataBuffer,
quote: params.quote,
programState: this.program.programState.publicKey,
}
);
return instruction;
}
async teeHeartbeat(
params: OracleTeeHeartbeatParams,
options?: SendTransactionObjectOptions
): Promise<TransactionSignature> {
const oracle = await this.loadData();
const tokenWallet = params?.tokenWallet ?? oracle.tokenAccount;
const queueAccount =
params?.queueAccount ??
new QueueAccount(this.program, oracle.queuePubkey);
const queue = params?.queue ?? (await queueAccount.loadData());
const oracles = await queueAccount.loadOracles();
let lastPubkey = this.publicKey;
if (oracles.length !== 0) {
lastPubkey = oracles[queue.gcIdx];
}
const [permissionAccount, permissionBump] =
params?.permission ??
this.getPermissionAccount(
queueAccount.publicKey,
queue.authority,
oracle.oracleAuthority
);
try {
await permissionAccount.loadData();
} catch (_) {
throw new Error(
"A requested oracle permission pda account has not been initialized."
);
}
if (
params?.authority &&
!oracle.oracleAuthority.equals(params.authority.publicKey)
) {
throw new errors.IncorrectAuthority(
oracle.oracleAuthority,
params.authority.publicKey
);
}
const heartbeatTxn = new TransactionObject(
this.program.walletPubkey,
[
this.teeHeartbeatInstruction({
tokenWallet: tokenWallet,
gcOracle: lastPubkey,
oracleQueue: queueAccount.publicKey,
dataBuffer: queue.dataBuffer,
permission: [permissionAccount, permissionBump],
authority: oracle.oracleAuthority,
quote: params.quoteKeypair.publicKey,
queueAuthority: params.queueAuthority ?? queue.authority,
}),
],
params?.authority
? [params.authority, params.quoteKeypair]
: [params.quoteKeypair],
options
);
const txnSignature = await this.program.signAndSend(heartbeatTxn, options);
return txnSignature;
}
async withdrawInstruction(
payer: PublicKey,
params: OracleWithdrawParams,
@ -628,13 +718,14 @@ export class OracleAccount extends Account<types.OracleAccountData> {
public getPermissionAccount(
queuePubkey: PublicKey,
queueAuthority: PublicKey
queueAuthority: PublicKey,
grantee: PublicKey = this.publicKey
): [PermissionAccount, number] {
return PermissionAccount.fromSeed(
this.program,
queueAuthority,
queuePubkey,
this.publicKey
grantee
);
}
@ -769,3 +860,25 @@ export interface OracleWithdrawWalletParams extends OracleWithdrawBaseParams {
export type OracleWithdrawParams =
| OracleWithdrawUnwrapParams
| OracleWithdrawWalletParams;
export type OracleTeeHeartbeatSyncParams = {
quote: PublicKey;
dataBuffer: PublicKey;
oracleQueue: PublicKey;
tokenWallet: PublicKey;
queueAuthority: PublicKey;
gcOracle: PublicKey;
// queue: types.OracleQueueAccountData;
permission: [PermissionAccount, number];
authority: PublicKey;
};
export type OracleTeeHeartbeatParams = {
quoteKeypair: Keypair;
queueAccount?: QueueAccount;
tokenWallet?: PublicKey;
queueAuthority?: PublicKey;
queue?: types.OracleQueueAccountData;
permission?: [PermissionAccount, number];
authority?: Keypair;
};

View File

@ -1,11 +1,11 @@
import * as errors from "../errors.js";
import * as types from "../generated/index.js";
import * as types from "../generated/oracle-program/index.js";
import {
PermitNone,
PermitOracleHeartbeat,
PermitOracleQueueUsage,
PermitVrfRequests,
} from "../generated/types/SwitchboardPermission.js";
} from "../generated/oracle-program/types/SwitchboardPermission.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import {
SendTransactionObjectOptions,

View File

@ -1,5 +1,5 @@
import * as errors from "../errors.js";
import * as types from "../generated/index.js";
import * as types from "../generated/oracle-program/index.js";
import { Mint } from "../mint.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import { TransactionObject } from "../TransactionObject.js";
@ -9,9 +9,7 @@ import { Account } from "./account.js";
import * as anchor from "@coral-xyz/anchor";
import * as spl from "@solana/spl-token";
import {
AccountInfo,
Keypair,
LAMPORTS_PER_SOL,
PublicKey,
SystemProgram,
TransactionInstruction,
@ -35,43 +33,17 @@ export class ProgramStateAccount extends Account<types.SbState> {
public readonly size = this.program.account.sbState.size;
/**
* Return a program state account state initialized to the default values.
* Finds the {@linkcode ProgramStateAccount} from the static seed from which it was generated.
* @return ProgramStateAccount and PDA bump tuple.
*/
public static default(): types.SbState {
const buffer = Buffer.alloc(ProgramStateAccount.size, 0);
types.SbState.discriminator.copy(buffer, 0);
return types.SbState.decode(buffer);
}
/**
* Create a mock account info for a given program state config. Useful for test integrations.
*/
public static createMock(
programId: PublicKey,
data: Partial<types.SbState>,
options?: {
lamports?: number;
rentEpoch?: number;
}
): AccountInfo<Buffer> {
const fields: types.SbStateFields = {
...ProgramStateAccount.default(),
...data,
// any cleanup actions here
};
const state = new types.SbState(fields);
const buffer = Buffer.alloc(ProgramStateAccount.size, 0);
types.SbState.discriminator.copy(buffer, 0);
types.SbState.layout.encode(state, buffer, 8);
return {
executable: false,
owner: programId,
lamports: options?.lamports ?? 1 * LAMPORTS_PER_SOL,
data: buffer,
rentEpoch: options?.rentEpoch ?? 0,
};
public static fromSeed(
program: SwitchboardProgram
): [ProgramStateAccount, number] {
const [publicKey, bump] = PublicKey.findProgramAddressSync(
[Buffer.from("STATE")],
program.programId
);
return [new ProgramStateAccount(program, publicKey), bump];
}
/** Load the ProgramStateAccount with its current on-chain state */
@ -234,17 +206,18 @@ export class ProgramStateAccount extends Account<types.SbState> {
}
/**
* Finds the {@linkcode ProgramStateAccount} from the static seed from which it was generated.
* @return ProgramStateAccount and PDA bump tuple.
* Find the index of an enclave in an array and return -1 if not found
*/
public static fromSeed(
program: SwitchboardProgram
): [ProgramStateAccount, number] {
const [publicKey, bump] = PublicKey.findProgramAddressSync(
[Buffer.from("STATE")],
program.programId
);
return [new ProgramStateAccount(program, publicKey), bump];
public static findEnclaveIdx(
enclaves: Array<Uint8Array>,
enclave: Uint8Array
): number {
for (const [n, e] of enclaves.entries()) {
if (Buffer.compare(e, enclave) === 0) {
return n;
}
}
return -1;
}
/**

View File

@ -1,10 +1,10 @@
import * as errors from "../errors.js";
import * as types from "../generated/index.js";
import * as types from "../generated/oracle-program/index.js";
import {
PermitOracleHeartbeat,
PermitOracleQueueUsage,
PermitVrfRequests,
} from "../generated/types/SwitchboardPermission.js";
} from "../generated/oracle-program/types/SwitchboardPermission.js";
import { SolanaClock } from "../SolanaClock.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import {
@ -318,13 +318,22 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
public async createOracleInstructions(
/** The publicKey of the account that will pay for the new accounts. Will also be used as the account authority if no other authority is provided. */
payer: PublicKey,
params: CreateQueueOracleParams,
params: CreateQueueOracleParams & { teeOracle?: boolean },
options?: TransactionObjectOptions
): Promise<[OracleAccount, Array<TransactionObject>]> {
const queueAuthorityPubkey = params.queueAuthority
? params.queueAuthority.publicKey
: params.queueAuthorityPubkey ?? (await this.loadData()).authority;
if (
params.teeOracle &&
(!params.authority || !(params.authority instanceof Keypair))
) {
throw new Error(
`Need to provide authority keypair when creating a teeOracle`
);
}
const [oracleAccount, createOracleTxnObject] =
await OracleAccount.createInstructions(
this.program,
@ -336,13 +345,17 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
options
);
const permissionGrantee = params.teeOracle
? params.authority.publicKey
: oracleAccount.publicKey;
const [permissionAccount, createPermissionTxnObject] =
PermissionAccount.createInstruction(
this.program,
payer,
{
granter: this.publicKey,
grantee: oracleAccount.publicKey,
grantee: permissionGrantee,
authority: queueAuthorityPubkey,
},
options
@ -393,7 +406,7 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
* ```
*/
public async createOracle(
params: CreateQueueOracleParams,
params: CreateQueueOracleParams & { teeOracle?: boolean },
options?: SendTransactionObjectOptions
): Promise<[OracleAccount, Array<TransactionSignature>]> {
const signers: Keypair[] = [];
@ -1275,6 +1288,7 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
params.unpermissionedFeedsEnabled ?? null,
unpermissionedVrfEnabled: params.unpermissionedVrfEnabled ?? null,
enableBufferRelayers: params.enableBufferRelayers ?? null,
enableTeeOnly: params.enableTeeOnly ?? null,
slashingEnabled: params.slashingEnabled ?? null,
reward: reward,
minStake: minStake,
@ -1287,7 +1301,6 @@ export class QueueAccount extends Account<types.OracleQueueAccountData> {
? new BN(params.consecutiveOracleFailureLimit)
: null,
varianceToleranceMultiplier: multiplier,
enableTeeOnly: params.enableTeeOnly ?? false,
},
},
{
@ -1417,6 +1430,10 @@ export interface QueueInitParams {
* Enabling this setting will allow buffer relayer accounts to call openRound.
*/
enableBufferRelayers?: boolean;
/**
* Only allow TEE oracles to heartbeat on this queue.
*/
enableTeeOnly?: boolean;
/**
* The account to delegate authority to for creating permissions targeted at the queue.
*
@ -1426,11 +1443,13 @@ export interface QueueInitParams {
keypair?: Keypair;
dataBufferKeypair?: Keypair;
enableTeeOnly?: boolean;
}
export interface QueueSetConfigParams {
/** Alternative keypair that is the queue authority and is permitted to make account changes. Defaults to the payer if not provided. */
/**
* Alternative keypair that is the queue authority and is permitted to make account changes.
* Defaults to the payer if not provided.
*/
authority?: anchor.web3.Keypair;
/**
* A name to assign to this {@linkcode QueueAccount}
@ -1445,14 +1464,18 @@ export interface QueueSetConfigParams {
*/
unpermissionedFeedsEnabled?: boolean;
/**
* Enabling this setting means data feeds do not need explicit permission
* to request VRF proofs and verifications from this queue.
* Enabling this setting means data feeds do not need explicit permission to request VRF proofs
* and verifications from this queue.
*/
unpermissionedVrfEnabled?: boolean;
/**
* Enabling this setting will allow buffer relayer accounts to call openRound.
*/
enableBufferRelayers?: boolean;
/**
* Only allow TEE oracles to heartbeat on this queue.
*/
enableTeeOnly?: boolean;
/**
* Whether slashing is enabled on this queue.
*/
@ -1483,7 +1506,6 @@ export interface QueueSetConfigParams {
* Consecutive failure limit for an oracle before oracle permission is revoked.
*/
consecutiveOracleFailureLimit?: number;
enableTeeOnly?: boolean;
}
export type QueueAccountsJSON = Omit<

View File

@ -1,5 +1,5 @@
import * as errors from "../errors.js";
import * as types from "../generated/index.js";
import * as types from "../generated/oracle-program/index.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import {

View File

@ -0,0 +1,425 @@
import { Account } from "../accounts/account.js";
import * as errors from "../errors.js";
import * as types from "../generated/attestation-program/index.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import {
SendTransactionObjectOptions,
TransactionObject,
TransactionObjectOptions,
} from "../TransactionObject.js";
import { RawBuffer } from "../types.js";
import { parseMrEnclave, parseRawBuffer } from "../utils.js";
import {
AttestationPermissionAccount,
AttestationQueueAccount,
} from "./index.js";
import * as anchor from "@coral-xyz/anchor";
import {
Keypair,
PublicKey,
SystemProgram,
TransactionInstruction,
TransactionSignature,
} from "@solana/web3.js";
export const QUOTE_SEED: string = "QuoteAccountData";
/**
* Parameters for initializing an {@linkcode QuoteAccount}
*/
export interface QuoteAccountInitParams {
/**
* Key to lookup the buffer data on IPFS or an alternative decentralized storage solution.
*/
registryKey: Uint8Array;
/**
* The queue to which this function account will be linked
*/
queueAccount: AttestationQueueAccount;
/**
* A keypair to be used to address this account
*
* @default Keypair.generate()
*/
keypair?: Keypair;
/**
* An authority to be used to control this account.
*
* @default payer
*/
authority?: PublicKey;
}
/**
* Parameters for an {@linkcode types.quoteHeartbeat} instruction.
*/
export interface QuoteHeartbeatSyncParams {
gcOracle: PublicKey;
attestationQueue: PublicKey;
permission: [AttestationPermissionAccount, number];
queueAuthority: PublicKey;
}
/**
* Parameters for an {@linkcode types.quoteHeartbeat} instruction.
*/
export type QuoteHeartbeatParams = Partial<QuoteHeartbeatSyncParams> & {
securedSigner: Keypair;
} & Partial<{
quote: types.QuoteAccountData;
queue: types.AttestationQueueAccountData;
}>;
/**
* Parameters for an {@linkcode types.quoteVerify} instruction.
*/
export interface QuoteVerifyParams {
/**
* @TODO: Docs for timestamp
*/
timestamp: anchor.BN;
/**
* @TODO: Docs for mrEnclave
*/
mrEnclave: RawBuffer;
/**
* Keypair of the secured signer generated in the verifiers secure enclave
*/
verifierSecuredSigner: Keypair;
verifier: PublicKey;
}
/**
* Parameters for an {@linkcode types.quoteRotate} instruction.
*/
export interface QuoteRotateParams {
authority?: Keypair;
securedSigner: Keypair;
registryKey: string | Buffer | Uint8Array;
}
/**
* Account type representing a Switchboard Attestation quote.
*
* Data: {@linkcode types.QuoteAccountData}
*/
export class QuoteAccount extends Account<types.QuoteAccountData> {
static accountName = "QuoteAccountData";
/**
* Load an existing {@linkcode QuoteAccount} with its current on-chain state
*/
public static async load(
program: SwitchboardProgram,
address: PublicKey | string
): Promise<[QuoteAccount, types.QuoteAccountData]> {
program.verifyAttestation();
const quoteAccount = new QuoteAccount(program, address);
const state = await quoteAccount.loadData();
return [quoteAccount, state];
}
/**
* Finds the {@linkcode QuoteAccount} from the seed from which it was generated.
*
* Only applicable for QuoteAccounts tied to a {@linkcode FunctionAccount}. Quotes can also be generated from a keypair.
*
* @return QuoteAccount and PDA bump tuple.
*/
public static fromSeed(
program: SwitchboardProgram,
functionPubkey: PublicKey
): [QuoteAccount, number] {
const [publicKey, bump] = PublicKey.findProgramAddressSync(
[Buffer.from(QUOTE_SEED), functionPubkey.toBytes()],
program.attestationProgramId
);
return [new QuoteAccount(program, publicKey), bump];
}
/**
* Create a transaction object to initialize a quote account.
*/
public static async createInstruction(
program: SwitchboardProgram,
payer: PublicKey,
params: QuoteAccountInitParams,
options?: TransactionObjectOptions
): Promise<[QuoteAccount, TransactionObject]> {
program.verifyAttestation();
const quoteKeypair = params.keypair ?? Keypair.generate();
program.verifyNewKeypair(quoteKeypair);
const queueData = await params.queueAccount.loadData();
const registryKey = Array.from(params.registryKey)
.concat(Array(64).fill(0))
.slice(0, 64);
const instruction = types.quoteInit(
program,
{ params: { registryKey } },
{
quote: quoteKeypair.publicKey,
attestationQueue: params.queueAccount.publicKey,
queueAuthority: queueData.authority,
authority: params.authority ?? payer,
payer,
systemProgram: SystemProgram.programId,
}
);
return [
new QuoteAccount(program, quoteKeypair.publicKey),
new TransactionObject(payer, [instruction], [quoteKeypair], options),
];
}
public static async create(
program: SwitchboardProgram,
params: QuoteAccountInitParams,
options?: SendTransactionObjectOptions
): Promise<[QuoteAccount, TransactionSignature]> {
const [account, txnObject] = await this.createInstruction(
program,
program.walletPubkey,
params,
options
);
const txSignature = await program.signAndSend(txnObject, options);
return [account, txSignature];
}
public getPermissionAccount(
queuePubkey: PublicKey,
queueAuthority: PublicKey,
owner: PublicKey
): [AttestationPermissionAccount, number] {
return AttestationPermissionAccount.fromSeed(
this.program,
queueAuthority,
queuePubkey,
owner
);
}
static getVerificationStatus(
state: types.QuoteAccountData
): types.VerificationStatusKind {
switch (state.verificationStatus) {
case types.VerificationStatus.None.discriminator:
return new types.VerificationStatus.None();
case types.VerificationStatus.VerificationPending.discriminator:
return new types.VerificationStatus.VerificationPending();
case types.VerificationStatus.VerificationFailure.discriminator:
return new types.VerificationStatus.VerificationFailure();
case types.VerificationStatus.VerificationSuccess.discriminator:
return new types.VerificationStatus.VerificationSuccess();
case types.VerificationStatus.VerificationOverride.discriminator:
return new types.VerificationStatus.VerificationOverride();
}
throw new Error(
`Failed to get the verification status, expected [${types.VerificationStatus.None.discriminator}, ${types.VerificationStatus.VerificationPending.discriminator}, ${types.VerificationStatus.VerificationFailure.discriminator}, ${types.VerificationStatus.VerificationSuccess.discriminator}], or ${types.VerificationStatus.VerificationOverride.discriminator}], received ${state.verificationStatus}`
);
}
/**
* Get the size of an {@linkcode QuoteAccount} on-chain.
*/
public readonly size = this.program.attestationAccount.quoteAccountData.size;
/**
* Retrieve and decode the {@linkcode types.QuoteAccountData} stored in this account.
*/
public async loadData(): Promise<types.QuoteAccountData> {
this.program.verifyAttestation();
const data = await types.QuoteAccountData.fetch(
this.program,
this.publicKey
);
if (data) return data;
throw new errors.AccountNotFoundError("Quote", this.publicKey);
}
public heartbeatInstruction(params: {
gcOracle: PublicKey;
attestationQueue: PublicKey;
permission: [AttestationPermissionAccount, number];
queueAuthority: PublicKey;
securedSigner: PublicKey;
}): TransactionInstruction {
this.program.verifyAttestation();
const [permissionAccount, permissionBump] = params.permission;
const instruction = types.quoteHeartbeat(
this.program,
{ params: {} },
{
quote: this.publicKey,
securedSigner: params.securedSigner,
attestationQueue: params.attestationQueue,
queueAuthority: params.queueAuthority,
gcNode: params.gcOracle,
permission: permissionAccount.publicKey,
}
);
return instruction;
}
public async heartbeat(
params: QuoteHeartbeatParams,
options?: SendTransactionObjectOptions
): Promise<TransactionSignature> {
const quote = params.quote ?? (await this.loadData());
const queue =
params.queue ??
(await new AttestationQueueAccount(
this.program,
quote.attestationQueue
).loadData());
const quotes = queue.data.slice(0, queue.dataLen);
let lastPubkey = this.publicKey;
if (quotes.length !== 0 && quotes.length > queue.gcIdx) {
lastPubkey = quotes[queue.gcIdx];
}
const heartbeatIxn = this.heartbeatInstruction({
queueAuthority: queue.authority,
permission:
params.permission ??
this.getPermissionAccount(
quote.attestationQueue,
queue.authority,
this.publicKey
),
gcOracle: lastPubkey,
attestationQueue: quote.attestationQueue,
securedSigner: params.securedSigner.publicKey,
});
const heartbeatTxn = new TransactionObject(
this.program.walletPubkey,
[heartbeatIxn],
[params.securedSigner],
options
);
const txnSignature = await this.program.signAndSend(heartbeatTxn, options);
return txnSignature;
}
public async rotateInstruction(
payer: PublicKey,
params: QuoteRotateParams,
options?: TransactionObjectOptions
): Promise<TransactionObject> {
this.program.verifyAttestation();
const registryKey = parseRawBuffer(params.registryKey, 64);
const quoteData = await this.loadData();
const authority = params.authority ? params.authority.publicKey : payer;
if (!quoteData.authority.equals(authority)) {
throw new errors.IncorrectAuthority(quoteData.authority, authority);
}
const rotateIxn = types.quoteRotate(
this.program,
{
params: { registryKey: [...registryKey].slice(0, 64) },
},
{
quote: this.publicKey,
authority: authority,
securedSigner: params.securedSigner.publicKey,
attestationQueue: quoteData.attestationQueue,
}
);
const rotateTxn: TransactionObject = new TransactionObject(
payer,
[rotateIxn],
params.authority
? [params.authority, params.securedSigner]
: [params.securedSigner],
options
);
return rotateTxn;
}
public async rotate(
params: QuoteRotateParams,
options?: SendTransactionObjectOptions
): Promise<TransactionSignature> {
return await this.rotateInstruction(
this.program.walletPubkey,
params,
options
).then((txn) => this.program.signAndSend(txn, options));
}
public async verifyInstruction(
payer: PublicKey,
params: QuoteVerifyParams,
options?: TransactionObjectOptions
): Promise<TransactionObject> {
this.program.verifyAttestation();
const quoteData = await this.loadData();
const attestationQueueAccount = new AttestationQueueAccount(
this.program,
quoteData.attestationQueue
);
const attestationQueue = await attestationQueueAccount.loadData();
const verifierIdx = attestationQueue.data
.slice(0, attestationQueue.dataLen)
.findIndex((pubkey) => pubkey.equals(params.verifier));
if (verifierIdx === -1) {
throw new Error(`Verifier not found on the attestation queue`);
}
const instruction = types.quoteVerify(
this.program,
{
params: {
timestamp: params.timestamp,
mrEnclave: Array.from(parseMrEnclave(params.mrEnclave)),
idx: verifierIdx,
},
},
{
quote: this.publicKey,
quoteSigner: quoteData.securedSigner,
securedSigner: params.verifierSecuredSigner.publicKey,
verifier: params.verifier,
attestationQueue: quoteData.attestationQueue,
}
);
return new TransactionObject(
payer,
[instruction],
[params.verifierSecuredSigner],
options
);
}
public async verify(
params: QuoteVerifyParams,
options?: SendTransactionObjectOptions
): Promise<TransactionSignature> {
return await this.verifyInstruction(
this.program.walletPubkey,
params,
options
).then((txn) => this.program.signAndSend(txn, options));
}
}

View File

@ -1,6 +1,6 @@
import * as errors from "../errors.js";
import * as types from "../generated/index.js";
import { vrfCloseAction } from "../generated/index.js";
import * as types from "../generated/oracle-program/index.js";
import { vrfCloseAction } from "../generated/oracle-program/index.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import {
SendTransactionObjectOptions,

View File

@ -1,7 +1,7 @@
import * as errors from "../errors.js";
import * as types from "../generated/index.js";
import { vrfLiteInit } from "../generated/index.js";
import { vrfLiteCloseAction } from "../generated/instructions/vrfLiteCloseAction.js";
import { vrfLiteInit } from "../generated/oracle-program/index.js";
import * as types from "../generated/oracle-program/index.js";
import { vrfLiteCloseAction } from "../generated/oracle-program/instructions/vrfLiteCloseAction.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import {
TransactionObject,

View File

@ -1,6 +1,6 @@
import { VRF_POOL_REQUEST_AMOUNT } from "../const.js";
import { AccountNotFoundError, InsufficientFundsError } from "../errors.js";
import * as types from "../generated/index.js";
import * as types from "../generated/oracle-program/index.js";
import { VrfPoolRequestEvent } from "../SwitchboardEvents.js";
import { SwitchboardProgram } from "../SwitchboardProgram.js";
import { TransactionObject } from "../TransactionObject.js";

View File

@ -100,3 +100,12 @@ export class IncorrectOwner extends Error {
Object.setPrototypeOf(this, IncorrectOwner.prototype);
}
}
export class InvalidCronSchedule extends Error {
constructor(schedule: string) {
super(
`invalid cron schedule, expected format: '* * * * * *', received: ${schedule}`
);
Object.setPrototypeOf(this, IncorrectOwner.prototype);
}
}

View File

@ -0,0 +1,2 @@
export * from "./attestation-program/accounts/index.js";
export * from "./oracle-program/accounts/index.js";

View File

@ -0,0 +1,140 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { Connection, PublicKey } from "@solana/web3.js";
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface AttestationPermissionAccountDataFields {
authority: PublicKey;
permissions: number;
granter: PublicKey;
grantee: PublicKey;
expiration: BN;
bump: number;
ebuf: Array<number>;
}
export interface AttestationPermissionAccountDataJSON {
authority: string;
permissions: number;
granter: string;
grantee: string;
expiration: string;
bump: number;
ebuf: Array<number>;
}
export class AttestationPermissionAccountData {
readonly authority: PublicKey;
readonly permissions: number;
readonly granter: PublicKey;
readonly grantee: PublicKey;
readonly expiration: BN;
readonly bump: number;
readonly ebuf: Array<number>;
static readonly discriminator = Buffer.from([
63, 83, 122, 184, 22, 35, 31, 70,
]);
static readonly layout = borsh.struct([
borsh.publicKey("authority"),
borsh.u32("permissions"),
borsh.publicKey("granter"),
borsh.publicKey("grantee"),
borsh.i64("expiration"),
borsh.u8("bump"),
borsh.array(borsh.u8(), 256, "ebuf"),
]);
constructor(fields: AttestationPermissionAccountDataFields) {
this.authority = fields.authority;
this.permissions = fields.permissions;
this.granter = fields.granter;
this.grantee = fields.grantee;
this.expiration = fields.expiration;
this.bump = fields.bump;
this.ebuf = fields.ebuf;
}
static async fetch(
program: SwitchboardProgram,
address: PublicKey
): Promise<AttestationPermissionAccountData | null> {
const info = await program.connection.getAccountInfo(address);
if (info === null) {
return null;
}
if (!info.owner.equals(program.attestationProgramId)) {
throw new Error("account doesn't belong to this program");
}
return this.decode(info.data);
}
static async fetchMultiple(
program: SwitchboardProgram,
addresses: PublicKey[]
): Promise<Array<AttestationPermissionAccountData | null>> {
const infos = await program.connection.getMultipleAccountsInfo(addresses);
return infos.map((info) => {
if (info === null) {
return null;
}
if (!info.owner.equals(program.attestationProgramId)) {
throw new Error("account doesn't belong to this program");
}
return this.decode(info.data);
});
}
static decode(data: Buffer): AttestationPermissionAccountData {
if (
!data.slice(0, 8).equals(AttestationPermissionAccountData.discriminator)
) {
throw new Error("invalid account discriminator");
}
const dec = AttestationPermissionAccountData.layout.decode(data.slice(8));
return new AttestationPermissionAccountData({
authority: dec.authority,
permissions: dec.permissions,
granter: dec.granter,
grantee: dec.grantee,
expiration: dec.expiration,
bump: dec.bump,
ebuf: dec.ebuf,
});
}
toJSON(): AttestationPermissionAccountDataJSON {
return {
authority: this.authority.toString(),
permissions: this.permissions,
granter: this.granter.toString(),
grantee: this.grantee.toString(),
expiration: this.expiration.toString(),
bump: this.bump,
ebuf: this.ebuf,
};
}
static fromJSON(
obj: AttestationPermissionAccountDataJSON
): AttestationPermissionAccountData {
return new AttestationPermissionAccountData({
authority: new PublicKey(obj.authority),
permissions: obj.permissions,
granter: new PublicKey(obj.granter),
grantee: new PublicKey(obj.grantee),
expiration: new BN(obj.expiration),
bump: obj.bump,
ebuf: obj.ebuf,
});
}
}

View File

@ -0,0 +1,206 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { Connection, PublicKey } from "@solana/web3.js";
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface AttestationQueueAccountDataFields {
authority: PublicKey;
mrEnclaves: Array<Array<number>>;
mrEnclavesLen: number;
data: Array<PublicKey>;
dataLen: number;
allowAuthorityOverrideAfter: BN;
requireAuthorityHeartbeatPermission: boolean;
requireUsagePermissions: boolean;
maxQuoteVerificationAge: BN;
reward: number;
lastHeartbeat: BN;
nodeTimeout: BN;
currIdx: number;
gcIdx: number;
ebuf: Array<number>;
}
export interface AttestationQueueAccountDataJSON {
authority: string;
mrEnclaves: Array<Array<number>>;
mrEnclavesLen: number;
data: Array<string>;
dataLen: number;
allowAuthorityOverrideAfter: string;
requireAuthorityHeartbeatPermission: boolean;
requireUsagePermissions: boolean;
maxQuoteVerificationAge: string;
reward: number;
lastHeartbeat: string;
nodeTimeout: string;
currIdx: number;
gcIdx: number;
ebuf: Array<number>;
}
export class AttestationQueueAccountData {
readonly authority: PublicKey;
readonly mrEnclaves: Array<Array<number>>;
readonly mrEnclavesLen: number;
readonly data: Array<PublicKey>;
readonly dataLen: number;
readonly allowAuthorityOverrideAfter: BN;
readonly requireAuthorityHeartbeatPermission: boolean;
readonly requireUsagePermissions: boolean;
readonly maxQuoteVerificationAge: BN;
readonly reward: number;
readonly lastHeartbeat: BN;
readonly nodeTimeout: BN;
readonly currIdx: number;
readonly gcIdx: number;
readonly ebuf: Array<number>;
static readonly discriminator = Buffer.from([
192, 53, 130, 67, 234, 207, 39, 171,
]);
static readonly layout = borsh.struct([
borsh.publicKey("authority"),
borsh.array(borsh.array(borsh.u8(), 32), 32, "mrEnclaves"),
borsh.u32("mrEnclavesLen"),
borsh.array(borsh.publicKey(), 128, "data"),
borsh.u32("dataLen"),
borsh.i64("allowAuthorityOverrideAfter"),
borsh.bool("requireAuthorityHeartbeatPermission"),
borsh.bool("requireUsagePermissions"),
borsh.i64("maxQuoteVerificationAge"),
borsh.u32("reward"),
borsh.i64("lastHeartbeat"),
borsh.i64("nodeTimeout"),
borsh.u32("currIdx"),
borsh.u32("gcIdx"),
borsh.array(borsh.u8(), 1024, "ebuf"),
]);
constructor(fields: AttestationQueueAccountDataFields) {
this.authority = fields.authority;
this.mrEnclaves = fields.mrEnclaves;
this.mrEnclavesLen = fields.mrEnclavesLen;
this.data = fields.data;
this.dataLen = fields.dataLen;
this.allowAuthorityOverrideAfter = fields.allowAuthorityOverrideAfter;
this.requireAuthorityHeartbeatPermission =
fields.requireAuthorityHeartbeatPermission;
this.requireUsagePermissions = fields.requireUsagePermissions;
this.maxQuoteVerificationAge = fields.maxQuoteVerificationAge;
this.reward = fields.reward;
this.lastHeartbeat = fields.lastHeartbeat;
this.nodeTimeout = fields.nodeTimeout;
this.currIdx = fields.currIdx;
this.gcIdx = fields.gcIdx;
this.ebuf = fields.ebuf;
}
static async fetch(
program: SwitchboardProgram,
address: PublicKey
): Promise<AttestationQueueAccountData | null> {
const info = await program.connection.getAccountInfo(address);
if (info === null) {
return null;
}
if (!info.owner.equals(program.attestationProgramId)) {
throw new Error("account doesn't belong to this program");
}
return this.decode(info.data);
}
static async fetchMultiple(
program: SwitchboardProgram,
addresses: PublicKey[]
): Promise<Array<AttestationQueueAccountData | null>> {
const infos = await program.connection.getMultipleAccountsInfo(addresses);
return infos.map((info) => {
if (info === null) {
return null;
}
if (!info.owner.equals(program.attestationProgramId)) {
throw new Error("account doesn't belong to this program");
}
return this.decode(info.data);
});
}
static decode(data: Buffer): AttestationQueueAccountData {
if (!data.slice(0, 8).equals(AttestationQueueAccountData.discriminator)) {
throw new Error("invalid account discriminator");
}
const dec = AttestationQueueAccountData.layout.decode(data.slice(8));
return new AttestationQueueAccountData({
authority: dec.authority,
mrEnclaves: dec.mrEnclaves,
mrEnclavesLen: dec.mrEnclavesLen,
data: dec.data,
dataLen: dec.dataLen,
allowAuthorityOverrideAfter: dec.allowAuthorityOverrideAfter,
requireAuthorityHeartbeatPermission:
dec.requireAuthorityHeartbeatPermission,
requireUsagePermissions: dec.requireUsagePermissions,
maxQuoteVerificationAge: dec.maxQuoteVerificationAge,
reward: dec.reward,
lastHeartbeat: dec.lastHeartbeat,
nodeTimeout: dec.nodeTimeout,
currIdx: dec.currIdx,
gcIdx: dec.gcIdx,
ebuf: dec.ebuf,
});
}
toJSON(): AttestationQueueAccountDataJSON {
return {
authority: this.authority.toString(),
mrEnclaves: this.mrEnclaves,
mrEnclavesLen: this.mrEnclavesLen,
data: this.data.map((item) => item.toString()),
dataLen: this.dataLen,
allowAuthorityOverrideAfter: this.allowAuthorityOverrideAfter.toString(),
requireAuthorityHeartbeatPermission:
this.requireAuthorityHeartbeatPermission,
requireUsagePermissions: this.requireUsagePermissions,
maxQuoteVerificationAge: this.maxQuoteVerificationAge.toString(),
reward: this.reward,
lastHeartbeat: this.lastHeartbeat.toString(),
nodeTimeout: this.nodeTimeout.toString(),
currIdx: this.currIdx,
gcIdx: this.gcIdx,
ebuf: this.ebuf,
};
}
static fromJSON(
obj: AttestationQueueAccountDataJSON
): AttestationQueueAccountData {
return new AttestationQueueAccountData({
authority: new PublicKey(obj.authority),
mrEnclaves: obj.mrEnclaves,
mrEnclavesLen: obj.mrEnclavesLen,
data: obj.data.map((item) => new PublicKey(item)),
dataLen: obj.dataLen,
allowAuthorityOverrideAfter: new BN(obj.allowAuthorityOverrideAfter),
requireAuthorityHeartbeatPermission:
obj.requireAuthorityHeartbeatPermission,
requireUsagePermissions: obj.requireUsagePermissions,
maxQuoteVerificationAge: new BN(obj.maxQuoteVerificationAge),
reward: obj.reward,
lastHeartbeat: new BN(obj.lastHeartbeat),
nodeTimeout: new BN(obj.nodeTimeout),
currIdx: obj.currIdx,
gcIdx: obj.gcIdx,
ebuf: obj.ebuf,
});
}
}

View File

@ -0,0 +1,222 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { Connection, PublicKey } from "@solana/web3.js";
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface FunctionAccountDataFields {
name: Array<number>;
metadata: Array<number>;
authority: PublicKey;
/** */
containerRegistry: Array<number>;
container: Array<number>;
version: Array<number>;
/** */
attestationQueue: PublicKey;
queueIdx: number;
lastExecutionTimestamp: BN;
nextAllowedTimestamp: BN;
schedule: Array<number>;
escrow: PublicKey;
status: types.FunctionStatusKind;
createdAt: BN;
isTriggered: boolean;
addressLookupTable: PublicKey;
ebuf: Array<number>;
}
export interface FunctionAccountDataJSON {
name: Array<number>;
metadata: Array<number>;
authority: string;
/** */
containerRegistry: Array<number>;
container: Array<number>;
version: Array<number>;
/** */
attestationQueue: string;
queueIdx: number;
lastExecutionTimestamp: string;
nextAllowedTimestamp: string;
schedule: Array<number>;
escrow: string;
status: types.FunctionStatusJSON;
createdAt: string;
isTriggered: boolean;
addressLookupTable: string;
ebuf: Array<number>;
}
export class FunctionAccountData {
readonly name: Array<number>;
readonly metadata: Array<number>;
readonly authority: PublicKey;
/** */
readonly containerRegistry: Array<number>;
readonly container: Array<number>;
readonly version: Array<number>;
/** */
readonly attestationQueue: PublicKey;
readonly queueIdx: number;
readonly lastExecutionTimestamp: BN;
readonly nextAllowedTimestamp: BN;
readonly schedule: Array<number>;
readonly escrow: PublicKey;
readonly status: types.FunctionStatusKind;
readonly createdAt: BN;
readonly isTriggered: boolean;
readonly addressLookupTable: PublicKey;
readonly ebuf: Array<number>;
static readonly discriminator = Buffer.from([
76, 139, 47, 44, 240, 182, 148, 200,
]);
static readonly layout = borsh.struct([
borsh.array(borsh.u8(), 64, "name"),
borsh.array(borsh.u8(), 256, "metadata"),
borsh.publicKey("authority"),
borsh.array(borsh.u8(), 64, "containerRegistry"),
borsh.array(borsh.u8(), 64, "container"),
borsh.array(borsh.u8(), 32, "version"),
borsh.publicKey("attestationQueue"),
borsh.u32("queueIdx"),
borsh.i64("lastExecutionTimestamp"),
borsh.i64("nextAllowedTimestamp"),
borsh.array(borsh.u8(), 64, "schedule"),
borsh.publicKey("escrow"),
types.FunctionStatus.layout("status"),
borsh.i64("createdAt"),
borsh.bool("isTriggered"),
borsh.publicKey("addressLookupTable"),
borsh.array(borsh.u8(), 991, "ebuf"),
]);
constructor(fields: FunctionAccountDataFields) {
this.name = fields.name;
this.metadata = fields.metadata;
this.authority = fields.authority;
this.containerRegistry = fields.containerRegistry;
this.container = fields.container;
this.version = fields.version;
this.attestationQueue = fields.attestationQueue;
this.queueIdx = fields.queueIdx;
this.lastExecutionTimestamp = fields.lastExecutionTimestamp;
this.nextAllowedTimestamp = fields.nextAllowedTimestamp;
this.schedule = fields.schedule;
this.escrow = fields.escrow;
this.status = fields.status;
this.createdAt = fields.createdAt;
this.isTriggered = fields.isTriggered;
this.addressLookupTable = fields.addressLookupTable;
this.ebuf = fields.ebuf;
}
static async fetch(
program: SwitchboardProgram,
address: PublicKey
): Promise<FunctionAccountData | null> {
const info = await program.connection.getAccountInfo(address);
if (info === null) {
return null;
}
if (!info.owner.equals(program.attestationProgramId)) {
throw new Error("account doesn't belong to this program");
}
return this.decode(info.data);
}
static async fetchMultiple(
program: SwitchboardProgram,
addresses: PublicKey[]
): Promise<Array<FunctionAccountData | null>> {
const infos = await program.connection.getMultipleAccountsInfo(addresses);
return infos.map((info) => {
if (info === null) {
return null;
}
if (!info.owner.equals(program.attestationProgramId)) {
throw new Error("account doesn't belong to this program");
}
return this.decode(info.data);
});
}
static decode(data: Buffer): FunctionAccountData {
if (!data.slice(0, 8).equals(FunctionAccountData.discriminator)) {
throw new Error("invalid account discriminator");
}
const dec = FunctionAccountData.layout.decode(data.slice(8));
return new FunctionAccountData({
name: dec.name,
metadata: dec.metadata,
authority: dec.authority,
containerRegistry: dec.containerRegistry,
container: dec.container,
version: dec.version,
attestationQueue: dec.attestationQueue,
queueIdx: dec.queueIdx,
lastExecutionTimestamp: dec.lastExecutionTimestamp,
nextAllowedTimestamp: dec.nextAllowedTimestamp,
schedule: dec.schedule,
escrow: dec.escrow,
status: types.FunctionStatus.fromDecoded(dec.status),
createdAt: dec.createdAt,
isTriggered: dec.isTriggered,
addressLookupTable: dec.addressLookupTable,
ebuf: dec.ebuf,
});
}
toJSON(): FunctionAccountDataJSON {
return {
name: this.name,
metadata: this.metadata,
authority: this.authority.toString(),
containerRegistry: this.containerRegistry,
container: this.container,
version: this.version,
attestationQueue: this.attestationQueue.toString(),
queueIdx: this.queueIdx,
lastExecutionTimestamp: this.lastExecutionTimestamp.toString(),
nextAllowedTimestamp: this.nextAllowedTimestamp.toString(),
schedule: this.schedule,
escrow: this.escrow.toString(),
status: this.status.toJSON(),
createdAt: this.createdAt.toString(),
isTriggered: this.isTriggered,
addressLookupTable: this.addressLookupTable.toString(),
ebuf: this.ebuf,
};
}
static fromJSON(obj: FunctionAccountDataJSON): FunctionAccountData {
return new FunctionAccountData({
name: obj.name,
metadata: obj.metadata,
authority: new PublicKey(obj.authority),
containerRegistry: obj.containerRegistry,
container: obj.container,
version: obj.version,
attestationQueue: new PublicKey(obj.attestationQueue),
queueIdx: obj.queueIdx,
lastExecutionTimestamp: new BN(obj.lastExecutionTimestamp),
nextAllowedTimestamp: new BN(obj.nextAllowedTimestamp),
schedule: obj.schedule,
escrow: new PublicKey(obj.escrow),
status: types.FunctionStatus.fromJSON(obj.status),
createdAt: new BN(obj.createdAt),
isTriggered: obj.isTriggered,
addressLookupTable: new PublicKey(obj.addressLookupTable),
ebuf: obj.ebuf,
});
}
}

View File

@ -1,4 +1,4 @@
import { SwitchboardProgram } from "../../SwitchboardProgram.js";
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
@ -6,7 +6,7 @@ import { Connection, PublicKey } from "@solana/web3.js";
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface QuoteAccountDataFields {
delegatedSecuredSigner: PublicKey;
securedSigner: PublicKey;
bump: number;
/** TODO: Add description */
quoteRegistry: Array<number>;
@ -22,11 +22,13 @@ export interface QuoteAccountDataFields {
isOnQueue: boolean;
/** The last time the quote heartbeated. */
lastHeartbeat: BN;
authority: PublicKey;
createdAt: BN;
ebuf: Array<number>;
}
export interface QuoteAccountDataJSON {
delegatedSecuredSigner: string;
securedSigner: string;
bump: number;
/** TODO: Add description */
quoteRegistry: Array<number>;
@ -42,11 +44,13 @@ export interface QuoteAccountDataJSON {
isOnQueue: boolean;
/** The last time the quote heartbeated. */
lastHeartbeat: string;
authority: string;
createdAt: string;
ebuf: Array<number>;
}
export class QuoteAccountData {
readonly delegatedSecuredSigner: PublicKey;
readonly securedSigner: PublicKey;
readonly bump: number;
/** TODO: Add description */
readonly quoteRegistry: Array<number>;
@ -62,6 +66,8 @@ export class QuoteAccountData {
readonly isOnQueue: boolean;
/** The last time the quote heartbeated. */
readonly lastHeartbeat: BN;
readonly authority: PublicKey;
readonly createdAt: BN;
readonly ebuf: Array<number>;
static readonly discriminator = Buffer.from([
@ -69,7 +75,7 @@ export class QuoteAccountData {
]);
static readonly layout = borsh.struct([
borsh.publicKey("delegatedSecuredSigner"),
borsh.publicKey("securedSigner"),
borsh.u8("bump"),
borsh.array(borsh.u8(), 32, "quoteRegistry"),
borsh.array(borsh.u8(), 64, "registryKey"),
@ -80,11 +86,13 @@ export class QuoteAccountData {
borsh.i64("validUntil"),
borsh.bool("isOnQueue"),
borsh.i64("lastHeartbeat"),
borsh.array(borsh.u8(), 1024, "ebuf"),
borsh.publicKey("authority"),
borsh.i64("createdAt"),
borsh.array(borsh.u8(), 992, "ebuf"),
]);
constructor(fields: QuoteAccountDataFields) {
this.delegatedSecuredSigner = fields.delegatedSecuredSigner;
this.securedSigner = fields.securedSigner;
this.bump = fields.bump;
this.quoteRegistry = fields.quoteRegistry;
this.registryKey = fields.registryKey;
@ -95,6 +103,8 @@ export class QuoteAccountData {
this.validUntil = fields.validUntil;
this.isOnQueue = fields.isOnQueue;
this.lastHeartbeat = fields.lastHeartbeat;
this.authority = fields.authority;
this.createdAt = fields.createdAt;
this.ebuf = fields.ebuf;
}
@ -107,7 +117,7 @@ export class QuoteAccountData {
if (info === null) {
return null;
}
if (!info.owner.equals(program.programId)) {
if (!info.owner.equals(program.attestationProgramId)) {
throw new Error("account doesn't belong to this program");
}
@ -124,7 +134,7 @@ export class QuoteAccountData {
if (info === null) {
return null;
}
if (!info.owner.equals(program.programId)) {
if (!info.owner.equals(program.attestationProgramId)) {
throw new Error("account doesn't belong to this program");
}
@ -140,7 +150,7 @@ export class QuoteAccountData {
const dec = QuoteAccountData.layout.decode(data.slice(8));
return new QuoteAccountData({
delegatedSecuredSigner: dec.delegatedSecuredSigner,
securedSigner: dec.securedSigner,
bump: dec.bump,
quoteRegistry: dec.quoteRegistry,
registryKey: dec.registryKey,
@ -151,13 +161,15 @@ export class QuoteAccountData {
validUntil: dec.validUntil,
isOnQueue: dec.isOnQueue,
lastHeartbeat: dec.lastHeartbeat,
authority: dec.authority,
createdAt: dec.createdAt,
ebuf: dec.ebuf,
});
}
toJSON(): QuoteAccountDataJSON {
return {
delegatedSecuredSigner: this.delegatedSecuredSigner.toString(),
securedSigner: this.securedSigner.toString(),
bump: this.bump,
quoteRegistry: this.quoteRegistry,
registryKey: this.registryKey,
@ -168,13 +180,15 @@ export class QuoteAccountData {
validUntil: this.validUntil.toString(),
isOnQueue: this.isOnQueue,
lastHeartbeat: this.lastHeartbeat.toString(),
authority: this.authority.toString(),
createdAt: this.createdAt.toString(),
ebuf: this.ebuf,
};
}
static fromJSON(obj: QuoteAccountDataJSON): QuoteAccountData {
return new QuoteAccountData({
delegatedSecuredSigner: new PublicKey(obj.delegatedSecuredSigner),
securedSigner: new PublicKey(obj.securedSigner),
bump: obj.bump,
quoteRegistry: obj.quoteRegistry,
registryKey: obj.registryKey,
@ -185,6 +199,8 @@ export class QuoteAccountData {
validUntil: new BN(obj.validUntil),
isOnQueue: obj.isOnQueue,
lastHeartbeat: new BN(obj.lastHeartbeat),
authority: new PublicKey(obj.authority),
createdAt: new BN(obj.createdAt),
ebuf: obj.ebuf,
});
}

View File

@ -0,0 +1,96 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import { Connection, PublicKey } from "@solana/web3.js";
import { BN } from "@switchboard-xyz/common"; // eslint-disable-line @typescript-eslint/no-unused-vars
export interface StateFields {
bump: number;
ebuf: Array<number>;
}
export interface StateJSON {
bump: number;
ebuf: Array<number>;
}
export class State {
readonly bump: number;
readonly ebuf: Array<number>;
static readonly discriminator = Buffer.from([
216, 146, 107, 94, 104, 75, 182, 177,
]);
static readonly layout = borsh.struct([
borsh.u8("bump"),
borsh.array(borsh.u8(), 2048, "ebuf"),
]);
constructor(fields: StateFields) {
this.bump = fields.bump;
this.ebuf = fields.ebuf;
}
static async fetch(
program: SwitchboardProgram,
address: PublicKey
): Promise<State | null> {
const info = await program.connection.getAccountInfo(address);
if (info === null) {
return null;
}
if (!info.owner.equals(program.attestationProgramId)) {
throw new Error("account doesn't belong to this program");
}
return this.decode(info.data);
}
static async fetchMultiple(
program: SwitchboardProgram,
addresses: PublicKey[]
): Promise<Array<State | null>> {
const infos = await program.connection.getMultipleAccountsInfo(addresses);
return infos.map((info) => {
if (info === null) {
return null;
}
if (!info.owner.equals(program.attestationProgramId)) {
throw new Error("account doesn't belong to this program");
}
return this.decode(info.data);
});
}
static decode(data: Buffer): State {
if (!data.slice(0, 8).equals(State.discriminator)) {
throw new Error("invalid account discriminator");
}
const dec = State.layout.decode(data.slice(8));
return new State({
bump: dec.bump,
ebuf: dec.ebuf,
});
}
toJSON(): StateJSON {
return {
bump: this.bump,
ebuf: this.ebuf,
};
}
static fromJSON(obj: StateJSON): State {
return new State({
bump: obj.bump,
ebuf: obj.ebuf,
});
}
}

View File

@ -0,0 +1,22 @@
export type {
AttestationPermissionAccountDataFields,
AttestationPermissionAccountDataJSON,
} from "./AttestationPermissionAccountData.js";
export { AttestationPermissionAccountData } from "./AttestationPermissionAccountData.js";
export type {
AttestationQueueAccountDataFields,
AttestationQueueAccountDataJSON,
} from "./AttestationQueueAccountData.js";
export { AttestationQueueAccountData } from "./AttestationQueueAccountData.js";
export type {
FunctionAccountDataFields,
FunctionAccountDataJSON,
} from "./FunctionAccountData.js";
export { FunctionAccountData } from "./FunctionAccountData.js";
export type {
QuoteAccountDataFields,
QuoteAccountDataJSON,
} from "./QuoteAccountData.js";
export { QuoteAccountData } from "./QuoteAccountData.js";
export type { StateFields, StateJSON } from "./State.js";
export { State } from "./State.js";

View File

@ -1,4 +1,4 @@
import { SwitchboardProgram } from '../../SwitchboardProgram';
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
export type AnchorError =
| InstructionMissing
| InstructionFallbackNotFound
@ -58,68 +58,68 @@ export type AnchorError =
export class InstructionMissing extends Error {
static readonly code = 100;
readonly code = 100;
readonly name = 'InstructionMissing';
readonly msg = '8 byte instruction identifier not provided';
readonly name = "InstructionMissing";
readonly msg = "8 byte instruction identifier not provided";
constructor(readonly logs?: string[]) {
super('100: 8 byte instruction identifier not provided');
super("100: 8 byte instruction identifier not provided");
}
}
export class InstructionFallbackNotFound extends Error {
static readonly code = 101;
readonly code = 101;
readonly name = 'InstructionFallbackNotFound';
readonly msg = 'Fallback functions are not supported';
readonly name = "InstructionFallbackNotFound";
readonly msg = "Fallback functions are not supported";
constructor(readonly logs?: string[]) {
super('101: Fallback functions are not supported');
super("101: Fallback functions are not supported");
}
}
export class InstructionDidNotDeserialize extends Error {
static readonly code = 102;
readonly code = 102;
readonly name = 'InstructionDidNotDeserialize';
readonly msg = 'The program could not deserialize the given instruction';
readonly name = "InstructionDidNotDeserialize";
readonly msg = "The program could not deserialize the given instruction";
constructor(readonly logs?: string[]) {
super('102: The program could not deserialize the given instruction');
super("102: The program could not deserialize the given instruction");
}
}
export class InstructionDidNotSerialize extends Error {
static readonly code = 103;
readonly code = 103;
readonly name = 'InstructionDidNotSerialize';
readonly msg = 'The program could not serialize the given instruction';
readonly name = "InstructionDidNotSerialize";
readonly msg = "The program could not serialize the given instruction";
constructor(readonly logs?: string[]) {
super('103: The program could not serialize the given instruction');
super("103: The program could not serialize the given instruction");
}
}
export class IdlInstructionStub extends Error {
static readonly code = 1000;
readonly code = 1000;
readonly name = 'IdlInstructionStub';
readonly msg = 'The program was compiled without idl instructions';
readonly name = "IdlInstructionStub";
readonly msg = "The program was compiled without idl instructions";
constructor(readonly logs?: string[]) {
super('1000: The program was compiled without idl instructions');
super("1000: The program was compiled without idl instructions");
}
}
export class IdlInstructionInvalidProgram extends Error {
static readonly code = 1001;
readonly code = 1001;
readonly name = 'IdlInstructionInvalidProgram';
readonly name = "IdlInstructionInvalidProgram";
readonly msg =
'The transaction was given an invalid program for the IDL instruction';
"The transaction was given an invalid program for the IDL instruction";
constructor(readonly logs?: string[]) {
super(
'1001: The transaction was given an invalid program for the IDL instruction'
"1001: The transaction was given an invalid program for the IDL instruction"
);
}
}
@ -127,387 +127,387 @@ export class IdlInstructionInvalidProgram extends Error {
export class ConstraintMut extends Error {
static readonly code = 2000;
readonly code = 2000;
readonly name = 'ConstraintMut';
readonly msg = 'A mut constraint was violated';
readonly name = "ConstraintMut";
readonly msg = "A mut constraint was violated";
constructor(readonly logs?: string[]) {
super('2000: A mut constraint was violated');
super("2000: A mut constraint was violated");
}
}
export class ConstraintHasOne extends Error {
static readonly code = 2001;
readonly code = 2001;
readonly name = 'ConstraintHasOne';
readonly msg = 'A has_one constraint was violated';
readonly name = "ConstraintHasOne";
readonly msg = "A has_one constraint was violated";
constructor(readonly logs?: string[]) {
super('2001: A has_one constraint was violated');
super("2001: A has_one constraint was violated");
}
}
export class ConstraintSigner extends Error {
static readonly code = 2002;
readonly code = 2002;
readonly name = 'ConstraintSigner';
readonly msg = 'A signer constraint was violated';
readonly name = "ConstraintSigner";
readonly msg = "A signer constraint was violated";
constructor(readonly logs?: string[]) {
super('2002: A signer constraint was violated');
super("2002: A signer constraint was violated");
}
}
export class ConstraintRaw extends Error {
static readonly code = 2003;
readonly code = 2003;
readonly name = 'ConstraintRaw';
readonly msg = 'A raw constraint was violated';
readonly name = "ConstraintRaw";
readonly msg = "A raw constraint was violated";
constructor(readonly logs?: string[]) {
super('2003: A raw constraint was violated');
super("2003: A raw constraint was violated");
}
}
export class ConstraintOwner extends Error {
static readonly code = 2004;
readonly code = 2004;
readonly name = 'ConstraintOwner';
readonly msg = 'An owner constraint was violated';
readonly name = "ConstraintOwner";
readonly msg = "An owner constraint was violated";
constructor(readonly logs?: string[]) {
super('2004: An owner constraint was violated');
super("2004: An owner constraint was violated");
}
}
export class ConstraintRentExempt extends Error {
static readonly code = 2005;
readonly code = 2005;
readonly name = 'ConstraintRentExempt';
readonly msg = 'A rent exemption constraint was violated';
readonly name = "ConstraintRentExempt";
readonly msg = "A rent exemption constraint was violated";
constructor(readonly logs?: string[]) {
super('2005: A rent exemption constraint was violated');
super("2005: A rent exemption constraint was violated");
}
}
export class ConstraintSeeds extends Error {
static readonly code = 2006;
readonly code = 2006;
readonly name = 'ConstraintSeeds';
readonly msg = 'A seeds constraint was violated';
readonly name = "ConstraintSeeds";
readonly msg = "A seeds constraint was violated";
constructor(readonly logs?: string[]) {
super('2006: A seeds constraint was violated');
super("2006: A seeds constraint was violated");
}
}
export class ConstraintExecutable extends Error {
static readonly code = 2007;
readonly code = 2007;
readonly name = 'ConstraintExecutable';
readonly msg = 'An executable constraint was violated';
readonly name = "ConstraintExecutable";
readonly msg = "An executable constraint was violated";
constructor(readonly logs?: string[]) {
super('2007: An executable constraint was violated');
super("2007: An executable constraint was violated");
}
}
export class ConstraintState extends Error {
static readonly code = 2008;
readonly code = 2008;
readonly name = 'ConstraintState';
readonly msg = 'A state constraint was violated';
readonly name = "ConstraintState";
readonly msg = "A state constraint was violated";
constructor(readonly logs?: string[]) {
super('2008: A state constraint was violated');
super("2008: A state constraint was violated");
}
}
export class ConstraintAssociated extends Error {
static readonly code = 2009;
readonly code = 2009;
readonly name = 'ConstraintAssociated';
readonly msg = 'An associated constraint was violated';
readonly name = "ConstraintAssociated";
readonly msg = "An associated constraint was violated";
constructor(readonly logs?: string[]) {
super('2009: An associated constraint was violated');
super("2009: An associated constraint was violated");
}
}
export class ConstraintAssociatedInit extends Error {
static readonly code = 2010;
readonly code = 2010;
readonly name = 'ConstraintAssociatedInit';
readonly msg = 'An associated init constraint was violated';
readonly name = "ConstraintAssociatedInit";
readonly msg = "An associated init constraint was violated";
constructor(readonly logs?: string[]) {
super('2010: An associated init constraint was violated');
super("2010: An associated init constraint was violated");
}
}
export class ConstraintClose extends Error {
static readonly code = 2011;
readonly code = 2011;
readonly name = 'ConstraintClose';
readonly msg = 'A close constraint was violated';
readonly name = "ConstraintClose";
readonly msg = "A close constraint was violated";
constructor(readonly logs?: string[]) {
super('2011: A close constraint was violated');
super("2011: A close constraint was violated");
}
}
export class ConstraintAddress extends Error {
static readonly code = 2012;
readonly code = 2012;
readonly name = 'ConstraintAddress';
readonly msg = 'An address constraint was violated';
readonly name = "ConstraintAddress";
readonly msg = "An address constraint was violated";
constructor(readonly logs?: string[]) {
super('2012: An address constraint was violated');
super("2012: An address constraint was violated");
}
}
export class ConstraintZero extends Error {
static readonly code = 2013;
readonly code = 2013;
readonly name = 'ConstraintZero';
readonly msg = 'Expected zero account discriminant';
readonly name = "ConstraintZero";
readonly msg = "Expected zero account discriminant";
constructor(readonly logs?: string[]) {
super('2013: Expected zero account discriminant');
super("2013: Expected zero account discriminant");
}
}
export class ConstraintTokenMint extends Error {
static readonly code = 2014;
readonly code = 2014;
readonly name = 'ConstraintTokenMint';
readonly msg = 'A token mint constraint was violated';
readonly name = "ConstraintTokenMint";
readonly msg = "A token mint constraint was violated";
constructor(readonly logs?: string[]) {
super('2014: A token mint constraint was violated');
super("2014: A token mint constraint was violated");
}
}
export class ConstraintTokenOwner extends Error {
static readonly code = 2015;
readonly code = 2015;
readonly name = 'ConstraintTokenOwner';
readonly msg = 'A token owner constraint was violated';
readonly name = "ConstraintTokenOwner";
readonly msg = "A token owner constraint was violated";
constructor(readonly logs?: string[]) {
super('2015: A token owner constraint was violated');
super("2015: A token owner constraint was violated");
}
}
export class ConstraintMintMintAuthority extends Error {
static readonly code = 2016;
readonly code = 2016;
readonly name = 'ConstraintMintMintAuthority';
readonly msg = 'A mint mint authority constraint was violated';
readonly name = "ConstraintMintMintAuthority";
readonly msg = "A mint mint authority constraint was violated";
constructor(readonly logs?: string[]) {
super('2016: A mint mint authority constraint was violated');
super("2016: A mint mint authority constraint was violated");
}
}
export class ConstraintMintFreezeAuthority extends Error {
static readonly code = 2017;
readonly code = 2017;
readonly name = 'ConstraintMintFreezeAuthority';
readonly msg = 'A mint freeze authority constraint was violated';
readonly name = "ConstraintMintFreezeAuthority";
readonly msg = "A mint freeze authority constraint was violated";
constructor(readonly logs?: string[]) {
super('2017: A mint freeze authority constraint was violated');
super("2017: A mint freeze authority constraint was violated");
}
}
export class ConstraintMintDecimals extends Error {
static readonly code = 2018;
readonly code = 2018;
readonly name = 'ConstraintMintDecimals';
readonly msg = 'A mint decimals constraint was violated';
readonly name = "ConstraintMintDecimals";
readonly msg = "A mint decimals constraint was violated";
constructor(readonly logs?: string[]) {
super('2018: A mint decimals constraint was violated');
super("2018: A mint decimals constraint was violated");
}
}
export class ConstraintSpace extends Error {
static readonly code = 2019;
readonly code = 2019;
readonly name = 'ConstraintSpace';
readonly msg = 'A space constraint was violated';
readonly name = "ConstraintSpace";
readonly msg = "A space constraint was violated";
constructor(readonly logs?: string[]) {
super('2019: A space constraint was violated');
super("2019: A space constraint was violated");
}
}
export class RequireViolated extends Error {
static readonly code = 2500;
readonly code = 2500;
readonly name = 'RequireViolated';
readonly msg = 'A require expression was violated';
readonly name = "RequireViolated";
readonly msg = "A require expression was violated";
constructor(readonly logs?: string[]) {
super('2500: A require expression was violated');
super("2500: A require expression was violated");
}
}
export class RequireEqViolated extends Error {
static readonly code = 2501;
readonly code = 2501;
readonly name = 'RequireEqViolated';
readonly msg = 'A require_eq expression was violated';
readonly name = "RequireEqViolated";
readonly msg = "A require_eq expression was violated";
constructor(readonly logs?: string[]) {
super('2501: A require_eq expression was violated');
super("2501: A require_eq expression was violated");
}
}
export class RequireKeysEqViolated extends Error {
static readonly code = 2502;
readonly code = 2502;
readonly name = 'RequireKeysEqViolated';
readonly msg = 'A require_keys_eq expression was violated';
readonly name = "RequireKeysEqViolated";
readonly msg = "A require_keys_eq expression was violated";
constructor(readonly logs?: string[]) {
super('2502: A require_keys_eq expression was violated');
super("2502: A require_keys_eq expression was violated");
}
}
export class RequireNeqViolated extends Error {
static readonly code = 2503;
readonly code = 2503;
readonly name = 'RequireNeqViolated';
readonly msg = 'A require_neq expression was violated';
readonly name = "RequireNeqViolated";
readonly msg = "A require_neq expression was violated";
constructor(readonly logs?: string[]) {
super('2503: A require_neq expression was violated');
super("2503: A require_neq expression was violated");
}
}
export class RequireKeysNeqViolated extends Error {
static readonly code = 2504;
readonly code = 2504;
readonly name = 'RequireKeysNeqViolated';
readonly msg = 'A require_keys_neq expression was violated';
readonly name = "RequireKeysNeqViolated";
readonly msg = "A require_keys_neq expression was violated";
constructor(readonly logs?: string[]) {
super('2504: A require_keys_neq expression was violated');
super("2504: A require_keys_neq expression was violated");
}
}
export class RequireGtViolated extends Error {
static readonly code = 2505;
readonly code = 2505;
readonly name = 'RequireGtViolated';
readonly msg = 'A require_gt expression was violated';
readonly name = "RequireGtViolated";
readonly msg = "A require_gt expression was violated";
constructor(readonly logs?: string[]) {
super('2505: A require_gt expression was violated');
super("2505: A require_gt expression was violated");
}
}
export class RequireGteViolated extends Error {
static readonly code = 2506;
readonly code = 2506;
readonly name = 'RequireGteViolated';
readonly msg = 'A require_gte expression was violated';
readonly name = "RequireGteViolated";
readonly msg = "A require_gte expression was violated";
constructor(readonly logs?: string[]) {
super('2506: A require_gte expression was violated');
super("2506: A require_gte expression was violated");
}
}
export class AccountDiscriminatorAlreadySet extends Error {
static readonly code = 3000;
readonly code = 3000;
readonly name = 'AccountDiscriminatorAlreadySet';
readonly msg = 'The account discriminator was already set on this account';
readonly name = "AccountDiscriminatorAlreadySet";
readonly msg = "The account discriminator was already set on this account";
constructor(readonly logs?: string[]) {
super('3000: The account discriminator was already set on this account');
super("3000: The account discriminator was already set on this account");
}
}
export class AccountDiscriminatorNotFound extends Error {
static readonly code = 3001;
readonly code = 3001;
readonly name = 'AccountDiscriminatorNotFound';
readonly msg = 'No 8 byte discriminator was found on the account';
readonly name = "AccountDiscriminatorNotFound";
readonly msg = "No 8 byte discriminator was found on the account";
constructor(readonly logs?: string[]) {
super('3001: No 8 byte discriminator was found on the account');
super("3001: No 8 byte discriminator was found on the account");
}
}
export class AccountDiscriminatorMismatch extends Error {
static readonly code = 3002;
readonly code = 3002;
readonly name = 'AccountDiscriminatorMismatch';
readonly msg = '8 byte discriminator did not match what was expected';
readonly name = "AccountDiscriminatorMismatch";
readonly msg = "8 byte discriminator did not match what was expected";
constructor(readonly logs?: string[]) {
super('3002: 8 byte discriminator did not match what was expected');
super("3002: 8 byte discriminator did not match what was expected");
}
}
export class AccountDidNotDeserialize extends Error {
static readonly code = 3003;
readonly code = 3003;
readonly name = 'AccountDidNotDeserialize';
readonly msg = 'Failed to deserialize the account';
readonly name = "AccountDidNotDeserialize";
readonly msg = "Failed to deserialize the account";
constructor(readonly logs?: string[]) {
super('3003: Failed to deserialize the account');
super("3003: Failed to deserialize the account");
}
}
export class AccountDidNotSerialize extends Error {
static readonly code = 3004;
readonly code = 3004;
readonly name = 'AccountDidNotSerialize';
readonly msg = 'Failed to serialize the account';
readonly name = "AccountDidNotSerialize";
readonly msg = "Failed to serialize the account";
constructor(readonly logs?: string[]) {
super('3004: Failed to serialize the account');
super("3004: Failed to serialize the account");
}
}
export class AccountNotEnoughKeys extends Error {
static readonly code = 3005;
readonly code = 3005;
readonly name = 'AccountNotEnoughKeys';
readonly msg = 'Not enough account keys given to the instruction';
readonly name = "AccountNotEnoughKeys";
readonly msg = "Not enough account keys given to the instruction";
constructor(readonly logs?: string[]) {
super('3005: Not enough account keys given to the instruction');
super("3005: Not enough account keys given to the instruction");
}
}
export class AccountNotMutable extends Error {
static readonly code = 3006;
readonly code = 3006;
readonly name = 'AccountNotMutable';
readonly msg = 'The given account is not mutable';
readonly name = "AccountNotMutable";
readonly msg = "The given account is not mutable";
constructor(readonly logs?: string[]) {
super('3006: The given account is not mutable');
super("3006: The given account is not mutable");
}
}
export class AccountOwnedByWrongProgram extends Error {
static readonly code = 3007;
readonly code = 3007;
readonly name = 'AccountOwnedByWrongProgram';
readonly name = "AccountOwnedByWrongProgram";
readonly msg =
'The given account is owned by a different program than expected';
"The given account is owned by a different program than expected";
constructor(readonly logs?: string[]) {
super(
'3007: The given account is owned by a different program than expected'
"3007: The given account is owned by a different program than expected"
);
}
}
@ -515,101 +515,101 @@ export class AccountOwnedByWrongProgram extends Error {
export class InvalidProgramId extends Error {
static readonly code = 3008;
readonly code = 3008;
readonly name = 'InvalidProgramId';
readonly msg = 'Program ID was not as expected';
readonly name = "InvalidProgramId";
readonly msg = "Program ID was not as expected";
constructor(readonly logs?: string[]) {
super('3008: Program ID was not as expected');
super("3008: Program ID was not as expected");
}
}
export class InvalidProgramExecutable extends Error {
static readonly code = 3009;
readonly code = 3009;
readonly name = 'InvalidProgramExecutable';
readonly msg = 'Program account is not executable';
readonly name = "InvalidProgramExecutable";
readonly msg = "Program account is not executable";
constructor(readonly logs?: string[]) {
super('3009: Program account is not executable');
super("3009: Program account is not executable");
}
}
export class AccountNotSigner extends Error {
static readonly code = 3010;
readonly code = 3010;
readonly name = 'AccountNotSigner';
readonly msg = 'The given account did not sign';
readonly name = "AccountNotSigner";
readonly msg = "The given account did not sign";
constructor(readonly logs?: string[]) {
super('3010: The given account did not sign');
super("3010: The given account did not sign");
}
}
export class AccountNotSystemOwned extends Error {
static readonly code = 3011;
readonly code = 3011;
readonly name = 'AccountNotSystemOwned';
readonly msg = 'The given account is not owned by the system program';
readonly name = "AccountNotSystemOwned";
readonly msg = "The given account is not owned by the system program";
constructor(readonly logs?: string[]) {
super('3011: The given account is not owned by the system program');
super("3011: The given account is not owned by the system program");
}
}
export class AccountNotInitialized extends Error {
static readonly code = 3012;
readonly code = 3012;
readonly name = 'AccountNotInitialized';
readonly msg = 'The program expected this account to be already initialized';
readonly name = "AccountNotInitialized";
readonly msg = "The program expected this account to be already initialized";
constructor(readonly logs?: string[]) {
super('3012: The program expected this account to be already initialized');
super("3012: The program expected this account to be already initialized");
}
}
export class AccountNotProgramData extends Error {
static readonly code = 3013;
readonly code = 3013;
readonly name = 'AccountNotProgramData';
readonly msg = 'The given account is not a program data account';
readonly name = "AccountNotProgramData";
readonly msg = "The given account is not a program data account";
constructor(readonly logs?: string[]) {
super('3013: The given account is not a program data account');
super("3013: The given account is not a program data account");
}
}
export class AccountNotAssociatedTokenAccount extends Error {
static readonly code = 3014;
readonly code = 3014;
readonly name = 'AccountNotAssociatedTokenAccount';
readonly msg = 'The given account is not the associated token account';
readonly name = "AccountNotAssociatedTokenAccount";
readonly msg = "The given account is not the associated token account";
constructor(readonly logs?: string[]) {
super('3014: The given account is not the associated token account');
super("3014: The given account is not the associated token account");
}
}
export class AccountSysvarMismatch extends Error {
static readonly code = 3015;
readonly code = 3015;
readonly name = 'AccountSysvarMismatch';
readonly msg = 'The given public key does not match the required sysvar';
readonly name = "AccountSysvarMismatch";
readonly msg = "The given public key does not match the required sysvar";
constructor(readonly logs?: string[]) {
super('3015: The given public key does not match the required sysvar');
super("3015: The given public key does not match the required sysvar");
}
}
export class AccountReallocExceedsLimit extends Error {
static readonly code = 3016;
readonly code = 3016;
readonly name = 'AccountReallocExceedsLimit';
readonly name = "AccountReallocExceedsLimit";
readonly msg =
'The account reallocation exceeds the MAX_PERMITTED_DATA_INCREASE limit';
"The account reallocation exceeds the MAX_PERMITTED_DATA_INCREASE limit";
constructor(readonly logs?: string[]) {
super(
'3016: The account reallocation exceeds the MAX_PERMITTED_DATA_INCREASE limit'
"3016: The account reallocation exceeds the MAX_PERMITTED_DATA_INCREASE limit"
);
}
}
@ -617,46 +617,46 @@ export class AccountReallocExceedsLimit extends Error {
export class AccountDuplicateReallocs extends Error {
static readonly code = 3017;
readonly code = 3017;
readonly name = 'AccountDuplicateReallocs';
readonly msg = 'The account was duplicated for more than one reallocation';
readonly name = "AccountDuplicateReallocs";
readonly msg = "The account was duplicated for more than one reallocation";
constructor(readonly logs?: string[]) {
super('3017: The account was duplicated for more than one reallocation');
super("3017: The account was duplicated for more than one reallocation");
}
}
export class StateInvalidAddress extends Error {
static readonly code = 4000;
readonly code = 4000;
readonly name = 'StateInvalidAddress';
readonly msg = 'The given state account does not have the correct address';
readonly name = "StateInvalidAddress";
readonly msg = "The given state account does not have the correct address";
constructor(readonly logs?: string[]) {
super('4000: The given state account does not have the correct address');
super("4000: The given state account does not have the correct address");
}
}
export class DeclaredProgramIdMismatch extends Error {
static readonly code = 4100;
readonly code = 4100;
readonly name = 'DeclaredProgramIdMismatch';
readonly msg = 'The declared program id does not match the actual program id';
readonly name = "DeclaredProgramIdMismatch";
readonly msg = "The declared program id does not match the actual program id";
constructor(readonly logs?: string[]) {
super('4100: The declared program id does not match the actual program id');
super("4100: The declared program id does not match the actual program id");
}
}
export class Deprecated extends Error {
static readonly code = 5000;
readonly code = 5000;
readonly name = 'Deprecated';
readonly name = "Deprecated";
readonly msg =
'The API being used is deprecated and should no longer be used';
"The API being used is deprecated and should no longer be used";
constructor(readonly logs?: string[]) {
super(
'5000: The API being used is deprecated and should no longer be used'
"5000: The API being used is deprecated and should no longer be used"
);
}
}

View File

@ -0,0 +1,308 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
export type CustomError =
| GenericError
| InvalidQuoteError
| QuoteExpiredError
| InvalidNodeError
| InsufficientQueueError
| QueueFullError
| InvalidSignerError
| MrEnclaveAlreadyExists
| MrEnclaveDoesntExist
| MrEnclaveAtCapacity
| PermissionDenied
| InvalidConstraint
| InvalidTimestamp
| InvalidMrEnclave
| InvalidReportData
| InsufficientLoadAmountError
| IncorrectObservedTimeError
| InvalidQuoteMode
| InvalidVerifierIdx
| InvalidSelfVerifyRequest
| IncorrectMrEnclave
| InvalidResponder
| InvalidAddressLookupAddress;
export class GenericError extends Error {
static readonly code = 6000;
readonly code = 6000;
readonly name = "GenericError";
constructor(readonly logs?: string[]) {
super("6000: ");
}
}
export class InvalidQuoteError extends Error {
static readonly code = 6001;
readonly code = 6001;
readonly name = "InvalidQuoteError";
constructor(readonly logs?: string[]) {
super("6001: ");
}
}
export class QuoteExpiredError extends Error {
static readonly code = 6002;
readonly code = 6002;
readonly name = "QuoteExpiredError";
constructor(readonly logs?: string[]) {
super("6002: ");
}
}
export class InvalidNodeError extends Error {
static readonly code = 6003;
readonly code = 6003;
readonly name = "InvalidNodeError";
constructor(readonly logs?: string[]) {
super("6003: ");
}
}
export class InsufficientQueueError extends Error {
static readonly code = 6004;
readonly code = 6004;
readonly name = "InsufficientQueueError";
constructor(readonly logs?: string[]) {
super("6004: ");
}
}
export class QueueFullError extends Error {
static readonly code = 6005;
readonly code = 6005;
readonly name = "QueueFullError";
constructor(readonly logs?: string[]) {
super("6005: ");
}
}
export class InvalidSignerError extends Error {
static readonly code = 6006;
readonly code = 6006;
readonly name = "InvalidSignerError";
constructor(readonly logs?: string[]) {
super("6006: ");
}
}
export class MrEnclaveAlreadyExists extends Error {
static readonly code = 6007;
readonly code = 6007;
readonly name = "MrEnclaveAlreadyExists";
constructor(readonly logs?: string[]) {
super("6007: ");
}
}
export class MrEnclaveDoesntExist extends Error {
static readonly code = 6008;
readonly code = 6008;
readonly name = "MrEnclaveDoesntExist";
constructor(readonly logs?: string[]) {
super("6008: ");
}
}
export class MrEnclaveAtCapacity extends Error {
static readonly code = 6009;
readonly code = 6009;
readonly name = "MrEnclaveAtCapacity";
constructor(readonly logs?: string[]) {
super("6009: ");
}
}
export class PermissionDenied extends Error {
static readonly code = 6010;
readonly code = 6010;
readonly name = "PermissionDenied";
constructor(readonly logs?: string[]) {
super("6010: ");
}
}
export class InvalidConstraint extends Error {
static readonly code = 6011;
readonly code = 6011;
readonly name = "InvalidConstraint";
constructor(readonly logs?: string[]) {
super("6011: ");
}
}
export class InvalidTimestamp extends Error {
static readonly code = 6012;
readonly code = 6012;
readonly name = "InvalidTimestamp";
constructor(readonly logs?: string[]) {
super("6012: ");
}
}
export class InvalidMrEnclave extends Error {
static readonly code = 6013;
readonly code = 6013;
readonly name = "InvalidMrEnclave";
constructor(readonly logs?: string[]) {
super("6013: ");
}
}
export class InvalidReportData extends Error {
static readonly code = 6014;
readonly code = 6014;
readonly name = "InvalidReportData";
constructor(readonly logs?: string[]) {
super("6014: ");
}
}
export class InsufficientLoadAmountError extends Error {
static readonly code = 6015;
readonly code = 6015;
readonly name = "InsufficientLoadAmountError";
constructor(readonly logs?: string[]) {
super("6015: ");
}
}
export class IncorrectObservedTimeError extends Error {
static readonly code = 6016;
readonly code = 6016;
readonly name = "IncorrectObservedTimeError";
constructor(readonly logs?: string[]) {
super("6016: ");
}
}
export class InvalidQuoteMode extends Error {
static readonly code = 6017;
readonly code = 6017;
readonly name = "InvalidQuoteMode";
constructor(readonly logs?: string[]) {
super("6017: ");
}
}
export class InvalidVerifierIdx extends Error {
static readonly code = 6018;
readonly code = 6018;
readonly name = "InvalidVerifierIdx";
constructor(readonly logs?: string[]) {
super("6018: ");
}
}
export class InvalidSelfVerifyRequest extends Error {
static readonly code = 6019;
readonly code = 6019;
readonly name = "InvalidSelfVerifyRequest";
constructor(readonly logs?: string[]) {
super("6019: ");
}
}
export class IncorrectMrEnclave extends Error {
static readonly code = 6020;
readonly code = 6020;
readonly name = "IncorrectMrEnclave";
constructor(readonly logs?: string[]) {
super("6020: ");
}
}
export class InvalidResponder extends Error {
static readonly code = 6021;
readonly code = 6021;
readonly name = "InvalidResponder";
constructor(readonly logs?: string[]) {
super("6021: ");
}
}
export class InvalidAddressLookupAddress extends Error {
static readonly code = 6022;
readonly code = 6022;
readonly name = "InvalidAddressLookupAddress";
constructor(readonly logs?: string[]) {
super("6022: ");
}
}
export function fromCode(code: number, logs?: string[]): CustomError | null {
switch (code) {
case 6000:
return new GenericError(logs);
case 6001:
return new InvalidQuoteError(logs);
case 6002:
return new QuoteExpiredError(logs);
case 6003:
return new InvalidNodeError(logs);
case 6004:
return new InsufficientQueueError(logs);
case 6005:
return new QueueFullError(logs);
case 6006:
return new InvalidSignerError(logs);
case 6007:
return new MrEnclaveAlreadyExists(logs);
case 6008:
return new MrEnclaveDoesntExist(logs);
case 6009:
return new MrEnclaveAtCapacity(logs);
case 6010:
return new PermissionDenied(logs);
case 6011:
return new InvalidConstraint(logs);
case 6012:
return new InvalidTimestamp(logs);
case 6013:
return new InvalidMrEnclave(logs);
case 6014:
return new InvalidReportData(logs);
case 6015:
return new InsufficientLoadAmountError(logs);
case 6016:
return new IncorrectObservedTimeError(logs);
case 6017:
return new InvalidQuoteMode(logs);
case 6018:
return new InvalidVerifierIdx(logs);
case 6019:
return new InvalidSelfVerifyRequest(logs);
case 6020:
return new IncorrectMrEnclave(logs);
case 6021:
return new InvalidResponder(logs);
case 6022:
return new InvalidAddressLookupAddress(logs);
}
return null;
}

View File

@ -0,0 +1,61 @@
import { PROGRAM_ID } from "../programId.js";
import * as anchor from "./anchor.js";
import * as custom from "./custom.js";
export function fromAttestationCode(
code: number,
logs?: string[]
): custom.CustomError | anchor.AnchorError | null {
return code >= 6000
? custom.fromCode(code, logs)
: anchor.fromCode(code, logs);
}
function hasOwnProperty<X extends object, Y extends PropertyKey>(
obj: X,
prop: Y
): obj is X & Record<Y, unknown> {
return Object.hasOwnProperty.call(obj, prop);
}
const errorRe = /Program (\w+) failed: custom program error: (\w+)/;
export function fromAttestationTxError(
err: unknown
): custom.CustomError | anchor.AnchorError | null {
if (
typeof err !== "object" ||
err === null ||
!hasOwnProperty(err, "logs") ||
!Array.isArray(err.logs)
) {
return null;
}
let firstMatch: RegExpExecArray | null = null;
for (const logLine of err.logs) {
firstMatch = errorRe.exec(logLine);
if (firstMatch !== null) {
break;
}
}
if (firstMatch === null) {
return null;
}
const [programIdRaw, codeRaw] = firstMatch.slice(1);
if (programIdRaw !== PROGRAM_ID.toString()) {
return null;
}
let errorCode: number;
try {
errorCode = parseInt(codeRaw, 16);
} catch (parseErr) {
return null;
}
return fromAttestationCode(errorCode, err.logs);
}

View File

@ -0,0 +1,4 @@
export * from "./accounts/index.js";
export * from "./errors/index.js";
export * from "./instructions/index.js";
export * from "./types/index.js";

View File

@ -0,0 +1,57 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} 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
export interface AttestationPermissionInitArgs {
params: types.AttestationPermissionInitParamsFields;
}
export interface AttestationPermissionInitAccounts {
permission: PublicKey;
authority: PublicKey;
attestationQueue: PublicKey;
node: PublicKey;
payer: PublicKey;
systemProgram: PublicKey;
}
export const layout = borsh.struct([
types.AttestationPermissionInitParams.layout("params"),
]);
export function attestationPermissionInit(
program: SwitchboardProgram,
args: AttestationPermissionInitArgs,
accounts: AttestationPermissionInitAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.permission, isSigner: false, isWritable: true },
{ pubkey: accounts.authority, isSigner: false, isWritable: false },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: false },
{ pubkey: accounts.node, isSigner: false, isWritable: false },
{ pubkey: accounts.payer, isSigner: true, isWritable: true },
{ pubkey: accounts.systemProgram, isSigner: false, isWritable: false },
];
const identifier = Buffer.from([219, 80, 131, 73, 164, 190, 142, 215]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.AttestationPermissionInitParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -0,0 +1,53 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} 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
export interface AttestationPermissionSetArgs {
params: types.AttestationPermissionSetParamsFields;
}
export interface AttestationPermissionSetAccounts {
permission: PublicKey;
authority: PublicKey;
attestationQueue: PublicKey;
node: PublicKey;
}
export const layout = borsh.struct([
types.AttestationPermissionSetParams.layout("params"),
]);
export function attestationPermissionSet(
program: SwitchboardProgram,
args: AttestationPermissionSetArgs,
accounts: AttestationPermissionSetAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.permission, isSigner: false, isWritable: true },
{ pubkey: accounts.authority, isSigner: true, isWritable: false },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: false },
{ pubkey: accounts.node, isSigner: false, isWritable: false },
];
const identifier = Buffer.from([56, 253, 255, 201, 100, 153, 10, 76]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.AttestationPermissionSetParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -0,0 +1,49 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} 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
export interface AttestationQueueAddMrEnclaveArgs {
params: types.AttestationQueueAddMrEnclaveParamsFields;
}
export interface AttestationQueueAddMrEnclaveAccounts {
queue: PublicKey;
authority: PublicKey;
}
export const layout = borsh.struct([
types.AttestationQueueAddMrEnclaveParams.layout("params"),
]);
export function attestationQueueAddMrEnclave(
program: SwitchboardProgram,
args: AttestationQueueAddMrEnclaveArgs,
accounts: AttestationQueueAddMrEnclaveAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.queue, isSigner: false, isWritable: true },
{ pubkey: accounts.authority, isSigner: true, isWritable: false },
];
const identifier = Buffer.from([62, 27, 24, 221, 30, 240, 63, 167]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.AttestationQueueAddMrEnclaveParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -0,0 +1,53 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} 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
export interface AttestationQueueInitArgs {
params: types.AttestationQueueInitParamsFields;
}
export interface AttestationQueueInitAccounts {
queue: PublicKey;
authority: PublicKey;
payer: PublicKey;
systemProgram: PublicKey;
}
export const layout = borsh.struct([
types.AttestationQueueInitParams.layout("params"),
]);
export function attestationQueueInit(
program: SwitchboardProgram,
args: AttestationQueueInitArgs,
accounts: AttestationQueueInitAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.queue, isSigner: true, isWritable: true },
{ pubkey: accounts.authority, isSigner: false, isWritable: false },
{ pubkey: accounts.payer, isSigner: true, isWritable: true },
{ pubkey: accounts.systemProgram, isSigner: false, isWritable: false },
];
const identifier = Buffer.from([82, 211, 133, 63, 177, 112, 210, 216]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.AttestationQueueInitParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -0,0 +1,51 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} 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
export interface AttestationQueueRemoveMrEnclaveArgs {
params: types.AttestationQueueRemoveMrEnclaveParamsFields;
}
export interface AttestationQueueRemoveMrEnclaveAccounts {
queue: PublicKey;
authority: PublicKey;
}
export const layout = borsh.struct([
types.AttestationQueueRemoveMrEnclaveParams.layout("params"),
]);
export function attestationQueueRemoveMrEnclave(
program: SwitchboardProgram,
args: AttestationQueueRemoveMrEnclaveArgs,
accounts: AttestationQueueRemoveMrEnclaveAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.queue, isSigner: false, isWritable: true },
{ pubkey: accounts.authority, isSigner: true, isWritable: false },
];
const identifier = Buffer.from([202, 141, 93, 179, 212, 230, 34, 238]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.AttestationQueueRemoveMrEnclaveParams.toEncodable(
args.params
),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -0,0 +1,63 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} 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
export interface FunctionFundArgs {
params: types.FunctionFundParamsFields;
}
export interface FunctionFundAccounts {
function: PublicKey;
attestationQueue: PublicKey;
escrow: PublicKey;
funder: PublicKey;
funderAuthority: PublicKey;
state: PublicKey;
tokenProgram: PublicKey;
associatedTokenProgram: PublicKey;
}
export const layout = borsh.struct([types.FunctionFundParams.layout("params")]);
export function functionFund(
program: SwitchboardProgram,
args: FunctionFundArgs,
accounts: FunctionFundAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.function, isSigner: false, isWritable: true },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: false },
{ pubkey: accounts.escrow, isSigner: false, isWritable: true },
{ pubkey: accounts.funder, isSigner: false, isWritable: true },
{ pubkey: accounts.funderAuthority, isSigner: true, isWritable: false },
{ pubkey: accounts.state, isSigner: false, isWritable: true },
{ pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
{
pubkey: accounts.associatedTokenProgram,
isSigner: false,
isWritable: false,
},
];
const identifier = Buffer.from([216, 39, 120, 216, 124, 169, 163, 62]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.FunctionFundParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -0,0 +1,79 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} 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
export interface FunctionInitArgs {
params: types.FunctionInitParamsFields;
}
export interface FunctionInitAccounts {
function: PublicKey;
addressLookupTable: PublicKey;
authority: PublicKey;
quote: PublicKey;
attestationQueue: PublicKey;
permission: PublicKey;
payer: PublicKey;
escrow: PublicKey;
state: PublicKey;
mint: PublicKey;
tokenProgram: PublicKey;
associatedTokenProgram: PublicKey;
systemProgram: PublicKey;
addressLookupProgram: PublicKey;
}
export const layout = borsh.struct([types.FunctionInitParams.layout("params")]);
export function functionInit(
program: SwitchboardProgram,
args: FunctionInitArgs,
accounts: FunctionInitAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.function, isSigner: true, isWritable: true },
{ pubkey: accounts.addressLookupTable, isSigner: false, isWritable: true },
{ pubkey: accounts.authority, isSigner: true, isWritable: true },
{ pubkey: accounts.quote, isSigner: false, isWritable: true },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: false },
{ pubkey: accounts.permission, isSigner: false, isWritable: true },
{ pubkey: accounts.payer, isSigner: true, isWritable: true },
{ pubkey: accounts.escrow, isSigner: false, isWritable: true },
{ pubkey: accounts.state, isSigner: false, isWritable: true },
{ pubkey: accounts.mint, isSigner: false, isWritable: false },
{ pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
{
pubkey: accounts.associatedTokenProgram,
isSigner: false,
isWritable: false,
},
{ pubkey: accounts.systemProgram, isSigner: false, isWritable: false },
{
pubkey: accounts.addressLookupProgram,
isSigner: false,
isWritable: false,
},
];
const identifier = Buffer.from([0, 20, 30, 24, 100, 146, 13, 162]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.FunctionInitParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -0,0 +1,73 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} 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
export interface FunctionVerifyArgs {
params: types.FunctionVerifyParamsFields;
}
export interface FunctionVerifyAccounts {
function: PublicKey;
fnSigner: PublicKey;
fnQuote: PublicKey;
verifierQuote: PublicKey;
securedSigner: PublicKey;
attestationQueue: PublicKey;
escrow: PublicKey;
receiver: PublicKey;
verifierPermission: PublicKey;
fnPermission: PublicKey;
state: PublicKey;
tokenProgram: PublicKey;
payer: PublicKey;
systemProgram: PublicKey;
}
export const layout = borsh.struct([
types.FunctionVerifyParams.layout("params"),
]);
export function functionVerify(
program: SwitchboardProgram,
args: FunctionVerifyArgs,
accounts: FunctionVerifyAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.function, isSigner: false, isWritable: true },
{ pubkey: accounts.fnSigner, isSigner: true, isWritable: false },
{ pubkey: accounts.fnQuote, isSigner: false, isWritable: true },
{ pubkey: accounts.verifierQuote, isSigner: false, isWritable: false },
{ pubkey: accounts.securedSigner, isSigner: true, isWritable: false },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: false },
{ pubkey: accounts.escrow, isSigner: false, isWritable: true },
{ pubkey: accounts.receiver, isSigner: false, isWritable: true },
{ pubkey: accounts.verifierPermission, isSigner: false, isWritable: false },
{ pubkey: accounts.fnPermission, isSigner: false, isWritable: false },
{ pubkey: accounts.state, isSigner: false, isWritable: true },
{ pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
{ pubkey: accounts.payer, isSigner: true, isWritable: true },
{ pubkey: accounts.systemProgram, isSigner: false, isWritable: false },
];
const identifier = Buffer.from([210, 108, 154, 138, 198, 14, 53, 191]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.FunctionVerifyParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -0,0 +1,59 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} 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
export interface FunctionWithdrawArgs {
params: types.FunctionWithdrawParamsFields;
}
export interface FunctionWithdrawAccounts {
function: PublicKey;
attestationQueue: PublicKey;
authority: PublicKey;
escrow: PublicKey;
receiver: PublicKey;
state: PublicKey;
tokenProgram: PublicKey;
}
export const layout = borsh.struct([
types.FunctionWithdrawParams.layout("params"),
]);
export function functionWithdraw(
program: SwitchboardProgram,
args: FunctionWithdrawArgs,
accounts: FunctionWithdrawAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.function, isSigner: false, isWritable: true },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: false },
{ pubkey: accounts.authority, isSigner: true, isWritable: true },
{ pubkey: accounts.escrow, isSigner: false, isWritable: true },
{ pubkey: accounts.receiver, isSigner: false, isWritable: true },
{ pubkey: accounts.state, isSigner: false, isWritable: true },
{ pubkey: accounts.tokenProgram, isSigner: false, isWritable: false },
];
const identifier = Buffer.from([6, 182, 241, 39, 40, 111, 65, 195]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.FunctionWithdrawParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -0,0 +1,52 @@
export type {
AttestationPermissionInitAccounts,
AttestationPermissionInitArgs,
} from "./attestationPermissionInit.js";
export { attestationPermissionInit } from "./attestationPermissionInit.js";
export type {
AttestationPermissionSetAccounts,
AttestationPermissionSetArgs,
} from "./attestationPermissionSet.js";
export { attestationPermissionSet } from "./attestationPermissionSet.js";
export type {
AttestationQueueAddMrEnclaveAccounts,
AttestationQueueAddMrEnclaveArgs,
} from "./attestationQueueAddMrEnclave.js";
export { attestationQueueAddMrEnclave } from "./attestationQueueAddMrEnclave.js";
export type {
AttestationQueueInitAccounts,
AttestationQueueInitArgs,
} from "./attestationQueueInit.js";
export { attestationQueueInit } from "./attestationQueueInit.js";
export type {
AttestationQueueRemoveMrEnclaveAccounts,
AttestationQueueRemoveMrEnclaveArgs,
} from "./attestationQueueRemoveMrEnclave.js";
export { attestationQueueRemoveMrEnclave } from "./attestationQueueRemoveMrEnclave.js";
export type { FunctionFundAccounts, FunctionFundArgs } from "./functionFund.js";
export { functionFund } from "./functionFund.js";
export type { FunctionInitAccounts, FunctionInitArgs } from "./functionInit.js";
export { functionInit } from "./functionInit.js";
export type {
FunctionVerifyAccounts,
FunctionVerifyArgs,
} from "./functionVerify.js";
export { functionVerify } from "./functionVerify.js";
export type {
FunctionWithdrawAccounts,
FunctionWithdrawArgs,
} from "./functionWithdraw.js";
export { functionWithdraw } from "./functionWithdraw.js";
export type {
QuoteHeartbeatAccounts,
QuoteHeartbeatArgs,
} from "./quoteHeartbeat.js";
export { quoteHeartbeat } from "./quoteHeartbeat.js";
export type { QuoteInitAccounts, QuoteInitArgs } from "./quoteInit.js";
export { quoteInit } from "./quoteInit.js";
export type { QuoteRotateAccounts, QuoteRotateArgs } from "./quoteRotate.js";
export { quoteRotate } from "./quoteRotate.js";
export type { QuoteVerifyAccounts, QuoteVerifyArgs } from "./quoteVerify.js";
export { quoteVerify } from "./quoteVerify.js";
export type { StateInitAccounts, StateInitArgs } from "./stateInit.js";
export { stateInit } from "./stateInit.js";

View File

@ -0,0 +1,57 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} 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
export interface QuoteHeartbeatArgs {
params: types.QuoteHeartbeatParamsFields;
}
export interface QuoteHeartbeatAccounts {
quote: PublicKey;
securedSigner: PublicKey;
attestationQueue: PublicKey;
queueAuthority: PublicKey;
gcNode: PublicKey;
permission: PublicKey;
}
export const layout = borsh.struct([
types.QuoteHeartbeatParams.layout("params"),
]);
export function quoteHeartbeat(
program: SwitchboardProgram,
args: QuoteHeartbeatArgs,
accounts: QuoteHeartbeatAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.quote, isSigner: false, isWritable: true },
{ pubkey: accounts.securedSigner, isSigner: true, isWritable: false },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: true },
{ pubkey: accounts.queueAuthority, isSigner: false, isWritable: false },
{ pubkey: accounts.gcNode, isSigner: false, isWritable: true },
{ pubkey: accounts.permission, isSigner: false, isWritable: false },
];
const identifier = Buffer.from([202, 24, 19, 240, 75, 39, 154, 110]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.QuoteHeartbeatParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -0,0 +1,55 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} 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
export interface QuoteInitArgs {
params: types.QuoteInitParamsFields;
}
export interface QuoteInitAccounts {
quote: PublicKey;
attestationQueue: PublicKey;
queueAuthority: PublicKey;
authority: PublicKey;
payer: PublicKey;
systemProgram: PublicKey;
}
export const layout = borsh.struct([types.QuoteInitParams.layout("params")]);
export function quoteInit(
program: SwitchboardProgram,
args: QuoteInitArgs,
accounts: QuoteInitAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.quote, isSigner: true, isWritable: true },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: true },
{ pubkey: accounts.queueAuthority, isSigner: false, isWritable: false },
{ pubkey: accounts.authority, isSigner: false, isWritable: false },
{ pubkey: accounts.payer, isSigner: true, isWritable: true },
{ pubkey: accounts.systemProgram, isSigner: false, isWritable: false },
];
const identifier = Buffer.from([124, 251, 28, 247, 136, 141, 198, 116]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.QuoteInitParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -0,0 +1,51 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} 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
export interface QuoteRotateArgs {
params: types.QuoteRotateParamsFields;
}
export interface QuoteRotateAccounts {
quote: PublicKey;
authority: PublicKey;
securedSigner: PublicKey;
attestationQueue: PublicKey;
}
export const layout = borsh.struct([types.QuoteRotateParams.layout("params")]);
export function quoteRotate(
program: SwitchboardProgram,
args: QuoteRotateArgs,
accounts: QuoteRotateAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.quote, isSigner: false, isWritable: true },
{ pubkey: accounts.authority, isSigner: true, isWritable: false },
{ pubkey: accounts.securedSigner, isSigner: false, isWritable: false },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: true },
];
const identifier = Buffer.from([153, 94, 246, 7, 7, 124, 62, 7]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.QuoteRotateParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -0,0 +1,53 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} 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
export interface QuoteVerifyArgs {
params: types.QuoteVerifyParamsFields;
}
export interface QuoteVerifyAccounts {
quote: PublicKey;
quoteSigner: PublicKey;
verifier: PublicKey;
securedSigner: PublicKey;
attestationQueue: PublicKey;
}
export const layout = borsh.struct([types.QuoteVerifyParams.layout("params")]);
export function quoteVerify(
program: SwitchboardProgram,
args: QuoteVerifyArgs,
accounts: QuoteVerifyAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.quote, isSigner: false, isWritable: true },
{ pubkey: accounts.quoteSigner, isSigner: false, isWritable: false },
{ pubkey: accounts.verifier, isSigner: false, isWritable: false },
{ pubkey: accounts.securedSigner, isSigner: true, isWritable: false },
{ pubkey: accounts.attestationQueue, isSigner: false, isWritable: false },
];
const identifier = Buffer.from([158, 203, 69, 10, 212, 218, 45, 184]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.QuoteVerifyParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -0,0 +1,49 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars
import {
AccountMeta,
PublicKey,
TransactionInstruction,
} 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
export interface StateInitArgs {
params: types.StateInitParamsFields;
}
export interface StateInitAccounts {
state: PublicKey;
payer: PublicKey;
systemProgram: PublicKey;
}
export const layout = borsh.struct([types.StateInitParams.layout("params")]);
export function stateInit(
program: SwitchboardProgram,
args: StateInitArgs,
accounts: StateInitAccounts
) {
const keys: Array<AccountMeta> = [
{ pubkey: accounts.state, isSigner: false, isWritable: true },
{ pubkey: accounts.payer, isSigner: true, isWritable: true },
{ pubkey: accounts.systemProgram, isSigner: false, isWritable: false },
];
const identifier = Buffer.from([103, 241, 106, 190, 217, 153, 87, 105]);
const buffer = Buffer.alloc(1000);
const len = layout.encode(
{
params: types.StateInitParams.toEncodable(args.params),
},
buffer
);
const data = Buffer.concat([identifier, buffer]).slice(0, 8 + len);
const ix = new TransactionInstruction({
keys,
programId: program.attestationProgramId,
data,
});
return ix;
}

View File

@ -0,0 +1,9 @@
import { PublicKey } from "@solana/web3.js";
// Program ID passed with the cli --program-id flag when running the code generator. Do not edit, it will get overwritten.
export const PROGRAM_ID_CLI = new PublicKey(
"2No5FVKPAAYqytpkEoq93tVh33fo4p6DgAnm4S6oZHo7"
);
// This constant will not get overwritten on subsequent code generations and it's safe to modify it's value.
export const PROGRAM_ID: PublicKey = PROGRAM_ID_CLI;

View File

@ -0,0 +1,41 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
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
export interface AttestationPermissionInitParamsFields {}
export interface AttestationPermissionInitParamsJSON {}
export class AttestationPermissionInitParams {
constructor(fields: AttestationPermissionInitParamsFields) {}
static layout(property?: string) {
return borsh.struct([], property);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new AttestationPermissionInitParams({});
}
static toEncodable(fields: AttestationPermissionInitParamsFields) {
return {};
}
toJSON(): AttestationPermissionInitParamsJSON {
return {};
}
static fromJSON(
obj: AttestationPermissionInitParamsJSON
): AttestationPermissionInitParams {
return new AttestationPermissionInitParams({});
}
toEncodable() {
return AttestationPermissionInitParams.toEncodable(this);
}
}

View File

@ -0,0 +1,68 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
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
export interface AttestationPermissionSetParamsFields {
permission: number;
enable: boolean;
}
export interface AttestationPermissionSetParamsJSON {
permission: number;
enable: boolean;
}
export class AttestationPermissionSetParams {
readonly permission: number;
readonly enable: boolean;
constructor(fields: AttestationPermissionSetParamsFields) {
this.permission = fields.permission;
this.enable = fields.enable;
}
static layout(property?: string) {
return borsh.struct(
[borsh.u32("permission"), borsh.bool("enable")],
property
);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new AttestationPermissionSetParams({
permission: obj.permission,
enable: obj.enable,
});
}
static toEncodable(fields: AttestationPermissionSetParamsFields) {
return {
permission: fields.permission,
enable: fields.enable,
};
}
toJSON(): AttestationPermissionSetParamsJSON {
return {
permission: this.permission,
enable: this.enable,
};
}
static fromJSON(
obj: AttestationPermissionSetParamsJSON
): AttestationPermissionSetParams {
return new AttestationPermissionSetParams({
permission: obj.permission,
enable: obj.enable,
});
}
toEncodable() {
return AttestationPermissionSetParams.toEncodable(this);
}
}

View File

@ -0,0 +1,57 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
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
export interface AttestationQueueAddMrEnclaveParamsFields {
mrEnclave: Array<number>;
}
export interface AttestationQueueAddMrEnclaveParamsJSON {
mrEnclave: Array<number>;
}
export class AttestationQueueAddMrEnclaveParams {
readonly mrEnclave: Array<number>;
constructor(fields: AttestationQueueAddMrEnclaveParamsFields) {
this.mrEnclave = fields.mrEnclave;
}
static layout(property?: string) {
return borsh.struct([borsh.array(borsh.u8(), 32, "mrEnclave")], property);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new AttestationQueueAddMrEnclaveParams({
mrEnclave: obj.mrEnclave,
});
}
static toEncodable(fields: AttestationQueueAddMrEnclaveParamsFields) {
return {
mrEnclave: fields.mrEnclave,
};
}
toJSON(): AttestationQueueAddMrEnclaveParamsJSON {
return {
mrEnclave: this.mrEnclave,
};
}
static fromJSON(
obj: AttestationQueueAddMrEnclaveParamsJSON
): AttestationQueueAddMrEnclaveParams {
return new AttestationQueueAddMrEnclaveParams({
mrEnclave: obj.mrEnclave,
});
}
toEncodable() {
return AttestationQueueAddMrEnclaveParams.toEncodable(this);
}
}

View File

@ -0,0 +1,112 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
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
export interface AttestationQueueInitParamsFields {
allowAuthorityOverrideAfter: number;
requireAuthorityHeartbeatPermission: boolean;
requireUsagePermissions: boolean;
maxQuoteVerificationAge: number;
reward: number;
nodeTimeout: number;
}
export interface AttestationQueueInitParamsJSON {
allowAuthorityOverrideAfter: number;
requireAuthorityHeartbeatPermission: boolean;
requireUsagePermissions: boolean;
maxQuoteVerificationAge: number;
reward: number;
nodeTimeout: number;
}
export class AttestationQueueInitParams {
readonly allowAuthorityOverrideAfter: number;
readonly requireAuthorityHeartbeatPermission: boolean;
readonly requireUsagePermissions: boolean;
readonly maxQuoteVerificationAge: number;
readonly reward: number;
readonly nodeTimeout: number;
constructor(fields: AttestationQueueInitParamsFields) {
this.allowAuthorityOverrideAfter = fields.allowAuthorityOverrideAfter;
this.requireAuthorityHeartbeatPermission =
fields.requireAuthorityHeartbeatPermission;
this.requireUsagePermissions = fields.requireUsagePermissions;
this.maxQuoteVerificationAge = fields.maxQuoteVerificationAge;
this.reward = fields.reward;
this.nodeTimeout = fields.nodeTimeout;
}
static layout(property?: string) {
return borsh.struct(
[
borsh.u32("allowAuthorityOverrideAfter"),
borsh.bool("requireAuthorityHeartbeatPermission"),
borsh.bool("requireUsagePermissions"),
borsh.u32("maxQuoteVerificationAge"),
borsh.u32("reward"),
borsh.u32("nodeTimeout"),
],
property
);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new AttestationQueueInitParams({
allowAuthorityOverrideAfter: obj.allowAuthorityOverrideAfter,
requireAuthorityHeartbeatPermission:
obj.requireAuthorityHeartbeatPermission,
requireUsagePermissions: obj.requireUsagePermissions,
maxQuoteVerificationAge: obj.maxQuoteVerificationAge,
reward: obj.reward,
nodeTimeout: obj.nodeTimeout,
});
}
static toEncodable(fields: AttestationQueueInitParamsFields) {
return {
allowAuthorityOverrideAfter: fields.allowAuthorityOverrideAfter,
requireAuthorityHeartbeatPermission:
fields.requireAuthorityHeartbeatPermission,
requireUsagePermissions: fields.requireUsagePermissions,
maxQuoteVerificationAge: fields.maxQuoteVerificationAge,
reward: fields.reward,
nodeTimeout: fields.nodeTimeout,
};
}
toJSON(): AttestationQueueInitParamsJSON {
return {
allowAuthorityOverrideAfter: this.allowAuthorityOverrideAfter,
requireAuthorityHeartbeatPermission:
this.requireAuthorityHeartbeatPermission,
requireUsagePermissions: this.requireUsagePermissions,
maxQuoteVerificationAge: this.maxQuoteVerificationAge,
reward: this.reward,
nodeTimeout: this.nodeTimeout,
};
}
static fromJSON(
obj: AttestationQueueInitParamsJSON
): AttestationQueueInitParams {
return new AttestationQueueInitParams({
allowAuthorityOverrideAfter: obj.allowAuthorityOverrideAfter,
requireAuthorityHeartbeatPermission:
obj.requireAuthorityHeartbeatPermission,
requireUsagePermissions: obj.requireUsagePermissions,
maxQuoteVerificationAge: obj.maxQuoteVerificationAge,
reward: obj.reward,
nodeTimeout: obj.nodeTimeout,
});
}
toEncodable() {
return AttestationQueueInitParams.toEncodable(this);
}
}

View File

@ -0,0 +1,57 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
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
export interface AttestationQueueRemoveMrEnclaveParamsFields {
mrEnclave: Array<number>;
}
export interface AttestationQueueRemoveMrEnclaveParamsJSON {
mrEnclave: Array<number>;
}
export class AttestationQueueRemoveMrEnclaveParams {
readonly mrEnclave: Array<number>;
constructor(fields: AttestationQueueRemoveMrEnclaveParamsFields) {
this.mrEnclave = fields.mrEnclave;
}
static layout(property?: string) {
return borsh.struct([borsh.array(borsh.u8(), 32, "mrEnclave")], property);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new AttestationQueueRemoveMrEnclaveParams({
mrEnclave: obj.mrEnclave,
});
}
static toEncodable(fields: AttestationQueueRemoveMrEnclaveParamsFields) {
return {
mrEnclave: fields.mrEnclave,
};
}
toJSON(): AttestationQueueRemoveMrEnclaveParamsJSON {
return {
mrEnclave: this.mrEnclave,
};
}
static fromJSON(
obj: AttestationQueueRemoveMrEnclaveParamsJSON
): AttestationQueueRemoveMrEnclaveParams {
return new AttestationQueueRemoveMrEnclaveParams({
mrEnclave: obj.mrEnclave,
});
}
toEncodable() {
return AttestationQueueRemoveMrEnclaveParams.toEncodable(this);
}
}

View File

@ -0,0 +1,55 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
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
export interface FunctionFundParamsFields {
amount: BN;
}
export interface FunctionFundParamsJSON {
amount: string;
}
export class FunctionFundParams {
readonly amount: BN;
constructor(fields: FunctionFundParamsFields) {
this.amount = fields.amount;
}
static layout(property?: string) {
return borsh.struct([borsh.u64("amount")], property);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new FunctionFundParams({
amount: obj.amount,
});
}
static toEncodable(fields: FunctionFundParamsFields) {
return {
amount: fields.amount,
};
}
toJSON(): FunctionFundParamsJSON {
return {
amount: this.amount.toString(),
};
}
static fromJSON(obj: FunctionFundParamsJSON): FunctionFundParams {
return new FunctionFundParams({
amount: new BN(obj.amount),
});
}
toEncodable() {
return FunctionFundParams.toEncodable(this);
}
}

View File

@ -0,0 +1,171 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
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
export interface FunctionInitParamsFields {
name: Uint8Array;
metadata: Uint8Array;
container: Uint8Array;
containerRegistry: Uint8Array;
version: Uint8Array;
schedule: Uint8Array;
mrEnclave: Array<number>;
recentSlot: BN;
}
export interface FunctionInitParamsJSON {
name: Array<number>;
metadata: Array<number>;
container: Array<number>;
containerRegistry: Array<number>;
version: Array<number>;
schedule: Array<number>;
mrEnclave: Array<number>;
recentSlot: string;
}
export class FunctionInitParams {
readonly name: Uint8Array;
readonly metadata: Uint8Array;
readonly container: Uint8Array;
readonly containerRegistry: Uint8Array;
readonly version: Uint8Array;
readonly schedule: Uint8Array;
readonly mrEnclave: Array<number>;
readonly recentSlot: BN;
constructor(fields: FunctionInitParamsFields) {
this.name = fields.name;
this.metadata = fields.metadata;
this.container = fields.container;
this.containerRegistry = fields.containerRegistry;
this.version = fields.version;
this.schedule = fields.schedule;
this.mrEnclave = fields.mrEnclave;
this.recentSlot = fields.recentSlot;
}
static layout(property?: string) {
return borsh.struct(
[
borsh.vecU8("name"),
borsh.vecU8("metadata"),
borsh.vecU8("container"),
borsh.vecU8("containerRegistry"),
borsh.vecU8("version"),
borsh.vecU8("schedule"),
borsh.array(borsh.u8(), 32, "mrEnclave"),
borsh.u64("recentSlot"),
],
property
);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new FunctionInitParams({
name: new Uint8Array(
obj.name.buffer,
obj.name.byteOffset,
obj.name.length
),
metadata: new Uint8Array(
obj.metadata.buffer,
obj.metadata.byteOffset,
obj.metadata.length
),
container: new Uint8Array(
obj.container.buffer,
obj.container.byteOffset,
obj.container.length
),
containerRegistry: new Uint8Array(
obj.containerRegistry.buffer,
obj.containerRegistry.byteOffset,
obj.containerRegistry.length
),
version: new Uint8Array(
obj.version.buffer,
obj.version.byteOffset,
obj.version.length
),
schedule: new Uint8Array(
obj.schedule.buffer,
obj.schedule.byteOffset,
obj.schedule.length
),
mrEnclave: obj.mrEnclave,
recentSlot: obj.recentSlot,
});
}
static toEncodable(fields: FunctionInitParamsFields) {
return {
name: Buffer.from(
fields.name.buffer,
fields.name.byteOffset,
fields.name.length
),
metadata: Buffer.from(
fields.metadata.buffer,
fields.metadata.byteOffset,
fields.metadata.length
),
container: Buffer.from(
fields.container.buffer,
fields.container.byteOffset,
fields.container.length
),
containerRegistry: Buffer.from(
fields.containerRegistry.buffer,
fields.containerRegistry.byteOffset,
fields.containerRegistry.length
),
version: Buffer.from(
fields.version.buffer,
fields.version.byteOffset,
fields.version.length
),
schedule: Buffer.from(
fields.schedule.buffer,
fields.schedule.byteOffset,
fields.schedule.length
),
mrEnclave: fields.mrEnclave,
recentSlot: fields.recentSlot,
};
}
toJSON(): FunctionInitParamsJSON {
return {
name: Array.from(this.name.values()),
metadata: Array.from(this.metadata.values()),
container: Array.from(this.container.values()),
containerRegistry: Array.from(this.containerRegistry.values()),
version: Array.from(this.version.values()),
schedule: Array.from(this.schedule.values()),
mrEnclave: this.mrEnclave,
recentSlot: this.recentSlot.toString(),
};
}
static fromJSON(obj: FunctionInitParamsJSON): FunctionInitParams {
return new FunctionInitParams({
name: Uint8Array.from(obj.name),
metadata: Uint8Array.from(obj.metadata),
container: Uint8Array.from(obj.container),
containerRegistry: Uint8Array.from(obj.containerRegistry),
version: Uint8Array.from(obj.version),
schedule: Uint8Array.from(obj.schedule),
mrEnclave: obj.mrEnclave,
recentSlot: new BN(obj.recentSlot),
});
}
toEncodable() {
return FunctionInitParams.toEncodable(this);
}
}

View File

@ -0,0 +1,212 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
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
export interface NoneJSON {
kind: "None";
}
export class None {
static readonly discriminator = 0;
static readonly kind = "None";
readonly discriminator = 0;
readonly kind = "None";
toJSON(): NoneJSON {
return {
kind: "None",
};
}
toEncodable() {
return {
None: {},
};
}
}
export interface ActiveJSON {
kind: "Active";
}
export class Active {
static readonly discriminator = 1;
static readonly kind = "Active";
readonly discriminator = 1;
readonly kind = "Active";
toJSON(): ActiveJSON {
return {
kind: "Active",
};
}
toEncodable() {
return {
Active: {},
};
}
}
export interface NonExecutableJSON {
kind: "NonExecutable";
}
export class NonExecutable {
static readonly discriminator = 2;
static readonly kind = "NonExecutable";
readonly discriminator = 2;
readonly kind = "NonExecutable";
toJSON(): NonExecutableJSON {
return {
kind: "NonExecutable",
};
}
toEncodable() {
return {
NonExecutable: {},
};
}
}
export interface ExpiredJSON {
kind: "Expired";
}
export class Expired {
static readonly discriminator = 3;
static readonly kind = "Expired";
readonly discriminator = 3;
readonly kind = "Expired";
toJSON(): ExpiredJSON {
return {
kind: "Expired",
};
}
toEncodable() {
return {
Expired: {},
};
}
}
export interface OutOfFundsJSON {
kind: "OutOfFunds";
}
export class OutOfFunds {
static readonly discriminator = 4;
static readonly kind = "OutOfFunds";
readonly discriminator = 4;
readonly kind = "OutOfFunds";
toJSON(): OutOfFundsJSON {
return {
kind: "OutOfFunds",
};
}
toEncodable() {
return {
OutOfFunds: {},
};
}
}
export interface InvalidPermissionsJSON {
kind: "InvalidPermissions";
}
export class InvalidPermissions {
static readonly discriminator = 5;
static readonly kind = "InvalidPermissions";
readonly discriminator = 5;
readonly kind = "InvalidPermissions";
toJSON(): InvalidPermissionsJSON {
return {
kind: "InvalidPermissions",
};
}
toEncodable() {
return {
InvalidPermissions: {},
};
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function fromDecoded(obj: any): types.FunctionStatusKind {
if (typeof obj !== "object") {
throw new Error("Invalid enum object");
}
if ("None" in obj) {
return new None();
}
if ("Active" in obj) {
return new Active();
}
if ("NonExecutable" in obj) {
return new NonExecutable();
}
if ("Expired" in obj) {
return new Expired();
}
if ("OutOfFunds" in obj) {
return new OutOfFunds();
}
if ("InvalidPermissions" in obj) {
return new InvalidPermissions();
}
throw new Error("Invalid enum object");
}
export function fromJSON(
obj: types.FunctionStatusJSON
): types.FunctionStatusKind {
switch (obj.kind) {
case "None": {
return new None();
}
case "Active": {
return new Active();
}
case "NonExecutable": {
return new NonExecutable();
}
case "Expired": {
return new Expired();
}
case "OutOfFunds": {
return new OutOfFunds();
}
case "InvalidPermissions": {
return new InvalidPermissions();
}
}
}
export function layout(property?: string) {
const ret = borsh.rustEnum([
borsh.struct([], "None"),
borsh.struct([], "Active"),
borsh.struct([], "NonExecutable"),
borsh.struct([], "Expired"),
borsh.struct([], "OutOfFunds"),
borsh.struct([], "InvalidPermissions"),
]);
if (property !== undefined) {
return ret.replicate(property);
}
return ret;
}

View File

@ -0,0 +1,87 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
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
export interface FunctionVerifyParamsFields {
observedTime: BN;
nextAllowedTimestamp: BN;
isFailure: boolean;
mrEnclave: Array<number>;
}
export interface FunctionVerifyParamsJSON {
observedTime: string;
nextAllowedTimestamp: string;
isFailure: boolean;
mrEnclave: Array<number>;
}
export class FunctionVerifyParams {
readonly observedTime: BN;
readonly nextAllowedTimestamp: BN;
readonly isFailure: boolean;
readonly mrEnclave: Array<number>;
constructor(fields: FunctionVerifyParamsFields) {
this.observedTime = fields.observedTime;
this.nextAllowedTimestamp = fields.nextAllowedTimestamp;
this.isFailure = fields.isFailure;
this.mrEnclave = fields.mrEnclave;
}
static layout(property?: string) {
return borsh.struct(
[
borsh.i64("observedTime"),
borsh.i64("nextAllowedTimestamp"),
borsh.bool("isFailure"),
borsh.array(borsh.u8(), 32, "mrEnclave"),
],
property
);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new FunctionVerifyParams({
observedTime: obj.observedTime,
nextAllowedTimestamp: obj.nextAllowedTimestamp,
isFailure: obj.isFailure,
mrEnclave: obj.mrEnclave,
});
}
static toEncodable(fields: FunctionVerifyParamsFields) {
return {
observedTime: fields.observedTime,
nextAllowedTimestamp: fields.nextAllowedTimestamp,
isFailure: fields.isFailure,
mrEnclave: fields.mrEnclave,
};
}
toJSON(): FunctionVerifyParamsJSON {
return {
observedTime: this.observedTime.toString(),
nextAllowedTimestamp: this.nextAllowedTimestamp.toString(),
isFailure: this.isFailure,
mrEnclave: this.mrEnclave,
};
}
static fromJSON(obj: FunctionVerifyParamsJSON): FunctionVerifyParams {
return new FunctionVerifyParams({
observedTime: new BN(obj.observedTime),
nextAllowedTimestamp: new BN(obj.nextAllowedTimestamp),
isFailure: obj.isFailure,
mrEnclave: obj.mrEnclave,
});
}
toEncodable() {
return FunctionVerifyParams.toEncodable(this);
}
}

View File

@ -0,0 +1,55 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
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
export interface FunctionWithdrawParamsFields {
amount: BN;
}
export interface FunctionWithdrawParamsJSON {
amount: string;
}
export class FunctionWithdrawParams {
readonly amount: BN;
constructor(fields: FunctionWithdrawParamsFields) {
this.amount = fields.amount;
}
static layout(property?: string) {
return borsh.struct([borsh.u64("amount")], property);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new FunctionWithdrawParams({
amount: obj.amount,
});
}
static toEncodable(fields: FunctionWithdrawParamsFields) {
return {
amount: fields.amount,
};
}
toJSON(): FunctionWithdrawParamsJSON {
return {
amount: this.amount.toString(),
};
}
static fromJSON(obj: FunctionWithdrawParamsJSON): FunctionWithdrawParams {
return new FunctionWithdrawParams({
amount: new BN(obj.amount),
});
}
toEncodable() {
return FunctionWithdrawParams.toEncodable(this);
}
}

View File

@ -0,0 +1,39 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
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
export interface QuoteHeartbeatParamsFields {}
export interface QuoteHeartbeatParamsJSON {}
export class QuoteHeartbeatParams {
constructor(fields: QuoteHeartbeatParamsFields) {}
static layout(property?: string) {
return borsh.struct([], property);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new QuoteHeartbeatParams({});
}
static toEncodable(fields: QuoteHeartbeatParamsFields) {
return {};
}
toJSON(): QuoteHeartbeatParamsJSON {
return {};
}
static fromJSON(obj: QuoteHeartbeatParamsJSON): QuoteHeartbeatParams {
return new QuoteHeartbeatParams({});
}
toEncodable() {
return QuoteHeartbeatParams.toEncodable(this);
}
}

View File

@ -0,0 +1,39 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
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
export interface QuoteInitParamsFields {}
export interface QuoteInitParamsJSON {}
export class QuoteInitParams {
constructor(fields: QuoteInitParamsFields) {}
static layout(property?: string) {
return borsh.struct([], property);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new QuoteInitParams({});
}
static toEncodable(fields: QuoteInitParamsFields) {
return {};
}
toJSON(): QuoteInitParamsJSON {
return {};
}
static fromJSON(obj: QuoteInitParamsJSON): QuoteInitParams {
return new QuoteInitParams({});
}
toEncodable() {
return QuoteInitParams.toEncodable(this);
}
}

View File

@ -0,0 +1,55 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
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
export interface QuoteRotateParamsFields {
registryKey: Array<number>;
}
export interface QuoteRotateParamsJSON {
registryKey: Array<number>;
}
export class QuoteRotateParams {
readonly registryKey: Array<number>;
constructor(fields: QuoteRotateParamsFields) {
this.registryKey = fields.registryKey;
}
static layout(property?: string) {
return borsh.struct([borsh.array(borsh.u8(), 64, "registryKey")], property);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new QuoteRotateParams({
registryKey: obj.registryKey,
});
}
static toEncodable(fields: QuoteRotateParamsFields) {
return {
registryKey: fields.registryKey,
};
}
toJSON(): QuoteRotateParamsJSON {
return {
registryKey: this.registryKey,
};
}
static fromJSON(obj: QuoteRotateParamsJSON): QuoteRotateParams {
return new QuoteRotateParams({
registryKey: obj.registryKey,
});
}
toEncodable() {
return QuoteRotateParams.toEncodable(this);
}
}

View File

@ -0,0 +1,78 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
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
export interface QuoteVerifyParamsFields {
timestamp: BN;
mrEnclave: Array<number>;
idx: number;
}
export interface QuoteVerifyParamsJSON {
timestamp: string;
mrEnclave: Array<number>;
idx: number;
}
export class QuoteVerifyParams {
readonly timestamp: BN;
readonly mrEnclave: Array<number>;
readonly idx: number;
constructor(fields: QuoteVerifyParamsFields) {
this.timestamp = fields.timestamp;
this.mrEnclave = fields.mrEnclave;
this.idx = fields.idx;
}
static layout(property?: string) {
return borsh.struct(
[
borsh.i64("timestamp"),
borsh.array(borsh.u8(), 32, "mrEnclave"),
borsh.u32("idx"),
],
property
);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new QuoteVerifyParams({
timestamp: obj.timestamp,
mrEnclave: obj.mrEnclave,
idx: obj.idx,
});
}
static toEncodable(fields: QuoteVerifyParamsFields) {
return {
timestamp: fields.timestamp,
mrEnclave: fields.mrEnclave,
idx: fields.idx,
};
}
toJSON(): QuoteVerifyParamsJSON {
return {
timestamp: this.timestamp.toString(),
mrEnclave: this.mrEnclave,
idx: this.idx,
};
}
static fromJSON(obj: QuoteVerifyParamsJSON): QuoteVerifyParams {
return new QuoteVerifyParams({
timestamp: new BN(obj.timestamp),
mrEnclave: obj.mrEnclave,
idx: obj.idx,
});
}
toEncodable() {
return QuoteVerifyParams.toEncodable(this);
}
}

View File

@ -0,0 +1,39 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
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
export interface StateInitParamsFields {}
export interface StateInitParamsJSON {}
export class StateInitParams {
constructor(fields: StateInitParamsFields) {}
static layout(property?: string) {
return borsh.struct([], property);
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
static fromDecoded(obj: any) {
return new StateInitParams({});
}
static toEncodable(fields: StateInitParamsFields) {
return {};
}
toJSON(): StateInitParamsJSON {
return {};
}
static fromJSON(obj: StateInitParamsJSON): StateInitParams {
return new StateInitParams({});
}
toEncodable() {
return StateInitParams.toEncodable(this);
}
}

View File

@ -0,0 +1,94 @@
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
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
export interface PermitNodeheartbeatJSON {
kind: "PermitNodeheartbeat";
}
export class PermitNodeheartbeat {
static readonly discriminator = 1;
static readonly kind = "PermitNodeheartbeat";
readonly discriminator = 1;
readonly kind = "PermitNodeheartbeat";
toJSON(): PermitNodeheartbeatJSON {
return {
kind: "PermitNodeheartbeat",
};
}
toEncodable() {
return {
PermitNodeheartbeat: {},
};
}
}
export interface PermitQueueUsageJSON {
kind: "PermitQueueUsage";
}
export class PermitQueueUsage {
static readonly discriminator = 2;
static readonly kind = "PermitQueueUsage";
readonly discriminator = 2;
readonly kind = "PermitQueueUsage";
toJSON(): PermitQueueUsageJSON {
return {
kind: "PermitQueueUsage",
};
}
toEncodable() {
return {
PermitQueueUsage: {},
};
}
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function fromDecoded(
obj: any
): types.SwitchboardAttestationPermissionKind {
if (typeof obj !== "object") {
throw new Error("Invalid enum object");
}
if ("PermitNodeheartbeat" in obj) {
return new PermitNodeheartbeat();
}
if ("PermitQueueUsage" in obj) {
return new PermitQueueUsage();
}
throw new Error("Invalid enum object");
}
export function fromJSON(
obj: types.SwitchboardAttestationPermissionJSON
): types.SwitchboardAttestationPermissionKind {
switch (obj.kind) {
case "PermitNodeheartbeat": {
return new PermitNodeheartbeat();
}
case "PermitQueueUsage": {
return new PermitQueueUsage();
}
}
}
export function layout(property?: string) {
const ret = borsh.rustEnum([
borsh.struct([], "PermitNodeheartbeat"),
borsh.struct([], "PermitQueueUsage"),
]);
if (property !== undefined) {
return ret.replicate(property);
}
return ret;
}

View File

@ -1,17 +1,42 @@
import { SwitchboardProgram } from "../../SwitchboardProgram.js";
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "./index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
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/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh";
export interface NoneJSON {
kind: "None";
}
export class None {
static readonly discriminator = 0;
static readonly kind = "None";
readonly discriminator = 0;
readonly kind = "None";
toJSON(): NoneJSON {
return {
kind: "None",
};
}
toEncodable() {
return {
None: {},
};
}
}
export interface VerificationPendingJSON {
kind: "VerificationPending";
}
export class VerificationPending {
static readonly discriminator = 0;
static readonly discriminator = 1;
static readonly kind = "VerificationPending";
readonly discriminator = 0;
readonly discriminator = 1;
readonly kind = "VerificationPending";
toJSON(): VerificationPendingJSON {
@ -32,9 +57,9 @@ export interface VerificationFailureJSON {
}
export class VerificationFailure {
static readonly discriminator = 1;
static readonly discriminator = 2;
static readonly kind = "VerificationFailure";
readonly discriminator = 1;
readonly discriminator = 2;
readonly kind = "VerificationFailure";
toJSON(): VerificationFailureJSON {
@ -55,9 +80,9 @@ export interface VerificationSuccessJSON {
}
export class VerificationSuccess {
static readonly discriminator = 2;
static readonly discriminator = 4;
static readonly kind = "VerificationSuccess";
readonly discriminator = 2;
readonly discriminator = 4;
readonly kind = "VerificationSuccess";
toJSON(): VerificationSuccessJSON {
@ -78,9 +103,9 @@ export interface VerificationOverrideJSON {
}
export class VerificationOverride {
static readonly discriminator = 3;
static readonly discriminator = 8;
static readonly kind = "VerificationOverride";
readonly discriminator = 3;
readonly discriminator = 8;
readonly kind = "VerificationOverride";
toJSON(): VerificationOverrideJSON {
@ -102,6 +127,9 @@ export function fromDecoded(obj: any): types.VerificationStatusKind {
throw new Error("Invalid enum object");
}
if ("None" in obj) {
return new None();
}
if ("VerificationPending" in obj) {
return new VerificationPending();
}
@ -122,6 +150,9 @@ export function fromJSON(
obj: types.VerificationStatusJSON
): types.VerificationStatusKind {
switch (obj.kind) {
case "None": {
return new None();
}
case "VerificationPending": {
return new VerificationPending();
}
@ -139,6 +170,7 @@ export function fromJSON(
export function layout(property?: string) {
const ret = borsh.rustEnum([
borsh.struct([], "None"),
borsh.struct([], "VerificationPending"),
borsh.struct([], "VerificationFailure"),
borsh.struct([], "VerificationSuccess"),

View File

@ -0,0 +1,114 @@
import * as FunctionStatus from "./FunctionStatus.js";
import * as SwitchboardAttestationPermission from "./SwitchboardAttestationPermission.js";
import * as VerificationStatus from "./VerificationStatus.js";
export type {
AttestationPermissionInitParamsFields,
AttestationPermissionInitParamsJSON,
} from "./AttestationPermissionInitParams.js";
export { AttestationPermissionInitParams } from "./AttestationPermissionInitParams.js";
export type {
AttestationPermissionSetParamsFields,
AttestationPermissionSetParamsJSON,
} from "./AttestationPermissionSetParams.js";
export { AttestationPermissionSetParams } from "./AttestationPermissionSetParams.js";
export type {
AttestationQueueAddMrEnclaveParamsFields,
AttestationQueueAddMrEnclaveParamsJSON,
} from "./AttestationQueueAddMrEnclaveParams.js";
export { AttestationQueueAddMrEnclaveParams } from "./AttestationQueueAddMrEnclaveParams.js";
export type {
AttestationQueueInitParamsFields,
AttestationQueueInitParamsJSON,
} from "./AttestationQueueInitParams.js";
export { AttestationQueueInitParams } from "./AttestationQueueInitParams.js";
export type {
AttestationQueueRemoveMrEnclaveParamsFields,
AttestationQueueRemoveMrEnclaveParamsJSON,
} from "./AttestationQueueRemoveMrEnclaveParams.js";
export { AttestationQueueRemoveMrEnclaveParams } from "./AttestationQueueRemoveMrEnclaveParams.js";
export type {
FunctionFundParamsFields,
FunctionFundParamsJSON,
} from "./FunctionFundParams.js";
export { FunctionFundParams } from "./FunctionFundParams.js";
export type {
FunctionInitParamsFields,
FunctionInitParamsJSON,
} from "./FunctionInitParams.js";
export { FunctionInitParams } from "./FunctionInitParams.js";
export type {
FunctionVerifyParamsFields,
FunctionVerifyParamsJSON,
} from "./FunctionVerifyParams.js";
export { FunctionVerifyParams } from "./FunctionVerifyParams.js";
export type {
FunctionWithdrawParamsFields,
FunctionWithdrawParamsJSON,
} from "./FunctionWithdrawParams.js";
export { FunctionWithdrawParams } from "./FunctionWithdrawParams.js";
export type {
QuoteHeartbeatParamsFields,
QuoteHeartbeatParamsJSON,
} from "./QuoteHeartbeatParams.js";
export { QuoteHeartbeatParams } from "./QuoteHeartbeatParams.js";
export type {
QuoteInitParamsFields,
QuoteInitParamsJSON,
} from "./QuoteInitParams.js";
export { QuoteInitParams } from "./QuoteInitParams.js";
export type {
QuoteRotateParamsFields,
QuoteRotateParamsJSON,
} from "./QuoteRotateParams.js";
export { QuoteRotateParams } from "./QuoteRotateParams.js";
export type {
QuoteVerifyParamsFields,
QuoteVerifyParamsJSON,
} from "./QuoteVerifyParams.js";
export { QuoteVerifyParams } from "./QuoteVerifyParams.js";
export type {
StateInitParamsFields,
StateInitParamsJSON,
} from "./StateInitParams.js";
export { StateInitParams } from "./StateInitParams.js";
export { FunctionStatus };
export type FunctionStatusKind =
| FunctionStatus.None
| FunctionStatus.Active
| FunctionStatus.NonExecutable
| FunctionStatus.Expired
| FunctionStatus.OutOfFunds
| FunctionStatus.InvalidPermissions;
export type FunctionStatusJSON =
| FunctionStatus.NoneJSON
| FunctionStatus.ActiveJSON
| FunctionStatus.NonExecutableJSON
| FunctionStatus.ExpiredJSON
| FunctionStatus.OutOfFundsJSON
| FunctionStatus.InvalidPermissionsJSON;
export { VerificationStatus };
export type VerificationStatusKind =
| VerificationStatus.None
| VerificationStatus.VerificationPending
| VerificationStatus.VerificationFailure
| VerificationStatus.VerificationSuccess
| VerificationStatus.VerificationOverride;
export type VerificationStatusJSON =
| VerificationStatus.NoneJSON
| VerificationStatus.VerificationPendingJSON
| VerificationStatus.VerificationFailureJSON
| VerificationStatus.VerificationSuccessJSON
| VerificationStatus.VerificationOverrideJSON;
export { SwitchboardAttestationPermission };
export type SwitchboardAttestationPermissionKind =
| SwitchboardAttestationPermission.PermitNodeheartbeat
| SwitchboardAttestationPermission.PermitQueueUsage;
export type SwitchboardAttestationPermissionJSON =
| SwitchboardAttestationPermission.PermitNodeheartbeatJSON
| SwitchboardAttestationPermission.PermitQueueUsageJSON;

View File

@ -0,0 +1,2 @@
export * from "./attestation-program/errors/index.js";
export * from "./oracle-program/errors/index.js";

View File

@ -1,4 +1,2 @@
export * from "./accounts/index.js";
export * from "./errors/index.js";
export * from "./instructions/index.js";
export * from "./types/index.js";
export * from "./attestation-program/index.js";
export * from "./oracle-program/index.js";

View File

@ -0,0 +1,2 @@
export * from "./attestation-program/instructions/index.js";
export * from "./oracle-program/instructions/index.js";

View File

@ -1,4 +1,4 @@
import { SwitchboardProgram } from "../../SwitchboardProgram.js";
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars

View File

@ -1,4 +1,4 @@
import { SwitchboardProgram } from "../../SwitchboardProgram.js";
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars

View File

@ -1,4 +1,4 @@
import { SwitchboardProgram } from "../../SwitchboardProgram.js";
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars

View File

@ -1,4 +1,4 @@
import { SwitchboardProgram } from "../../SwitchboardProgram.js";
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars

View File

@ -1,4 +1,4 @@
import { SwitchboardProgram } from "../../SwitchboardProgram.js";
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars

View File

@ -1,4 +1,4 @@
import { SwitchboardProgram } from "../../SwitchboardProgram.js";
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars

View File

@ -1,4 +1,4 @@
import { SwitchboardProgram } from "../../SwitchboardProgram.js";
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars

View File

@ -1,4 +1,4 @@
import { SwitchboardProgram } from "../../SwitchboardProgram.js";
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars

View File

@ -1,4 +1,4 @@
import { SwitchboardProgram } from "../../SwitchboardProgram.js";
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars

View File

@ -1,4 +1,4 @@
import { SwitchboardProgram } from "../../SwitchboardProgram.js";
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars

View File

@ -1,4 +1,4 @@
import { SwitchboardProgram } from "../../SwitchboardProgram.js";
import { SwitchboardProgram } from "../../../SwitchboardProgram.js";
import * as types from "../types/index.js"; // eslint-disable-line @typescript-eslint/no-unused-vars
import * as borsh from "@coral-xyz/borsh"; // eslint-disable-line @typescript-eslint/no-unused-vars

Some files were not shown because too many files have changed in this diff Show More