|
|
|
@ -14,24 +14,50 @@ interface ChainMetadataWithRpcConnectionInfo extends ChainMetadata { |
|
|
|
|
publicRpcUrls: RpcConfigWithConnectionInfo[]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export class HyperlaneSmartProvider extends providers.BaseProvider { |
|
|
|
|
export enum ProviderMethod { |
|
|
|
|
Call = 'call', |
|
|
|
|
EstimateGas = 'estimateGas', |
|
|
|
|
GetBalance = 'getBalance', |
|
|
|
|
GetBlock = 'getBlock', |
|
|
|
|
GetBlockNumber = 'getBlockNumber', |
|
|
|
|
GetCode = 'getCode', |
|
|
|
|
GetGasPrice = 'getGasPrice', |
|
|
|
|
GetStorageAt = 'getStorageAt', |
|
|
|
|
GetTransaction = 'getTransaction', |
|
|
|
|
GetTransactionCount = 'getTransactionCount', |
|
|
|
|
GetTransactionReceipt = 'getTransactionReceipt', |
|
|
|
|
GetLogs = 'getLogs', |
|
|
|
|
SendTransaction = 'sendTransaction', |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const AllProviderMethods = Object.values(ProviderMethod); |
|
|
|
|
|
|
|
|
|
interface IProviderMethods { |
|
|
|
|
readonly supportedMethods: ProviderMethod[]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export class HyperlaneSmartProvider extends providers.BaseProvider implements IProviderMethods { |
|
|
|
|
public readonly chainMetadata: ChainMetadataWithRpcConnectionInfo; |
|
|
|
|
// TODO also support blockscout here
|
|
|
|
|
public readonly explorerProviders: HyperlaneEtherscanProvider[]; |
|
|
|
|
public readonly rpcProviders: providers.StaticJsonRpcProvider[]; |
|
|
|
|
public readonly rpcProviders: HyperlaneJsonRpcProvider[]; |
|
|
|
|
public readonly supportedMethods: ProviderMethod[]; |
|
|
|
|
|
|
|
|
|
constructor(chainMetadata: ChainMetadataWithRpcConnectionInfo) { |
|
|
|
|
const network = chainMetadataToProviderNetwork(chainMetadata); |
|
|
|
|
super(network); |
|
|
|
|
this.chainMetadata = chainMetadata; |
|
|
|
|
const supportedMethods = new Set<ProviderMethod>(); |
|
|
|
|
|
|
|
|
|
if (chainMetadata.blockExplorers?.length) { |
|
|
|
|
this.explorerProviders = chainMetadata.blockExplorers |
|
|
|
|
.map((explorerConfig) => { |
|
|
|
|
if (!explorerConfig.family || explorerConfig.family === ExplorerFamily.Etherscan) |
|
|
|
|
return new HyperlaneEtherscanProvider(explorerConfig, network); |
|
|
|
|
// TODO also support blockscout here
|
|
|
|
|
else return null; |
|
|
|
|
if (!explorerConfig.family || explorerConfig.family === ExplorerFamily.Etherscan) { |
|
|
|
|
const newProvider = new HyperlaneEtherscanProvider(explorerConfig, network); |
|
|
|
|
newProvider.supportedMethods.forEach((m) => supportedMethods.add(m)); |
|
|
|
|
return newProvider; |
|
|
|
|
// TODO also support blockscout here
|
|
|
|
|
} else return null; |
|
|
|
|
}) |
|
|
|
|
.filter((e): e is HyperlaneEtherscanProvider => !!e); |
|
|
|
|
} else { |
|
|
|
@ -39,12 +65,16 @@ export class HyperlaneSmartProvider extends providers.BaseProvider { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (chainMetadata.publicRpcUrls?.length) { |
|
|
|
|
this.rpcProviders = chainMetadata.publicRpcUrls.map( |
|
|
|
|
(rpcConfig) => new HyperlaneJsonRpcProvider(rpcConfig, network), |
|
|
|
|
); |
|
|
|
|
this.rpcProviders = chainMetadata.publicRpcUrls.map((rpcConfig) => { |
|
|
|
|
const newProvider = new HyperlaneJsonRpcProvider(rpcConfig, network); |
|
|
|
|
newProvider.supportedMethods.forEach((m) => supportedMethods.add(m)); |
|
|
|
|
return newProvider; |
|
|
|
|
}); |
|
|
|
|
} else { |
|
|
|
|
this.rpcProviders = []; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.supportedMethods = [...supportedMethods.values()]; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async detectNetwork(): Promise<providers.Network> { |
|
|
|
@ -57,9 +87,15 @@ export class HyperlaneSmartProvider extends providers.BaseProvider { |
|
|
|
|
async perform(method: string, params: { [name: string]: any }): Promise<any> { |
|
|
|
|
const allProviders = [...this.explorerProviders, ...this.rpcProviders]; |
|
|
|
|
if (!allProviders.length) throw new Error('No providers available'); |
|
|
|
|
if (!this.supportedMethods.includes(method as ProviderMethod)) |
|
|
|
|
throw new Error(`No providers available for method ${method}`); |
|
|
|
|
|
|
|
|
|
const supportedProviders = allProviders.filter((p) => |
|
|
|
|
p.supportedMethods.includes(method as ProviderMethod), |
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
// TODO consider implementing quorum and/or retry logic here similar to FallbackProvider/RetryProvider
|
|
|
|
|
for (const provider of allProviders) { |
|
|
|
|
for (const provider of supportedProviders) { |
|
|
|
|
const providerUrl = |
|
|
|
|
provider instanceof providers.JsonRpcProvider ? provider.connection.url : provider.baseUrl; |
|
|
|
|
try { |
|
|
|
@ -77,9 +113,16 @@ export class HyperlaneSmartProvider extends providers.BaseProvider { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export class HyperlaneEtherscanProvider extends providers.EtherscanProvider { |
|
|
|
|
export class HyperlaneEtherscanProvider |
|
|
|
|
extends providers.EtherscanProvider |
|
|
|
|
implements IProviderMethods |
|
|
|
|
{ |
|
|
|
|
public readonly supportedMethods: ProviderMethod[]; |
|
|
|
|
|
|
|
|
|
constructor(public readonly explorerConfig: ExplorerConfig, network: providers.Network) { |
|
|
|
|
super(network, explorerConfig.apiKey); |
|
|
|
|
const unsupportedMethods: ProviderMethod[] = [ProviderMethod.SendTransaction]; |
|
|
|
|
this.supportedMethods = AllProviderMethods.filter((m) => !unsupportedMethods.includes(m)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
getBaseUrl(): string { |
|
|
|
@ -101,9 +144,20 @@ export class HyperlaneEtherscanProvider extends providers.EtherscanProvider { |
|
|
|
|
getPostUrl(): string { |
|
|
|
|
return `${this.getBaseUrl()}/api`; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
async fetch(module: string, params: Record<string, any>, post?: boolean): Promise<any> { |
|
|
|
|
// TODO wrap this in intelligent rate limiting based on this.isCommunityResource
|
|
|
|
|
return super.fetch(module, params, post); |
|
|
|
|
} |
|
|
|
|
//TODO fix bug with getTxCount method
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
export class HyperlaneJsonRpcProvider extends providers.StaticJsonRpcProvider { |
|
|
|
|
export class HyperlaneJsonRpcProvider |
|
|
|
|
extends providers.StaticJsonRpcProvider |
|
|
|
|
implements IProviderMethods |
|
|
|
|
{ |
|
|
|
|
public readonly supportedMethods = AllProviderMethods; |
|
|
|
|
|
|
|
|
|
constructor(rpcConfig: RpcConfigWithConnectionInfo, network: providers.Network) { |
|
|
|
|
super(rpcConfig.connection ?? rpcConfig.http, network); |
|
|
|
|
} |
|
|
|
|