feat(sdk): Add ownership transfer to update (#4175)

### Description
Add transfer ownership to warp update

### Related issues
https://github.com/hyperlane-xyz/hyperlane-monorepo/issues/4174

### Backward compatibility
Yes

### Testing
Manual/Unit test
pull/4197/head
Lee 4 months ago committed by GitHub
parent 957a262d54
commit 8533f9e66c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 5
      .changeset/khaki-crabs-perform.md
  2. 38
      typescript/sdk/src/token/EvmERC20WarpModule.hardhat-test.ts
  3. 38
      typescript/sdk/src/token/EvmERC20WarpModule.ts

@ -0,0 +1,5 @@
---
'@hyperlane-xyz/sdk': minor
---
Adds transferOwnership to warp update to allow ownership to be transferred if the onchain owner differ

@ -482,5 +482,43 @@ describe('EvmERC20WarpHyperlaneModule', async () => {
updatedConfig = await evmERC20WarpModule.read();
expect(Object.keys(updatedConfig.remoteRouters!).length).to.be.equal(2);
});
it('should update the owner only if they are different', async () => {
const config = {
...baseConfig,
type: TokenType.native,
hook: hookAddress,
ismFactoryAddresses,
} as TokenRouterConfig;
const owner = randomAddress();
const evmERC20WarpModule = await EvmERC20WarpModule.create({
chain,
config: {
...config,
interchainSecurityModule: ismAddress,
},
multiProvider,
});
expect(owner).to.equal(owner);
const newOwner = randomAddress();
await sendTxs(
await evmERC20WarpModule.update({
...config,
owner: newOwner,
}),
);
const latestConfig = normalizeConfig(await evmERC20WarpModule.read());
expect(latestConfig.owner).to.equal(newOwner);
// No op if the same owner
const txs = await evmERC20WarpModule.update({
...config,
owner: newOwner,
});
expect(txs.length).to.equal(0);
});
});
});

@ -1,5 +1,6 @@
import {
MailboxClient__factory,
Ownable__factory,
TokenRouter__factory,
} from '@hyperlane-xyz/core';
import { buildArtifact as coreBuildArtifact } from '@hyperlane-xyz/core/buildArtifact.js';
@ -11,6 +12,7 @@ import {
addressToBytes32,
assert,
deepEquals,
eqAddress,
isObjEmpty,
normalizeConfig,
rootLogger,
@ -94,7 +96,8 @@ export class EvmERC20WarpModule extends HyperlaneModule<
transactions.push(
...(await this.updateIsm(actualConfig, expectedConfig)),
...(await this.updateRemoteRouters(actualConfig, expectedConfig)),
...this.updateRemoteRouters(actualConfig, expectedConfig),
...this.updateOwnership(actualConfig, expectedConfig),
);
return transactions;
@ -107,10 +110,10 @@ export class EvmERC20WarpModule extends HyperlaneModule<
* @param expectedConfig - The expected token router configuration.
* @returns A array with a single Ethereum transaction that need to be executed to enroll the routers
*/
async updateRemoteRouters(
updateRemoteRouters(
actualConfig: TokenRouterConfig,
expectedConfig: TokenRouterConfig,
): Promise<AnnotatedEV5Transaction[]> {
): AnnotatedEV5Transaction[] {
const updateTransactions: AnnotatedEV5Transaction[] = [];
if (!expectedConfig.remoteRouters) {
return [];
@ -202,6 +205,35 @@ export class EvmERC20WarpModule extends HyperlaneModule<
return updateTransactions;
}
/**
* Transfer ownership of an existing Warp route with a given config.
*
* @param actualConfig - The on-chain router configuration.
* @param expectedConfig - The expected token router configuration.
* @returns Ethereum transaction that need to be executed to update the owner.
*/
updateOwnership(
actualConfig: TokenRouterConfig,
expectedConfig: TokenRouterConfig,
): AnnotatedEV5Transaction[] {
const updateTransactions: AnnotatedEV5Transaction[] = [];
if (!eqAddress(actualConfig.owner, expectedConfig.owner)) {
const { deployedTokenRoute } = this.args.addresses;
const { owner: newOwner } = expectedConfig;
updateTransactions.push({
annotation: `Transferring ownership of Warp route ${deployedTokenRoute} to ${newOwner}`,
chainId: this.domainId,
to: deployedTokenRoute,
data: Ownable__factory.createInterface().encodeFunctionData(
'transferOwnership(address)',
[newOwner],
),
});
}
return updateTransactions;
}
/**
* Updates or deploys the ISM using the provided configuration.
*

Loading…
Cancel
Save