diff --git a/src/core/index.ts b/src/core/index.ts index 21d5646a..a8aa9fe2 100644 --- a/src/core/index.ts +++ b/src/core/index.ts @@ -7,6 +7,7 @@ export * from './modules/CreateContract'; export * from './modules/impl/BlockHeightInteractionsSorter'; export * from './modules/impl/ContractDefinitionLoader'; +export * from './modules/impl/RedstoneGatewayContractDefinitionLoader'; export * from './modules/impl/ArweaveGatewayInteractionsLoader'; export * from './modules/impl/RedstoneGatewayInteractionsLoader'; export * from './modules/impl/DefaultStateEvaluator'; diff --git a/src/core/modules/impl/RedstoneGatewayContractDefinitionLoader.ts b/src/core/modules/impl/RedstoneGatewayContractDefinitionLoader.ts new file mode 100644 index 00000000..5fc0942a --- /dev/null +++ b/src/core/modules/impl/RedstoneGatewayContractDefinitionLoader.ts @@ -0,0 +1,48 @@ +import { ContractDefinition, LoggerFactory, stripTrailingSlash, SwCache } from '@smartweave'; +import Arweave from 'arweave'; +import 'isomorphic-fetch'; +import { ContractDefinitionLoader } from './ContractDefinitionLoader'; + +/** + * An extension to {@link ContractDefinitionLoader} that makes use of + * Redstone Gateway ({@link https://github.com/redstone-finance/redstone-sw-gateway}) + * to load Contract Data. + * + * If the contract data is not available on RedStone Gateway - it fallbacks to default implementation + * in {@link ContractDefinitionLoader} - i.e. loads the definition from Arweave gateway. + */ +export class RedstoneGatewayContractDefinitionLoader extends ContractDefinitionLoader { + private readonly rLogger = LoggerFactory.INST.create('ContractDefinitionLoader'); + + constructor( + private readonly baseUrl: string, + arweave: Arweave, + cache?: SwCache> + ) { + super(arweave, cache); + this.baseUrl = stripTrailingSlash(baseUrl); + } + + async doLoad(contractTxId: string, forcedSrcTxId?: string): Promise> { + if (forcedSrcTxId) { + // no support for the evolve yet.. + return await super.doLoad(contractTxId, forcedSrcTxId); + } + + try { + return await fetch(`${this.baseUrl}/gateway/contracts/${contractTxId}`) + .then((res) => { + return res.ok ? res.json() : Promise.reject(res); + }) + .catch((error) => { + if (error.body?.message) { + this.rLogger.error(error.body.message); + } + throw new Error(`Unable to retrieve contract data. Redstone gateway responded with status ${error.status}.`); + }); + } catch (e) { + this.rLogger.warn('Falling back to default contracts loader'); + return await super.doLoad(contractTxId, forcedSrcTxId); + } + } +}