Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create CLI Submitter #3730

Merged
merged 14 commits into from
May 15, 2024
Merged

Create CLI Submitter #3730

merged 14 commits into from
May 15, 2024

Conversation

nbayindirli
Copy link
Contributor

@nbayindirli nbayindirli commented May 7, 2024

Description

  • A CLI-side submitter to interact with the SDK's tx submitter builder

Drive-by changes

  • None

Related issues

Backward compatibility

  • Yes

Testing

  • None

Copy link

changeset-bot bot commented May 7, 2024

🦋 Changeset detected

Latest commit: de28885

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 7 packages
Name Type
@hyperlane-xyz/sdk Minor
@hyperlane-xyz/cli Minor
@hyperlane-xyz/helloworld Minor
@hyperlane-xyz/infra Minor
@hyperlane-xyz/core Minor
@hyperlane-xyz/ccip-server Minor
@hyperlane-xyz/utils Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@nbayindirli nbayindirli marked this pull request as draft May 7, 2024 21:52
Copy link

codecov bot commented May 7, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 63.96%. Comparing base (344a716) to head (de28885).
Report is 1 commits behind head on main.

Additional details and impacted files
@@           Coverage Diff           @@
##             main    #3730   +/-   ##
=======================================
  Coverage   63.96%   63.96%           
=======================================
  Files         124      124           
  Lines        1543     1543           
  Branches      167      167           
=======================================
  Hits          987      987           
  Misses        530      530           
  Partials       26       26           
Components Coverage Δ
core 84.61% <ø> (ø)
hooks 67.50% <ø> (ø)
isms 39.52% <ø> (ø)
token 65.41% <ø> (ø)
middlewares 77.05% <ø> (ø)

@nbayindirli nbayindirli changed the title [WIP] CLI-Submitter Integration Create CLI Submitter May 8, 2024
@nbayindirli nbayindirli marked this pull request as ready for review May 8, 2024 21:23
Copy link
Contributor

@jmrossy jmrossy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mostly looks good! Just a few small questions/comments to clear up.

I'd also appreciate it if we could exercise this in the ci-test.sh e2e test please. It's been useful for catching CLI regressions in the past.

@@ -0,0 +1,5 @@
---
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Separate changesets for the CLI and SDK, very nice thank you.

@@ -0,0 +1,33 @@
import type {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Convention is to call this file just types and let it's location provide the context

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah– I thought I refactored this back to types. Updated

'Must provide EV5ImpersonatedAccountTxSubmitterProps for impersonated account submitter.',
);

await verifyAnvil();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would this switch case ever get invoked for a situation other than --dry-run? If not, do we need this call when we already do it in context.ts?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're absolutely right– once utilized by any of the command modules this will sit behind the context so there's no need to verify or fork here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i dont think so

Comment on lines 48 to 51
if (!settings)
throw new Error(
'Must provide EV5ImpersonatedAccountTxSubmitterProps for impersonated account submitter.',
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check out the little assert function in our utils package.
assert(settings, 'EV5ImpersonatedAccountTxSubmitterProps required for impersonated account submitter')

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For whatever reason it seems like we were using this convention more CLI-side, and assert SDK-side. In either case, now using the utils assert!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the one downside is its slightly less readable to the average TS dev but I like the brevity :)

export enum TxSubmitterType {
JSON_RPC = 'JSON RPC',
IMPERSONATED_ACCOUNT = 'Impersonated Account',
GNOSIS_SAFE = 'Gnosis Safe',
}

export interface EV5GnosisSafeTxSubmitterProps {
safeAddress: Address;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be just address for consistency?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not think so, since safeAddress is definitely only used to set the safeAddress for proposals

With that said, I updated the below field on EV5ImpersonatedAccountTxSubmitterProps to be userAddress for symmetry (also more accurate)

@nbayindirli nbayindirli requested a review from jmrossy May 9, 2024 20:51
Copy link
Member

@yorhodes yorhodes left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great start
I think we can cut down further on the number of new config interfaces here

Comment on lines 48 to 51
if (!settings)
throw new Error(
'Must provide EV5ImpersonatedAccountTxSubmitterProps for impersonated account submitter.',
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the one downside is its slightly less readable to the average TS dev but I like the brevity :)

'Must provide EV5ImpersonatedAccountTxSubmitterProps for impersonated account submitter.',
);

await verifyAnvil();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i dont think so

