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

fix: reuse SDK transaction types in submitters #4598

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 9 additions & 17 deletions typescript/cli/src/config/submit.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { stringify as yamlStringify } from 'yaml';

import {
PopulatedTransactions,
PopulatedTransactionsSchema,
AnnotatedEV5Transaction,
SubmissionStrategy,
} from '@hyperlane-xyz/sdk';
import { PopulatedTransaction } from '@hyperlane-xyz/sdk';
import { MultiProvider } from '@hyperlane-xyz/sdk';
import { assert, errorToString } from '@hyperlane-xyz/utils';

import { WriteCommandContext } from '../context/types.js';
Expand Down Expand Up @@ -36,7 +33,7 @@ export async function runSubmit({
'Submission strategy required to submit transactions.\nPlease create a submission strategy. See examples in cli/examples/submit/strategy/*.',
);
const transactions = getTransactions(transactionsFilepath);
const chain = getChainFromTxs(multiProvider, transactions);
const chain = getChainFromTxs(transactions);

const protocol = chainMetadata[chain].protocol;
const submitterBuilder = await getSubmitterBuilder<typeof protocol>({
Expand Down Expand Up @@ -70,22 +67,17 @@ export async function runSubmit({
* @returns The name of the chain that the transactions are submitted on.
* @throws If the transactions are not all on the same chain or chain is not found
*/
function getChainFromTxs(
multiProvider: MultiProvider,
transactions: PopulatedTransactions,
) {
function getChainFromTxs(transactions: AnnotatedEV5Transaction[]) {
const firstTransaction = transactions[0];
const sameChainIds = transactions.every(
(t: PopulatedTransaction) => t.chainId === firstTransaction.chainId,
(t: AnnotatedEV5Transaction) => t.chainId === firstTransaction.chainId,
);
assert(sameChainIds, 'Transactions must be submitted on the same chains');

return multiProvider.getChainName(firstTransaction.chainId);
return firstTransaction.chain;
}

function getTransactions(transactionsFilepath: string): PopulatedTransactions {
const transactionsFileContent = readYamlOrJson<any[]>(
transactionsFilepath.trim(),
);
return PopulatedTransactionsSchema.parse(transactionsFileContent);
function getTransactions(
transactionsFilepath: string,
): AnnotatedEV5Transaction[] {
return readYamlOrJson<AnnotatedEV5Transaction[]>(transactionsFilepath.trim());
}
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ async function main() {
`Funding ${address} on chain '${chain}' with ${value} native tokens`,
);
await multiProvider.sendTransaction(chain, {
chain,
to: address,
value,
});
Expand Down
7 changes: 4 additions & 3 deletions typescript/infra/scripts/funding/fund-keys-from-deployer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -623,10 +623,10 @@ class ContextFunder {

if (igpBalance.gt(igpClaimThreshold)) {
logger.info({ chain }, 'IGP balance exceeds claim threshold, claiming');
await this.multiProvider.sendTransaction(
await this.multiProvider.sendTransaction(chain, {
...(await igp.populateTransaction.claim()),
chain,
await igp.populateTransaction.claim(),
);
});
} else {
logger.info(
{ chain },
Expand Down Expand Up @@ -720,6 +720,7 @@ class ContextFunder {
}

const tx = await this.multiProvider.sendTransaction(chain, {
chain,
to: key.address,
value: fundingAmount,
});
Expand Down
24 changes: 13 additions & 11 deletions typescript/infra/scripts/helloworld/kathy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -232,13 +232,15 @@ async function main(): Promise<boolean> {
messageReceiptSeconds.labels({ origin, remote }).inc(0);
}

chains.map(async (chain) => {
return updateWalletBalanceMetricFor(
app,
chain,
coreConfig.owners[chain].owner,
);
});
await Promise.allSettled(
chains.map(async (chain) => {
return updateWalletBalanceMetricFor(
app,
chain,
coreConfig.owners[chain].owner,
);
}),
);

// Incremented each time an entire cycle has occurred
let currentCycle = 0;
Expand Down Expand Up @@ -431,10 +433,10 @@ async function sendMessage(
let txReceipt: TypedTransactionReceipt;
if (tx.type == ProviderType.EthersV5) {
// Utilize the legacy evm-specific multiprovider utils to send the transaction
const receipt = await multiProvider.sendTransaction(
origin,
tx.transaction,
);
const receipt = await multiProvider.sendTransaction(origin, {
chain: origin,
...tx.transaction,
});
txReceipt = {
type: ProviderType.EthersV5,
receipt,
Expand Down
1 change: 1 addition & 0 deletions typescript/infra/src/govern/multisend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ export class SignerMultiSend extends MultiSend {
for (const call of calls) {
const estimate = await this.multiProvider.estimateGas(this.chain, call);
const receipt = await this.multiProvider.sendTransaction(this.chain, {
chain: this.chain,
gasLimit: addBufferToGasLimit(estimate),
...call,
});
Expand Down
1 change: 1 addition & 0 deletions typescript/infra/test/govern.hardhat-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export class HyperlaneTestGovernor extends HyperlaneAppGovernor<
): Promise<void> {
for (const call of calls) {
await this.checker.multiProvider.sendTransaction(chain, {
chain,
to: call.to,
data: call.data,
value: call.value,
Expand Down
49 changes: 3 additions & 46 deletions typescript/sdk/src/core/AbstractHyperlaneModule.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,8 @@
import { Logger } from 'pino';

import { Ownable__factory } from '@hyperlane-xyz/core';
import {
Address,
Annotated,
ProtocolType,
eqAddress,
} from '@hyperlane-xyz/utils';
import { Annotated, ProtocolType } from '@hyperlane-xyz/utils';

import {
AnnotatedEV5Transaction,
ProtocolTypedTransaction,
} from '../providers/ProviderType.js';
import { ProtocolTypedTransaction } from '../providers/ProviderType.js';
import { ChainNameOrId } from '../types.js';

export type HyperlaneModuleParams<
Expand Down Expand Up @@ -41,41 +32,7 @@ export abstract class HyperlaneModule<
public abstract read(): Promise<TConfig>;
public abstract update(
config: TConfig,
): Promise<Annotated<ProtocolTypedTransaction<TProtocol>['transaction'][]>>;

/**
* Transfers ownership of a contract to a new owner.
*
* @param actualOwner - The current owner of the contract.
* @param expectedOwner - The expected new owner of the contract.
* @param deployedAddress - The address of the deployed contract.
* @param chainId - The chain ID of the network the contract is deployed on.
* @returns An array of annotated EV5 transactions that need to be executed to update the owner.
*/
static createTransferOwnershipTx(params: {
actualOwner: Address;
expectedOwner: Address;
deployedAddress: Address;
chainId: number;
}): AnnotatedEV5Transaction[] {
const { actualOwner, expectedOwner, deployedAddress, chainId } = params;
const updateTransactions: AnnotatedEV5Transaction[] = [];
if (eqAddress(actualOwner, expectedOwner)) {
return [];
}

updateTransactions.push({
annotation: `Transferring ownership of ${deployedAddress} from current owner ${actualOwner} to new owner ${expectedOwner}`,
chainId,
to: deployedAddress,
data: Ownable__factory.createInterface().encodeFunctionData(
'transferOwnership(address)',
[expectedOwner],
),
});

return updateTransactions;
}
): Promise<Annotated<ProtocolTypedTransaction<TProtocol>['transaction']>[]>;

// /*
// Types and static methods can be challenging. Ensure each implementation includes a static create function.
Expand Down
5 changes: 4 additions & 1 deletion typescript/sdk/src/core/EvmCoreModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
import { HyperlaneAddresses } from '../contracts/types.js';
import { DeployedCoreAddresses } from '../core/schemas.js';
import { CoreConfig } from '../core/types.js';
import { EvmModuleDeployer } from '../deploy/EvmModuleDeployer.js';
import { HyperlaneProxyFactoryDeployer } from '../deploy/HyperlaneProxyFactoryDeployer.js';
import {
ProxyFactoryFactories,
Expand Down Expand Up @@ -132,6 +133,7 @@ export class EvmCoreModule extends HyperlaneModule<
data: contractToUpdate.interface.encodeFunctionData('setDefaultIsm', [
deployedIsm,
]),
chain: this.chainName,
});
}

Expand Down Expand Up @@ -196,11 +198,12 @@ export class EvmCoreModule extends HyperlaneModule<
actualConfig: CoreConfig,
expectedConfig: CoreConfig,
): AnnotatedEV5Transaction[] {
return EvmCoreModule.createTransferOwnershipTx({
return EvmModuleDeployer.createTransferOwnershipTx({
actualOwner: actualConfig.owner,
expectedOwner: expectedConfig.owner,
deployedAddress: this.args.addresses.mailbox,
chainId: this.domainId,
chain: this.chainName,
});
}

Expand Down
22 changes: 16 additions & 6 deletions typescript/sdk/src/core/HyperlaneCoreDeployer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,26 +143,36 @@ export class HyperlaneCoreDeployer extends HyperlaneDeployer<
mailbox,
defaultHook.address,
(_mailbox) => _mailbox.defaultHook(),
(_mailbox, _hook) =>
_mailbox.populateTransaction.setDefaultHook(_hook, { ...txOverrides }),
async (_mailbox, _hook) => {
const tx = await _mailbox.populateTransaction.setDefaultHook(_hook, {
...txOverrides,
});
return { ...tx, chain };
},
);

await this.configureHook(
chain,
mailbox,
requiredHook.address,
(_mailbox) => _mailbox.requiredHook(),
(_mailbox, _hook) =>
_mailbox.populateTransaction.setRequiredHook(_hook, { ...txOverrides }),
async (_mailbox, _hook) => {
const tx = await _mailbox.populateTransaction.setRequiredHook(_hook, {
...txOverrides,
});
return { ...tx, chain };
},
);

await this.configureIsm(
chain,
mailbox,
defaultIsm,
(_mailbox) => _mailbox.defaultIsm(),
(_mailbox, _module) =>
_mailbox.populateTransaction.setDefaultIsm(_module),
async (_mailbox, _module) => {
const tx = await _mailbox.populateTransaction.setDefaultIsm(_module);
return { ...tx, chain };
},
);

return mailbox;
Expand Down
7 changes: 6 additions & 1 deletion typescript/sdk/src/core/TestRecipientDeployer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,12 @@ export class TestRecipientDeployer extends HyperlaneDeployer<
testRecipient,
config.interchainSecurityModule,
(tr) => tr.interchainSecurityModule(),
(tr, ism) => tr.populateTransaction.setInterchainSecurityModule(ism),
async (tr, ism) => {
const tx = await tr.populateTransaction.setInterchainSecurityModule(
ism,
);
return { ...tx, chain };
},
);
} else {
this.logger.warn(`No ISM config provided for TestRecipient on ${chain}`);
Expand Down
46 changes: 45 additions & 1 deletion typescript/sdk/src/deploy/EvmModuleDeployer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,22 @@ import { ethers } from 'ethers';
import { Logger } from 'pino';

import {
Ownable__factory,
StaticAddressSetFactory,
StaticThresholdAddressSetFactory,
TransparentUpgradeableProxy__factory,
} from '@hyperlane-xyz/core';
import { buildArtifact as coreBuildArtifact } from '@hyperlane-xyz/core/buildArtifact.js';
import { Address, addBufferToGasLimit, rootLogger } from '@hyperlane-xyz/utils';
import {
Address,
addBufferToGasLimit,
eqAddress,
rootLogger,
} from '@hyperlane-xyz/utils';

import { HyperlaneContracts, HyperlaneFactories } from '../contracts/types.js';
import { MultiProvider } from '../providers/MultiProvider.js';
import { AnnotatedEV5Transaction } from '../providers/ProviderType.js';
import { ChainMap, ChainName } from '../types.js';

import { isProxy, proxyConstructorArgs } from './proxy.js';
Expand Down Expand Up @@ -315,4 +322,41 @@ export class EvmModuleDeployer<Factories extends HyperlaneFactories> {

return address;
}

/**
* Transfers ownership of a contract to a new owner.
*
* @param actualOwner - The current owner of the contract.
* @param expectedOwner - The expected new owner of the contract.
* @param deployedAddress - The address of the deployed contract.
* @param chainId - The chain ID of the network the contract is deployed on.
* @returns An array of annotated EV5 transactions that need to be executed to update the owner.
*/
static createTransferOwnershipTx(params: {
actualOwner: Address;
expectedOwner: Address;
deployedAddress: Address;
chainId: number;
chain: ChainName;
}): AnnotatedEV5Transaction[] {
const { actualOwner, expectedOwner, deployedAddress, chainId, chain } =
params;
const updateTransactions: AnnotatedEV5Transaction[] = [];
if (eqAddress(actualOwner, expectedOwner)) {
return [];
}

updateTransactions.push({
chain,
annotation: `Transferring ownership of ${deployedAddress} from current owner ${actualOwner} to new owner ${expectedOwner}`,
chainId,
to: deployedAddress,
data: Ownable__factory.createInterface().encodeFunctionData(
'transferOwnership(address)',
[expectedOwner],
),
});

return updateTransactions;
}
}
Loading
Loading