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

feat: WarpModule with create() #3838

Merged
merged 80 commits into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from 79 commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
eb2172a
Saving initial work
ltyu Apr 29, 2024
8ac752b
draft push
paulbalaji Apr 30, 2024
3686051
Add read to WarpCrud, change totalSupply to use zod schema type, some…
ltyu Apr 30, 2024
2c74413
Derive WarpConfig from TokenRouter address (#3671)
ltyu Apr 29, 2024
fc4a8a4
Saving initial work
ltyu Apr 29, 2024
4da8778
Add read to WarpCrud, change totalSupply to use zod schema type, some…
ltyu Apr 30, 2024
0ccaa38
Fix unit tests. Incorporate some of Paul's Abstract CrudModule changes
ltyu Apr 30, 2024
3632eb8
fix conflicts
ltyu Apr 30, 2024
2c524cc
Re-add a few more overwritten merge lines
ltyu Apr 30, 2024
186a185
Add EvmERC20WarpCrudModule.create()
ltyu May 1, 2024
635ccf3
Add deploy given an Ism Object
ltyu May 1, 2024
10bd6cb
draft push
paulbalaji Apr 30, 2024
0378f8c
split deploy/update in EvmIsmCreator
paulbalaji May 2, 2024
e140813
Add update logic for Hook and ISM. This commit excludes working logic…
ltyu May 2, 2024
9b0a464
Fix conflicts
ltyu May 2, 2024
707967e
Fix conflicts
ltyu May 2, 2024
d40417f
Derive WarpConfig from TokenRouter address (#3671)
ltyu Apr 29, 2024
f32e5fc
Saving initial work
ltyu Apr 29, 2024
cd2e1a6
Derive WarpConfig from TokenRouter address (#3671)
ltyu Apr 29, 2024
062a00b
Saving initial work
ltyu Apr 29, 2024
76eb931
Add read to WarpCrud, change totalSupply to use zod schema type, some…
ltyu Apr 30, 2024
4e30f18
Fix unit tests. Incorporate some of Paul's Abstract CrudModule changes
ltyu Apr 30, 2024
d4cb141
Add read to WarpCrud, change totalSupply to use zod schema type, some…
ltyu Apr 30, 2024
c3ae3bf
Re-add a few more overwritten merge lines
ltyu Apr 30, 2024
fdc41f4
Add EvmERC20WarpCrudModule.create()
ltyu May 1, 2024
1efd295
Add deploy given an Ism Object
ltyu May 1, 2024
3d27f80
Add update logic for Hook and ISM. This commit excludes working logic…
ltyu May 2, 2024
d435b76
Ensure owners are configured correctly (#3677)
yorhodes Apr 30, 2024
8fcc2bc
Migrate SDK consts to Registry and use new registry utilities (#3615)
jmrossy May 1, 2024
80cc359
Avoid sinon import in exported lib files (#3685)
jmrossy May 1, 2024
965f8cd
feat: Modular Tx Submission – Create Transformer + Submitter + Builde…
nbayindirli May 1, 2024
3d439b3
export tx provider from sdk & remove safe util from infra (#3694)
nbayindirli May 2, 2024
c820d15
do not exit if @safe-global/protocol-kit/**/Multi_send.ts dne (#3696)
nbayindirli May 2, 2024
886b2b9
add defaultDescription to yargs --key option (#3697)
nbayindirli May 2, 2024
9e4c0d2
Fix conflicts
ltyu May 2, 2024
2b65365
Fix conflicts... again
ltyu May 3, 2024
9ac51d3
Fix conflicts
ltyu May 3, 2024
7be39b7
Merge branch 'main' into warpCrudModule
ltyu May 3, 2024
43fac78
Implement deployIsm(), clean up duplicate unit tests, add ismFactoryA…
ltyu May 6, 2024
71849ce
Update to use type DerivedTokenRouterConfig instead of base TokenRout…
ltyu May 6, 2024
5a2a289
Add changeset
ltyu May 6, 2024
d5b615d
Fix test name add comments
ltyu May 6, 2024
119e2e5
Merge branch 'main' into warpCrudModule
ltyu May 6, 2024
9d17eec
Fix conflicts
ltyu May 9, 2024
fc37f4e
Fix conflicts - moved additional logic in reader.ts into new EvmERC20…
ltyu May 13, 2024
988151e
Update according to PR comments
ltyu May 13, 2024
3bffa94
Updates according to comments, IsmConfig to always be an object inste…
ltyu May 14, 2024
88f5a41
Remove Hyperlane from name
ltyu May 14, 2024
3c64619
Use Promise.all, reduce extra read() calls
ltyu May 14, 2024
3b1e502
Update updateHook()
ltyu May 14, 2024
497111d
Add logic to encode tx instead of populateTransaction()
ltyu May 15, 2024
b6c2ba3
Add test4
ltyu May 15, 2024
0f2c953
Update tests to use chain, param
ltyu May 15, 2024
ab25db8
Update ProxyFactoryFactoriesSchema vals to be strings
ltyu May 15, 2024
2921096
nan ism module for cherry-picking
paulbalaji May 16, 2024
1a66022
Remove 'crud' from name. Update unit test to accomedate test4. Update…
ltyu May 16, 2024
fa8024a
Update AddressIsmConfig to CustomIsmConfig
ltyu May 16, 2024
d095c35
Update IsmConfig to use custom instead of address
ltyu May 16, 2024
67ec6b0
Merge branch 'cli-2.0' into warpCrudModule
ltyu May 16, 2024
72de4c5
Add Custom Type to DeployedIsmType
ltyu May 16, 2024
40344ac
Merge branch 'warpCrudModule' of https://github.com/hyperlane-xyz/hyp…
ltyu May 16, 2024
dddd0cf
Merge branch 'cli-2.0' into warpCrudModule
ltyu May 21, 2024
50d5d80
Update to fix bug deriving native and synthetic
ltyu May 21, 2024
2e34aaf
Rip out update logic
ltyu May 22, 2024
bd31efe
Update according to PR comments
ltyu May 23, 2024
26fb6d8
Add new changeset file
ltyu May 24, 2024
95b1945
Update typescript/sdk/src/token/EvmERC20WarpModule.ts
ltyu May 24, 2024
33957ea
Update typescript/sdk/src/token/EvmERC20WarpModule.ts
ltyu May 24, 2024
e99f375
Split out WarpModule and Reader tests
ltyu May 24, 2024
911da47
Clean up deploy.hardhat-test.ts
ltyu May 24, 2024
a910681
Add additional tests for create(), support collateralVault test.
ltyu May 24, 2024
07e68f1
Fix linter errors
ltyu May 24, 2024
9bd4308
yorke PR review
ltyu May 28, 2024
e726f08
Fix conflicts
ltyu Jun 5, 2024
7b40cca
Add deriveNative. Update to simplify deriveTokenType, to use TokenRou…
ltyu Jun 5, 2024
526bfca
Add custom type to descriptions
ltyu Jun 5, 2024
ee18f2b
Merge branch 'cli-2.0' into warpCrudModule_createOnly
ltyu Jun 5, 2024
b43bdd4
Revert promise.any
ltyu Jun 5, 2024
e05cd60
Remove extra deploy test
ltyu Jun 5, 2024
d28ab7d
Update according to PR review
ltyu Jun 6, 2024
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
5 changes: 5 additions & 0 deletions .changeset/five-baboons-smoke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hyperlane-xyz/sdk': minor
---

Add EvmWarpModule with create()
1 change: 1 addition & 0 deletions typescript/cli/src/config/ism.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ const ISM_TYPE_DESCRIPTIONS: Record<IsmType, string> = {
'ISM where you can deliver messages without any validation (WARNING: only for testing, do not use in production)',
[IsmType.OP_STACK]: '',
[IsmType.PAUSABLE]: '',
[IsmType.CUSTOM]: '',
ltyu marked this conversation as resolved.
Show resolved Hide resolved
};

export async function createIsmConfig(
Expand Down
1 change: 1 addition & 0 deletions typescript/sdk/src/hook/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export enum OnchainHookType {
}

export enum HookType {
ADDRESS = 'address',
ltyu marked this conversation as resolved.
Show resolved Hide resolved
ltyu marked this conversation as resolved.
Show resolved Hide resolved
MERKLE_TREE = 'merkleTreeHook',
INTERCHAIN_GAS_PAYMASTER = 'interchainGasPaymaster',
AGGREGATION = 'aggregationHook',
Expand Down
4 changes: 2 additions & 2 deletions typescript/sdk/src/ism/HyperlaneIsmFactory.hardhat-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,13 +353,13 @@ describe('HyperlaneIsmFactory', async () => {
});
const existingIsm = ism.address;
const domainsBefore = await (ism as DomainRoutingIsm).domains();

// deleting the domain and removing from multiprovider should unenroll the domain
// NB: we'll deploy new multisigIsms for the domains bc of new factories but the routingIsm address should be the same because of existingIsmAddress
delete exampleRoutingConfig.domains['test3'];
multiProvider = multiProvider.intersect([
TestChainName.test1,
'test2',
TestChainName.test2,
ltyu marked this conversation as resolved.
Show resolved Hide resolved
TestChainName.test4,
]).result;
ismFactoryDeployer = new HyperlaneProxyFactoryDeployer(multiProvider);
ismFactory = new HyperlaneIsmFactory(
Expand Down
4 changes: 4 additions & 0 deletions typescript/sdk/src/ism/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { z } from 'zod';

import {
IAggregationIsm,
IInterchainSecurityModule,
IMultisigIsm,
IRoutingIsm,
OPStackIsm,
Expand Down Expand Up @@ -39,6 +40,7 @@ export enum ModuleType {
// this enum can be adjusted as per deployments necessary
// meant for the deployer and checker
export enum IsmType {
CUSTOM = 'custom',
OP_STACK = 'opStackIsm',
ROUTING = 'domainRoutingIsm',
FALLBACK_ROUTING = 'defaultFallbackRoutingIsm',
Expand Down Expand Up @@ -73,6 +75,7 @@ export function ismTypeToModuleType(ismType: IsmType): ModuleType {
case IsmType.OP_STACK:
case IsmType.TEST_ISM:
case IsmType.PAUSABLE:
case IsmType.CUSTOM:
ltyu marked this conversation as resolved.
Show resolved Hide resolved
case IsmType.TRUSTED_RELAYER:
return ModuleType.NULL;
}
Expand Down Expand Up @@ -111,6 +114,7 @@ export type AggregationIsmConfig = {
export type IsmConfig = z.infer<typeof IsmConfigSchema>;

export type DeployedIsmType = {
[IsmType.CUSTOM]: IInterchainSecurityModule;
[IsmType.ROUTING]: IRoutingIsm;
[IsmType.FALLBACK_ROUTING]: IRoutingIsm;
[IsmType.AGGREGATION]: IAggregationIsm;
Expand Down
203 changes: 203 additions & 0 deletions typescript/sdk/src/token/EvmERC20WarpModule.hardhat-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers.js';
import { expect } from 'chai';
import { constants } from 'ethers';
import hre from 'hardhat';

import {
ERC20Test,
ERC20Test__factory,
ERC4626Test__factory,
GasRouter,
HypERC20CollateralVaultDeposit__factory,
HypERC20__factory,
HypNative__factory,
Mailbox,
Mailbox__factory,
} from '@hyperlane-xyz/core';
import {
HyperlaneContractsMap,
RouterConfig,
TestChainName,
} from '@hyperlane-xyz/sdk';

import { TestCoreApp } from '../core/TestCoreApp.js';
import { TestCoreDeployer } from '../core/TestCoreDeployer.js';
import { HyperlaneProxyFactoryDeployer } from '../deploy/HyperlaneProxyFactoryDeployer.js';
import { ProxyFactoryFactories } from '../deploy/contracts.js';
import { HyperlaneIsmFactory } from '../ism/HyperlaneIsmFactory.js';
import { MultiProvider } from '../providers/MultiProvider.js';
import { ChainMap } from '../types.js';

import { EvmERC20WarpModule } from './EvmERC20WarpModule.js';
import { TokenType } from './config.js';
import { TokenRouterConfig } from './schemas.js';

describe('EvmERC20WarpHyperlaneModule', async () => {
const TOKEN_NAME = 'fake';
const TOKEN_SUPPLY = '100000000000000000000';
const TOKEN_DECIMALS = 18;
const chain = TestChainName.test4;
let mailbox: Mailbox;
let hookAddress: string;
let ismFactory: HyperlaneIsmFactory;
let factories: HyperlaneContractsMap<ProxyFactoryFactories>;
let erc20Factory: ERC20Test__factory;
let token: ERC20Test;
let signer: SignerWithAddress;
let multiProvider: MultiProvider;
let coreApp: TestCoreApp;
let routerConfigMap: ChainMap<RouterConfig>;
let baseConfig: RouterConfig;

async function validateCoreValues(deployedToken: GasRouter) {
expect(await deployedToken.mailbox()).to.equal(mailbox.address);
expect(await deployedToken.hook()).to.equal(hookAddress);
expect(await deployedToken.interchainSecurityModule()).to.equal(
constants.AddressZero,
);
expect(await deployedToken.owner()).to.equal(signer.address);
}
before(async () => {
[signer] = await hre.ethers.getSigners();
multiProvider = MultiProvider.createTestMultiProvider({ signer });
const ismFactoryDeployer = new HyperlaneProxyFactoryDeployer(multiProvider);
factories = await ismFactoryDeployer.deploy(
multiProvider.mapKnownChains(() => ({})),
);
ismFactory = new HyperlaneIsmFactory(factories, multiProvider);
coreApp = await new TestCoreDeployer(multiProvider, ismFactory).deployApp();
routerConfigMap = coreApp.getRouterConfig(signer.address);

erc20Factory = new ERC20Test__factory(signer);
token = await erc20Factory.deploy(
TOKEN_NAME,
TOKEN_NAME,
TOKEN_SUPPLY,
TOKEN_DECIMALS,
);

baseConfig = routerConfigMap[chain];

mailbox = Mailbox__factory.connect(baseConfig.mailbox, signer);
hookAddress = await mailbox.defaultHook();
});

it('should create with a a collateral config', async () => {
const config = {
...baseConfig,
type: TokenType.collateral,
token: token.address,
hook: hookAddress,
};

// Deploy using WarpModule
const evmERC20WarpModule = await EvmERC20WarpModule.create({
chain,
config,
multiProvider,
});

// Let's derive it's onchain token type
const { collateral } = evmERC20WarpModule.serialize();
const tokenType: TokenType =
await evmERC20WarpModule.reader.deriveTokenType(collateral);
expect(tokenType).to.equal(TokenType.collateral);
});

it('should create with a collateral vault config', async () => {
const vaultFactory = new ERC4626Test__factory(signer);
const vault = await vaultFactory.deploy(
token.address,
TOKEN_NAME,
TOKEN_NAME,
);
const config = {
type: TokenType.collateralVault,
token: vault.address,
hook: hookAddress,
...baseConfig,
};

// Deploy using WarpModule
const evmERC20WarpModule = await EvmERC20WarpModule.create({
chain,
config,
multiProvider,
});

// Let's derive it's onchain token type
const { collateralVault: collateralVaultAddr } =
evmERC20WarpModule.serialize();
const tokenType: TokenType =
await evmERC20WarpModule.reader.deriveTokenType(collateralVaultAddr);
expect(tokenType).to.equal(TokenType.collateralVault);

// Validate onchain token values
const collateralVault = HypERC20CollateralVaultDeposit__factory.connect(
collateralVaultAddr,
signer,
);
await validateCoreValues(collateralVault);
expect(await collateralVault.vault()).to.equal(vault.address);
expect(await collateralVault.wrappedToken()).to.equal(token.address);
});

it('should create with a a synthetic config', async () => {
const config = {
type: TokenType.synthetic,
token: token.address,
hook: hookAddress,
name: TOKEN_NAME,
symbol: TOKEN_NAME,
decimals: TOKEN_DECIMALS,
totalSupply: TOKEN_SUPPLY,
...baseConfig,
};

// Deploy using WarpModule
const evmERC20WarpModule = await EvmERC20WarpModule.create({
chain,
config,
multiProvider,
});

// Let's derive it's onchain token type
const { synthetic: syntheticAddr } = evmERC20WarpModule.serialize();
const tokenType: TokenType =
await evmERC20WarpModule.reader.deriveTokenType(syntheticAddr);
expect(tokenType).to.equal(TokenType.synthetic);

// Validate onchain token values
const synthetic = HypERC20__factory.connect(syntheticAddr, signer);
await validateCoreValues(synthetic);
expect(await synthetic.name()).to.equal(TOKEN_NAME);
expect(await synthetic.symbol()).to.equal(TOKEN_NAME);
expect(await synthetic.decimals()).to.equal(TOKEN_DECIMALS);
expect(await synthetic.totalSupply()).to.equal(TOKEN_SUPPLY);
});

it('should create with a a native config', async () => {
const config = {
type: TokenType.native,
hook: hookAddress,
...baseConfig,
} as TokenRouterConfig;

// Deploy using WarpModule
const evmERC20WarpModule = await EvmERC20WarpModule.create({
chain,
config,
multiProvider,
});

// Let's derive it's onchain token type
const { native: nativeAddr } = evmERC20WarpModule.serialize();
const tokenType: TokenType =
await evmERC20WarpModule.reader.deriveTokenType(nativeAddr);
expect(tokenType).to.equal(TokenType.native);

// Validate onchain token values
const native = HypNative__factory.connect(nativeAddr, signer);
await validateCoreValues(native);
});
});
97 changes: 97 additions & 0 deletions typescript/sdk/src/token/EvmERC20WarpModule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { Address, ProtocolType, rootLogger } from '@hyperlane-xyz/utils';

import { serializeContracts } from '../contracts/contracts.js';
import { HyperlaneAddresses } from '../contracts/types.js';
import {
HyperlaneModule,
HyperlaneModuleParams,
} from '../core/AbstractHyperlaneModule.js';
import { MultiProvider } from '../providers/MultiProvider.js';
import { AnnotatedEV5Transaction } from '../providers/ProviderType.js';
import { ChainNameOrId } from '../types.js';

import { EvmERC20WarpRouteReader } from './EvmERC20WarpRouteReader.js';
import { HypERC20Factories } from './contracts.js';
import { HypERC20Deployer } from './deploy.js';
import { TokenRouterConfig } from './schemas.js';

export class EvmERC20WarpModule extends HyperlaneModule<
ProtocolType.Ethereum,
TokenRouterConfig,
HyperlaneAddresses<HypERC20Factories> & {
ltyu marked this conversation as resolved.
Show resolved Hide resolved
deployedTokenRoute: Address;
}
> {
protected logger = rootLogger.child({
module: 'EvmERC20WarpModule',
});
reader: EvmERC20WarpRouteReader;

constructor(
protected readonly multiProvider: MultiProvider,
args: HyperlaneModuleParams<
TokenRouterConfig,
HyperlaneAddresses<HypERC20Factories> & {
deployedTokenRoute: Address;
}
ltyu marked this conversation as resolved.
Show resolved Hide resolved
>,
) {
super(args);

this.reader = new EvmERC20WarpRouteReader(multiProvider, args.chain);
}

/**
* Retrieves the token router configuration for the specified address.
*
* @param address - The address to derive the token router configuration from.
* @returns A promise that resolves to the token router configuration.
*/
public async read(): Promise<TokenRouterConfig> {
return this.reader.deriveWarpRouteConfig(
this.args.addresses.deployedTokenRoute,
);
}

/**
* Updates the Warp Route contract with the provided configuration.
*
* @remark Currently only supports updating ISM or hook.
*
* @param expectedConfig - The configuration for the token router to be updated.
* @returns An array of Ethereum transactions that were executed to update the contract, or an error if the update failed.
*/
public async update(
_expectedConfig: TokenRouterConfig,
): Promise<AnnotatedEV5Transaction[]> {
throw Error('Not implemented');
}

/**
* Deploys the Warp Route.
*
* @param chain - The chain to deploy the module on.
* @param config - The configuration for the token router.
* @param multiProvider - The multi-provider instance to use.
* @returns A new instance of the EvmERC20WarpHyperlaneModule.
*/
public static async create(params: {
chain: ChainNameOrId;
config: TokenRouterConfig;
multiProvider: MultiProvider;
}): Promise<EvmERC20WarpModule> {
const { chain, config, multiProvider } = params;
const chainName = multiProvider.getChainName(chain);
const deployer = new HypERC20Deployer(multiProvider);
const deployedContracts = await deployer.deployContracts(chainName, config);

return new EvmERC20WarpModule(multiProvider, {
addresses: {
...serializeContracts(deployedContracts),
ltyu marked this conversation as resolved.
Show resolved Hide resolved
deployedTokenRoute: deployedContracts[config.type].address,
},
chain,
config,
});
}
}
Loading
Loading