Comment on lines 64 to 67
if (!settings)
throw new Error(
'Must provide EV5GnosisSafeTxSubmitterProps for Gnosis safe submitter.',
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we have the required settings somehow be derived from the discriminated union?
ie the JSON_RPC submitter has an empty/undefined settings object etc

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we could also use zod schemas here to validate the input

Comment on lines 77 to 88
async function getTransformers<TProtocol extends ProtocolType>(
multiProvider: MultiProvider,
metadata: TransformerMetadata[],
): Promise<TxTransformerInterface<TProtocol>[]> {
return Promise.all(
metadata.map(({ type, settings }) =>
getTransformer<TProtocol>(multiProvider, { type, settings }),
),
);
}

async function getTransformer<TProtocol extends ProtocolType>(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these do not need to be async

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't look resolved?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this doesn't look resolved?

We chatted about this in the office– since getTransformer must call getCallRemote (which in turn might make a call to network), we're ok with keeping this async

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the async transform doesnt happen in this function iiuc

Comment on lines 15 to 18
export interface SubmitterMetadata {
type: TxSubmitterType;
settings?: SubmitterSettings;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can the settings type be derived from the TxSubmitterType?

Suggested change
export interface SubmitterMetadata {
type: TxSubmitterType;
settings?: SubmitterSettings;
}
export interface SubmitterMetadata<T extends TxSubmitterType> {
type: T;
settings?: SubmitterSettings<T>;
}

something like this

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and at that point submitter metadata seems superfluous with the submitter settings interface itself

Comment on lines 35 to 36
this.multiProvider.setSharedSigner(impersonatedAccount);
super.multiProvider.setSharedSigner(impersonatedAccount);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we just reuse supers?

Suggested change
this.multiProvider.setSharedSigner(impersonatedAccount);
super.multiProvider.setSharedSigner(impersonatedAccount);
super.multiProvider.setSharedSigner(impersonatedAccount);

Comment on lines 9 to 14
export interface EV5InterchainAccountTxTransformerProps {
chain: ChainName;
interchainAccount: InterchainAccount;
accountConfig: AccountConfig;
hookMetadata?: string;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would it be possible to just say Parameters<typeof InterchainAccount['callRemote'] or something?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is definitely possible, but since getCallRemote's args aren't destructed, we'd have to index into the parameter array (instead of using type names) or refactor to ICA class. Additionally, we set destination & innerCalls based on the txs (both params of getCallRemote), which seems like an antipattern if we have to write back to props (or avoid using two of its fields)

const innerCalls: CallData[] = txs.map(
({ to, data, value }: PopulatedTransaction) => {
({ to, data, value, chainId }: PopulatedTransaction) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice :)

Comment on lines 32 to 39
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.`,
);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we can leverage zod schemas here too

this.chain,
this.multiProvider.getChainName(this.chain), //chainIdToMetadata[destinationChainId].name,
this.props.chain,
this.multiProvider.getChainName(txs[0].chainId!),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose we should assert that the chain Id is consistent, or actually produce separate callRemote bundles for different chain Ids

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably the latter

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep love this idea– added a network -> tx bundle mapping to broadcast

Copy link
Contributor

@jmrossy jmrossy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


Recommend waiting for Yorke's approval too :)

Comment on lines +35 to 36
super.multiProvider.setSharedSigner(impersonatedAccount);
return await super.submit(...txs);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idk what the implication is of not doing this but should we
stopImpersonating after submitting?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting- I think we should do this in order to keep the submission atomic, and I don't think this should have any downstream effects since we are also impersonating during this call

will address as a part of #3786

Comment on lines +5 to +13
export interface EV5GnosisSafeTxSubmitterProps {
chain: ChainName;
safeAddress: Address;
}

export interface EV5ImpersonatedAccountTxSubmitterProps {
chain: ChainName;
userAddress: Address;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is chain needed for every submitter?
maybe we can omit that from each

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not actually – EV5ImpersonatedAccountTxSubmitterProps does not actually need a specific network tied to it, so will remove chain here. Gnosis does need it in order to verify the submitted transactions can be used with that submitter

will address as a part of #3786

@nbayindirli nbayindirli merged commit eba3936 into main May 15, 2024
34 checks passed
@nbayindirli nbayindirli deleted the noah/cli-submitter branch May 15, 2024 14:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

Implement CLI Submitter
3 participants