From 038966bd4955f63ed0b14ccf44ca1337a1e99d6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noah=20Bayindirli=20=F0=9F=A5=82?= Date: Wed, 8 May 2024 17:23:08 -0400 Subject: [PATCH 1/9] add CLI submitter --- typescript/cli/src/submit/submit.ts | 105 +++++++++++++++++++++++ typescript/cli/src/submit/submitTypes.ts | 35 ++++++++ 2 files changed, 140 insertions(+) create mode 100644 typescript/cli/src/submit/submit.ts create mode 100644 typescript/cli/src/submit/submitTypes.ts diff --git a/typescript/cli/src/submit/submit.ts b/typescript/cli/src/submit/submit.ts new file mode 100644 index 0000000000..8acc9abb11 --- /dev/null +++ b/typescript/cli/src/submit/submit.ts @@ -0,0 +1,105 @@ +import { + EV5GnosisSafeTxSubmitter, + EV5ImpersonatedAccountTxSubmitter, + EV5InterchainAccountTxTransformer, + EV5JsonRpcTxSubmitter, + MultiProvider, + TxSubmitterBuilder, + TxSubmitterInterface, + TxSubmitterType, + TxTransformerInterface, + TxTransformerType, +} from '@hyperlane-xyz/sdk'; +import { ProtocolType } from '@hyperlane-xyz/utils'; + +import { forkNetworkToMultiProvider, verifyAnvil } from '../deploy/dry-run.js'; + +import { + SubmitterBuilderSettings, + SubmitterMetadata, + TransformerMetadata, +} from './submitTypes.js'; + +export async function getSubmitterBuilder({ + submitterMetadata, + transformersMetadata, + multiProvider, +}: SubmitterBuilderSettings): Promise> { + const submitter = await getSubmitter( + multiProvider, + submitterMetadata, + ); + const transformers = await getTransformers( + multiProvider, + transformersMetadata, + ); + + return new TxSubmitterBuilder(submitter, transformers); +} + +async function getSubmitter( + multiProvider: MultiProvider, + { type, chain, settings }: SubmitterMetadata, +): Promise> { + switch (type) { + case TxSubmitterType.JSON_RPC: + return new EV5JsonRpcTxSubmitter(multiProvider, chain); + case TxSubmitterType.IMPERSONATED_ACCOUNT: + if (!settings?.userAddress) + throw new Error( + `Missing param 'userAddress': Cannot instantiate EV5ImpersonatedAccountTxSubmitter.`, + ); + + await verifyAnvil(); + await forkNetworkToMultiProvider(multiProvider, chain); + + return new EV5ImpersonatedAccountTxSubmitter(multiProvider, chain, { + address: settings?.userAddress, + }); + case TxSubmitterType.GNOSIS_SAFE: + if (!settings?.safeAddress) + throw new Error( + `Missing param 'safeAddress': Cannot instantiate EV5GnosisSafeTxSubmitter.`, + ); + return new EV5GnosisSafeTxSubmitter(multiProvider, chain, { + safeAddress: settings?.safeAddress, + }); + default: + throw new Error(`Invalid TxSubmitterType: ${type}`); + } +} + +async function getTransformers( + multiProvider: MultiProvider, + metadata: TransformerMetadata[], +): Promise[]> { + return Promise.all( + metadata.map(({ type, chain, settings }) => + getTransformer(multiProvider, { type, chain, settings }), + ), + ); +} + +async function getTransformer( + multiProvider: MultiProvider, + { type, chain, settings }: TransformerMetadata, +): Promise> { + switch (type) { + case TxTransformerType.ICA: + if (!settings?.interchainAccount) + throw new Error( + `Missing param 'interchainAccount': Cannot instantiate EV5InterchainAccountTxTransformer.`, + ); + if (!settings?.accountConfig) + throw new Error( + `Missing param 'accountConfig': Cannot instantiate EV5InterchainAccountTxTransformer.`, + ); + return new EV5InterchainAccountTxTransformer(multiProvider, chain, { + interchainAccount: settings.interchainAccount, + accountConfig: settings.accountConfig, + hookMetadata: settings.hookMetadata, + }); + default: + throw new Error(`Invalid TxTransformerType: ${type}`); + } +} diff --git a/typescript/cli/src/submit/submitTypes.ts b/typescript/cli/src/submit/submitTypes.ts new file mode 100644 index 0000000000..0125d04d3d --- /dev/null +++ b/typescript/cli/src/submit/submitTypes.ts @@ -0,0 +1,35 @@ +import type { + AccountConfig, + ChainName, + InterchainAccount, + MultiProvider, + TxSubmitterType, + TxTransformerType, +} from '@hyperlane-xyz/sdk'; +import { Address } from '@hyperlane-xyz/utils'; + +export interface SubmitterBuilderSettings { + submitterMetadata: SubmitterMetadata; + transformersMetadata: TransformerMetadata[]; + multiProvider: MultiProvider; +} +export interface SubmitterMetadata { + type: TxSubmitterType; + chain: ChainName; + settings?: SubmitterSettings; +} +export interface TransformerMetadata { + type: TxTransformerType; + chain: ChainName; + settings?: TransformerSettings; +} + +interface SubmitterSettings { + safeAddress?: Address; + userAddress?: Address; +} +interface TransformerSettings { + interchainAccount?: InterchainAccount; + accountConfig?: AccountConfig; + hookMetadata?: any; +} From 4849c80424510f6877f95992a30ad39b9d9458c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noah=20Bayindirli=20=F0=9F=A5=82?= Date: Wed, 8 May 2024 17:53:07 -0400 Subject: [PATCH 2/9] export submitter/transformer props from SDK for use in CLI-submitter --- typescript/cli/src/submit/submit.ts | 42 +++++++++---------- typescript/cli/src/submit/submitTypes.ts | 14 +++---- typescript/sdk/src/index.ts | 11 ++++- .../submitter/TxSubmitterTypes.ts | 10 +++++ .../ethersV5/EV5GnosisSafeTxSubmitter.ts | 9 ++-- .../EV5ImpersonatedAccountTxSubmitter.ts | 10 ++--- .../transformer/TxTransformerTypes.ts | 9 ++++ .../EV5InterchainAccountTxTransformer.ts | 13 ++---- 8 files changed, 67 insertions(+), 51 deletions(-) diff --git a/typescript/cli/src/submit/submit.ts b/typescript/cli/src/submit/submit.ts index 8acc9abb11..2166cf05e3 100644 --- a/typescript/cli/src/submit/submit.ts +++ b/typescript/cli/src/submit/submit.ts @@ -45,25 +45,29 @@ async function getSubmitter( case TxSubmitterType.JSON_RPC: return new EV5JsonRpcTxSubmitter(multiProvider, chain); case TxSubmitterType.IMPERSONATED_ACCOUNT: - if (!settings?.userAddress) + if (!settings) throw new Error( - `Missing param 'userAddress': Cannot instantiate EV5ImpersonatedAccountTxSubmitter.`, + 'Must provide EV5ImpersonatedAccountTxSubmitterProps for impersonated account submitter.', ); await verifyAnvil(); await forkNetworkToMultiProvider(multiProvider, chain); - return new EV5ImpersonatedAccountTxSubmitter(multiProvider, chain, { - address: settings?.userAddress, - }); + return new EV5ImpersonatedAccountTxSubmitter( + multiProvider, + chain, + settings.eV5ImpersonatedAccountProps, + ); case TxSubmitterType.GNOSIS_SAFE: - if (!settings?.safeAddress) + if (!settings) throw new Error( - `Missing param 'safeAddress': Cannot instantiate EV5GnosisSafeTxSubmitter.`, + 'Must provide EV5GnosisSafeTxSubmitterProps for Gnosis safe submitter.', ); - return new EV5GnosisSafeTxSubmitter(multiProvider, chain, { - safeAddress: settings?.safeAddress, - }); + return new EV5GnosisSafeTxSubmitter( + multiProvider, + chain, + settings.eV5GnosisSafeProps, + ); default: throw new Error(`Invalid TxSubmitterType: ${type}`); } @@ -86,19 +90,15 @@ async function getTransformer( ): Promise> { switch (type) { case TxTransformerType.ICA: - if (!settings?.interchainAccount) + if (!settings) throw new Error( - `Missing param 'interchainAccount': Cannot instantiate EV5InterchainAccountTxTransformer.`, + 'Must provide EV5InterchainAccountTxTransformerProps for ICA transformer.', ); - if (!settings?.accountConfig) - throw new Error( - `Missing param 'accountConfig': Cannot instantiate EV5InterchainAccountTxTransformer.`, - ); - return new EV5InterchainAccountTxTransformer(multiProvider, chain, { - interchainAccount: settings.interchainAccount, - accountConfig: settings.accountConfig, - hookMetadata: settings.hookMetadata, - }); + return new EV5InterchainAccountTxTransformer( + multiProvider, + chain, + settings.eV5InterchainAccountProps, + ); default: throw new Error(`Invalid TxTransformerType: ${type}`); } diff --git a/typescript/cli/src/submit/submitTypes.ts b/typescript/cli/src/submit/submitTypes.ts index 0125d04d3d..04c00cd379 100644 --- a/typescript/cli/src/submit/submitTypes.ts +++ b/typescript/cli/src/submit/submitTypes.ts @@ -1,12 +1,12 @@ import type { - AccountConfig, ChainName, - InterchainAccount, + EV5GnosisSafeTxSubmitterProps, + EV5ImpersonatedAccountTxSubmitterProps, + EV5InterchainAccountTxTransformerProps, MultiProvider, TxSubmitterType, TxTransformerType, } from '@hyperlane-xyz/sdk'; -import { Address } from '@hyperlane-xyz/utils'; export interface SubmitterBuilderSettings { submitterMetadata: SubmitterMetadata; @@ -25,11 +25,9 @@ export interface TransformerMetadata { } interface SubmitterSettings { - safeAddress?: Address; - userAddress?: Address; + eV5GnosisSafeProps: EV5GnosisSafeTxSubmitterProps; + eV5ImpersonatedAccountProps: EV5ImpersonatedAccountTxSubmitterProps; } interface TransformerSettings { - interchainAccount?: InterchainAccount; - accountConfig?: AccountConfig; - hookMetadata?: any; + eV5InterchainAccountProps: EV5InterchainAccountTxTransformerProps; } diff --git a/typescript/sdk/src/index.ts b/typescript/sdk/src/index.ts index d0e2c66c94..99e388892b 100644 --- a/typescript/sdk/src/index.ts +++ b/typescript/sdk/src/index.ts @@ -304,14 +304,21 @@ export { protocolToDefaultProviderBuilder, } from './providers/providerBuilders.js'; export { TxSubmitterInterface } from './providers/transactions/submitter/TxSubmitterInterface.js'; -export { TxSubmitterType } from './providers/transactions/submitter/TxSubmitterTypes.js'; +export { + TxSubmitterType, + EV5GnosisSafeTxSubmitterProps, + EV5ImpersonatedAccountTxSubmitterProps, +} from './providers/transactions/submitter/TxSubmitterTypes.js'; export { TxSubmitterBuilder } from './providers/transactions/submitter/builder/TxSubmitterBuilder.js'; export { EV5GnosisSafeTxSubmitter } from './providers/transactions/submitter/ethersV5/EV5GnosisSafeTxSubmitter.js'; export { EV5ImpersonatedAccountTxSubmitter } from './providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.js'; export { EV5JsonRpcTxSubmitter } from './providers/transactions/submitter/ethersV5/EV5JsonRpcTxSubmitter.js'; export { EV5TxSubmitterInterface } from './providers/transactions/submitter/ethersV5/EV5TxSubmitterInterface.js'; export { TxTransformerInterface } from './providers/transactions/transformer/TxTransformerInterface.js'; -export { TxTransformerType } from './providers/transactions/transformer/TxTransformerTypes.js'; +export { + TxTransformerType, + EV5InterchainAccountTxTransformerProps, +} from './providers/transactions/transformer/TxTransformerTypes.js'; export { EV5InterchainAccountTxTransformer } from './providers/transactions/transformer/ethersV5/EV5InterchainAccountTxTransformer.js'; export { EV5TxTransformerInterface } from './providers/transactions/transformer/ethersV5/EV5TxTransformerInterface.js'; export { GasRouterDeployer } from './router/GasRouterDeployer.js'; diff --git a/typescript/sdk/src/providers/transactions/submitter/TxSubmitterTypes.ts b/typescript/sdk/src/providers/transactions/submitter/TxSubmitterTypes.ts index 4e38f9c25a..306062a701 100644 --- a/typescript/sdk/src/providers/transactions/submitter/TxSubmitterTypes.ts +++ b/typescript/sdk/src/providers/transactions/submitter/TxSubmitterTypes.ts @@ -1,5 +1,15 @@ +import { Address } from '@hyperlane-xyz/utils'; + export enum TxSubmitterType { JSON_RPC = 'JSON RPC', IMPERSONATED_ACCOUNT = 'Impersonated Account', GNOSIS_SAFE = 'Gnosis Safe', } + +export interface EV5GnosisSafeTxSubmitterProps { + safeAddress: Address; +} + +export interface EV5ImpersonatedAccountTxSubmitterProps { + address: Address; +} diff --git a/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5GnosisSafeTxSubmitter.ts b/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5GnosisSafeTxSubmitter.ts index 9975f560d3..e3e81e2b74 100644 --- a/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5GnosisSafeTxSubmitter.ts +++ b/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5GnosisSafeTxSubmitter.ts @@ -7,14 +7,13 @@ import { ChainName } from '../../../../types.js'; // @ts-ignore import { getSafe, getSafeService } from '../../../../utils/gnosisSafe.js'; import { MultiProvider } from '../../../MultiProvider.js'; -import { TxSubmitterType } from '../TxSubmitterTypes.js'; +import { + EV5GnosisSafeTxSubmitterProps, + TxSubmitterType, +} from '../TxSubmitterTypes.js'; import { EV5TxSubmitterInterface } from './EV5TxSubmitterInterface.js'; -interface EV5GnosisSafeTxSubmitterProps { - safeAddress: Address; -} - export class EV5GnosisSafeTxSubmitter implements EV5TxSubmitterInterface { public readonly txSubmitterType: TxSubmitterType = TxSubmitterType.GNOSIS_SAFE; diff --git a/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts b/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts index 3511d00b16..4fe8b7ab09 100644 --- a/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts +++ b/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts @@ -3,19 +3,17 @@ import { PopulatedTransaction } from 'ethers'; import { Logger } from 'pino'; import { rootLogger } from '@hyperlane-xyz/utils'; -import { Address } from '@hyperlane-xyz/utils'; import { ChainName } from '../../../../types.js'; import { impersonateAccount } from '../../../../utils/fork.js'; import { MultiProvider } from '../../../MultiProvider.js'; -import { TxSubmitterType } from '../TxSubmitterTypes.js'; +import { + EV5ImpersonatedAccountTxSubmitterProps, + TxSubmitterType, +} from '../TxSubmitterTypes.js'; import { EV5JsonRpcTxSubmitter } from './EV5JsonRpcTxSubmitter.js'; -interface EV5ImpersonatedAccountTxSubmitterProps { - address: Address; -} - export class EV5ImpersonatedAccountTxSubmitter extends EV5JsonRpcTxSubmitter { public readonly txSubmitterType: TxSubmitterType = TxSubmitterType.IMPERSONATED_ACCOUNT; diff --git a/typescript/sdk/src/providers/transactions/transformer/TxTransformerTypes.ts b/typescript/sdk/src/providers/transactions/transformer/TxTransformerTypes.ts index b8e029b2c1..a0a4ac29b7 100644 --- a/typescript/sdk/src/providers/transactions/transformer/TxTransformerTypes.ts +++ b/typescript/sdk/src/providers/transactions/transformer/TxTransformerTypes.ts @@ -1,3 +1,12 @@ +import { InterchainAccount } from '../../../middleware/account/InterchainAccount.js'; +import { AccountConfig } from '../../../middleware/account/types.js'; + export enum TxTransformerType { ICA = 'Interchain Account', } + +export interface EV5InterchainAccountTxTransformerProps { + interchainAccount: InterchainAccount; + accountConfig: AccountConfig; + hookMetadata?: string; +} diff --git a/typescript/sdk/src/providers/transactions/transformer/ethersV5/EV5InterchainAccountTxTransformer.ts b/typescript/sdk/src/providers/transactions/transformer/ethersV5/EV5InterchainAccountTxTransformer.ts index 2e2ddfb520..9e51274fe2 100644 --- a/typescript/sdk/src/providers/transactions/transformer/ethersV5/EV5InterchainAccountTxTransformer.ts +++ b/typescript/sdk/src/providers/transactions/transformer/ethersV5/EV5InterchainAccountTxTransformer.ts @@ -3,20 +3,15 @@ import { Logger } from 'pino'; import { CallData, assert, rootLogger } from '@hyperlane-xyz/utils'; -import { InterchainAccount } from '../../../../middleware/account/InterchainAccount.js'; -import { AccountConfig } from '../../../../middleware/account/types.js'; import { ChainName } from '../../../../types.js'; import { MultiProvider } from '../../../MultiProvider.js'; -import { TxTransformerType } from '../TxTransformerTypes.js'; +import { + EV5InterchainAccountTxTransformerProps, + TxTransformerType, +} from '../TxTransformerTypes.js'; import { EV5TxTransformerInterface } from './EV5TxTransformerInterface.js'; -interface EV5InterchainAccountTxTransformerProps { - interchainAccount: InterchainAccount; - accountConfig: AccountConfig; - hookMetadata?: string; -} - export class EV5InterchainAccountTxTransformer implements EV5TxTransformerInterface { From 6865bd18f832043da2cc777104aa3d2e7e630404 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noah=20Bayindirli=20=F0=9F=A5=82?= Date: Wed, 8 May 2024 17:54:59 -0400 Subject: [PATCH 3/9] add changesets --- .changeset/quiet-cheetahs-own.md | 5 +++++ .changeset/sixty-avocados-double.md | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 .changeset/quiet-cheetahs-own.md create mode 100644 .changeset/sixty-avocados-double.md diff --git a/.changeset/quiet-cheetahs-own.md b/.changeset/quiet-cheetahs-own.md new file mode 100644 index 0000000000..df89570596 --- /dev/null +++ b/.changeset/quiet-cheetahs-own.md @@ -0,0 +1,5 @@ +--- +'@hyperlane-xyz/sdk': patch +--- + +Exports submitter and transformer props types. diff --git a/.changeset/sixty-avocados-double.md b/.changeset/sixty-avocados-double.md new file mode 100644 index 0000000000..821e105c03 --- /dev/null +++ b/.changeset/sixty-avocados-double.md @@ -0,0 +1,5 @@ +--- +'@hyperlane-xyz/cli': minor +--- + +Add CLI-side submitter to use SDK submitter from CRUD and other command modules. From 7d2584218a29d6780935f27605fff9e0b0b1e9de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noah=20Bayindirli=20=F0=9F=A5=82?= Date: Thu, 9 May 2024 15:25:22 -0400 Subject: [PATCH 4/9] decouple 'chain' from submitters and transformers --- typescript/cli/src/submit/submit.ts | 18 +++++++-------- typescript/cli/src/submit/submitTypes.ts | 3 --- .../submitter/TxSubmitterInterface.ts | 5 ---- .../submitter/TxSubmitterTypes.ts | 4 ++++ .../submitter/builder/TxSubmitterBuilder.ts | 3 --- .../ethersV5/EV5GnosisSafeTxSubmitter.ts | 23 +++++++++++-------- .../EV5ImpersonatedAccountTxSubmitter.ts | 8 +++---- .../ethersV5/EV5JsonRpcTxSubmitter.ts | 14 +++++------ .../transformer/TxTransformerTypes.ts | 2 ++ .../EV5InterchainAccountTxTransformer.ts | 20 ++++++++-------- 10 files changed, 47 insertions(+), 53 deletions(-) diff --git a/typescript/cli/src/submit/submit.ts b/typescript/cli/src/submit/submit.ts index 2166cf05e3..3c7154201d 100644 --- a/typescript/cli/src/submit/submit.ts +++ b/typescript/cli/src/submit/submit.ts @@ -39,11 +39,11 @@ export async function getSubmitterBuilder({ async function getSubmitter( multiProvider: MultiProvider, - { type, chain, settings }: SubmitterMetadata, + { type, settings }: SubmitterMetadata, ): Promise> { switch (type) { case TxSubmitterType.JSON_RPC: - return new EV5JsonRpcTxSubmitter(multiProvider, chain); + return new EV5JsonRpcTxSubmitter(multiProvider); case TxSubmitterType.IMPERSONATED_ACCOUNT: if (!settings) throw new Error( @@ -51,11 +51,13 @@ async function getSubmitter( ); await verifyAnvil(); - await forkNetworkToMultiProvider(multiProvider, chain); + await forkNetworkToMultiProvider( + multiProvider, + settings.eV5ImpersonatedAccountProps.chain, + ); return new EV5ImpersonatedAccountTxSubmitter( multiProvider, - chain, settings.eV5ImpersonatedAccountProps, ); case TxSubmitterType.GNOSIS_SAFE: @@ -65,7 +67,6 @@ async function getSubmitter( ); return new EV5GnosisSafeTxSubmitter( multiProvider, - chain, settings.eV5GnosisSafeProps, ); default: @@ -78,15 +79,15 @@ async function getTransformers( metadata: TransformerMetadata[], ): Promise[]> { return Promise.all( - metadata.map(({ type, chain, settings }) => - getTransformer(multiProvider, { type, chain, settings }), + metadata.map(({ type, settings }) => + getTransformer(multiProvider, { type, settings }), ), ); } async function getTransformer( multiProvider: MultiProvider, - { type, chain, settings }: TransformerMetadata, + { type, settings }: TransformerMetadata, ): Promise> { switch (type) { case TxTransformerType.ICA: @@ -96,7 +97,6 @@ async function getTransformer( ); return new EV5InterchainAccountTxTransformer( multiProvider, - chain, settings.eV5InterchainAccountProps, ); default: diff --git a/typescript/cli/src/submit/submitTypes.ts b/typescript/cli/src/submit/submitTypes.ts index 04c00cd379..f4e2c6b41d 100644 --- a/typescript/cli/src/submit/submitTypes.ts +++ b/typescript/cli/src/submit/submitTypes.ts @@ -1,5 +1,4 @@ import type { - ChainName, EV5GnosisSafeTxSubmitterProps, EV5ImpersonatedAccountTxSubmitterProps, EV5InterchainAccountTxTransformerProps, @@ -15,12 +14,10 @@ export interface SubmitterBuilderSettings { } export interface SubmitterMetadata { type: TxSubmitterType; - chain: ChainName; settings?: SubmitterSettings; } export interface TransformerMetadata { type: TxTransformerType; - chain: ChainName; settings?: TransformerSettings; } diff --git a/typescript/sdk/src/providers/transactions/submitter/TxSubmitterInterface.ts b/typescript/sdk/src/providers/transactions/submitter/TxSubmitterInterface.ts index b857bd990d..69f8718e2b 100644 --- a/typescript/sdk/src/providers/transactions/submitter/TxSubmitterInterface.ts +++ b/typescript/sdk/src/providers/transactions/submitter/TxSubmitterInterface.ts @@ -1,6 +1,5 @@ import { ProtocolType } from '@hyperlane-xyz/utils'; -import { ChainName } from '../../../types.js'; import { ProtocolTypedProvider, ProtocolTypedReceipt, @@ -14,10 +13,6 @@ export interface TxSubmitterInterface { * Defines the type of tx submitter. */ txSubmitterType: TxSubmitterType; - /** - * The chain to submit transactions on. - */ - chain: ChainName; /** * The provider to use for transaction submission. */ diff --git a/typescript/sdk/src/providers/transactions/submitter/TxSubmitterTypes.ts b/typescript/sdk/src/providers/transactions/submitter/TxSubmitterTypes.ts index 306062a701..3eabfaf0a6 100644 --- a/typescript/sdk/src/providers/transactions/submitter/TxSubmitterTypes.ts +++ b/typescript/sdk/src/providers/transactions/submitter/TxSubmitterTypes.ts @@ -1,5 +1,7 @@ import { Address } from '@hyperlane-xyz/utils'; +import { ChainName } from '../../../types.js'; + export enum TxSubmitterType { JSON_RPC = 'JSON RPC', IMPERSONATED_ACCOUNT = 'Impersonated Account', @@ -7,9 +9,11 @@ export enum TxSubmitterType { } export interface EV5GnosisSafeTxSubmitterProps { + chain: ChainName; safeAddress: Address; } export interface EV5ImpersonatedAccountTxSubmitterProps { + chain: ChainName; address: Address; } diff --git a/typescript/sdk/src/providers/transactions/submitter/builder/TxSubmitterBuilder.ts b/typescript/sdk/src/providers/transactions/submitter/builder/TxSubmitterBuilder.ts index 628bda0352..797f3ea73f 100644 --- a/typescript/sdk/src/providers/transactions/submitter/builder/TxSubmitterBuilder.ts +++ b/typescript/sdk/src/providers/transactions/submitter/builder/TxSubmitterBuilder.ts @@ -3,7 +3,6 @@ import { Logger } from 'pino'; import { rootLogger } from '@hyperlane-xyz/utils'; import { ProtocolType } from '@hyperlane-xyz/utils'; -import { ChainName } from '../../../../types.js'; import { ProtocolTypedReceipt, ProtocolTypedTransaction, @@ -35,7 +34,6 @@ export class TxSubmitterBuilder implements TxSubmitterInterface { public readonly txSubmitterType: TxSubmitterType; - public readonly chain: ChainName; protected readonly logger: Logger = rootLogger.child({ module: 'submitter-builder', @@ -46,7 +44,6 @@ export class TxSubmitterBuilder private currentTransformers: TxTransformerInterface[] = [], ) { this.txSubmitterType = this.currentSubmitter.txSubmitterType; - this.chain = this.currentSubmitter.chain; } /** diff --git a/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5GnosisSafeTxSubmitter.ts b/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5GnosisSafeTxSubmitter.ts index e3e81e2b74..9db0e15dbc 100644 --- a/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5GnosisSafeTxSubmitter.ts +++ b/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5GnosisSafeTxSubmitter.ts @@ -3,7 +3,6 @@ import { Logger } from 'pino'; import { Address, assert, rootLogger } from '@hyperlane-xyz/utils'; -import { ChainName } from '../../../../types.js'; // @ts-ignore import { getSafe, getSafeService } from '../../../../utils/gnosisSafe.js'; import { MultiProvider } from '../../../MultiProvider.js'; @@ -24,25 +23,31 @@ export class EV5GnosisSafeTxSubmitter implements EV5TxSubmitterInterface { constructor( public readonly multiProvider: MultiProvider, - public readonly chain: ChainName, public readonly props: EV5GnosisSafeTxSubmitterProps, ) {} public async submit(...txs: PopulatedTransaction[]): Promise { const safe = await getSafe( - this.chain, + this.props.chain, this.multiProvider, this.props.safeAddress, ); - const safeService = await getSafeService(this.chain, this.multiProvider); + const safeService = await getSafeService( + this.props.chain, + this.multiProvider, + ); const nextNonce: number = await safeService.getNextNonce( this.props.safeAddress, ); const safeTransactionBatch: any[] = txs.map( - ({ to, data, value }: PopulatedTransaction) => { + ({ to, data, value, chainId }: PopulatedTransaction) => { + assert(to, 'Invalid PopulatedTransaction: Missing to field'); + assert(data, 'Invalid PopulatedTransaction: Missing data field'); + assert(chainId, 'Invalid PopulatedTransaction: Missing chainId field'); + const txChain = this.multiProvider.getChainName(chainId); assert( - to && data, - 'Invalid PopulatedTransaction: Missing required field to or data.', + txChain === this.props.chain, + `Invalid PopulatedTransaction: Cannot submit ${txChain} tx to ${this.props.chain} submitter.`, ); return { to, data, value: value?.toString() ?? '0' }; }, @@ -54,13 +59,13 @@ export class EV5GnosisSafeTxSubmitter implements EV5TxSubmitterInterface { const safeTransactionData: any = safeTransaction.data; const safeTxHash: string = await safe.getTransactionHash(safeTransaction); const senderAddress: Address = await this.multiProvider.getSignerAddress( - this.chain, + this.props.chain, ); const safeSignature: any = await safe.signTransactionHash(safeTxHash); const senderSignature: string = safeSignature.data; this.logger.debug( - `Submitting transaction proposal to ${this.props.safeAddress} on ${this.chain}: ${safeTxHash}`, + `Submitting transaction proposal to ${this.props.safeAddress} on ${this.props.chain}: ${safeTxHash}`, ); return safeService.proposeTransaction({ diff --git a/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts b/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts index 4fe8b7ab09..f9ea2d39dc 100644 --- a/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts +++ b/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts @@ -4,7 +4,6 @@ import { Logger } from 'pino'; import { rootLogger } from '@hyperlane-xyz/utils'; -import { ChainName } from '../../../../types.js'; import { impersonateAccount } from '../../../../utils/fork.js'; import { MultiProvider } from '../../../MultiProvider.js'; import { @@ -24,18 +23,17 @@ export class EV5ImpersonatedAccountTxSubmitter extends EV5JsonRpcTxSubmitter { constructor( public readonly multiProvider: MultiProvider, - public readonly chain: ChainName, public readonly props: EV5ImpersonatedAccountTxSubmitterProps, ) { - super(multiProvider, chain); + super(multiProvider); } public async submit( ...txs: PopulatedTransaction[] ): Promise { const impersonatedAccount = await impersonateAccount(this.props.address); - this.multiProvider.setSigner(this.chain, impersonatedAccount); - super.multiProvider.setSigner(this.chain, impersonatedAccount); + this.multiProvider.setSharedSigner(impersonatedAccount); + super.multiProvider.setSharedSigner(impersonatedAccount); return await super.submit(...txs); } } diff --git a/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5JsonRpcTxSubmitter.ts b/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5JsonRpcTxSubmitter.ts index e1077d7c5c..f50c7f8228 100644 --- a/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5JsonRpcTxSubmitter.ts +++ b/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5JsonRpcTxSubmitter.ts @@ -2,9 +2,8 @@ import { TransactionReceipt } from '@ethersproject/providers'; import { ContractReceipt, PopulatedTransaction } from 'ethers'; import { Logger } from 'pino'; -import { rootLogger } from '@hyperlane-xyz/utils'; +import { assert, rootLogger } from '@hyperlane-xyz/utils'; -import { ChainName } from '../../../../types.js'; import { MultiProvider } from '../../../MultiProvider.js'; import { TxSubmitterType } from '../TxSubmitterTypes.js'; @@ -17,22 +16,21 @@ export class EV5JsonRpcTxSubmitter implements EV5TxSubmitterInterface { module: 'json-rpc-submitter', }); - constructor( - public readonly multiProvider: MultiProvider, - public readonly chain: ChainName, - ) {} + constructor(public readonly multiProvider: MultiProvider) {} public async submit( ...txs: PopulatedTransaction[] ): Promise { const receipts: TransactionReceipt[] = []; for (const tx of txs) { + assert(tx.chainId, 'Invalid PopulatedTransaction: Missing chainId field'); + const txChain = this.multiProvider.getChainName(tx.chainId); const receipt: ContractReceipt = await this.multiProvider.sendTransaction( - this.chain, + txChain, tx, ); this.logger.debug( - `Submitted PopulatedTransaction on ${this.chain}: ${receipt.transactionHash}`, + `Submitted PopulatedTransaction on ${txChain}: ${receipt.transactionHash}`, ); receipts.push(receipt); } diff --git a/typescript/sdk/src/providers/transactions/transformer/TxTransformerTypes.ts b/typescript/sdk/src/providers/transactions/transformer/TxTransformerTypes.ts index a0a4ac29b7..2e064fb65d 100644 --- a/typescript/sdk/src/providers/transactions/transformer/TxTransformerTypes.ts +++ b/typescript/sdk/src/providers/transactions/transformer/TxTransformerTypes.ts @@ -1,11 +1,13 @@ import { InterchainAccount } from '../../../middleware/account/InterchainAccount.js'; import { AccountConfig } from '../../../middleware/account/types.js'; +import { ChainName } from '../../../types.js'; export enum TxTransformerType { ICA = 'Interchain Account', } export interface EV5InterchainAccountTxTransformerProps { + chain: ChainName; interchainAccount: InterchainAccount; accountConfig: AccountConfig; hookMetadata?: string; diff --git a/typescript/sdk/src/providers/transactions/transformer/ethersV5/EV5InterchainAccountTxTransformer.ts b/typescript/sdk/src/providers/transactions/transformer/ethersV5/EV5InterchainAccountTxTransformer.ts index 9e51274fe2..e89fb72137 100644 --- a/typescript/sdk/src/providers/transactions/transformer/ethersV5/EV5InterchainAccountTxTransformer.ts +++ b/typescript/sdk/src/providers/transactions/transformer/ethersV5/EV5InterchainAccountTxTransformer.ts @@ -3,7 +3,6 @@ import { Logger } from 'pino'; import { CallData, assert, rootLogger } from '@hyperlane-xyz/utils'; -import { ChainName } from '../../../../types.js'; import { MultiProvider } from '../../../MultiProvider.js'; import { EV5InterchainAccountTxTransformerProps, @@ -22,31 +21,30 @@ export class EV5InterchainAccountTxTransformer constructor( public readonly multiProvider: MultiProvider, - public readonly chain: ChainName, public readonly props: EV5InterchainAccountTxTransformerProps, ) {} public async transform( ...txs: PopulatedTransaction[] ): Promise { - const destinationChainId = txs[0].chainId; - assert( - destinationChainId, - 'Missing destination chainId in PopulatedTransaction.', - ); - const innerCalls: CallData[] = txs.map( - ({ to, data, value }: PopulatedTransaction) => { + ({ to, data, value, chainId }: PopulatedTransaction) => { assert(to, 'Invalid PopulatedTransaction: Missing to field'); assert(data, 'Invalid PopulatedTransaction: Missing data field'); + assert(chainId, 'Invalid PopulatedTransaction: Missing chainId field'); + const txChain = this.multiProvider.getChainName(chainId); + assert( + txChain === this.props.chain, + `Invalid PopulatedTransaction: Cannot submit ${txChain} tx to ${this.props.chain} submitter.`, + ); return { to, data, value }; }, ); return [ await this.props.interchainAccount.getCallRemote( - this.chain, - this.multiProvider.getChainName(this.chain), //chainIdToMetadata[destinationChainId].name, + this.props.chain, + this.multiProvider.getChainName(txs[0].chainId!), innerCalls, this.props.accountConfig, this.props.hookMetadata, From 3d204af3bb17a6ccd52589364e445f05ed9ffae5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noah=20Bayindirli=20=F0=9F=A5=82?= Date: Thu, 9 May 2024 16:51:42 -0400 Subject: [PATCH 5/9] address Rossy's comments --- typescript/cli/src/submit/submit.ts | 36 ++++++++----------- .../src/submit/{submitTypes.ts => types.ts} | 0 .../submitter/TxSubmitterTypes.ts | 2 +- .../EV5ImpersonatedAccountTxSubmitter.ts | 4 ++- 4 files changed, 19 insertions(+), 23 deletions(-) rename typescript/cli/src/submit/{submitTypes.ts => types.ts} (100%) diff --git a/typescript/cli/src/submit/submit.ts b/typescript/cli/src/submit/submit.ts index 3c7154201d..f72abc0ce0 100644 --- a/typescript/cli/src/submit/submit.ts +++ b/typescript/cli/src/submit/submit.ts @@ -10,15 +10,13 @@ import { TxTransformerInterface, TxTransformerType, } from '@hyperlane-xyz/sdk'; -import { ProtocolType } from '@hyperlane-xyz/utils'; - -import { forkNetworkToMultiProvider, verifyAnvil } from '../deploy/dry-run.js'; +import { ProtocolType, assert } from '@hyperlane-xyz/utils'; import { SubmitterBuilderSettings, SubmitterMetadata, TransformerMetadata, -} from './submitTypes.js'; +} from './types.js'; export async function getSubmitterBuilder({ submitterMetadata, @@ -45,15 +43,9 @@ async function getSubmitter( case TxSubmitterType.JSON_RPC: return new EV5JsonRpcTxSubmitter(multiProvider); case TxSubmitterType.IMPERSONATED_ACCOUNT: - if (!settings) - throw new Error( - 'Must provide EV5ImpersonatedAccountTxSubmitterProps for impersonated account submitter.', - ); - - await verifyAnvil(); - await forkNetworkToMultiProvider( - multiProvider, - settings.eV5ImpersonatedAccountProps.chain, + assert( + settings, + 'Must provide EV5ImpersonatedAccountTxSubmitterProps for impersonated account submitter.', ); return new EV5ImpersonatedAccountTxSubmitter( @@ -61,10 +53,11 @@ async function getSubmitter( settings.eV5ImpersonatedAccountProps, ); case TxSubmitterType.GNOSIS_SAFE: - if (!settings) - throw new Error( - 'Must provide EV5GnosisSafeTxSubmitterProps for Gnosis safe submitter.', - ); + assert( + settings, + 'Must provide EV5GnosisSafeTxSubmitterProps for Gnosis safe submitter.', + ); + return new EV5GnosisSafeTxSubmitter( multiProvider, settings.eV5GnosisSafeProps, @@ -91,10 +84,11 @@ async function getTransformer( ): Promise> { switch (type) { case TxTransformerType.ICA: - if (!settings) - throw new Error( - 'Must provide EV5InterchainAccountTxTransformerProps for ICA transformer.', - ); + assert( + settings, + 'Must provide EV5InterchainAccountTxTransformerProps for ICA transformer.', + ); + return new EV5InterchainAccountTxTransformer( multiProvider, settings.eV5InterchainAccountProps, diff --git a/typescript/cli/src/submit/submitTypes.ts b/typescript/cli/src/submit/types.ts similarity index 100% rename from typescript/cli/src/submit/submitTypes.ts rename to typescript/cli/src/submit/types.ts diff --git a/typescript/sdk/src/providers/transactions/submitter/TxSubmitterTypes.ts b/typescript/sdk/src/providers/transactions/submitter/TxSubmitterTypes.ts index 3eabfaf0a6..7ed3eac7f5 100644 --- a/typescript/sdk/src/providers/transactions/submitter/TxSubmitterTypes.ts +++ b/typescript/sdk/src/providers/transactions/submitter/TxSubmitterTypes.ts @@ -15,5 +15,5 @@ export interface EV5GnosisSafeTxSubmitterProps { export interface EV5ImpersonatedAccountTxSubmitterProps { chain: ChainName; - address: Address; + userAddress: Address; } diff --git a/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts b/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts index f9ea2d39dc..6c5f8369c9 100644 --- a/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts +++ b/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts @@ -31,7 +31,9 @@ export class EV5ImpersonatedAccountTxSubmitter extends EV5JsonRpcTxSubmitter { public async submit( ...txs: PopulatedTransaction[] ): Promise { - const impersonatedAccount = await impersonateAccount(this.props.address); + const impersonatedAccount = await impersonateAccount( + this.props.userAddress, + ); this.multiProvider.setSharedSigner(impersonatedAccount); super.multiProvider.setSharedSigner(impersonatedAccount); return await super.submit(...txs); From c424ca3045f9d07b0c5d4d5bf51981bd9ad62cc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noah=20Bayindirli=20=F0=9F=A5=82?= Date: Fri, 10 May 2024 14:15:23 -0400 Subject: [PATCH 6/9] use descriminated union to improve branching and remove error handling (zod-support next) --- typescript/cli/src/submit/submit.ts | 41 ++++++++++------------------- typescript/cli/src/submit/types.ts | 15 +++++------ 2 files changed, 20 insertions(+), 36 deletions(-) diff --git a/typescript/cli/src/submit/submit.ts b/typescript/cli/src/submit/submit.ts index f72abc0ce0..cc344c2f0b 100644 --- a/typescript/cli/src/submit/submit.ts +++ b/typescript/cli/src/submit/submit.ts @@ -1,6 +1,8 @@ import { EV5GnosisSafeTxSubmitter, + EV5GnosisSafeTxSubmitterProps, EV5ImpersonatedAccountTxSubmitter, + EV5ImpersonatedAccountTxSubmitterProps, EV5InterchainAccountTxTransformer, EV5JsonRpcTxSubmitter, MultiProvider, @@ -10,7 +12,7 @@ import { TxTransformerInterface, TxTransformerType, } from '@hyperlane-xyz/sdk'; -import { ProtocolType, assert } from '@hyperlane-xyz/utils'; +import { ProtocolType } from '@hyperlane-xyz/utils'; import { SubmitterBuilderSettings, @@ -37,33 +39,23 @@ export async function getSubmitterBuilder({ async function getSubmitter( multiProvider: MultiProvider, - { type, settings }: SubmitterMetadata, + submitterMetadata: SubmitterMetadata, ): Promise> { - switch (type) { + switch (submitterMetadata.type) { case TxSubmitterType.JSON_RPC: return new EV5JsonRpcTxSubmitter(multiProvider); case TxSubmitterType.IMPERSONATED_ACCOUNT: - assert( - settings, - 'Must provide EV5ImpersonatedAccountTxSubmitterProps for impersonated account submitter.', - ); - return new EV5ImpersonatedAccountTxSubmitter( multiProvider, - settings.eV5ImpersonatedAccountProps, + submitterMetadata.props as EV5ImpersonatedAccountTxSubmitterProps, ); case TxSubmitterType.GNOSIS_SAFE: - assert( - settings, - 'Must provide EV5GnosisSafeTxSubmitterProps for Gnosis safe submitter.', - ); - return new EV5GnosisSafeTxSubmitter( multiProvider, - settings.eV5GnosisSafeProps, + submitterMetadata.props as EV5GnosisSafeTxSubmitterProps, ); default: - throw new Error(`Invalid TxSubmitterType: ${type}`); + throw new Error(`Invalid TxSubmitterType: ${submitterMetadata.type}`); } } @@ -72,28 +64,23 @@ async function getTransformers( metadata: TransformerMetadata[], ): Promise[]> { return Promise.all( - metadata.map(({ type, settings }) => - getTransformer(multiProvider, { type, settings }), + metadata.map(({ type, props: settings }) => + getTransformer(multiProvider, { type, props: settings }), ), ); } async function getTransformer( multiProvider: MultiProvider, - { type, settings }: TransformerMetadata, + transformerMetadata: TransformerMetadata, ): Promise> { - switch (type) { + switch (transformerMetadata.type) { case TxTransformerType.ICA: - assert( - settings, - 'Must provide EV5InterchainAccountTxTransformerProps for ICA transformer.', - ); - return new EV5InterchainAccountTxTransformer( multiProvider, - settings.eV5InterchainAccountProps, + transformerMetadata.props, ); default: - throw new Error(`Invalid TxTransformerType: ${type}`); + throw new Error(`Invalid TxTransformerType: ${transformerMetadata.type}`); } } diff --git a/typescript/cli/src/submit/types.ts b/typescript/cli/src/submit/types.ts index f4e2c6b41d..d50a63e22c 100644 --- a/typescript/cli/src/submit/types.ts +++ b/typescript/cli/src/submit/types.ts @@ -14,17 +14,14 @@ export interface SubmitterBuilderSettings { } export interface SubmitterMetadata { type: TxSubmitterType; - settings?: SubmitterSettings; + props: SubmitterProps; } export interface TransformerMetadata { type: TxTransformerType; - settings?: TransformerSettings; + props: TransformerProps; } -interface SubmitterSettings { - eV5GnosisSafeProps: EV5GnosisSafeTxSubmitterProps; - eV5ImpersonatedAccountProps: EV5ImpersonatedAccountTxSubmitterProps; -} -interface TransformerSettings { - eV5InterchainAccountProps: EV5InterchainAccountTxTransformerProps; -} +type SubmitterProps = + | EV5ImpersonatedAccountTxSubmitterProps + | EV5GnosisSafeTxSubmitterProps; +type TransformerProps = EV5InterchainAccountTxTransformerProps; From 28067347e6f8e2ad409b81a8d741e067bfa03db1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noah=20Bayindirli=20=F0=9F=A5=82?= Date: Fri, 10 May 2024 14:27:59 -0400 Subject: [PATCH 7/9] move EV5 submitter/transformer types into ethersV5 dir --- typescript/sdk/src/index.ts | 10 ++++------ .../transactions/submitter/TxSubmitterTypes.ts | 14 -------------- .../submitter/ethersV5/EV5GnosisSafeTxSubmitter.ts | 6 ++---- .../ethersV5/EV5ImpersonatedAccountTxSubmitter.ts | 6 ++---- .../submitter/ethersV5/EV5TxSubmitterTypes.ts | 13 +++++++++++++ .../transformer/ethersV5/EV5TxTransformerTypes.ts | 10 ++++++++++ 6 files changed, 31 insertions(+), 28 deletions(-) create mode 100644 typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5TxSubmitterTypes.ts create mode 100644 typescript/sdk/src/providers/transactions/transformer/ethersV5/EV5TxTransformerTypes.ts diff --git a/typescript/sdk/src/index.ts b/typescript/sdk/src/index.ts index cabe23127d..fd338351e7 100644 --- a/typescript/sdk/src/index.ts +++ b/typescript/sdk/src/index.ts @@ -304,21 +304,19 @@ export { protocolToDefaultProviderBuilder, } from './providers/providerBuilders.js'; export { TxSubmitterInterface } from './providers/transactions/submitter/TxSubmitterInterface.js'; +export { TxSubmitterType } from './providers/transactions/submitter/TxSubmitterTypes.js'; export { - TxSubmitterType, EV5GnosisSafeTxSubmitterProps, EV5ImpersonatedAccountTxSubmitterProps, -} from './providers/transactions/submitter/TxSubmitterTypes.js'; +} from './providers/transactions/submitter/ethersV5/EV5TxSubmitterTypes.js'; export { TxSubmitterBuilder } from './providers/transactions/submitter/builder/TxSubmitterBuilder.js'; export { EV5GnosisSafeTxSubmitter } from './providers/transactions/submitter/ethersV5/EV5GnosisSafeTxSubmitter.js'; export { EV5ImpersonatedAccountTxSubmitter } from './providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.js'; export { EV5JsonRpcTxSubmitter } from './providers/transactions/submitter/ethersV5/EV5JsonRpcTxSubmitter.js'; export { EV5TxSubmitterInterface } from './providers/transactions/submitter/ethersV5/EV5TxSubmitterInterface.js'; export { TxTransformerInterface } from './providers/transactions/transformer/TxTransformerInterface.js'; -export { - TxTransformerType, - EV5InterchainAccountTxTransformerProps, -} from './providers/transactions/transformer/TxTransformerTypes.js'; +export { TxTransformerType } from './providers/transactions/transformer/TxTransformerTypes.js'; +export { EV5InterchainAccountTxTransformerProps } from './providers/transactions/transformer/ethersV5/EV5TxTransformerTypes.js'; export { EV5InterchainAccountTxTransformer } from './providers/transactions/transformer/ethersV5/EV5InterchainAccountTxTransformer.js'; export { EV5TxTransformerInterface } from './providers/transactions/transformer/ethersV5/EV5TxTransformerInterface.js'; export { GasRouterDeployer } from './router/GasRouterDeployer.js'; diff --git a/typescript/sdk/src/providers/transactions/submitter/TxSubmitterTypes.ts b/typescript/sdk/src/providers/transactions/submitter/TxSubmitterTypes.ts index 7ed3eac7f5..4e38f9c25a 100644 --- a/typescript/sdk/src/providers/transactions/submitter/TxSubmitterTypes.ts +++ b/typescript/sdk/src/providers/transactions/submitter/TxSubmitterTypes.ts @@ -1,19 +1,5 @@ -import { Address } from '@hyperlane-xyz/utils'; - -import { ChainName } from '../../../types.js'; - export enum TxSubmitterType { JSON_RPC = 'JSON RPC', IMPERSONATED_ACCOUNT = 'Impersonated Account', GNOSIS_SAFE = 'Gnosis Safe', } - -export interface EV5GnosisSafeTxSubmitterProps { - chain: ChainName; - safeAddress: Address; -} - -export interface EV5ImpersonatedAccountTxSubmitterProps { - chain: ChainName; - userAddress: Address; -} diff --git a/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5GnosisSafeTxSubmitter.ts b/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5GnosisSafeTxSubmitter.ts index 9db0e15dbc..5fb760e327 100644 --- a/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5GnosisSafeTxSubmitter.ts +++ b/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5GnosisSafeTxSubmitter.ts @@ -6,12 +6,10 @@ import { Address, assert, rootLogger } from '@hyperlane-xyz/utils'; // @ts-ignore import { getSafe, getSafeService } from '../../../../utils/gnosisSafe.js'; import { MultiProvider } from '../../../MultiProvider.js'; -import { - EV5GnosisSafeTxSubmitterProps, - TxSubmitterType, -} from '../TxSubmitterTypes.js'; +import { TxSubmitterType } from '../TxSubmitterTypes.js'; import { EV5TxSubmitterInterface } from './EV5TxSubmitterInterface.js'; +import { EV5GnosisSafeTxSubmitterProps } from './EV5TxSubmitterTypes.js'; export class EV5GnosisSafeTxSubmitter implements EV5TxSubmitterInterface { public readonly txSubmitterType: TxSubmitterType = diff --git a/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts b/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts index 6c5f8369c9..7df62f825e 100644 --- a/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts +++ b/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts @@ -6,12 +6,10 @@ import { rootLogger } from '@hyperlane-xyz/utils'; import { impersonateAccount } from '../../../../utils/fork.js'; import { MultiProvider } from '../../../MultiProvider.js'; -import { - EV5ImpersonatedAccountTxSubmitterProps, - TxSubmitterType, -} from '../TxSubmitterTypes.js'; +import { TxSubmitterType } from '../TxSubmitterTypes.js'; import { EV5JsonRpcTxSubmitter } from './EV5JsonRpcTxSubmitter.js'; +import { EV5ImpersonatedAccountTxSubmitterProps } from './EV5TxSubmitterTypes.js'; export class EV5ImpersonatedAccountTxSubmitter extends EV5JsonRpcTxSubmitter { public readonly txSubmitterType: TxSubmitterType = diff --git a/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5TxSubmitterTypes.ts b/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5TxSubmitterTypes.ts new file mode 100644 index 0000000000..cf6f7f164c --- /dev/null +++ b/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5TxSubmitterTypes.ts @@ -0,0 +1,13 @@ +import { Address } from '@hyperlane-xyz/utils'; + +import { ChainName } from '../../../../types.js'; + +export interface EV5GnosisSafeTxSubmitterProps { + chain: ChainName; + safeAddress: Address; +} + +export interface EV5ImpersonatedAccountTxSubmitterProps { + chain: ChainName; + userAddress: Address; +} diff --git a/typescript/sdk/src/providers/transactions/transformer/ethersV5/EV5TxTransformerTypes.ts b/typescript/sdk/src/providers/transactions/transformer/ethersV5/EV5TxTransformerTypes.ts new file mode 100644 index 0000000000..e8c7eb06aa --- /dev/null +++ b/typescript/sdk/src/providers/transactions/transformer/ethersV5/EV5TxTransformerTypes.ts @@ -0,0 +1,10 @@ +import { InterchainAccount } from '../../../../middleware/account/InterchainAccount.js'; +import { AccountConfig } from '../../../../middleware/account/types.js'; +import { ChainName } from '../../../../types.js'; + +export interface EV5InterchainAccountTxTransformerProps { + chain: ChainName; + interchainAccount: InterchainAccount; + accountConfig: AccountConfig; + hookMetadata?: string; +} From 5aee461a7c739ab5468ec9f48e391e1f975d7972 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noah=20Bayindirli=20=F0=9F=A5=82?= Date: Fri, 10 May 2024 14:32:36 -0400 Subject: [PATCH 8/9] reuse parent class mp --- .../submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts b/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts index 7df62f825e..816baf0535 100644 --- a/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts +++ b/typescript/sdk/src/providers/transactions/submitter/ethersV5/EV5ImpersonatedAccountTxSubmitter.ts @@ -20,7 +20,7 @@ export class EV5ImpersonatedAccountTxSubmitter extends EV5JsonRpcTxSubmitter { }); constructor( - public readonly multiProvider: MultiProvider, + multiProvider: MultiProvider, public readonly props: EV5ImpersonatedAccountTxSubmitterProps, ) { super(multiProvider); @@ -32,7 +32,6 @@ export class EV5ImpersonatedAccountTxSubmitter extends EV5JsonRpcTxSubmitter { const impersonatedAccount = await impersonateAccount( this.props.userAddress, ); - this.multiProvider.setSharedSigner(impersonatedAccount); super.multiProvider.setSharedSigner(impersonatedAccount); return await super.submit(...txs); } From 1f40e36226a85e089761fafc2e48a7f746a0804e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Noah=20Bayindirli=20=F0=9F=A5=82?= Date: Fri, 10 May 2024 17:11:31 -0400 Subject: [PATCH 9/9] add ICA innerCall batching based on network --- .../transformer/TxTransformerTypes.ts | 11 ---- .../EV5InterchainAccountTxTransformer.ts | 55 ++++++++++--------- 2 files changed, 28 insertions(+), 38 deletions(-) diff --git a/typescript/sdk/src/providers/transactions/transformer/TxTransformerTypes.ts b/typescript/sdk/src/providers/transactions/transformer/TxTransformerTypes.ts index 2e064fb65d..b8e029b2c1 100644 --- a/typescript/sdk/src/providers/transactions/transformer/TxTransformerTypes.ts +++ b/typescript/sdk/src/providers/transactions/transformer/TxTransformerTypes.ts @@ -1,14 +1,3 @@ -import { InterchainAccount } from '../../../middleware/account/InterchainAccount.js'; -import { AccountConfig } from '../../../middleware/account/types.js'; -import { ChainName } from '../../../types.js'; - export enum TxTransformerType { ICA = 'Interchain Account', } - -export interface EV5InterchainAccountTxTransformerProps { - chain: ChainName; - interchainAccount: InterchainAccount; - accountConfig: AccountConfig; - hookMetadata?: string; -} diff --git a/typescript/sdk/src/providers/transactions/transformer/ethersV5/EV5InterchainAccountTxTransformer.ts b/typescript/sdk/src/providers/transactions/transformer/ethersV5/EV5InterchainAccountTxTransformer.ts index e89fb72137..25ae331e76 100644 --- a/typescript/sdk/src/providers/transactions/transformer/ethersV5/EV5InterchainAccountTxTransformer.ts +++ b/typescript/sdk/src/providers/transactions/transformer/ethersV5/EV5InterchainAccountTxTransformer.ts @@ -3,13 +3,12 @@ import { Logger } from 'pino'; import { CallData, assert, rootLogger } from '@hyperlane-xyz/utils'; +import { ChainName } from '../../../../types.js'; import { MultiProvider } from '../../../MultiProvider.js'; -import { - EV5InterchainAccountTxTransformerProps, - TxTransformerType, -} from '../TxTransformerTypes.js'; +import { TxTransformerType } from '../TxTransformerTypes.js'; import { EV5TxTransformerInterface } from './EV5TxTransformerInterface.js'; +import { EV5InterchainAccountTxTransformerProps } from './EV5TxTransformerTypes.js'; export class EV5InterchainAccountTxTransformer implements EV5TxTransformerInterface @@ -27,28 +26,30 @@ export class EV5InterchainAccountTxTransformer public async transform( ...txs: PopulatedTransaction[] ): Promise { - const innerCalls: CallData[] = txs.map( - ({ to, data, value, chainId }: PopulatedTransaction) => { - assert(to, 'Invalid PopulatedTransaction: Missing to field'); - assert(data, 'Invalid PopulatedTransaction: Missing data field'); - assert(chainId, 'Invalid PopulatedTransaction: Missing chainId field'); - const txChain = this.multiProvider.getChainName(chainId); - assert( - txChain === this.props.chain, - `Invalid PopulatedTransaction: Cannot submit ${txChain} tx to ${this.props.chain} submitter.`, - ); - return { to, data, value }; - }, - ); - - return [ - await this.props.interchainAccount.getCallRemote( - this.props.chain, - this.multiProvider.getChainName(txs[0].chainId!), - innerCalls, - this.props.accountConfig, - this.props.hookMetadata, - ), - ]; + const txChainsToInnerCalls: Record = {}; + + txs.map(({ to, data, value, chainId }: PopulatedTransaction) => { + assert(to, 'Invalid PopulatedTransaction: Missing to field'); + assert(data, 'Invalid PopulatedTransaction: Missing data field'); + assert(chainId, 'Invalid PopulatedTransaction: Missing chainId field'); + const txChain = this.multiProvider.getChainName(chainId); + if (!txChainsToInnerCalls[txChain]) txChainsToInnerCalls[txChain] = []; + txChainsToInnerCalls[txChain].push({ to, data, value }); + }); + + const transformedTxs: Promise[] = []; + Object.keys(txChainsToInnerCalls).map((txChain: ChainName) => { + transformedTxs.push( + this.props.interchainAccount.getCallRemote( + this.props.chain, + txChain, + txChainsToInnerCalls[txChain], + this.props.accountConfig, + this.props.hookMetadata, + ), + ); + }); + + return Promise.all(transformedTxs); } }