UNPKG

@orao-network/solana-vrf-cb

Version:

ORAO Verifiable Random Function with Callback for Solana.

319 lines (318 loc) 12.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.RemainingAccount = exports.Callback = exports.Fulfilled = exports.ValidatedLookupAccount = exports.ValidatedRemainingAccount = exports.ValidatedCallbackAlt = exports.ValidatedCallback = exports.PendingAlt = exports.Pending = exports.RequestAccount = exports.RequestAltAccount = exports.Response = exports.Client = exports.NetworkConfiguration = exports.NetworkState = void 0; const _1 = require("."); const sha2_1 = require("@noble/hashes/sha2"); /** * On-chain VRF state. */ class NetworkState { constructor(bump, config, numRequests, numRegistered, numTerminated) { this.bump = bump; this.config = config; this.numRequests = numRequests; this.numRegistered = numRegistered; this.numTerminated = numTerminated; } /** See {@link networkStateAddress} */ static findAddress(vrf_id = _1.PROGRAM_ID) { return (0, _1.networkStateAddress)(vrf_id); } /** See {@link networkStateAddress} */ static createAddress(bump, vrf_id = _1.PROGRAM_ID) { return (0, _1.networkStateAddress)(bump, vrf_id); } } exports.NetworkState = NetworkState; /** * On-chain VRF configuration. */ class NetworkConfiguration { constructor(authority, treasury, requestFee, callbackDeadline, fulfillAuthorities) { this.authority = authority; this.treasury = treasury; this.requestFee = requestFee; this.callbackDeadline = callbackDeadline; this.fulfillAuthorities = fulfillAuthorities; } } exports.NetworkConfiguration = NetworkConfiguration; /** * Registered client PDA. * * This PDA is created by the Callback VRF upon new client registration. * * Note that the balance of this PDA is used to pay request fees and rent. */ class Client { constructor(bump, owner, program, state, numRequests, callback) { this.bump = bump; this.owner = owner; this.program = program; this.state = state; this.numRequests = numRequests; this.callback = callback; } } exports.Client = Client; /** * Response of a single fulfill authority. */ class Response { constructor(pubkey, randomness) { this.pubkey = pubkey; this.randomness = Array.isArray(randomness) ? new Uint8Array(randomness) : randomness; } static fromRawData(data) { return new Response(data.pubkey, data.randomness); } } exports.Response = Response; /** * A PDA allocated for every randomness request with Address Lookup Tables support. * * Holds request metadata and state. */ class RequestAltAccount { constructor(bump, slot, client, seed, state) { this.bump = bump; this.slot = slot; this.client = client; this.seed = Array.isArray(seed) ? new Uint8Array(seed) : seed; this.state = state; } /** See {@link requestAccountAddress} */ static findAddress(client, seed, vrf_id = _1.PROGRAM_ID) { return (0, _1.requestAltAccountAddress)(client, seed, vrf_id); } /** See {@link requestAccountAddress} */ static createAddress(client, seed, bump, vrf_id = _1.PROGRAM_ID) { return (0, _1.requestAltAccountAddress)(client, seed, bump, vrf_id); } static fromRawAccount(accountData) { let state = "pending" in accountData.state ? new PendingAlt(accountData.state.pending["0"].responses.map(Response.fromRawData), accountData.state.pending["0"].callback ? ValidatedCallbackAlt.fromRawData(accountData.state.pending["0"].callback) : null, accountData.state.pending["0"].lookupTables) : new Fulfilled(accountData.state.fulfilled["0"].randomness, accountData.state.fulfilled["0"].responses ? accountData.state.fulfilled["0"].responses.map(Response.fromRawData) : null); return new RequestAltAccount(accountData.bump, accountData.slot, accountData.client, accountData.seed, state); } /** Returns the request seed */ getSeed() { return this.seed; } /** Returns the {@link Client} PDA address */ getClient() { return this.client; } /** Returns pending state (or `null` if this request was fulfilled) */ getPending() { return "randomness" in this.state ? null : this.state; } /** Returns fulfilled state (or `null` if this request is still pending) */ getFulfilled() { return "randomness" in this.state ? this.state : null; } } exports.RequestAltAccount = RequestAltAccount; /** * A PDA allocated for every randomness request. * * Holds request metadata and state. */ class RequestAccount { constructor(bump, slot, client, seed, state) { this.bump = bump; this.slot = slot; this.client = client; this.seed = Array.isArray(seed) ? new Uint8Array(seed) : seed; this.state = state; } /** See {@link requestAccountAddress} */ static findAddress(client, seed, vrf_id = _1.PROGRAM_ID) { return (0, _1.requestAccountAddress)(client, seed, vrf_id); } /** See {@link requestAccountAddress} */ static createAddress(client, seed, bump, vrf_id = _1.PROGRAM_ID) { return (0, _1.requestAccountAddress)(client, seed, bump, vrf_id); } static fromRawAccount(accountData) { let state = "pending" in accountData.state ? new Pending(accountData.state.pending["0"].responses.map(Response.fromRawData), accountData.state.pending["0"].callback ? ValidatedCallback.fromRawData(accountData.state.pending["0"].callback) : null, accountData.state.pending["0"].callbackOverride) : new Fulfilled(accountData.state.fulfilled["0"].randomness, accountData.state.fulfilled["0"].responses ? accountData.state.fulfilled["0"].responses.map(Response.fromRawData) : null); return new RequestAccount(accountData.bump, accountData.slot, accountData.client, accountData.seed, state); } /** Returns the request seed */ getSeed() { return this.seed; } /** Returns the {@link Client} PDA address */ getClient() { return this.client; } /** Returns pending state (or `null` if this request was fulfilled) */ getPending() { return "randomness" in this.state ? null : this.state; } /** Returns fulfilled state (or `null` if this request is still pending) */ getFulfilled() { return "randomness" in this.state ? this.state : null; } } exports.RequestAccount = RequestAccount; /** Represents a state of a pending randomness request {@link RequestAccount.state } */ class Pending { constructor(responses, callback, callbackOverride) { this.responses = responses; this.callback = callback; this.callbackOverride = callbackOverride; } isFulfilledBy(key) { return this.responses.find((response) => response.pubkey.equals(key)) !== undefined; } } exports.Pending = Pending; /** Represents a state of a pending randomness request {@link RequestAltAccount.state } */ class PendingAlt { constructor(responses, callback, lookupTables) { this.responses = responses; this.callback = callback; this.lookupTables = lookupTables; } isFulfilledBy(key) { return this.responses.find((response) => response.pubkey.equals(key)) !== undefined; } } exports.PendingAlt = PendingAlt; /** * This is a validated callback stored on-chain (see {@link Callback}). */ class ValidatedCallback { constructor(remainingAccounts, data) { this.remainingAccounts = remainingAccounts; this.data = Array.isArray(data) ? new Uint8Array(data) : data; } static fromRawData(data) { return new ValidatedCallback(data.remainingAccounts.map(ValidatedRemainingAccount.fromRawData), Array.isArray(data.data) ? new Uint8Array(data.data) : data.data); } } exports.ValidatedCallback = ValidatedCallback; /** * This is a validated callback stored on-chain (see {@link Callback}). */ class ValidatedCallbackAlt { constructor(accountsHash, remainingAccounts, data) { this.accountsHash = Array.isArray(accountsHash) ? new Uint8Array(accountsHash) : accountsHash; this.remainingAccounts = remainingAccounts; this.data = Array.isArray(data) ? new Uint8Array(data) : data; } static fromRawData(data) { return new ValidatedCallbackAlt(Array.isArray(data.accountsHash) ? new Uint8Array(data.accountsHash) : data.accountsHash, data.remainingAccounts.map((x) => { return "lookup" in x ? ValidatedLookupAccount.fromRawData(x.lookup[0]) : ValidatedRemainingAccount.fromRawData(x.plain[0]); }), Array.isArray(data.data) ? new Uint8Array(data.data) : data.data); } /** * Resolves lookup accounts back to plain accounts (see {@link compileAccounts}). * * @param lookupTables - the list of lookup tables given upon compilation */ decompile(lookupTables) { const accountsHashData = Buffer.alloc(32 * this.remainingAccounts.length); const output = []; for (const account of this.remainingAccounts) { if ("tableIndex" in account) { let table = lookupTables[account.tableIndex]; if (!table) { throw new Error("Table index out of bounds"); } let address = table.state.addresses[account.addressIndex]; if (!table) { throw new Error("Address index out of bounds"); } output.push({ pubkey: address, isWritable: account.isWritable }); } else { output.push(account); } } for (let i = 0; i < output.length; i++) { output[i].pubkey.toBuffer().copy(accountsHashData, 32 * i); } let expectedHash = Buffer.from((0, sha2_1.sha256)(accountsHashData)); if (!expectedHash.equals(this.accountsHash)) { throw new Error(`accountsHash mismatch ${expectedHash.toString("hex")} != ${Buffer.from(this.accountsHash).toString("hex")} `); } return output; } } exports.ValidatedCallbackAlt = ValidatedCallbackAlt; /** This is a validated remaining account stored on-chain (see {@link RemainingAccount}) */ class ValidatedRemainingAccount { constructor(pubkey, isWritable) { this.pubkey = pubkey; this.isWritable = isWritable; } static fromRawData(data) { return new ValidatedRemainingAccount(data.pubkey, data.isWritable); } } exports.ValidatedRemainingAccount = ValidatedRemainingAccount; /** This is a validated remaining account stored on-chain (see {@link RemainingAccount}) */ class ValidatedLookupAccount { constructor(tableIndex, addressIndex, isWritable) { this.tableIndex = tableIndex; this.addressIndex = addressIndex; this.isWritable = isWritable; } static fromRawData(data) { return new ValidatedLookupAccount(data.tableIndex, data.addressIndex, data.isWritable); } } exports.ValidatedLookupAccount = ValidatedLookupAccount; /** Represents a state of a fulfilled randomness request {@link RequestAccount.state } */ class Fulfilled { constructor(randomness, responses) { this.randomness = Array.isArray(randomness) ? new Uint8Array(randomness) : randomness; this.responses = responses; } } exports.Fulfilled = Fulfilled; /** * A callback definition. * * This structure is used to define client-level or request-level callbacks: * * 1. _client-level callback_ — defined upon the client registration and couldn't be avoided, but * you can override it with the _request-level callback_. Additionally You can update the * _client-level callback_ using the `SetCallback` instruction (see {@link SetCallbackBuilder}). * 2. _request-level callback_ — overrides the _client-level callback_ (even if it is not defined). */ class Callback { constructor(data, remainingAccounts = []) { this.data = data; this.remainingAccounts = remainingAccounts; } } exports.Callback = Callback; /** * An account to add to the callback invocation (see {@link Callback.remainingAccounts}) */ class RemainingAccount { constructor(pubkey, seeds) { this.pubkey = pubkey; this.seeds = seeds; } } exports.RemainingAccount = RemainingAccount;