@hyperlane-xyz/sdk
Version:
The official SDK for the Hyperlane Network
157 lines • 6.53 kB
JavaScript
import { objFilter, objMap, pick, rootLogger, } from '@hyperlane-xyz/utils';
import { multiProtocolTestChainMetadata } from '../consts/testChains.js';
import { ChainMetadataManager } from '../metadata/ChainMetadataManager.js';
import { MultiProvider } from './MultiProvider.js';
import { PROTOCOL_TO_DEFAULT_PROVIDER_TYPE, ProviderType, } from './ProviderType.js';
import { defaultProviderBuilderMap, } from './providerBuilders.js';
import { estimateTransactionFee, } from './transactionFeeEstimators.js';
/**
* A version of MultiProvider that can support different
* provider types across different protocol types.
*
* This uses a different interface for provider/signer related methods
* so it isn't strictly backwards compatible with MultiProvider.
*
* Unlike MultiProvider, this class does not support signer/signing methods (yet).
* @typeParam MetaExt - Extra metadata fields for chains (such as contract addresses)
*/
export class MultiProtocolProvider extends ChainMetadataManager {
options;
// Chain name -> provider type -> provider
providers;
// Chain name -> provider type -> signer
signers = {}; // TODO signer support
providerBuilders;
logger;
constructor(chainMetadata, options = {}) {
super(chainMetadata, options);
this.options = options;
this.logger =
options?.logger ||
rootLogger.child({
module: 'MultiProtocolProvider',
});
this.providers = options.providers || {};
this.providerBuilders =
options.providerBuilders || defaultProviderBuilderMap;
}
static fromMultiProvider(mp, options = {}) {
const newMp = new MultiProtocolProvider(mp.metadata, options);
const typedProviders = objMap(mp.providers, (_, provider) => ({
type: ProviderType.EthersV5,
provider,
}));
newMp.setProviders(typedProviders);
return newMp;
}
toMultiProvider(options) {
const newMp = new MultiProvider(this.metadata, options);
const providers = objMap(this.providers, (_, typeToProviders) => typeToProviders[ProviderType.EthersV5]?.provider);
const filteredProviders = objFilter(providers, (_, p) => !!p);
newMp.setProviders(filteredProviders);
return newMp;
}
extendChainMetadata(additionalMetadata) {
const newMetadata = super.extendChainMetadata(additionalMetadata).metadata;
const newMp = new MultiProtocolProvider(newMetadata, {
...this.options,
providers: this.providers,
});
return newMp;
}
tryGetProvider(chainNameOrId, type) {
const metadata = this.tryGetChainMetadata(chainNameOrId);
if (!metadata)
return null;
const { protocol, name, chainId, rpcUrls } = metadata;
type = type || PROTOCOL_TO_DEFAULT_PROVIDER_TYPE[protocol];
if (!type)
return null;
if (this.providers[name]?.[type])
return this.providers[name][type];
const builder = this.providerBuilders[type];
if (!rpcUrls.length || !builder)
return null;
const provider = builder(rpcUrls, chainId);
this.providers[name] ||= {};
this.providers[name][type] = provider;
return provider;
}
getProvider(chainNameOrId, type) {
const provider = this.tryGetProvider(chainNameOrId, type);
if (!provider)
throw new Error(`No provider available for ${chainNameOrId}`);
return provider;
}
getSpecificProvider(chainNameOrId, type) {
const provider = this.getProvider(chainNameOrId, type);
if (provider.type !== type)
throw new Error(`Invalid provider type, expected ${type} but found ${provider.type}`);
return provider.provider;
}
getEthersV5Provider(chainNameOrId) {
return this.getSpecificProvider(chainNameOrId, ProviderType.EthersV5);
}
getViemProvider(chainNameOrId) {
return this.getSpecificProvider(chainNameOrId, ProviderType.Viem);
}
getSolanaWeb3Provider(chainNameOrId) {
return this.getSpecificProvider(chainNameOrId, ProviderType.SolanaWeb3);
}
getCosmJsProvider(chainNameOrId) {
return this.getSpecificProvider(chainNameOrId, ProviderType.CosmJs);
}
getCosmJsWasmProvider(chainNameOrId) {
return this.getSpecificProvider(chainNameOrId, ProviderType.CosmJsWasm);
}
getCosmJsNativeProvider(chainNameOrId) {
return this.getSpecificProvider(chainNameOrId, ProviderType.CosmJsNative);
}
getStarknetProvider(chainNameOrId) {
return this.getSpecificProvider(chainNameOrId, ProviderType.Starknet);
}
setProvider(chainNameOrId, provider) {
const chainName = this.getChainName(chainNameOrId);
this.providers[chainName] ||= {};
this.providers[chainName][provider.type] = provider;
return provider;
}
setProviders(providers) {
for (const chain of Object.keys(providers)) {
this.setProvider(chain, providers[chain]);
}
}
estimateTransactionFee({ chainNameOrId, transaction, sender, senderPubKey, }) {
const provider = this.getProvider(chainNameOrId, transaction.type);
const chainMetadata = this.getChainMetadata(chainNameOrId);
return estimateTransactionFee({
transaction,
provider,
chainMetadata,
sender,
senderPubKey,
});
}
intersect(chains, throwIfNotSubset = false) {
const { intersection, result } = super.intersect(chains, throwIfNotSubset);
const multiProvider = new MultiProtocolProvider(result.metadata, {
...this.options,
providers: pick(this.providers, intersection),
});
return { intersection, result: multiProvider };
}
/**
* Creates a MultiProvider for test networks
*/
static createTestMultiProtocolProvider(metadata = multiProtocolTestChainMetadata, providers = {}) {
const mp = new MultiProtocolProvider(metadata);
const providerMap = {};
for (const [protocol, provider] of Object.entries(providers)) {
const chains = Object.values(metadata).filter((m) => m.protocol === protocol);
chains.forEach((c) => (providerMap[c.name] = provider));
}
mp.setProviders(providerMap);
return mp;
}
}
//# sourceMappingURL=MultiProtocolProvider.js.map