added TransactionObjectOptions to some aggregator methods

This commit is contained in:
Conner Gallagher 2023-01-05 12:37:37 -07:00
parent 98d85c7753
commit 5a663abbf2
10 changed files with 415 additions and 278 deletions

View File

@ -477,13 +477,11 @@ export class SwitchboardProgram {
if (isBrowser) throw new errors.SwitchboardProgramIsBrowserError();
if (this.isReadOnly) throw new errors.SwitchboardProgramReadOnlyError();
const packed = TransactionObject.pack(txns);
const txnSignatures: Array<TransactionSignature> = [];
for await (const [i, txn] of packed.entries()) {
for await (const [i, txn] of txns.entries()) {
txnSignatures.push(await this.signAndSend(txn, opts, txnOptions));
if (
i !== packed.length - 1 &&
i !== txns.length - 1 &&
delay &&
typeof delay === 'number' &&
delay > 0

View File

@ -931,7 +931,8 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
priorityFeeBumpPeriod: number;
maxPriorityFeeMultiplier: number;
force: boolean;
}>
}>,
options?: TransactionObjectOptions
): Promise<TransactionObject> {
if (!(params.force ?? false)) {
const aggregator = await this.loadData();
@ -989,7 +990,8 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
return new TransactionObject(
payer,
[setConfigIxn],
params.authority ? [params.authority] : []
params.authority ? [params.authority] : [],
options
);
}
@ -1009,11 +1011,13 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
priorityFeeBumpPeriod?: number;
maxPriorityFeeMultiplier?: number;
force: boolean;
}>
}>,
options?: TransactionObjectOptions
): Promise<TransactionSignature> {
const setConfigTxn = await this.setConfigInstruction(
this.program.walletPubkey,
params
params,
options
);
const txnSignature = await this.program.signAndSend(setConfigTxn);
return txnSignature;
@ -1024,7 +1028,8 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
params: {
queueAccount: QueueAccount;
authority?: Keypair;
}
},
options?: TransactionObjectOptions
): TransactionObject {
const setQueueIxn = types.aggregatorSetQueue(
this.program,
@ -1040,17 +1045,22 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
return new TransactionObject(
payer,
[setQueueIxn],
params.authority ? [params.authority] : []
params.authority ? [params.authority] : [],
options
);
}
public async setQueue(params: {
queueAccount: QueueAccount;
authority?: Keypair;
}): Promise<TransactionSignature> {
public async setQueue(
params: {
queueAccount: QueueAccount;
authority?: Keypair;
},
options?: TransactionObjectOptions
): Promise<TransactionSignature> {
const setQueueTxn = this.setQueueInstruction(
this.program.walletPubkey,
params
params,
options
);
const txnSignature = await this.program.signAndSend(setQueueTxn);
return txnSignature;
@ -1062,7 +1072,8 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
job: JobAccount;
weight?: number;
authority?: Keypair;
}
},
options?: TransactionObjectOptions
): TransactionObject {
const authority = params.authority ? params.authority.publicKey : payer;
const addJobIxn = types.aggregatorAddJob(
@ -1077,16 +1088,24 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
return new TransactionObject(
payer,
[addJobIxn],
params.authority ? [params.authority] : []
params.authority ? [params.authority] : [],
options
);
}
public async addJob(params: {
job: JobAccount;
weight?: number;
authority?: Keypair;
}): Promise<TransactionSignature> {
const txn = this.addJobInstruction(this.program.walletPubkey, params);
public async addJob(
params: {
job: JobAccount;
weight?: number;
authority?: Keypair;
},
options?: TransactionObjectOptions
): Promise<TransactionSignature> {
const txn = this.addJobInstruction(
this.program.walletPubkey,
params,
options
);
const txnSignature = await this.program.signAndSend(txn);
return txnSignature;
}
@ -1095,7 +1114,8 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
payer: PublicKey,
params: {
authority?: Keypair;
}
},
options?: TransactionObjectOptions
): TransactionObject {
return new TransactionObject(
payer,
@ -1109,14 +1129,22 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
}
),
],
params.authority ? [params.authority] : []
params.authority ? [params.authority] : [],
options
);
}
public async lock(params: {
authority?: Keypair;
}): Promise<TransactionSignature> {
const lockTxn = this.lockInstruction(this.program.walletPubkey, params);
public async lock(
params: {
authority?: Keypair;
},
options?: TransactionObjectOptions
): Promise<TransactionSignature> {
const lockTxn = this.lockInstruction(
this.program.walletPubkey,
params,
options
);
const txnSignature = await this.program.signAndSend(lockTxn);
return txnSignature;
}
@ -1126,7 +1154,8 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
params: {
newAuthority: PublicKey;
authority?: Keypair;
}
},
options?: TransactionObjectOptions
): TransactionObject {
return new TransactionObject(
payer,
@ -1141,17 +1170,22 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
}
),
],
params.authority ? [params.authority] : []
params.authority ? [params.authority] : [],
options
);
}
public async setAuthority(params: {
newAuthority: PublicKey;
authority?: Keypair;
}): Promise<TransactionSignature> {
public async setAuthority(
params: {
newAuthority: PublicKey;
authority?: Keypair;
},
options?: TransactionObjectOptions
): Promise<TransactionSignature> {
const setAuthorityTxn = this.setAuthorityInstruction(
this.program.walletPubkey,
params
params,
options
);
const txnSignature = await this.program.signAndSend(setAuthorityTxn);
return txnSignature;
@ -1164,13 +1198,18 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
jobIdx: number;
weight: number;
authority?: Keypair;
}
},
options?: TransactionObjectOptions
): TransactionObject {
const removeJob = this.removeJobInstruction(payer, {
job: params.job,
jobIdx: params.jobIdx,
authority: params.authority,
});
const removeJob = this.removeJobInstruction(
payer,
{
job: params.job,
jobIdx: params.jobIdx,
authority: params.authority,
},
options
);
const addJob = this.addJobInstruction(payer, {
job: params.job,
weight: params.weight,
@ -1179,15 +1218,19 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
return removeJob.combine(addJob);
}
public async updateJobWeight(params: {
job: JobAccount;
jobIdx: number;
weight: number;
authority?: Keypair;
}): Promise<TransactionSignature> {
public async updateJobWeight(
params: {
job: JobAccount;
jobIdx: number;
weight: number;
authority?: Keypair;
},
options?: TransactionObjectOptions
): Promise<TransactionSignature> {
const transaction = this.updateJobWeightInstruction(
this.program.walletPubkey,
params
params,
options
);
const signature = await this.program.signAndSend(transaction);
return signature;
@ -1199,7 +1242,8 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
job: JobAccount;
jobIdx: number;
authority?: Keypair;
}
},
options?: TransactionObjectOptions
): TransactionObject {
const authority = params.authority ? params.authority.publicKey : payer;
const removeJobIxn = types.aggregatorRemoveJob(
@ -1214,18 +1258,23 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
return new TransactionObject(
payer,
[removeJobIxn],
params.authority ? [params.authority] : []
params.authority ? [params.authority] : [],
options
);
}
public async removeJob(params: {
job: JobAccount;
jobIdx: number;
authority?: Keypair;
}): Promise<TransactionSignature> {
public async removeJob(
params: {
job: JobAccount;
jobIdx: number;
authority?: Keypair;
},
options?: TransactionObjectOptions
): Promise<TransactionSignature> {
const removeJobTxn = this.removeJobInstruction(
this.program.walletPubkey,
params
params,
options
);
const txnSignature = await this.program.signAndSend(removeJobTxn);
return txnSignature;
@ -1233,7 +1282,8 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
public async openRoundInstruction(
payer: PublicKey,
params?: { payoutWallet?: PublicKey }
params?: { payoutWallet?: PublicKey },
options?: TransactionObjectOptions
): Promise<TransactionObject> {
const aggregatorData = await this.loadData();
const queueAccount = new QueueAccount(
@ -1289,15 +1339,19 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
)
);
return new TransactionObject(payer, ixns, []);
return new TransactionObject(payer, ixns, [], options);
}
public async openRound(params?: {
payoutWallet?: PublicKey;
}): Promise<TransactionSignature> {
public async openRound(
params?: {
payoutWallet?: PublicKey;
},
options?: TransactionObjectOptions
): Promise<TransactionSignature> {
const openRoundTxn = await this.openRoundInstruction(
this.program.walletPubkey,
params
params,
options
);
const txnSignature = await this.program.signAndSend(openRoundTxn);
return txnSignature;
@ -1604,7 +1658,8 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
params: {
authority?: Keypair;
mode: types.AggregatorResolutionModeKind;
}
},
options?: TransactionObjectOptions
): TransactionObject {
return new TransactionObject(
payer,
@ -1623,17 +1678,22 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
}
),
],
params.authority ? [params.authority] : []
params.authority ? [params.authority] : [],
options
);
}
async setSlidingWindow(params: {
authority?: Keypair;
mode: types.AggregatorResolutionModeKind;
}): Promise<TransactionSignature> {
async setSlidingWindow(
params: {
authority?: Keypair;
mode: types.AggregatorResolutionModeKind;
},
options?: TransactionObjectOptions
): Promise<TransactionSignature> {
const setSlidingWindowTxn = this.setSlidingWindowInstruction(
this.program.walletPubkey,
params
params,
options
);
const txnSignature = await this.program.signAndSend(setSlidingWindowTxn);
return txnSignature;
@ -1643,7 +1703,8 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
params?: { payoutWallet?: PublicKey } & {
aggregator?: types.AggregatorAccountData;
},
timeout = 30000
timeout = 30000,
options?: TransactionObjectOptions
): Promise<[types.AggregatorAccountData, TransactionSignature | undefined]> {
const aggregator = params?.aggregator ?? (await this.loadData());
const currentRoundOpenSlot = aggregator.latestConfirmedRound.roundOpenSlot;
@ -1683,7 +1744,7 @@ export class AggregatorAccount extends Account<types.AggregatorAccountData> {
await closeWebsocket();
});
const openRoundSignature = await this.openRound(params).catch(
const openRoundSignature = await this.openRound(params, options).catch(
async error => {
await closeWebsocket();
throw new Error(`Failed to call openRound, ${error}`);

View File

@ -13,7 +13,10 @@ import * as errors from '../errors';
import * as types from '../generated';
import { SwitchboardProgram } from '../SwitchboardProgram';
import { Account } from './account';
import { TransactionObject } from '../TransactionObject';
import {
TransactionObject,
TransactionObjectOptions,
} from '../TransactionObject';
/**
* Account type storing a list of SwitchboardTasks {@linkcode OracleJob.Task} dictating how to source data off-chain.
@ -129,7 +132,8 @@ export class JobAccount extends Account<types.JobAccountData> {
public static createInstructions(
program: SwitchboardProgram,
payer: PublicKey,
params: JobInitParams
params: JobInitParams,
options?: TransactionObjectOptions
): [JobAccount, Array<TransactionObject>] {
if (params.data.byteLength > 6400) {
throw new Error('Switchboard jobs need to be less than 6400 bytes');
@ -168,7 +172,8 @@ export class JobAccount extends Account<types.JobAccountData> {
new TransactionObject(
payer,
[jobInitIxn],
params.authority ? [jobKeypair, params.authority] : [jobKeypair]
params.authority ? [jobKeypair, params.authority] : [jobKeypair],
options
)
);
} else {
@ -207,7 +212,8 @@ export class JobAccount extends Account<types.JobAccountData> {
new TransactionObject(
payer,
[jobInitIxn],
params.authority ? [jobKeypair, params.authority] : [jobKeypair]
params.authority ? [jobKeypair, params.authority] : [jobKeypair],
options
)
);
@ -229,7 +235,8 @@ export class JobAccount extends Account<types.JobAccountData> {
new TransactionObject(
payer,
[jobSetDataIxn],
params.authority ? [params.authority] : []
params.authority ? [params.authority] : [],
options
)
);
}
@ -240,12 +247,14 @@ export class JobAccount extends Account<types.JobAccountData> {
public static async create(
program: SwitchboardProgram,
params: JobInitParams
params: JobInitParams,
options?: TransactionObjectOptions
): Promise<[JobAccount, Array<TransactionSignature>]> {
const [account, transactions] = JobAccount.createInstructions(
program,
program.walletPubkey,
params
params,
options
);
const txSignature = await program.signAndSendAll(transactions);
return [account, txSignature];

View File

@ -16,7 +16,10 @@ import { promiseWithTimeout } from '@switchboard-xyz/common';
import * as errors from '../errors';
import * as types from '../generated';
import { SwitchboardProgram } from '../SwitchboardProgram';
import { TransactionObject } from '../TransactionObject';
import {
TransactionObject,
TransactionObjectOptions,
} from '../TransactionObject';
import { Account, OnAccountChangeCallback } from './account';
import { OracleAccount } from './oracleAccount';
import { PermissionAccount } from './permissionAccount';
@ -229,88 +232,69 @@ export class VrfAccount extends Account<types.VrfAccountData> {
public proveAndVerifyInstructions(
params: VrfProveAndVerifyParams,
tryCount = 278
): TransactionInstruction[] {
const ixns: TransactionInstruction[] = [];
const vrf = params.vrf;
const idx = vrf.builders.findIndex(builder =>
options?: TransactionObjectOptions,
numTxns = 40
): Array<TransactionObject> {
const idx = params.vrf.builders.findIndex(builder =>
params.oraclePubkey.equals(builder.producer)
);
if (idx === -1) {
throw new Error('OracleNotFoundError');
}
// only add proof in first ixn to optimally pack
ixns.push(
types.vrfProveAndVerify(
const remainingAccounts = params.vrf.callback.accounts.slice(
0,
params.vrf.callback.accountsLen
);
const txns = Array.from(Array(numTxns).keys()).map(i => {
const proveIxn = types.vrfProveAndVerify(
this.program,
{
params: {
nonce: 1,
nonce: i,
stateBump: this.program.programState.bump,
idx: idx,
proof: new Uint8Array(),
proofEncoded: params.proof,
counter: vrf.counter,
counter: params.vrf.counter,
},
},
{
vrf: this.publicKey,
callbackPid: vrf.callback.programId,
callbackPid: params.vrf.callback.programId,
tokenProgram: TOKEN_PROGRAM_ID,
escrow: vrf.escrow,
escrow: params.vrf.escrow,
programState: this.program.programState.publicKey,
oracle: params.oraclePubkey,
oracleAuthority: params.oracleAuthority,
oracleWallet: params.oracleTokenWallet,
instructionsSysvar: SYSVAR_INSTRUCTIONS_PUBKEY,
}
)
);
// add verify ixns
for (let i = 0; i < tryCount; ++i) {
ixns.push(
types.vrfProveAndVerify(
this.program,
{
params: {
nonce: i,
stateBump: this.program.programState.bump,
idx: idx,
proof: new Uint8Array(),
proofEncoded: '',
counter: vrf.counter,
},
},
{
vrf: this.publicKey,
callbackPid: vrf.callback.programId,
tokenProgram: TOKEN_PROGRAM_ID,
escrow: vrf.escrow,
programState: this.program.programState.publicKey,
oracle: params.oraclePubkey,
oracleAuthority: params.oracleAuthority,
oracleWallet: params.oracleTokenWallet,
instructionsSysvar: SYSVAR_INSTRUCTIONS_PUBKEY,
}
)
);
}
proveIxn.keys = proveIxn.keys.concat(remainingAccounts);
return ixns;
return new TransactionObject(this.program.walletPubkey, [proveIxn], [], {
computeUnitLimit: 1_400_000, // allow user to override
...options,
});
});
return txns;
}
public async proveAndVerify(params: {
vrf?: types.VrfAccountData;
proof?: string;
oraclePubkey?: PublicKey;
oracleTokenWallet?: PublicKey;
oracleAuthority?: PublicKey;
skipPreflight?: boolean;
}): Promise<Array<TransactionSignature>> {
public async proveAndVerify(
params: {
vrf?: types.VrfAccountData;
proof?: string;
oraclePubkey?: PublicKey;
oracleTokenWallet?: PublicKey;
oracleAuthority?: PublicKey;
skipPreflight?: boolean;
},
options?: TransactionObjectOptions,
numTxns = 40
): Promise<Array<TransactionSignature>> {
const vrf = params.vrf ?? (await this.loadData());
const oraclePubkey = params.oraclePubkey ?? vrf.builders[0].producer;
@ -323,15 +307,18 @@ export class VrfAccount extends Account<types.VrfAccountData> {
oracleAuthority = oracle.oracleAuthority;
}
const ixns = this.proveAndVerifyInstructions({
vrf,
proof: params.proof ?? '',
oraclePubkey,
oracleTokenWallet,
oracleAuthority,
});
const txns = this.proveAndVerifyInstructions(
{
vrf,
proof: params.proof ?? '',
oraclePubkey,
oracleTokenWallet,
oracleAuthority,
},
options,
numTxns
);
const txns = TransactionObject.packIxns(this.program.walletPubkey, ixns);
const txnSignatures = await this.program.signAndSendAll(txns, {
skipPreflight: params.skipPreflight ?? true,
});

View File

@ -15,7 +15,7 @@ anchor_vrf_parser = "4wTeTACfwiXqqvy44bNBB3V2rFjmSTXVoEr4ZAYamJEN"
url = "https://anchor.projectserum.com"
[scripts]
test = "yarn run ts-mocha -p ./tsconfig.json -t 30000 ./tests/*.test.ts"
test = "yarn run ts-mocha -p ./tsconfig.json -t 60000 ./tests/*.test.ts"
[test.validator]
url="https://api.devnet.solana.com"

View File

@ -14,7 +14,7 @@
"@solana/spl-token": "^0.3.6",
"@solana/web3.js": "^1.67.0",
"@switchboard-xyz/common": "^2.1.8",
"@switchboard-xyz/solana.js": "^2.0.52",
"@switchboard-xyz/solana.js": "^2.0.79",
"chalk": "^4.1.2",
"dotenv": "^16.0.1",
"yargs": "^17.5.1"
@ -275,6 +275,36 @@
"node": ">= 8"
}
},
"node_modules/@project-serum/anchor": {
"version": "0.26.0",
"resolved": "https://registry.npmjs.org/@project-serum/anchor/-/anchor-0.26.0.tgz",
"integrity": "sha512-Nq+COIjE1135T7qfnOHEn7E0q39bQTgXLFk837/rgFe6Hkew9WML7eHsS+lSYD2p3OJaTiUOHTAq1lHy36oIqQ==",
"dependencies": {
"@coral-xyz/borsh": "^0.26.0",
"@solana/web3.js": "^1.68.0",
"base64-js": "^1.5.1",
"bn.js": "^5.1.2",
"bs58": "^4.0.1",
"buffer-layout": "^1.2.2",
"camelcase": "^6.3.0",
"cross-fetch": "^3.1.5",
"crypto-hash": "^1.3.0",
"eventemitter3": "^4.0.7",
"js-sha256": "^0.9.0",
"pako": "^2.0.3",
"snake-case": "^3.0.4",
"superstruct": "^0.15.4",
"toml": "^3.0.0"
},
"engines": {
"node": ">=11"
}
},
"node_modules/@project-serum/anchor/node_modules/superstruct": {
"version": "0.15.5",
"resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz",
"integrity": "sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ=="
},
"node_modules/@project-serum/borsh": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/@project-serum/borsh/-/borsh-0.2.5.tgz",
@ -386,15 +416,16 @@
}
},
"node_modules/@solana/web3.js": {
"version": "1.70.1",
"resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.70.1.tgz",
"integrity": "sha512-AnaqCF1cJ3w7d0yhvLGAKAcRI+n5o+ursQihhoTe4cUh8/9d4gbT73SoHYElS7e67OtAgLmSfbcC5hcOAgdvnQ==",
"version": "1.73.0",
"resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.73.0.tgz",
"integrity": "sha512-YrgX3Py7ylh8NYkbanoINUPCj//bWUjYZ5/WPy9nQ9SK3Cl7QWCR+NmbDjmC/fTspZGR+VO9LTQslM++jr5PRw==",
"dependencies": {
"@babel/runtime": "^7.12.5",
"@noble/ed25519": "^1.7.0",
"@noble/hashes": "^1.1.2",
"@noble/secp256k1": "^1.6.3",
"@solana/buffer-layout": "^4.0.0",
"agentkeepalive": "^4.2.1",
"bigint-buffer": "^1.1.5",
"bn.js": "^5.0.0",
"borsh": "^0.7.0",
@ -445,61 +476,25 @@
}
},
"node_modules/@switchboard-xyz/solana.js": {
"version": "2.0.52",
"resolved": "https://registry.npmjs.org/@switchboard-xyz/solana.js/-/solana.js-2.0.52.tgz",
"integrity": "sha512-ppM64vBeR8DZ9RYeVi7mhG4OwwLvBOYAlitaa7v32/43Qlz7rHokdRkyQPYh50mr2rRiebVlpMINh6ZD6tWP6A==",
"version": "2.0.79",
"resolved": "https://registry.npmjs.org/@switchboard-xyz/solana.js/-/solana.js-2.0.79.tgz",
"integrity": "sha512-gQeseWGpzWDcpQEqivRNw+FgjGjV2nxmEXgcZWwRz7SpRYehuhZVBnkueTlQEAdGYmi/oXU32YpERcfm6s2jXg==",
"dependencies": {
"@project-serum/anchor": "^0.25.0",
"@project-serum/anchor": "^0.26.0",
"@project-serum/borsh": "^0.2.5",
"@solana/spl-token": "^0.3.5",
"@solana/web3.js": "^1.66.1",
"@solana/spl-token": "^0.3.6",
"@solana/web3.js": "^1.73.0",
"@switchboard-xyz/common": "^2.1.8",
"big.js": "^6.2.1",
"bn.js": "^5.2.1"
"bn.js": "^5.2.1",
"dotenv": "^16.0.3",
"lodash": "^4.17.21"
},
"engines": {
"node": ">=16.0.0",
"npm": ">=7.0.0"
}
},
"node_modules/@switchboard-xyz/solana.js/node_modules/@project-serum/anchor": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@project-serum/anchor/-/anchor-0.25.0.tgz",
"integrity": "sha512-E6A5Y/ijqpfMJ5psJvbw0kVTzLZFUcOFgs6eSM2M2iWE1lVRF18T6hWZVNl6zqZsoz98jgnNHtVGJMs+ds9A7A==",
"dependencies": {
"@project-serum/borsh": "^0.2.5",
"@solana/web3.js": "^1.36.0",
"base64-js": "^1.5.1",
"bn.js": "^5.1.2",
"bs58": "^4.0.1",
"buffer-layout": "^1.2.2",
"camelcase": "^5.3.1",
"cross-fetch": "^3.1.5",
"crypto-hash": "^1.3.0",
"eventemitter3": "^4.0.7",
"js-sha256": "^0.9.0",
"pako": "^2.0.3",
"snake-case": "^3.0.4",
"superstruct": "^0.15.4",
"toml": "^3.0.0"
},
"engines": {
"node": ">=11"
}
},
"node_modules/@switchboard-xyz/solana.js/node_modules/camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==",
"engines": {
"node": ">=6"
}
},
"node_modules/@switchboard-xyz/solana.js/node_modules/superstruct": {
"version": "0.15.5",
"resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz",
"integrity": "sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ=="
},
"node_modules/@tsconfig/node10": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
@ -808,6 +803,19 @@
"node": ">=0.4.0"
}
},
"node_modules/agentkeepalive": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz",
"integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==",
"dependencies": {
"debug": "^4.1.0",
"depd": "^1.1.2",
"humanize-ms": "^1.2.1"
},
"engines": {
"node": ">= 8.0.0"
}
},
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@ -1262,7 +1270,6 @@
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"dependencies": {
"ms": "2.1.2"
},
@ -1337,6 +1344,14 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/diff": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
@ -2152,6 +2167,14 @@
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
"dev": true
},
"node_modules/humanize-ms": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
"integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
"dependencies": {
"ms": "^2.0.0"
}
},
"node_modules/ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
@ -2930,8 +2953,7 @@
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"node_modules/nanoid": {
"version": "3.3.1",
@ -4762,6 +4784,35 @@
"fastq": "^1.6.0"
}
},
"@project-serum/anchor": {
"version": "0.26.0",
"resolved": "https://registry.npmjs.org/@project-serum/anchor/-/anchor-0.26.0.tgz",
"integrity": "sha512-Nq+COIjE1135T7qfnOHEn7E0q39bQTgXLFk837/rgFe6Hkew9WML7eHsS+lSYD2p3OJaTiUOHTAq1lHy36oIqQ==",
"requires": {
"@coral-xyz/borsh": "^0.26.0",
"@solana/web3.js": "^1.68.0",
"base64-js": "^1.5.1",
"bn.js": "^5.1.2",
"bs58": "^4.0.1",
"buffer-layout": "^1.2.2",
"camelcase": "^6.3.0",
"cross-fetch": "^3.1.5",
"crypto-hash": "^1.3.0",
"eventemitter3": "^4.0.7",
"js-sha256": "^0.9.0",
"pako": "^2.0.3",
"snake-case": "^3.0.4",
"superstruct": "^0.15.4",
"toml": "^3.0.0"
},
"dependencies": {
"superstruct": {
"version": "0.15.5",
"resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz",
"integrity": "sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ=="
}
}
},
"@project-serum/borsh": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/@project-serum/borsh/-/borsh-0.2.5.tgz",
@ -4855,15 +4906,16 @@
}
},
"@solana/web3.js": {
"version": "1.70.1",
"resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.70.1.tgz",
"integrity": "sha512-AnaqCF1cJ3w7d0yhvLGAKAcRI+n5o+ursQihhoTe4cUh8/9d4gbT73SoHYElS7e67OtAgLmSfbcC5hcOAgdvnQ==",
"version": "1.73.0",
"resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.73.0.tgz",
"integrity": "sha512-YrgX3Py7ylh8NYkbanoINUPCj//bWUjYZ5/WPy9nQ9SK3Cl7QWCR+NmbDjmC/fTspZGR+VO9LTQslM++jr5PRw==",
"requires": {
"@babel/runtime": "^7.12.5",
"@noble/ed25519": "^1.7.0",
"@noble/hashes": "^1.1.2",
"@noble/secp256k1": "^1.6.3",
"@solana/buffer-layout": "^4.0.0",
"agentkeepalive": "^4.2.1",
"bigint-buffer": "^1.1.5",
"bn.js": "^5.0.0",
"borsh": "^0.7.0",
@ -4899,51 +4951,19 @@
}
},
"@switchboard-xyz/solana.js": {
"version": "2.0.52",
"resolved": "https://registry.npmjs.org/@switchboard-xyz/solana.js/-/solana.js-2.0.52.tgz",
"integrity": "sha512-ppM64vBeR8DZ9RYeVi7mhG4OwwLvBOYAlitaa7v32/43Qlz7rHokdRkyQPYh50mr2rRiebVlpMINh6ZD6tWP6A==",
"version": "2.0.79",
"resolved": "https://registry.npmjs.org/@switchboard-xyz/solana.js/-/solana.js-2.0.79.tgz",
"integrity": "sha512-gQeseWGpzWDcpQEqivRNw+FgjGjV2nxmEXgcZWwRz7SpRYehuhZVBnkueTlQEAdGYmi/oXU32YpERcfm6s2jXg==",
"requires": {
"@project-serum/anchor": "^0.25.0",
"@project-serum/anchor": "^0.26.0",
"@project-serum/borsh": "^0.2.5",
"@solana/spl-token": "^0.3.5",
"@solana/web3.js": "^1.66.1",
"@solana/spl-token": "^0.3.6",
"@solana/web3.js": "^1.73.0",
"@switchboard-xyz/common": "^2.1.8",
"big.js": "^6.2.1",
"bn.js": "^5.2.1"
},
"dependencies": {
"@project-serum/anchor": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@project-serum/anchor/-/anchor-0.25.0.tgz",
"integrity": "sha512-E6A5Y/ijqpfMJ5psJvbw0kVTzLZFUcOFgs6eSM2M2iWE1lVRF18T6hWZVNl6zqZsoz98jgnNHtVGJMs+ds9A7A==",
"requires": {
"@project-serum/borsh": "^0.2.5",
"@solana/web3.js": "^1.36.0",
"base64-js": "^1.5.1",
"bn.js": "^5.1.2",
"bs58": "^4.0.1",
"buffer-layout": "^1.2.2",
"camelcase": "^5.3.1",
"cross-fetch": "^3.1.5",
"crypto-hash": "^1.3.0",
"eventemitter3": "^4.0.7",
"js-sha256": "^0.9.0",
"pako": "^2.0.3",
"snake-case": "^3.0.4",
"superstruct": "^0.15.4",
"toml": "^3.0.0"
}
},
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
},
"superstruct": {
"version": "0.15.5",
"resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz",
"integrity": "sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ=="
}
"bn.js": "^5.2.1",
"dotenv": "^16.0.3",
"lodash": "^4.17.21"
}
},
"@tsconfig/node10": {
@ -5153,6 +5173,16 @@
"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
"dev": true
},
"agentkeepalive": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz",
"integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==",
"requires": {
"debug": "^4.1.0",
"depd": "^1.1.2",
"humanize-ms": "^1.2.1"
}
},
"ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@ -5479,7 +5509,6 @@
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"requires": {
"ms": "2.1.2"
}
@ -5525,6 +5554,11 @@
"resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz",
"integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw=="
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ=="
},
"diff": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz",
@ -6144,6 +6178,14 @@
"integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==",
"dev": true
},
"humanize-ms": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz",
"integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==",
"requires": {
"ms": "^2.0.0"
}
},
"ieee754": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
@ -6714,8 +6756,7 @@
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
},
"nanoid": {
"version": "3.3.1",

View File

@ -11,8 +11,17 @@
"sbv2-vrf-example": "./sbv2-vrf-example.sh"
},
"scripts": {
"build": "echo \"For workspace anchor-vrf-parser, run 'anchor build' from the project root\" && exit 0",
"lint": "eslint --ext .js,.json,.ts 'src/**' --fix"
"lint": "eslint --ext .js,.json,.ts 'src/**' --fix",
"pubkey": "solana-keygen pubkey target/deploy/anchor_vrf_parser-keypair.json",
"localnet": "npm run localnet:down || exit 0; 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 2TfB33aLaneQb5TNVwyDz3jSZXS6jdW2ARw1Dgf84XCG `# programId` --clone J4CArpsbrZqu1axqQ4AnrqREs3jwoyA1M5LMiQQmAzB9 `# programDataAddress` --clone CKwZcshn4XDvhaWVH9EXnk3iu19t6t5xP2Sy2pD6TRDp `# idlAddress` --clone BYM81n8HvTJuqZU1PmTVcwZ9G8uoji7FKM6EaPkwphPt `# programState` --clone FVLfR6C2ckZhbSwBzZY4CX7YBcddUSge5BNeGQv5eKhy `# switchboardVault` & npm run localnet:wait",
"localnet:wait": "for attempt in {1..30}; do sleep 1; if curl -sS http://localhost:8899 -X POST -H 'Content-Type: application/json' -d '{\"jsonrpc\":\"2.0\",\"id\":1, \"method\":\"getBlockHeight\"}'; then echo ready; break; fi; done",
"localnet:down": "kill -9 $(pgrep command solana-test-validator) || exit 0",
"network:create": "sbv2 solana network create --keypair ~/.config/solana/id.json --configFile .switchboard/networks/default.config.json --schemaFile .switchboard/networks/default.json --cluster localnet --force",
"network:start": "sbv2 solana network start --keypair ~/.config/solana/id.json --schemaFile .switchboard/networks/default.json --cluster localnet --nodeImage dev-v2-RC_01_05_23_18_41a-beta",
"network:start:dev": "VERBOSE=1 DEBUG=1 CHAIN=solana CLUSTER=localnet TASK_RUNNER_SOLANA_RPC=https://api.mainnet-beta.solana.com FS_PAYER_SECRET_PATH=~/.config/solana/id.json RPC_URL=http://localhost:8899 ORACLE_KEY=Ei4HcqRQtf6TfwbuRXKRwCtt8PDXhmq9NhYLWpoh23xp ts-node ../../../switchboard-oracle-v2/node/src/apps/oracle",
"build": "anchor build && npx anchor-client-gen target/idl/lottery.json client/generated --program-id $(solana-keygen pubkey target/deploy/anchor_vrf_parser-keypair.json) && npx prettier client/generated --write",
"test": "npm run localnet && npm run network:create && npm run network:start & sleep 60 && anchor test --skip-local-validator",
"test:dev": "npm run localnet && npm run network:create && npm run network:start:dev & sleep 15 && anchor test --skip-local-validator"
},
"dependencies": {
"@coral-xyz/anchor": "^0.26.0",
@ -21,7 +30,7 @@
"@solana/spl-token": "^0.3.6",
"@solana/web3.js": "^1.67.0",
"@switchboard-xyz/common": "^2.1.8",
"@switchboard-xyz/solana.js": "^2.0.52",
"@switchboard-xyz/solana.js": "^2.0.79",
"chalk": "^4.1.2",
"dotenv": "^16.0.1",
"yargs": "^17.5.1"

View File

@ -14,11 +14,11 @@ import {
AnchorWallet,
Callback,
PermissionAccount,
SwitchboardTestContext,
types,
} from "@switchboard-xyz/solana.js";
import { sleep } from "@switchboard-xyz/common";
import { TOKEN_PROGRAM_ID } from "@solana/spl-token";
import { Switchboard } from "./init";
describe("anchor-vrf-parser test", () => {
const provider = AnchorProvider.env();
@ -36,7 +36,7 @@ describe("anchor-vrf-parser test", () => {
const payer = (provider.wallet as AnchorWallet).payer;
let switchboard: SwitchboardTestContext;
let switchboard: Switchboard;
const vrfSecret = anchor.web3.Keypair.generate();
console.log(`VRF Account: ${vrfSecret.publicKey}`);
@ -63,40 +63,11 @@ describe("anchor-vrf-parser test", () => {
};
before(async () => {
// First, attempt to load the switchboard devnet PID
try {
switchboard = await SwitchboardTestContext.loadDevnetQueue(
provider as anchor.AnchorProvider,
"F8ce7MsckeZAbAGmxjJNetxYXQa9mKr9nnrC3qKubyYy",
5_000_000 // .005 wSOL
);
console.log("devnet detected");
return;
} catch (error: any) {
console.log(`Error: SBV2 Devnet - ${error.message}`);
// console.error(error);
}
// If fails, fallback to looking for a local env file
try {
switchboard = await SwitchboardTestContext.loadFromEnv(
provider,
undefined,
5_000_000 // .005 wSOL
);
console.log("localnet detected");
return;
} catch (error: any) {
console.log(`Error: SBV2 Localnet - ${error.message}`);
console.error(error);
}
// If fails, throw error
throw new Error(
`Failed to load the SwitchboardTestContext from devnet or from a switchboard.env file`
);
switchboard = await Switchboard.load(provider);
});
it("Creates a vrfClient account", async () => {
const queue = switchboard.queue;
const queue = switchboard.queue.account;
const { unpermissionedVrfEnabled, authority, dataBuffer } =
await queue.loadData();

View File

@ -0,0 +1,60 @@
import { AnchorProvider } from "@coral-xyz/anchor";
import { Cluster, clusterApiUrl, Keypair } from "@solana/web3.js";
import {
ISwitchboardNetwork,
SwitchboardNetwork,
SwitchboardProgram,
} from "@switchboard-xyz/solana.js";
import os from "os";
import path from "path";
export const DEFAULT_KEYPAIR_PATH = path.join(
os.homedir(),
".config/solana/id.json"
);
export function getCluster(
rpcEndpoint: string
): Cluster | "localnet" | undefined {
switch (rpcEndpoint) {
case "http://localhost:8899":
return "localnet";
case clusterApiUrl("devnet"):
return "devnet";
case clusterApiUrl("mainnet-beta"):
return "mainnet-beta";
default:
return undefined;
}
}
export class Switchboard extends SwitchboardNetwork {
private static _instances: Map<string, Promise<Switchboard>> = new Map();
private constructor(network: SwitchboardNetwork, readonly name: string) {
super(network);
}
public static load(
provider: AnchorProvider,
name = "default"
): Promise<Switchboard> {
if (!this._instances.has(name)) {
this._instances.set(
name,
new Promise(async (resolve, reject) => {
try {
const program = await SwitchboardProgram.fromProvider(provider);
const switchboardNetwork = SwitchboardNetwork.find(program, name);
const switchboard = new Switchboard(switchboardNetwork, name);
resolve(switchboard);
} catch (error) {
reject(error);
}
})
);
}
return this._instances.get(name)!;
}
}

View File

@ -12,6 +12,7 @@
"esModuleInterop": true,
"strict": false,
"strictNullChecks": false,
"target": "es6",
"paths": {
"@switchboard-xyz/switchboard-v2": ["../../javascript/switchboard-v2"],
"@switchboard-xyz/sbv2-utils": ["../../javascript/sbv2-utils"],