UNPKG

@orao-network/solana-vrf-cb

Version:

ORAO Verifiable Random Function with Callback for Solana.

1,223 lines 50.7 kB
"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