UNPKG

@nomad-xyz/sdk

Version:
297 lines 11.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 __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 __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.NomadContext = void 0; const multi_provider_1 = require("@nomad-xyz/multi-provider"); const config = __importStar(require("@nomad-xyz/configuration")); const cross_fetch_1 = __importDefault(require("cross-fetch")); const CoreContracts_1 = require("./CoreContracts"); const messageBackend_1 = require("./messageBackend"); /** * The NomadContext manages connections to Nomad core and Bridge contracts. * It inherits from the {@link MultiProvider}, and ensures that its contracts * always use the latest registered providers and signers. * * For convenience, we've pre-constructed contexts for mainnet and testnet * deployments. These can be imported directly. * * @example * // Set up mainnet and then access contracts as below: * let router = mainnet.mustGetBridge('celo').bridgeRouter; */ class NomadContext extends multi_provider_1.MultiProvider { constructor(environment = 'development', backend) { super(); const conf = typeof environment === 'string' ? config.getBuiltin(environment) : environment; config.validateConfig(conf); this.conf = conf; this._cores = new Map(); this._blacklist = new Set(); this._backend = backend; for (const network of this.conf.networks) { // register domain this.registerDomain(this.conf.protocol.networks[network]); // register RPC provider if (this.conf.rpcs[network] && this.conf.rpcs[network].length > 0) { this.registerRpcProvider(network, this.conf.rpcs[network][0]); } // set core contracts const netConf = this.conf.core[network]; // type discrimination if (!netConf.upgradeBeaconController) throw new Error('substrate not yet supported'); const core = new CoreContracts_1.CoreContracts(this, network, netConf); this._cores.set(core.domain, core); } } /** * Create default backend for the context */ withDefaultBackend() { // TODO: What if backend doesn't exist for this environment? this._backend = messageBackend_1.GoldSkyBackend.default(this.environment, this); return this; } get governor() { return this.conf.protocol.governor; } get environment() { return this.conf.environment; } /** * Register an ethers Provider for a specified domain. * * @param nameOrDomain A domain name or number. * @param provider An ethers Provider to be used by requests to that domain. */ registerProvider(nameOrDomain, provider) { const domain = this.resolveDomain(nameOrDomain); super.registerProvider(domain, provider); } /** * Register an ethers Signer for a specified domain. * * @param nameOrDomain A domain name or number. * @param signer An ethers Signer to be used by requests to that domain. */ registerSigner(nameOrDomain, signer) { const domain = this.resolveDomain(nameOrDomain); super.registerSigner(domain, signer); } /** * Remove the registered ethers Signer from a domain. This function will * attempt to preserve any Provider that was previously connected to this * domain. * * @param nameOrDomain A domain name or number. */ unregisterSigner(nameOrDomain) { const domain = this.resolveDomain(nameOrDomain); super.unregisterSigner(domain); } /** * Clear all signers from all registered domains. */ clearSigners() { super.clearSigners(); } /** * Get the {@link CoreContracts} for a given domain (or undefined) * * @param nameOrDomain A domain name or number. * @returns a {@link CoreContracts} object (or undefined) */ getCore(nameOrDomain) { const domain = this.resolveDomainName(nameOrDomain); return this._cores.get(domain); } /** * Get the {@link CoreContracts} for a given domain (or throw an error) * * @param nameOrDomain A domain name or number. * @returns a {@link CoreContracts} object * @throws if no {@link CoreContracts} object exists on that domain. */ mustGetCore(nameOrDomain) { const core = this.getCore(nameOrDomain); if (!core) { throw new Error(`Missing core for domain: ${nameOrDomain}`); } return core; } /** * Resolve the replica for the Home domain on the Remote domain (if any). * * WARNING: do not hold references to this contract, as it will not be * reconnected in the event the chain connection changes. * * @param home the sending domain * @param remote the receiving domain * @returns An interface for the Replica (if any) */ getReplicaFor(home, remote) { return this.getCore(remote)?.getReplica(home); } /** * Resolve the replica for the Home domain on the Remote domain (or throws). * * WARNING: do not hold references to this contract, as it will not be * reconnected in the event the chain connection changes. * * @param home the sending domain * @param remote the receiving domain * @returns An interface for the Replica * @throws If no replica is found. */ mustGetReplicaFor(home, remote) { const replica = this.getReplicaFor(home, remote); if (!replica) { throw new Error(`Missing replica for home ${home} & remote ${remote}`); } return replica; } /** * Discovers the governor domain of this nomad deployment and returns the * associated Core. * * @returns The identifier of the governing domain */ governorCore() { return this.mustGetCore(this.governor.domain); } /** * Proves and Processes a transaction on the destination chain. This is subsidize and * automatic on non-Ethereum destinations * * @dev Ensure that a transaction is ready to be processed. You should ensure the following * criteria have been met prior to calling this function: * 1. The tx has been relayed (has status of 2): * `const status = await NomadMessage.status()` * 2. The `confirmAt` timestamp for the tx is in the past: * `const confirmAt = await NomadMessage.confirmAt()` * * @param message NomadMessage * @param overrides Any tx overrides (e.g. gas limit, gas price) * @returns The Contract Transaction receipt */ async process(message, overrides = {}) { const data = await message.getProof(); if (!data) throw new Error('Unable to fetch proof'); return this.processProof(message.origin, message.destination, data, overrides); } async processProof(origin, destination, proof, overrides = {}) { // get replica contract const replica = this.mustGetReplicaFor(origin, destination); await replica.callStatic.proveAndProcess(proof.message, proof.proof.path, proof.proof.index, overrides); return replica.proveAndProcess(proof.message, proof.proof.path, proof.proof.index, overrides); } async fetchProof(origin, leafIndex) { const s3 = this.conf.s3; if (!s3) throw new Error('s3 data not configured'); const { bucket, region } = s3; const originName = this.resolveDomainName(origin); const uri = `https://${bucket}.s3.${region}.amazonaws.com/${originName}_${leafIndex}`; const response = await (0, cross_fetch_1.default)(uri); if (!response) throw new Error('Unable to fetch proof'); const data = await response.json(); if (data.proof && data.message) return data; throw new Error('Server returned invalid proof'); } async processByOriginDestinationAndLeaf(origin, destination, leafIndex) { const proof = await this.fetchProof(origin, leafIndex); return await this.processProof(origin, destination, proof); } blacklist() { return this._blacklist; } async checkHomes(networks) { for (const n of networks) { await this.checkHome(n); } } async checkHome(nameOrDomain) { const domain = this.resolveDomain(nameOrDomain); const home = this.mustGetCore(domain).home; const state = await home.state(); if (state === 2) { console.log(`Home for domain ${domain} is failed!`); this._blacklist.add(domain); } else { this._blacklist.delete(domain); } } /** * Fetch a config from the Nomad config static site. * * @param environment the environment name to attempt to fetch * @returns A NomadConfig * @throws If the site is down, the config is not on the site, or the config * is not of a valid format */ static async fetchConfig(environment) { const uri = `https://nomad-xyz.github.io/config/${environment}.json`; const config = await (await (0, cross_fetch_1.default)(uri, { cache: 'no-cache' })).json(); return config; } /** * Fetch a config from the Nomad config static site and instantiate a context * from it. If there is an issue, this function will fallback to the latest * version of the config shipped with the configuration package. * * Fallback may be disabled by setting `allowFallback` to false * * @param this this type for the descendant * @param env the environment name to attempt to fetch * @param allowFallback allow fallback to the builtin env configuration * @returns A NomadContext with the latest configuration for the specified env * @throws If `allowFallback` is false and the site is down, the config is * not on the site, or the config is not of a valid format */ static async fetch(env, allowFallback = true) { try { const config = await NomadContext.fetchConfig(env); return new this(config); } catch (e) { if (allowFallback) { console.warn(`Unable to retrieve config ${env}. Falling back to built-in config.\n${e}`); return new this(env); } throw e; } } } exports.NomadContext = NomadContext; //# sourceMappingURL=NomadContext.js.map