@orao-network/solana-vrf-cb
Version:
ORAO Verifiable Random Function with Callback for Solana.
1,223 lines • 50.7 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FulfillAltBuilder = exports.FulfillBuilder = exports.WithdrawBuilder = exports.TransferBuilder = exports.SetCallbackBuilder = exports.RegisterBuilder = exports.ConfigureBuilder = exports.InitializeBuilder = exports.OraoCb = exports.CB_REQUEST_ALT_ACCOUNT_SEED = exports.CB_REQUEST_ACCOUNT_SEED = exports.CB_CLIENT_ACCOUNT_SEED = exports.CB_CONFIG_ACCOUNT_SEED = exports.MAX_FULFILLMENT_AUTHORITIES = exports.PROGRAM_ID = exports.PROGRAM_ADDRESS = exports.IDL = exports.web3 = exports.MethodsBuilder = void 0;
exports.networkStateAddress = networkStateAddress;
exports.clientAddress = clientAddress;
exports.requestAltAccountAddress = requestAltAccountAddress;
exports.requestAccountAddress = requestAccountAddress;
exports.quorum = quorum;
exports.compileAccounts = compileAccounts;
const anchor_1 = require("@coral-xyz/anchor");
Object.defineProperty(exports, "web3", { enumerable: true, get: function () { return anchor_1.web3; } });
const web3_js_1 = require("@solana/web3.js");
const state_1 = require("./state");
const orao_vrf_cb_json_1 = __importDefault(require("./types/orao_vrf_cb.json"));
exports.IDL = orao_vrf_cb_json_1.default;
const methods_1 = require("@coral-xyz/anchor/dist/cjs/program/namespace/methods");
Object.defineProperty(exports, "MethodsBuilder", { enumerable: true, get: function () { return methods_1.MethodsBuilder; } });
const registry_1 = require("@coral-xyz/anchor/dist/cjs/utils/registry");
const sha2_1 = require("@noble/hashes/sha2");
__exportStar(require("./state"), exports);
/**
* Address of a deployed Callback VRF
*/
exports.PROGRAM_ADDRESS = orao_vrf_cb_json_1.default.address;
/**
* Id of a deployed Callback VRF
*/
exports.PROGRAM_ID = new anchor_1.web3.PublicKey(exports.PROGRAM_ADDRESS);
/**
* Maximum supported number of fulfill authorities.
*/
exports.MAX_FULFILLMENT_AUTHORITIES = 10;
exports.CB_CONFIG_ACCOUNT_SEED = Buffer.from("OraoVrfCbConfig");
exports.CB_CLIENT_ACCOUNT_SEED = Buffer.from("OraoVrfCbClient");
exports.CB_REQUEST_ACCOUNT_SEED = Buffer.from("OraoVrfCbRequest");
exports.CB_REQUEST_ALT_ACCOUNT_SEED = Buffer.from("OraoVrfCbRequestAlt");
function networkStateAddress(bump, vrf_id = exports.PROGRAM_ID) {
if ("number" === typeof bump) {
return [
anchor_1.web3.PublicKey.createProgramAddressSync([exports.CB_CONFIG_ACCOUNT_SEED, new Uint8Array([bump])], vrf_id),
bump,
];
}
else if (bump !== undefined) {
vrf_id = bump;
}
return anchor_1.web3.PublicKey.findProgramAddressSync([exports.CB_CONFIG_ACCOUNT_SEED], vrf_id);
}
function clientAddress(program, state, bump, vrf_id = exports.PROGRAM_ID) {
let seeds = [exports.CB_CLIENT_ACCOUNT_SEED, program.toBuffer(), state.toBuffer()];
if ("number" === typeof bump) {
return [
anchor_1.web3.PublicKey.createProgramAddressSync([...seeds, new Uint8Array([bump])], vrf_id),
bump,
];
}
else {
if (bump !== undefined) {
vrf_id = bump;
}
return anchor_1.web3.PublicKey.findProgramAddressSync(seeds, vrf_id);
}
}
function requestAltAccountAddress(client, seed, bump, vrf_id = exports.PROGRAM_ID) {
let seeds = [exports.CB_REQUEST_ALT_ACCOUNT_SEED, client.toBuffer(), seed];
if ("number" === typeof bump) {
return [
anchor_1.web3.PublicKey.createProgramAddressSync([...seeds, new Uint8Array([bump])], vrf_id),
bump,
];
}
else {
if (bump !== undefined) {
vrf_id = bump;
}
return anchor_1.web3.PublicKey.findProgramAddressSync(seeds, vrf_id);
}
}
function requestAccountAddress(client, seed, bump, vrf_id = exports.PROGRAM_ID) {
let seeds = [exports.CB_REQUEST_ACCOUNT_SEED, client.toBuffer(), seed];
if ("number" === typeof bump) {
return [
anchor_1.web3.PublicKey.createProgramAddressSync([...seeds, new Uint8Array([bump])], vrf_id),
bump,
];
}
else {
if (bump !== undefined) {
vrf_id = bump;
}
return anchor_1.web3.PublicKey.findProgramAddressSync(seeds, vrf_id);
}
}
/**
* Returns `true` if Byzantine quorum is achieved.
*
* @param count number of participants
* @param total total number of nodes
* @returns `true` if quorum is achieved
*/
function quorum(count, total) {
return count >= Math.floor((total * 2) / 3 + 1);
}
/**
* Compiles given `accounts` to a pair of `RemainingAccountAlt[]` and accountsHash
* given the list of lookup tables.
*
* This helper function can be used to populate the `CallbackAlt` structure fields.
*/
function compileAccounts(accounts, lookupTables) {
let accountsHashData = Buffer.alloc(32 * accounts.length, 0);
const out = [];
top: for (const account of accounts) {
account.pubkey.toBuffer().copy(accountsHashData, 32 * out.length);
for (let i in lookupTables) {
const table = lookupTables[i];
for (let j in table.state.addresses) {
const address = table.state.addresses[j];
if (address.equals(account.pubkey)) {
out.push({
lookup: {
0: {
tableIndex: i,
addressIndex: j,
seeds: account.seeds,
},
},
});
continue top;
}
}
}
out.push({
plain: {
0: account,
},
});
}
return [out, (0, sha2_1.sha256)(accountsHashData)];
}
/** Orao VRF program */
class OraoCb extends anchor_1.Program {
get payer() {
return this._payer;
}
/**
* Constructs a new program given the provider.
*
* Make sure to choose the desired {@link web3.Commitment} when building your provider.
*
* @param provider - an object that implements the {@link Provider} interface.
* Make sure it uses the desired `CommitmentLevel`.
* @param [id=PROGRAM_ID] - you can override the program ID.
*/
constructor(provider, id = exports.PROGRAM_ID) {
super(orao_vrf_cb_json_1.default, provider);
if (!provider.publicKey) {
throw new Error("Wallet not provided");
}
this._payer = provider.publicKey;
}
/**
* Returns VRF configuration (throws if not initialized).
*
* ```typescript
* const state = await vrf.getNetworkState();
* console.log("Request fee is " + state.config.requestFee);
* ```
*
* @param commitment - you can override the provider's commitment level.
*/
getNetworkState(commitment) {
return __awaiter(this, void 0, void 0, function* () {
let state = yield this.account.networkState.fetch(networkStateAddress(this.programId)[0], commitment);
let config = state.config;
return new state_1.NetworkState(state.bump, new state_1.NetworkConfiguration(config.authority, config.treasury, config.requestFee, config.callbackDeadline, config.fulfillAuthorities), state.numRequests, state.numRegistered, state.numTerminated);
});
}
getClient(arg1, arg2, commitment) {
return __awaiter(this, void 0, void 0, function* () {
let client = arg1;
if (arg2 instanceof anchor_1.web3.PublicKey) {
client = clientAddress(arg1, arg2, this.programId)[0];
}
else if (arg2) {
commitment = arg2;
}
let account = yield this.account.client.fetch(client, commitment);
let callback = account.callback
? new state_1.ValidatedCallback(account.callback.remainingAccounts.map((a) => new state_1.ValidatedRemainingAccount(a.pubkey, a.isWritable)), account.callback.data)
: null;
return new state_1.Client(account.bump, account.owner, account.program, account.state, account.numRequests, callback);
});
}
getRequestAccount(arg1, arg2, commitment) {
return __awaiter(this, void 0, void 0, function* () {
let accountAddress = arg1;
if ("string" !== typeof arg2 && arg2 !== undefined) {
accountAddress = requestAccountAddress(arg1, arg2, this.programId)[0];
}
let requestAccount = yield this.account.requestAccount.fetchNullable(accountAddress, commitment);
if (requestAccount === null) {
return null;
}
return requestAccount === null ? null : state_1.RequestAccount.fromRawAccount(requestAccount);
});
}
getRequestAltAccount(arg1, arg2, commitment) {
return __awaiter(this, void 0, void 0, function* () {
let accountAddress = arg1;
if ("string" !== typeof arg2 && arg2 !== undefined) {
accountAddress = requestAltAccountAddress(arg1, arg2, this.programId)[0];
}
let requestAccount = yield this.account.requestAltAccount.fetchNullable(accountAddress, commitment);
if (requestAccount === null) {
return null;
}
return requestAccount === null ? null : state_1.RequestAltAccount.fromRawAccount(requestAccount);
});
}
waitFulfilled(arg1, arg2, commitment) {
return __awaiter(this, void 0, void 0, function* () {
let accountAddress = arg1;
if ("string" !== typeof arg2 && arg2 !== undefined) {
if (commitment == "regular") {
accountAddress = requestAccountAddress(arg1, arg2, this.programId)[0];
}
else {
accountAddress = requestAltAccountAddress(arg1, arg2, this.programId)[0];
}
}
let actualCommitment = this.provider.connection.commitment;
if (commitment && commitment != "regular" && commitment != "alt") {
actualCommitment = commitment;
}
return new Promise((_resolve, reject) => __awaiter(this, void 0, void 0, function* () {
let resolved = false;
let maybeResolve = (subscriptionId, requestAccount) => {
if (requestAccount.getFulfilled() === null) {
return;
}
if (resolved) {
return;
}
resolved = true;
this.provider.connection.removeAccountChangeListener(subscriptionId);
_resolve(requestAccount);
};
try {
let subscriptionId = this.provider.connection.onAccountChange(accountAddress, (accountInfo, _ctx) => {
try {
let decoded = this.coder.accounts.decode("requestAccount", accountInfo.data);
maybeResolve(subscriptionId, state_1.RequestAccount.fromRawAccount(decoded));
}
catch (_a) {
let decoded = this.coder.accounts.decode("requestAltAccount", accountInfo.data);
maybeResolve(subscriptionId, state_1.RequestAltAccount.fromRawAccount(decoded));
}
}, { commitment: actualCommitment });
// In case it's already fulfilled
let rawAccount = yield this.provider.connection.getAccountInfo(accountAddress, actualCommitment);
if (rawAccount) {
try {
let decoded = this.coder.accounts.decode("requestAccount", rawAccount.data);
maybeResolve(subscriptionId, state_1.RequestAccount.fromRawAccount(decoded));
}
catch (_a) {
let decoded = this.coder.accounts.decode("requestAltAccount", rawAccount.data);
maybeResolve(subscriptionId, state_1.RequestAltAccount.fromRawAccount(decoded));
}
}
}
catch (e) {
reject(e);
}
}));
});
}
clientBalance(acc1, acc2) {
return __awaiter(this, void 0, void 0, function* () {
if (!acc2) {
let account = yield this.provider.connection.getAccountInfo(acc1);
let rent = yield this.provider.connection.getMinimumBalanceForRentExemption((account === null || account === void 0 ? void 0 : account.data.length) || 0);
return (account === null || account === void 0 ? void 0 : account.lamports) ? new anchor_1.BN(account.lamports - rent) : new anchor_1.BN(0);
}
else {
let [client] = clientAddress(acc1, acc2, this.programId);
return yield this.clientBalance(client);
}
});
}
}
exports.OraoCb = OraoCb;
class ComputeBudgetConfig {
constructor() {
this.computeUnitPrice = null;
this.computeUnitPriceMultiplier = null;
this.computeUnitLimit = null;
}
isEmpty() {
return this.computeUnitPrice === BigInt(0) && this.computeUnitLimit === null;
}
getInstructions(connection) {
return __awaiter(this, void 0, void 0, function* () {
const instructions = [];
if (this.computeUnitPrice !== BigInt(0)) {
let fee = yield get_recommended_micro_lamport_fee(connection, this.computeUnitPrice, this.computeUnitPriceMultiplier);
if (fee !== null) {
instructions.push(web3_js_1.ComputeBudgetProgram.setComputeUnitPrice({ microLamports: fee }));
}
}
if (this.computeUnitLimit !== null) {
instructions.push(web3_js_1.ComputeBudgetProgram.setComputeUnitLimit({ units: this.computeUnitLimit }));
}
return instructions;
});
}
}
/**
* A convenient builder for the `Initialize` instruction.
*
* Note that by default it will guess and apply a prioritization fee (see
* {@link InitializeBuilder.withComputeUnitPrice} and {@link InitializeBuilder.withComputeUnitLimit}
* to opt-out)
*
* @hidden
*/
class InitializeBuilder {
/**
* Creates a new init_network instruction builder.
*
* @param vrf ORAO VRF program instance.
* @param requestFee request fee (in lamports)
*/
constructor(vrf, requestFee) {
this.computeBudgetConfig = new ComputeBudgetConfig();
this.vrf = vrf;
this.requestFee = requestFee;
}
/**
* Adds a prioritization fee in micro-lamports (applied per compute unit).
*
* Adds `ComputeBudgetInstruction::SetComputeUnitPrice` to the request builder.
*
* * if not specified, then median fee of the last 150 confirmed
* slots is used (this is by default)
* * if zero, then compute unit price is not applied at all.
*/
withComputeUnitPrice(computeUnitPrice) {
this.computeBudgetConfig.computeUnitPrice = computeUnitPrice;
return this;
}
/**
* Defines a multiplier that is applied to a median compute unit price.
*
* This is only applied if no compute_unit_price specified, i.e. if compute unit price
* is measured as a median fee of the last 150 confirmed slots.
*
* * if not specified, then no multiplier is applied (this is by default)
* * if specified, then applied as follows: `compute_unit_price = median * multiplier`
*/
withComputeUnitPriceMultiplier(multiplier) {
this.computeBudgetConfig.computeUnitPriceMultiplier = multiplier;
return this;
}
/** Defines a specific compute unit limit that the transaction is allowed to consume.
*
* Adds `ComputeBudgetInstruction::SetComputeUnitLimit` to the request builder.
*
* * if not specified, then compute unit limit is not applied at all
* (this is by default)
* * if specified, then applied as is
*/
withComputeUnitLimit(computeUnitLimit) {
this.computeBudgetConfig.computeUnitLimit = computeUnitLimit;
return this;
}
/**
* Returns a {@link MethodsBuilder} instance for the `Initialize` instruction.
*
* Note, that compute budget instructions will be prepended to the returned
* instance (use {@link InitializeBuilder.withComputeUnitPrice} and
* {@link InitializeBuilder.withComputeUnitLimit} to opt-out).
*/
build() {
return __awaiter(this, void 0, void 0, function* () {
const networkState = networkStateAddress(this.vrf.programId)[0];
let params = { requestFee: this.requestFee };
let accounts = { networkState };
let tx = this.vrf.methods.initialize(params).accountsPartial(accounts);
if (!this.computeBudgetConfig.isEmpty()) {
tx = tx.preInstructions(yield this.computeBudgetConfig.getInstructions(this.vrf.provider.connection));
}
return tx;
});
}
/**
* Performs an RPC call.
*
* @returns a transaction signature.
*/
rpc() {
return __awaiter(this, void 0, void 0, function* () {
const tx = yield this.build();
return yield tx.rpc();
});
}
}
exports.InitializeBuilder = InitializeBuilder;
/**
* A convenient builder for the `Configure` instruction.
*
* Note that by default it will guess and apply a prioritization fee (see
* {@link ConfigureBuilder.withComputeUnitPrice} and {@link ConfigureBuilder.withComputeUnitLimit}
* to opt-out)
*
* @hidden
*/
class ConfigureBuilder {
/**
* Creates a new `Configure` instruction.
*
* @param vrf ORAO VRF program instance.
*/
constructor(vrf, newConfig) {
this.computeBudgetConfig = new ComputeBudgetConfig();
this.vrf = vrf;
this.newConfig = newConfig;
}
/** Change configuration authority. */
withAuthority(authority) {
this.newConfig.authority = authority;
return this;
}
/** Change treasury account address. */
withTreasury(treasury) {
this.newConfig.treasury = treasury;
return this;
}
/** Change fee (in lamports). */
withFee(requestFee) {
this.newConfig.requestFee = requestFee;
return this;
}
/** Change callback deadline (in slots). */
withCallbackDeadline(callbackDeadline) {
this.newConfig.callbackDeadline = callbackDeadline;
return this;
}
/** Change fulfill authorities. */
withFulfillAuthorities(fulfillAuthorities) {
this.newConfig.fulfillAuthorities = fulfillAuthorities;
return this;
}
/**
* Adds a prioritization fee in micro-lamports (applied per compute unit).
*
* Adds `ComputeBudgetInstruction::SetComputeUnitPrice` to the request builder.
*
* * if not specified, then median fee of the last 150 confirmed
* slots is used (this is by default)
* * if zero, then compute unit price is not applied at all.
*/
withComputeUnitPrice(computeUnitPrice) {
this.computeBudgetConfig.computeUnitPrice = computeUnitPrice;
return this;
}
/**
* Defines a multiplier that is applied to a median compute unit price.
*
* This is only applied if no compute_unit_price specified, i.e. if compute unit price
* is measured as a median fee of the last 150 confirmed slots.
*
* * if not specified, then no multiplier is applied (this is by default)
* * if specified, then applied as follows: `compute_unit_price = median * multiplier`
*/
withComputeUnitPriceMultiplier(multiplier) {
this.computeBudgetConfig.computeUnitPriceMultiplier = multiplier;
return this;
}
/** Defines a specific compute unit limit that the transaction is allowed to consume.
*
* Adds `ComputeBudgetInstruction::SetComputeUnitLimit` to the request builder.
*
* * if not specified, then compute unit limit is not applied at all
* (this is by default)
* * if specified, then applied as is
*/
withComputeUnitLimit(computeUnitLimit) {
this.computeBudgetConfig.computeUnitLimit = computeUnitLimit;
return this;
}
/**
* Returns a {@link MethodsBuilder} instance for the `UpdateNetwork` instruction.
*
* Note, that compute budget instructions will be prepended to the returned
* instance (use {@link ConfigureBuilder.withComputeUnitPrice} and
* {@link ConfigureBuilder.withComputeUnitLimit} to opt-out).
*/
build() {
return __awaiter(this, void 0, void 0, function* () {
const networkState = networkStateAddress(this.vrf.programId)[0];
let params = { newConfig: this.newConfig };
let accounts = { networkState };
let tx = this.vrf.methods.configure(params).accountsPartial(accounts);
if (!this.computeBudgetConfig.isEmpty()) {
tx = tx.preInstructions(yield this.computeBudgetConfig.getInstructions(this.vrf.provider.connection));
}
return tx;
});
}
/**
* Performs an RPC call.
*
* @returns a transaction signature.
*/
rpc() {
return __awaiter(this, void 0, void 0, function* () {
let tx = yield this.build();
return yield tx.rpc();
});
}
}
exports.ConfigureBuilder = ConfigureBuilder;
/**
* A convenient builder for the `Register` instruction.
*
* This instruction registers a new Callback VRF client. Every registration is performed for
* a pair of accounts:
* 1. Program account — it's a client program address capable of doing
* requests and handling callbacks (if any).
* 2. State account — it's an arbitrary PDA belonging to the client program that becomes
* a request authority, i.e. it must sign the `Request` CPI calls,
*
* Note that same program can be registered many times as long as unique state accounts are used
* for every registration.
*
* Note that by default it will guess and apply a prioritization fee (see
* {@link RegisterBuilder.withComputeUnitPrice} and {@link RegisterBuilder.withComputeUnitLimit}
* to opt-out)
*/
class RegisterBuilder {
/**
* Creates a `Register` instruction builder with empty client-level callback.
*
* @param vrf ORAO VRF program instance.
* @param program program being registered
* @param state the state PDA of a client being registered
* @param stateSeeds `state` seeds and bump
*/
constructor(vrf, program, state, stateSeeds) {
this.computeBudgetConfig = new ComputeBudgetConfig();
this.vrf = vrf;
this.program = program;
this.state = state;
this.stateSeeds = stateSeeds;
this.callback = null;
}
/** Sets the client-level callback */
withCallback(callback) {
this.callback = callback;
}
/**
* Adds a prioritization fee in micro-lamports (applied per compute unit).
*
* Adds `ComputeBudgetInstruction::SetComputeUnitPrice` to the request builder.
*
* * if not specified, then median fee of the last 150 confirmed
* slots is used (this is by default)
* * if zero, then compute unit price is not applied at all.
*/
withComputeUnitPrice(computeUnitPrice) {
this.computeBudgetConfig.computeUnitPrice = computeUnitPrice;
return this;
}
/**
* Defines a multiplier that is applied to a median compute unit price.
*
* This is only applied if no compute_unit_price specified, i.e. if compute unit price
* is measured as a median fee of the last 150 confirmed slots.
*
* * if not specified, then no multiplier is applied (this is by default)
* * if specified, then applied as follows: `compute_unit_price = median * multiplier`
*/
withComputeUnitPriceMultiplier(multiplier) {
this.computeBudgetConfig.computeUnitPriceMultiplier = multiplier;
return this;
}
/** Defines a specific compute unit limit that the transaction is allowed to consume.
*
* Adds `ComputeBudgetInstruction::SetComputeUnitLimit` to the request builder.
*
* * if not specified, then compute unit limit is not applied at all
* (this is by default)
* * if specified, then applied as is
*/
withComputeUnitLimit(computeUnitLimit) {
this.computeBudgetConfig.computeUnitLimit = computeUnitLimit;
return this;
}
/**
* Returns a {@link MethodsBuilder} instance for the `Register` instruction.
*
* Note, that compute budget instructions will be prepended to the returned
* instance (use {@link RegisterBuilder.withComputeUnitPrice} and
* {@link RegisterBuilder.withComputeUnitLimit} to opt-out).
*/
build() {
return __awaiter(this, void 0, void 0, function* () {
const networkState = networkStateAddress(this.vrf.programId)[0];
const client = clientAddress(this.program, this.state, this.vrf.programId)[0];
const clientProgramAccount = yield this.vrf.provider.connection.getAccountInfo(this.program);
if (clientProgramAccount === null) {
throw new Error("Client program not found");
}
const clientProgramData = (0, registry_1.decodeUpgradeableLoaderState)(clientProgramAccount.data).program
.programdataAddress;
let params = { stateSeeds: this.stateSeeds, callback: this.callback };
let accounts = {
program: this.program,
programData: clientProgramData,
state: this.state,
client,
networkState,
};
let tx = this.vrf.methods.register(params).accountsPartial(accounts);
if (!this.computeBudgetConfig.isEmpty()) {
tx = tx.preInstructions(yield this.computeBudgetConfig.getInstructions(this.vrf.provider.connection));
}
return tx;
});
}
/**
* Performs an RPC call.
*
* @returns a transaction signature.
*/
rpc() {
return __awaiter(this, void 0, void 0, function* () {
let tx = yield this.build();
const tx_signature = yield tx.rpc();
return tx_signature;
});
}
}
exports.RegisterBuilder = RegisterBuilder;
/**
* A convenient builder for the `SetCallback` instruction.
*
* This instruction updates the client-level callback for a client (see {@link Callback});
*
* Note that by default it will guess and apply a prioritization fee (see
* {@link RegisterBuilder.withComputeUnitPrice} and {@link RegisterBuilder.withComputeUnitLimit}
* to opt-out)
*/
class SetCallbackBuilder {
/**
* Creates a `SetCallback` instruction builder.
*
* @param vrf ORAO VRF program instance.
* @param client
* @param newCallback new client-level callback
*/
constructor(vrf, client, newCallback) {
this.computeBudgetConfig = new ComputeBudgetConfig();
this.vrf = vrf;
this.client = client;
this.newCallback = newCallback;
}
/**
* Adds a prioritization fee in micro-lamports (applied per compute unit).
*
* Adds `ComputeBudgetInstruction::SetComputeUnitPrice` to the request builder.
*
* * if not specified, then median fee of the last 150 confirmed
* slots is used (this is by default)
* * if zero, then compute unit price is not applied at all.
*/
withComputeUnitPrice(computeUnitPrice) {
this.computeBudgetConfig.computeUnitPrice = computeUnitPrice;
return this;
}
/**
* Defines a multiplier that is applied to a median compute unit price.
*
* This is only applied if no compute_unit_price specified, i.e. if compute unit price
* is measured as a median fee of the last 150 confirmed slots.
*
* * if not specified, then no multiplier is applied (this is by default)
* * if specified, then applied as follows: `compute_unit_price = median * multiplier`
*/
withComputeUnitPriceMultiplier(multiplier) {
this.computeBudgetConfig.computeUnitPriceMultiplier = multiplier;
return this;
}
/** Defines a specific compute unit limit that the transaction is allowed to consume.
*
* Adds `ComputeBudgetInstruction::SetComputeUnitLimit` to the request builder.
*
* * if not specified, then compute unit limit is not applied at all
* (this is by default)
* * if specified, then applied as is
*/
withComputeUnitLimit(computeUnitLimit) {
this.computeBudgetConfig.computeUnitLimit = computeUnitLimit;
return this;
}
/**
* Returns a {@link MethodsBuilder} instance for the `SetCallback` instruction.
*
* Note, that compute budget instructions will be prepended to the returned
* instance (use {@link SetCallbackBuilder.withComputeUnitPrice} and
* {@link SetCallbackBuilder.withComputeUnitLimit} to opt-out).
*/
build() {
return __awaiter(this, void 0, void 0, function* () {
let params = { newCallback: this.newCallback };
let accounts = {
client: this.client,
};
let tx = this.vrf.methods.setCallback(params).accountsPartial(accounts);
if (!this.computeBudgetConfig.isEmpty()) {
tx = tx.preInstructions(yield this.computeBudgetConfig.getInstructions(this.vrf.provider.connection));
}
return tx;
});
}
/**
* Performs an RPC call.
*
* @returns a transaction signature.
*/
rpc() {
return __awaiter(this, void 0, void 0, function* () {
let tx = yield this.build();
const tx_signature = yield tx.rpc();
return tx_signature;
});
}
}
exports.SetCallbackBuilder = SetCallbackBuilder;
/**
* A convenient builder for the `Transfer` instruction.
*
* This instruction transfers client ownership to another account. Client owner is able
* to update client-level callback and withdraw client funds.
*
* Note that by default it will guess and apply a prioritization fee (see
* {@link RegisterBuilder.withComputeUnitPrice} and {@link RegisterBuilder.withComputeUnitLimit}
* to opt-out)
*/
class TransferBuilder {
/**
* Creates a `Transfer` instruction builder.
*
* @param vrf ORAO VRF program instance.
* @param client
* @param newOwner new client owner
*/
constructor(vrf, client, newOwner) {
this.computeBudgetConfig = new ComputeBudgetConfig();
this.vrf = vrf;
this.client = client;
this.newOwner = newOwner;
}
/**
* Adds a prioritization fee in micro-lamports (applied per compute unit).
*
* Adds `ComputeBudgetInstruction::SetComputeUnitPrice` to the request builder.
*
* * if not specified, then median fee of the last 150 confirmed
* slots is used (this is by default)
* * if zero, then compute unit price is not applied at all.
*/
withComputeUnitPrice(computeUnitPrice) {
this.computeBudgetConfig.computeUnitPrice = computeUnitPrice;
return this;
}
/**
* Defines a multiplier that is applied to a median compute unit price.
*
* This is only applied if no compute_unit_price specified, i.e. if compute unit price
* is measured as a median fee of the last 150 confirmed slots.
*
* * if not specified, then no multiplier is applied (this is by default)
* * if specified, then applied as follows: `compute_unit_price = median * multiplier`
*/
withComputeUnitPriceMultiplier(multiplier) {
this.computeBudgetConfig.computeUnitPriceMultiplier = multiplier;
return this;
}
/** Defines a specific compute unit limit that the transaction is allowed to consume.
*
* Adds `ComputeBudgetInstruction::SetComputeUnitLimit` to the request builder.
*
* * if not specified, then compute unit limit is not applied at all
* (this is by default)
* * if specified, then applied as is
*/
withComputeUnitLimit(computeUnitLimit) {
this.computeBudgetConfig.computeUnitLimit = computeUnitLimit;
return this;
}
/**
* Returns a {@link MethodsBuilder} instance for the `Transfer` instruction.
*
* Note, that compute budget instructions will be prepended to the returned
* instance (use {@link TransferBuilder.withComputeUnitPrice} and
* {@link TransferBuilder.withComputeUnitLimit} to opt-out).
*/
build() {
return __awaiter(this, void 0, void 0, function* () {
let params = { newOwner: this.newOwner };
let accounts = {
client: this.client,
};
let tx = this.vrf.methods.transfer(params).accountsPartial(accounts);
if (!this.computeBudgetConfig.isEmpty()) {
tx = tx.preInstructions(yield this.computeBudgetConfig.getInstructions(this.vrf.provider.connection));
}
return tx;
});
}
/**
* Performs an RPC call.
*
* @returns a transaction signature.
*/
rpc() {
return __awaiter(this, void 0, void 0, function* () {
let tx = yield this.build();
const tx_signature = yield tx.rpc();
return tx_signature;
});
}
}
exports.TransferBuilder = TransferBuilder;
/**
* A convenient builder for the `Withdraw` instruction.
*
* This instructions withdraw funds from the {@link Client} PDA account. Note that you won't
* be able to withdraw past the rent exemption — use {@link OraoCb.clientBalance} to
* get the available balance.
*
* Note that by default it will guess and apply a prioritization fee (see
* {@link RegisterBuilder.withComputeUnitPrice} and {@link RegisterBuilder.withComputeUnitLimit}
* to opt-out)
*/
class WithdrawBuilder {
/**
* Creates a `Withdraw` instruction builder.
*
* @param vrf ORAO VRF program instance.
* @param client
* @param amount amount to withdraw (in lamports)
*/
constructor(vrf, client, amount) {
this.computeBudgetConfig = new ComputeBudgetConfig();
this.vrf = vrf;
this.client = client;
this.amount = amount;
}
/**
* Adds a prioritization fee in micro-lamports (applied per compute unit).
*
* Adds `ComputeBudgetInstruction::SetComputeUnitPrice` to the request builder.
*
* * if not specified, then median fee of the last 150 confirmed
* slots is used (this is by default)
* * if zero, then compute unit price is not applied at all.
*/
withComputeUnitPrice(computeUnitPrice) {
this.computeBudgetConfig.computeUnitPrice = computeUnitPrice;
return this;
}
/**
* Defines a multiplier that is applied to a median compute unit price.
*
* This is only applied if no compute_unit_price specified, i.e. if compute unit price
* is measured as a median fee of the last 150 confirmed slots.
*
* * if not specified, then no multiplier is applied (this is by default)
* * if specified, then applied as follows: `compute_unit_price = median * multiplier`
*/
withComputeUnitPriceMultiplier(multiplier) {
this.computeBudgetConfig.computeUnitPriceMultiplier = multiplier;
return this;
}
/** Defines a specific compute unit limit that the transaction is allowed to consume.
*
* Adds `ComputeBudgetInstruction::SetComputeUnitLimit` to the request builder.
*
* * if not specified, then compute unit limit is not applied at all
* (this is by default)
* * if specified, then applied as is
*/
withComputeUnitLimit(computeUnitLimit) {
this.computeBudgetConfig.computeUnitLimit = computeUnitLimit;
return this;
}
/**
* Returns a {@link MethodsBuilder} instance for the `Withdraw` instruction.
*
* Note, that compute budget instructions will be prepended to the returned
* instance (use {@link WithdrawBuilder.withComputeUnitPrice} and
* {@link WithdrawBuilder.withComputeUnitLimit} to opt-out).
*/
build() {
return __awaiter(this, void 0, void 0, function* () {
let params = { amount: this.amount };
let accounts = {
client: this.client,
};
let tx = this.vrf.methods.withdraw(params).accountsPartial(accounts);
if (!this.computeBudgetConfig.isEmpty()) {
tx = tx.preInstructions(yield this.computeBudgetConfig.getInstructions(this.vrf.provider.connection));
}
return tx;
});
}
/**
* Performs an RPC call.
*
* @returns a transaction signature.
*/
rpc() {
return __awaiter(this, void 0, void 0, function* () {
let tx = yield this.build();
const tx_signature = yield tx.rpc();
return tx_signature;
});
}
}
exports.WithdrawBuilder = WithdrawBuilder;
/**
* A convenient builder for the `Fulfill` instruction.
*
* Note that by default it will guess and apply a prioritization fee (see
* {@link RegisterBuilder.withComputeUnitPrice} and {@link RegisterBuilder.withComputeUnitLimit}
* to opt-out)
*
* @hidden
*/
class FulfillBuilder {
/**
* Creates a fulfill instruction builder.
*
* @param vrf ORAO VRF program instance.
* @param client the client that made the request
* @param seed seed value (32 bytes).
*/
constructor(vrf, client, seed) {
this.computeBudgetConfig = new ComputeBudgetConfig();
this.vrf = vrf;
this.client = client;
this.seed = seed;
}
/**
* Adds a prioritization fee in micro-lamports (applied per compute unit).
*
* Adds `ComputeBudgetInstruction::SetComputeUnitPrice` to the request builder.
*
* * if not specified, then median fee of the last 150 confirmed
* slots is used (this is by default)
* * if zero, then compute unit price is not applied at all.
*/
withComputeUnitPrice(computeUnitPrice) {
this.computeBudgetConfig.computeUnitPrice = computeUnitPrice;
return this;
}
/**
* Defines a multiplier that is applied to a median compute unit price.
*
* This is only applied if no compute_unit_price specified, i.e. if compute unit price
* is measured as a median fee of the last 150 confirmed slots.
*
* * if not specified, then no multiplier is applied (this is by default)
* * if specified, then applied as follows: `compute_unit_price = median * multiplier`
*/
withComputeUnitPriceMultiplier(multiplier) {
this.computeBudgetConfig.computeUnitPriceMultiplier = multiplier;
return this;
}
/** Defines a specific compute unit limit that the transaction is allowed to consume.
*
* Adds `ComputeBudgetInstruction::SetComputeUnitLimit` to the request builder.
*
* * if not specified, then compute unit limit is not applied at all
* (this is by default)
* * if specified, then applied as is
*/
withComputeUnitLimit(computeUnitLimit) {
this.computeBudgetConfig.computeUnitLimit = computeUnitLimit;
return this;
}
/**
* Returns a {@link MethodsBuilder} instance for the `Fulfill` instruction.
*
* Note, that compute budget instructions will be prepended to the returned
* instance (use {@link FulfillBuilder.withComputeUnitPrice} and
* {@link FulfillBuilder.withComputeUnitLimit} to opt-out).
*
* @param fulfillAuthority - public key of a fulfill authority
* @param signature - signature of a `client || seed`, performed by the fulfill authority
*/
build(fulfillAuthority, signature) {
return __awaiter(this, void 0, void 0, function* () {
const networkState = networkStateAddress(this.vrf.programId)[0];
const clientAccount = yield this.vrf.account.client.fetch(this.client);
const requestAccount = yield this.vrf.getRequestAccount(this.client, this.seed);
if (requestAccount === null) {
throw new Error("RequestAccount not found");
}
const pending = requestAccount.getPending();
if (pending === null) {
throw new Error("Already fulfilled");
}
let params = {};
let accounts = {
program: clientAccount.program,
state: clientAccount.state,
client: this.client,
request: requestAccountAddress(this.client, this.seed, requestAccount.bump)[0],
networkState,
instructionAcc: web3_js_1.SYSVAR_INSTRUCTIONS_PUBKEY,
};
let remainingAccounts = [];
if (pending.callback) {
for (const account of pending.callback.remainingAccounts) {
remainingAccounts.push({
pubkey: account.pubkey,
isSigner: false,
isWritable: account.isWritable,
});
}
}
let tx = this.vrf.methods
.fulfill(params)
.accountsPartial(accounts)
.remainingAccounts(remainingAccounts);
if (!this.computeBudgetConfig.isEmpty()) {
tx = tx.preInstructions(yield this.computeBudgetConfig.getInstructions(this.vrf.provider.connection));
}
let message = new Uint8Array([...this.client.toBuffer(), ...this.seed]);
tx = tx.preInstructions([
web3_js_1.Ed25519Program.createInstructionWithPublicKey({
publicKey: fulfillAuthority.toBytes(),
message,
signature,
}),
]);
return tx;
});
}
/**
* Performs an RPC call.
*
* @param fulfillAuthority - public key of a fulfill authority
* @param signature - signature of a `client || seed`, performed by the fulfill authority
*
* @returns a transaction signature.
*/
rpc(fulfillAuthority, signature) {
return __awaiter(this, void 0, void 0, function* () {
let tx = yield this.build(fulfillAuthority, signature);
const tx_signature = yield tx.rpc();
return tx_signature;
});
}
}
exports.FulfillBuilder = FulfillBuilder;
/**
* A convenient builder for the `FulfillAlt` instruction.
*
* Note that by default it will guess and apply a prioritization fee (see
* {@link RegisterBuilder.withComputeUnitPrice} and {@link RegisterBuilder.withComputeUnitLimit}
* to opt-out)
*
* @hidden
*/
class FulfillAltBuilder {
/**
* Creates a fulfill instruction builder.
*
* @param vrf ORAO VRF program instance.
* @param client the client that made the request
* @param seed seed value (32 bytes).
*/
constructor(vrf, client, seed) {
this.computeBudgetConfig = new ComputeBudgetConfig();
this.vrf = vrf;
this.client = client;
this.seed = seed;
}
/**
* Adds a prioritization fee in micro-lamports (applied per compute unit).
*
* Adds `ComputeBudgetInstruction::SetComputeUnitPrice` to the request builder.
*
* * if not specified, then median fee of the last 150 confirmed
* slots is used (this is by default)
* * if zero, then compute unit price is not applied at all.
*/
withComputeUnitPrice(computeUnitPrice) {
this.computeBudgetConfig.computeUnitPrice = computeUnitPrice;
return this;
}
/**
* Defines a multiplier that is applied to a median compute unit price.
*
* This is only applied if no compute_unit_price specified, i.e. if compute unit price
* is measured as a median fee of the last 150 confirmed slots.
*
* * if not specified, then no multiplier is applied (this is by default)
* * if specified, then applied as follows: `compute_unit_price = median * multiplier`
*/
withComputeUnitPriceMultiplier(multiplier) {
this.computeBudgetConfig.computeUnitPriceMultiplier = multiplier;
return this;
}
/** Defines a specific compute unit limit that the transaction is allowed to consume.
*
* Adds `ComputeBudgetInstruction::SetComputeUnitLimit` to the request builder.
*
* * if not specified, then compute unit limit is not applied at all
* (this is by default)
* * if specified, then applied as is
*/
withComputeUnitLimit(computeUnitLimit) {
this.computeBudgetConfig.computeUnitLimit = computeUnitLimit;
return this;
}
build_instructions(fulfillAuthority, signature, lookup_tables) {
return __awaiter(this, void 0, void 0, function* () {
const networkState = networkStateAddress(this.vrf.programId)[0];
const clientAccount = yield this.vrf.account.client.fetch(this.client);
const requestAccount = yield this.vrf.getRequestAltAccount(this.client, this.seed);
if (requestAccount === null) {
throw new Error("RequestAccount not found");
}
const pending = requestAccount.getPending();
if (pending === null) {
throw new Error("Already fulfilled");
}
let params = {};
let accounts = {
program: clientAccount.program,
state: clientAccount.state,
client: this.client,
request: requestAltAccountAddress(this.client, this.seed, requestAccount.bump)[0],
networkState,
instructionAcc: web3_js_1.SYSVAR_INSTRUCTIONS_PUBKEY,
};
let remainingAccounts = lookup_tables.map((x) => ({
pubkey: x.key,
isSigner: false,
isWritable: false,
}));
if (pending.callback) {
remainingAccounts = [
...remainingAccounts,
...pending.callback.decompile(lookup_tables).map((x) => ({
pubkey: x.pubkey,
isSigner: false,
isWritable: x.isWritable,
})),
];
}
let fulfillAltInstruction = yield this.vrf.methods
.fulfillAlt(params)
.accountsPartial(accounts)
.remainingAccounts(remainingAccounts)
.instruction();
let instructions = [];
if (!this.computeBudgetConfig.isEmpty()) {
instructions.push(...(yield this.computeBudgetConfig.getInstructions(this.vrf.provider.connection)));
}
let message = new Uint8Array([...this.client.toBuffer(), ...this.seed]);
instructions.push(web3_js_1.Ed25519Program.createInstructionWithPublicKey({
publicKey: fulfillAuthority.toBytes(),
message,
signature,
}));
instructions.push(fulfillAltInstruction);
return instructions;
});
}
}
exports.FulfillAltBuilder = FulfillAltBuilder;
function get_recommended_micro_lamport_fee(connection, computeUnitPrice, computeUnitPriceMultiplier) {
return __awaiter(this, void 0, void 0, function* () {
if (computeUnitPrice !== null) {
return computeUnitPrice;
}
let fees = yield connection.getRecentPrioritizationFees();
// Get the median fee from the most recent recent 150 slots' prioritization fee
fees.sort((a, b) => a.prioritizationFee - b.prioriti