UNPKG

@orao-network/solana-vrf

Version:

ORAO Verifiable Random Function for Solana.

769 lines (768 loc) 33.8 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 __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; 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.FulfillBuilder = exports.RequestBuilder = exports.UpdateBuilder = exports.InitBuilder = exports.ComputeBudgetConfig = exports.Orao = exports.quorum = exports.randomnessAccountAddress = exports.networkStateAccountAddress = exports.CONFIG_ACCOUNT_SEED = exports.RANDOMNESS_ACCOUNT_SEED = exports.PROGRAM_ID = exports.PROGRAM_ADDRESS = exports.FulfilledRandomnessAccountData = exports.FulfilledRequest = exports.PendingRequest = exports.RandomnessAccountDataV2 = exports.RandomnessV2 = exports.RandomnessAccountDataV1 = exports.OraoTokenFeeConfig = exports.NetworkState = exports.NetworkConfiguration = exports.RandomnessResponse = exports.FulfilledRandomness = exports.Randomness = void 0; const anchor_1 = require("@coral-xyz/anchor"); const web3_js_1 = require("@solana/web3.js"); const tweetnacl_1 = __importDefault(require("tweetnacl")); const state_1 = require("./state"); const IDL = __importStar(require("./types/orao_vrf.json")); var state_2 = require("./state"); Object.defineProperty(exports, "Randomness", { enumerable: true, get: function () { return state_2.Randomness; } }); Object.defineProperty(exports, "FulfilledRandomness", { enumerable: true, get: function () { return state_2.FulfilledRandomness; } }); Object.defineProperty(exports, "RandomnessResponse", { enumerable: true, get: function () { return state_2.RandomnessResponse; } }); Object.defineProperty(exports, "NetworkConfiguration", { enumerable: true, get: function () { return state_2.NetworkConfiguration; } }); Object.defineProperty(exports, "NetworkState", { enumerable: true, get: function () { return state_2.NetworkState; } }); Object.defineProperty(exports, "OraoTokenFeeConfig", { enumerable: true, get: function () { return state_2.OraoTokenFeeConfig; } }); Object.defineProperty(exports, "RandomnessAccountDataV1", { enumerable: true, get: function () { return state_2.RandomnessAccountDataV1; } }); Object.defineProperty(exports, "RandomnessV2", { enumerable: true, get: function () { return state_2.RandomnessV2; } }); Object.defineProperty(exports, "RandomnessAccountDataV2", { enumerable: true, get: function () { return state_2.RandomnessAccountDataV2; } }); Object.defineProperty(exports, "PendingRequest", { enumerable: true, get: function () { return state_2.PendingRequest; } }); Object.defineProperty(exports, "FulfilledRequest", { enumerable: true, get: function () { return state_2.FulfilledRequest; } }); Object.defineProperty(exports, "FulfilledRandomnessAccountData", { enumerable: true, get: function () { return state_2.FulfilledRandomnessAccountData; } }); exports.PROGRAM_ADDRESS = IDL.address; exports.PROGRAM_ID = new anchor_1.web3.PublicKey(exports.PROGRAM_ADDRESS); exports.RANDOMNESS_ACCOUNT_SEED = Buffer.from("orao-vrf-randomness-request"); exports.CONFIG_ACCOUNT_SEED = Buffer.from("orao-vrf-network-configuration"); let networkStateAddress = null; /** * Returns VRF configuration address (see helper {@link Orao.getNetworkState}). * * ```typescript * const networkStateAddress = networkStateAccountAddress(); * ``` * * @param [vrf_id=PROGRAM_ID] - you can override the program ID. */ function networkStateAccountAddress(vrf_id = exports.PROGRAM_ID) { if (networkStateAddress === null) { networkStateAddress = anchor_1.web3.PublicKey.findProgramAddressSync([exports.CONFIG_ACCOUNT_SEED], vrf_id)[0]; } return networkStateAddress; } exports.networkStateAccountAddress = networkStateAccountAddress; /** * Returns randomness account address for the given `seed` (see helper {@link Orao.getRandomness}). * * ```typescript * const seed = ...; * const randomnessAddress = randomnessAccountAddress(seed); * ``` * * @param seed Seed buffer. * @param [vrf_id=PROGRAM_ID] - you can override the program ID. */ function randomnessAccountAddress(seed, vrf_id = exports.PROGRAM_ID) { return anchor_1.web3.PublicKey.findProgramAddressSync([exports.RANDOMNESS_ACCOUNT_SEED, seed], vrf_id)[0]; } exports.randomnessAccountAddress = randomnessAccountAddress; /** * 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); } exports.quorum = quorum; /** Orao VRF program */ class Orao extends anchor_1.Program { get payer() { return this.provider.publicKey; } /** * Constructs a new program given the provider. * * Make sure to choose the desired `CommitmentLevel` 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(Object.assign(Object.assign({}, IDL), { address: id.toString() }), provider); } /** * Returns VRF configuration (throws if not initialized). * * ```typescript * const state = await vrf.getNetworkState(); * console.log("VRF treasury is " + state.config.treasury.toBase58()); * ``` * * @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(networkStateAccountAddress(this.programId), commitment); let config = state.config; let tokenFeeConfig = config.tokenFeeConfig; return new state_1.NetworkState(new state_1.NetworkConfiguration(state.config.authority, state.config.treasury, state.config.requestFee, state.config.fulfillmentAuthorities, tokenFeeConfig != null ? new state_1.OraoTokenFeeConfig(tokenFeeConfig.mint, tokenFeeConfig.treasury, tokenFeeConfig.fee) : null), state.numReceived); }); } /** * Returns randomness account data for the given seed (throws if account is absent). * * ```typescript * const randomnessAccount = await vrf.getRandomness(seed); * const randomness = randomnessAccount.fulfilled(); * if (randomness == null) { * console.error("Randomness is not yet fulfilled"); * } else { * console.log("Randomness is fulfilled " + bs58.encode(randomness)); * } * ``` * * @param seed - seed buffer. * @param commitment - you can override the provider's commitment level. */ getRandomness(seed, commitment) { return __awaiter(this, void 0, void 0, function* () { let address = randomnessAccountAddress(seed, this.programId); try { let randomness = yield this.account.randomnessV2.fetch(address, commitment); if ("pending" in randomness.request && randomness.request.pending !== undefined) { let pending = randomness.request.pending[0]; return new state_1.RandomnessAccountDataV2(new state_1.RandomnessV2(new state_1.PendingRequest(pending.seed, pending.client, pending.responses.map((x) => new state_1.RandomnessResponse(x.pubkey, x.randomness))))); } else { let fulfilled = randomness.request.fulfilled[0]; return new state_1.RandomnessAccountDataV2(new state_1.RandomnessV2(new state_1.FulfilledRequest(fulfilled.seed, fulfilled.client, fulfilled.randomness))); } } catch (_e) { let randomness = yield this.account.randomness.fetch(address, commitment); let responses = randomness.responses; return new state_1.RandomnessAccountDataV1(new state_1.Randomness(randomness.seed, randomness.randomness, responses.map((x) => new state_1.RandomnessResponse(x.pubkey, x.randomness)))); } }); } /** * Prepares a randomness request (see {@link RequestBuilder}). * * ```typescript * const [seed, tx] = await vrf.request().rpc(); * console.log("Your transaction signature", tx); * * // ... * * const randomnessAcc = await vrf.getRandomness(seed); * const randomness = randomnessAccount.fulfilled(); * if (randomness == null) { * console.error("Randomness is not yet fulfilled"); * } else { * console.log("Randomness is fulfilled " + bs58.encode(randomness)); * } * ``` * * @param seed seed value (32 bytes). Generated randomly, if not given. * @returns a {@link RequestBuilder} instance. */ request(seed) { return __awaiter(this, void 0, void 0, function* () { let actualSeed; if (seed) { actualSeed = seed; } else { actualSeed = tweetnacl_1.default.randomBytes(32); } return new RequestBuilder(this, actualSeed); }); } waitFulfilled(seed, commitment) { return __awaiter(this, void 0, void 0, function* () { let account = randomnessAccountAddress(seed, this.programId); let actualCommitment = this.provider.connection.commitment; if (commitment) { actualCommitment = commitment; } return new Promise((_resolve, reject) => __awaiter(this, void 0, void 0, function* () { let resolved = false; let maybeResolve = (subscriptionId, randomness) => { if (!randomness.getFulfilledRandomness()) { return; } if (resolved) { return; } resolved = true; this.provider.connection.removeAccountChangeListener(subscriptionId); _resolve(new state_1.FulfilledRandomnessAccountData(randomness)); }; try { let subscriptionId = this.provider.connection.onAccountChange(account, (accountInfo, _ctx) => { try { let randomness = this.account.randomness.coder.accounts.decode("randomnessV2", accountInfo.data); maybeResolve(subscriptionId, new state_1.RandomnessAccountDataV2(new state_1.RandomnessV2("fulfilled" in randomness.request ? new state_1.FulfilledRequest(randomness.request.fulfilled[0].seed, randomness.request.fulfilled[0].client, randomness.request.fulfilled[0].randomness) : new state_1.PendingRequest(randomness.request.pending[0].seed, randomness.request.pending[0].client, randomness.request.pending[0].responses.map((r) => new state_1.RandomnessResponse(r.pubkey, r.randomness)))))); } catch (_e) { let randomness = this.account.randomness.coder.accounts.decode("randomness", accountInfo.data); maybeResolve(subscriptionId, new state_1.RandomnessAccountDataV1(new state_1.Randomness(randomness.seed, randomness.randomness, randomness.responses.map((x) => new state_1.RandomnessResponse(x.pubkey, x.randomness))))); } }, commitment); // In case it's already fulfilled let randomness = yield this.getRandomness(seed, actualCommitment); maybeResolve(subscriptionId, randomness); } catch (e) { reject(e); } })); }); } } exports.Orao = Orao; 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; }); } } exports.ComputeBudgetConfig = ComputeBudgetConfig; /** * A convenient builder for the `InitNetwork` instruction. * * Note that by default it will guess and apply a prioritization fee (see * {@link InitBuilder.withComputeUnitPrice} and {@link InitBuilder.withComputeUnitLimit} * to opt-out) */ class InitBuilder { /** * Creates a new init_network instruction builder. * * @param vrf ORAO VRF program instance. * @param authority config update authority * @param treasury fee treasury * @param fulfillmentAuthorities list of authorized fulfillment authorities * @param requestFee request fee (in lamports) */ constructor(vrf, authority, treasury, fulfillmentAuthorities, requestFee) { this.computeBudgetConfig = new ComputeBudgetConfig(); if (!vrf.payer) { throw new Error("Wallet not provided"); } this.vrf = vrf; this.config = new state_1.NetworkConfiguration(authority, treasury, requestFee, fulfillmentAuthorities, null); } /** Change token fee configuration. */ withTokenFeeConfig(tokenFeeConfig) { this.config.tokenFeeConfig = tokenFeeConfig; 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 `InitNetwork` instruction. * * Note, that compute budget instructions will be prepended to the returned * instance (use {@link InitBuilder.withComputeUnitPrice} and * {@link InitBuilder.withComputeUnitLimit} to opt-out). */ build() { return __awaiter(this, void 0, void 0, function* () { const networkState = networkStateAccountAddress(this.vrf.programId); let tx = this.vrf.methods .initNetwork(this.config.requestFee, this.config.authority, this.config.fulfillmentAuthorities, this.config.tokenFeeConfig) .accountsPartial({ networkState, treasury: this.config.treasury, }); 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.InitBuilder = InitBuilder; /** * A convenient builder for the `UpdateNetwork` instruction. * * Note that by default it will guess and apply a prioritization fee (see * {@link UpdateBuilder.withComputeUnitPrice} and {@link UpdateBuilder.withComputeUnitLimit} * to opt-out) */ class UpdateBuilder { /** * Creates a new update_network instruction builder that updates nothing. * * @param vrf ORAO VRF program instance. */ constructor(vrf) { this.computeBudgetConfig = new ComputeBudgetConfig(); if (!vrf.payer) { throw new Error("Wallet not provided"); } this.vrf = vrf; } /** Change configuration authority. */ with_authority(authority) { this.authority = authority; return this; } /** Change treasury account address. */ with_treasury(treasury) { this.treasury = treasury; return this; } /** Change fee (in lamports). */ with_fee(requestFee) { this.requestFee = requestFee; return this; } /** Change fulfillment authorities. */ with_fulfillment_authorities(fulfillmentAuthorities) { this.fulfillmentAuthorities = fulfillmentAuthorities; return this; } /** Change token fee configuration. */ with_token_fee_config(tokenFeeConfig) { this.tokenFeeConfig = tokenFeeConfig; 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 UpdateBuilder.withComputeUnitPrice} and * {@link UpdateBuilder.withComputeUnitLimit} to opt-out). */ build() { return __awaiter(this, void 0, void 0, function* () { const networkState = networkStateAccountAddress(this.vrf.programId); const config = (yield this.vrf.getNetworkState()).config; let requestFee = this.requestFee ? this.requestFee : config.requestFee; let authority = this.authority ? this.authority : config.authority; let treasury = this.treasury ? this.treasury : config.treasury; let fulfillmentAuthorities = this.fulfillmentAuthorities ? this.fulfillmentAuthorities : config.fulfillmentAuthorities; let tokenFeeConfig = this.tokenFeeConfig !== undefined ? this.tokenFeeConfig : config.tokenFeeConfig; let tx = this.vrf.methods .updateNetwork(requestFee, authority, fulfillmentAuthorities, tokenFeeConfig) .accountsPartial({ networkState, treasury, }); 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.UpdateBuilder = UpdateBuilder; /** * A convenient builder for the `Request` instruction. * * Note that by default it will guess and apply a prioritization fee (see * {@link RequestBuilder.withComputeUnitPrice} and {@link RequestBuilder.withComputeUnitLimit} * to opt-out) */ class RequestBuilder { /** * Creates a randomness request builder (defaults to pay fees with SOL). * * @param vrf ORAO VRF program instance. * @param seed seed value (32 bytes). */ constructor(vrf, seed) { this.computeBudgetConfig = new ComputeBudgetConfig(); if (!vrf.payer) { throw new Error("Wallet not provided"); } this.vrf = vrf; this.seed = seed; this.tokenWallet = null; } /** * Pay fees with SPL token using given token wallet address. * * Instruction could fail if token fee is not configured for the contract * or given wallet is not a proper SPL wallet. * * @param tokenWallet SPL token wallet (belongs to a payer) */ payWithToken(tokenWallet) { this.tokenWallet = tokenWallet; 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 `Request` instruction. * * Note, that compute budget instructions will be prepended to the returned * instance (use {@link RequestBuilder.withComputeUnitPrice} and * {@link RequestBuilder.withComputeUnitLimit} to opt-out). */ build() { return __awaiter(this, void 0, void 0, function* () { const networkState = networkStateAccountAddress(this.vrf.programId); const networkStateAcc = yield this.vrf.getNetworkState(); let tx = this.vrf.methods.requestV2([...this.seed]).accountsPartial({ networkState, treasury: networkStateAcc.config.treasury, request: randomnessAccountAddress(this.seed, this.vrf.programId), }); if (!this.computeBudgetConfig.isEmpty()) { tx = tx.preInstructions(yield this.computeBudgetConfig.getInstructions(this.vrf.provider.connection)); } return tx; }); } /** * Performs an RPC call. * * @returns a pair of seed and transaction signature. */ rpc() { return __awaiter(this, void 0, void 0, function* () { const tx = yield this.build(); const signature = yield tx.rpc(); return [this.seed, signature]; }); } } exports.RequestBuilder = RequestBuilder; /** * A convenient builder for the `Fulfill` instruction. * * Note that by default it will guess and apply a prioritization fee (see * {@link FulfillBuilder.withComputeUnitPrice} and {@link FulfillBuilder.withComputeUnitLimit} * to opt-out) */ class FulfillBuilder { /** * Creates a fulfill instruction builder. * * @param vrf ORAO VRF program instance. * @param seed seed value (32 bytes). */ constructor(vrf, seed) { this.computeBudgetConfig = new ComputeBudgetConfig(); if (!vrf.payer) { throw new Error("Wallet not provided"); } this.vrf = vrf; 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 `Request` instruction. * * Note, that compute budget instructions will be prepended to the returned * instance (use {@link RequestBuilder.withComputeUnitPrice} and * {@link RequestBuilder.withComputeUnitLimit} to opt-out). * * @param fulfillmentAuthority - public key of a fulfillment authority * @param signature - signature of a seed, performed by the fulfillment authority */ build(fulfillmentAuthority, signature) { return __awaiter(this, void 0, void 0, function* () { let randomness = yield this.vrf.getRandomness(this.seed); let tx; if (randomness.getVersion() === "V1") { tx = this.vrf.methods.fulfill().accountsPartial({ instructionAcc: web3_js_1.SYSVAR_INSTRUCTIONS_PUBKEY, networkState: networkStateAccountAddress(this.vrf.programId), request: randomnessAccountAddress(this.seed, this.vrf.programId), }); } else { tx = this.vrf.methods.fulfillV2().accountsPartial({ instructionAcc: web3_js_1.SYSVAR_INSTRUCTIONS_PUBKEY, networkState: networkStateAccountAddress(this.vrf.programId), request: randomnessAccountAddress(this.seed, this.vrf.programId), client: randomness.getClient() || undefined, systemProgram: web3_js_1.SystemProgram.programId, }); } if (!this.computeBudgetConfig.isEmpty()) { tx = tx.preInstructions(yield this.computeBudgetConfig.getInstructions(this.vrf.provider.connection)); } tx = tx.preInstructions([ web3_js_1.Ed25519Program.createInstructionWithPublicKey({ publicKey: fulfillmentAuthority.toBytes(), message: this.seed, signature, }), ]); return tx; }); } /** * Performs an RPC call. * * @param fulfillmentAuthority - public key of a fulfillment authority * @param signature - signature of a seed, performed by the fulfillment authority * * @returns a transaction signature. */ rpc(fulfillmentAuthority, signature) { return __awaiter(this, void 0, void 0, function* () { let tx = yield this.build(fulfillmentAuthority, signature); const tx_signature = yield tx.rpc(); return tx_signature; }); } } exports.FulfillBuilder = FulfillBuilder; 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.prioritizationFee); let median_index = Math.floor(fees.length / 2); if (fees.length == 0) { return null; } let medianPriorityFee = 0; if (fees.length % 2 == 0) { medianPriorityFee = (fees[median_index - 1].prioritizationFee + fees[median_index].prioritizationFee) / 2; } else { medianPriorityFee = fees[median_index].prioritizationFee; } if (medianPriorityFee == 0) { return null; } if (computeUnitPriceMultiplier !== null) { medianPriorityFee = medianPriorityFee * computeUnitPriceMultiplier; } return BigInt(medianPriorityFee); }); }