UNPKG

@nomad-xyz/sdk

Version:
380 lines 12.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.GoldSkyBackend = void 0; const ethers_1 = require("ethers"); const graphql_request_1 = require("graphql-request"); const backend_1 = require("./backend"); const __1 = require(".."); const utils_1 = require("./utils"); const defaultGoldSkySecret = "mpa%H&RAHu9;eUe"; const supportedEnvironments = [ "production", "development", ]; /** * GoldSky backend for NomadMessage */ class GoldSkyBackend extends backend_1.MessageBackend { constructor(env, secret, context) { super(); this.env = env; this._secret = secret; this.messageCache = new Map(); this.dispatchTxToMessageHash = new Map(); this.context = context; } /** * Resolves current context used with the backend * @returns Nomad context */ getContext() { return this.context; } /** * Checks whether the backend environment is supported * @param environment name of the environment as string */ static checkEnvironment(environment) { if (!supportedEnvironments.includes(environment)) { throw new Error(`Only the following environments are supported: ${supportedEnvironments.join(', ')}. Provided: ${environment}`); } } /** * Returns default secret for Goldsky * @returns secret as a string */ static defaultSecret() { return defaultGoldSkySecret; } /** * Default GoldSky backend for the environment * @param environment name of the environment as string * @param context Nomad context to be used with the backend * @returns */ static default(environment = 'development', context) { const environmentString = typeof environment === 'string' ? environment : environment.environment; GoldSkyBackend.checkEnvironment(environmentString); const secret = process.env.GOLDSKY_SECRET || GoldSkyBackend.defaultSecret(); if (!secret) throw new Error(`GOLDSKY_SECRET not found in env`); return new GoldSkyBackend(environmentString, secret, context || new __1.NomadContext(environment)); } /** * Fills filter with default values required for fetching a message from backend * * @returns Filled event filter */ static fillFilter(f) { return { committedRoot: f.committedRoot || '', messageHash: f.messageHash || '', transactionHash: f.transactionHash || '', }; } /** * Prepares a URI that is used for fetching messages * * @returns uri */ get uri() { // return `https://${this.env}.goldsky.io/c/nomad/gql/v1/graphql` return `https://api.goldsky.io/c/nomad/gql/v1/graphql`; } /** * Prepares headers for connecting to hasura */ get headers() { return { 'content-type': 'application/json', 'x-goldsky-secret': this._secret, }; } /** * Prepares Dispatch events from backend's internal message representation * * @returns Dispatch events assiciated with transaction (if any) */ async getDispatches(tx, limit) { const ms = await this.getMessagesByTx(tx, limit); if (!ms) return undefined; return ms.map((m) => ({ args: { messageHash: m.message_hash, leafIndex: ethers_1.BigNumber.from(m.leaf_index), destinationAndNonce: ethers_1.BigNumber.from(m.destination_and_nonce), committedRoot: m.committed_root, message: m.message, }, transactionHash: m.dispatch_tx, })); } /** * Prepares a Dispatch event from backend's internal message representation * * @returns Dispatch event assiciated with message hash (if any) */ async getDispatchByMessageHash(messageHash) { const ms = await this.getMessage(messageHash); if (!ms) return; return ({ args: { messageHash: ms?.message_hash, leafIndex: ethers_1.BigNumber.from(ms.leaf_index), destinationAndNonce: ethers_1.BigNumber.from(ms.destination_and_nonce), committedRoot: ms.committed_root, message: ms.message, }, transactionHash: ms.dispatch_tx, }); } /** * Stores message into internal cache */ storeMessage(m) { this.messageCache.set(m.message_hash, m); const messageHashes = this.dispatchTxToMessageHash.get(m.dispatch_tx); if (!messageHashes) { this.dispatchTxToMessageHash.set(m.dispatch_tx, [m.message_hash]); } else { if (!messageHashes.includes(m.message_hash)) messageHashes.push(m.message_hash); } } /** * Get the message representation associated with this message (if any) * by message hash * * @returns A message representation (if any) */ async getMessage(messageHash, forceFetch = false) { let m = this.messageCache.get(messageHash); if (!m || forceFetch) { m = (await this.fetchMessages({ messageHash, }, 1))?.[0]; if (m) { this.storeMessage(m); } } return m; } /** * Get the message representation associated with this message (if any) * by dispatch transaction * * @returns A message representation (if any) */ async getMessagesByTx(tx, limit, forceFetch = true) { let ms; const messageHashes = this.dispatchTxToMessageHash.get(tx); const enoughMessages = limit && messageHashes && limit <= messageHashes.length; if (!enoughMessages || forceFetch) { ms = await this.fetchMessages({ transactionHash: tx, }); if (ms && ms.length) { ms.forEach((m) => this.storeMessage(m)); } } else { if (!messageHashes) throw new Error('MessageHashes are unexpectedly not existing'); ms = await Promise.all(messageHashes.map(async (hash) => { const message = await this.getMessage(hash); if (!message) throw new Error("Couldn't get a message from existing messages."); // Message must be in messageHashes return message; })); } return ms; } /** * Get the `Dispatch` transaction hash associated with this message (if any) * * @returns A dispatch tx (if any) */ async dispatchTx(messageHash) { let m = await this.getMessage(messageHash); if (!m?.dispatch_tx) m = await this.getMessage(messageHash, true); return m?.dispatch_tx; } /** * Get the `Relay` transaction hash associated with this message (if any) * * @returns A relay tx (if any) */ async relayTx(messageHash) { let m = await this.getMessage(messageHash); if (!m?.relay_tx) m = await this.getMessage(messageHash, true); return m?.relay_tx; } /** * Get the `Update` transaction hash associated with this message (if any) * * @returns A update tx (if any) */ async updateTx(messageHash) { let m = await this.getMessage(messageHash); if (!m?.update_tx) m = await this.getMessage(messageHash, true); return m?.update_tx; } /** * Get the `Process` transaction hash associated with this message (if any) * * @returns A relay tx (if any) */ async processTx(messageHash) { let m = await this.getMessage(messageHash); if (!m?.process_tx) m = await this.getMessage(messageHash, true); return m?.process_tx; } /** * Get the `Dispatch` transaction hash associated with this message (if any) * * @returns A dispatch tx (if any) */ async dispatchedAt(messageHash) { let m = await this.getMessage(messageHash); if (!m?.dispatched_at) m = await this.getMessage(messageHash, true); return m ? new Date(m.dispatched_at) : undefined; } /** * Get the `Relay` transaction hash associated with this message (if any) * * @returns A relay tx (if any) */ async relayedAt(messageHash) { let m = await this.getMessage(messageHash); if (!m?.relayed_at) m = await this.getMessage(messageHash, true); return m && m.relayed_at ? new Date(m.relayed_at) : undefined; } /** * Get the `Update` transaction hash associated with this message (if any) * * @returns A update tx (if any) */ async updatedAt(messageHash) { let m = await this.getMessage(messageHash); if (!m?.updated_at) m = await this.getMessage(messageHash, true); return m && m.updated_at ? new Date(m.updated_at) : undefined; } /** * Get the `Process` transaction hash associated with this message (if any) * * @returns A relay tx (if any) */ async processedAt(messageHash) { let m = await this.getMessage(messageHash); if (!m?.processed_at) m = await this.getMessage(messageHash, true); return m && m.processed_at ? new Date(m.processed_at) : undefined; } /** * Gets destination domain for a specific message * @param messageHash message hash identifier * @returns destination domain id */ async destinationDomainId(messageHash) { let m = await this.getMessage(messageHash); if (!m?.destination_domain_id) m = await this.getMessage(messageHash, true); return m?.destination_domain_id; } /** * Get message hash associated with this message (if any) * * @returns A message hash (if any) */ async getFirstMessageHash(tx) { const ms = await this.getMessagesByTx(tx); return ms?.[0]?.message_hash; } /** * Fetches internal message from backend * * @returns Internal message representation (if any) */ async fetchMessages(f, limit) { const eventsTable = `${this.env}_views_events`; const query = (0, graphql_request_1.gql) ` query Query( $committedRoot: String $messageHash: String $transactionHash: String $limit: Int ) { ${eventsTable}( where: { _or: [ { dispatch_tx: { _eq: $transactionHash } } { message_hash: { _eq: $messageHash } } { old_root: { _eq: $committedRoot } } ] } limit: $limit ) { committed_root destination_and_nonce destination_domain_id destination_domain_name dispatch_block dispatch_tx dispatched_at id leaf_index message message__action__amount message__action__details_hash message__action__to message__action__type message__token__domain message__token__id message_body message_hash message_type new_root nonce old_root origin_domain_id origin_domain_name process_block process_tx processed_at recipient_address relay_block relay_chain_id relay_tx relayed_at sender_address signature update_block update_chain_id update_tx updated_at } } `; const filter = { ...GoldSkyBackend.fillFilter(f), limit: limit || null, }; const response = await (0, graphql_request_1.request)(this.uri, query, filter, this.headers); const events = (0, utils_1.nulls2undefined)(response[eventsTable]); if (!events || events.length <= 0) return undefined; return events; } } exports.GoldSkyBackend = GoldSkyBackend; //# sourceMappingURL=goldsky.js.map