Skip to content

Commit f4ffec3

Browse files
authored
feat: configure default ISM for HyperEVM via upgrade handler (#607)
1 parent 9743884 commit f4ffec3

8 files changed

Lines changed: 144 additions & 0 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
- Configure the default Hyperlane ISM for HyperEVM via upgrade handler. ([#607](https://github.com/noble-assets/noble/pull/607))

app.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,7 @@ func (app *App) RegisterUpgradeHandler() error {
476476
app.ModuleManager,
477477
app.Configurator(),
478478
app.Logger(),
479+
app.HyperlaneKeeper.IsmKeeper,
479480
),
480481
)
481482

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"body": {
3+
"messages": [
4+
{
5+
"@type": "/hyperlane.core.interchain_security.v1.MsgCreateRoutingIsm",
6+
"creator": "noble13am065qmk680w86wya4u9refhnssqwcvgs0sfk",
7+
"routes": []
8+
}
9+
],
10+
"memo": "",
11+
"timeout_height": "0",
12+
"extension_options": [],
13+
"non_critical_extension_options": []
14+
},
15+
"auth_info": {
16+
"signer_infos": [],
17+
"fee": {
18+
"amount": [],
19+
"gas_limit": "200000",
20+
"payer": "",
21+
"granter": ""
22+
},
23+
"tip": null
24+
},
25+
"signatures": []
26+
}

e2e/go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ go 1.24.0
55
require (
66
cosmossdk.io/math v1.5.3
77
cosmossdk.io/x/upgrade v0.1.4
8+
github.com/bcp-innovations/hyperlane-cosmos v1.0.1
89
github.com/circlefin/noble-cctp v0.0.0-20241031192117-4285c94ec194
910
github.com/circlefin/noble-fiattokenfactory v0.0.0-20250123235012-5f9bd9dd2c5b
1011
github.com/cosmos/cosmos-sdk v0.50.14
@@ -208,6 +209,7 @@ require (
208209
github.com/ncruces/go-strftime v0.1.9 // indirect
209210
github.com/oasisprotocol/curve25519-voi v0.0.0-20230904125328-1f23a7beb09a // indirect
210211
github.com/oklog/run v1.1.0 // indirect
212+
github.com/onsi/ginkgo/v2 v2.23.3 // indirect
211213
github.com/onsi/gomega v1.37.0 // indirect
212214
github.com/opencontainers/go-digest v1.0.0 // indirect
213215
github.com/opencontainers/image-spec v1.1.0-rc2 // indirect

e2e/go.sum

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -727,6 +727,8 @@ github.com/aws/aws-sdk-go v1.44.122/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX
727727
github.com/aws/aws-sdk-go v1.44.224 h1:09CiaaF35nRmxrzWZ2uRq5v6Ghg/d2RiPjZnSgtt+RQ=
728728
github.com/aws/aws-sdk-go v1.44.224/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI=
729729
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
730+
github.com/bcp-innovations/hyperlane-cosmos v1.0.1 h1:gT8OqyJ866Q6AHOlIXKxSdLjd0p8crKG9XXERIWoh4c=
731+
github.com/bcp-innovations/hyperlane-cosmos v1.0.1/go.mod h1:3yfa0io5Ii6GmhHWsWl2LEAOEHsqWuMgw2R02+LPogw=
730732
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
731733
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
732734
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -1030,6 +1032,9 @@ github.com/go-playground/validator/v10 v10.11.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4
10301032
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
10311033
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
10321034
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
1035+
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
1036+
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
1037+
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
10331038
github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo=
10341039
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
10351040
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
@@ -1502,6 +1507,8 @@ github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vv
15021507
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
15031508
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
15041509
github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
1510+
github.com/onsi/ginkgo/v2 v2.23.3 h1:edHxnszytJ4lD9D5Jjc4tiDkPBZ3siDeJJkUZJJVkp0=
1511+
github.com/onsi/ginkgo/v2 v2.23.3/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM=
15051512
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
15061513
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
15071514
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=

e2e/upgrade_test.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,23 @@
1717
package e2e_test
1818

1919
import (
20+
"bytes"
21+
"context"
22+
_ "embed"
23+
"path"
2024
"testing"
2125

26+
ismtypes "github.com/bcp-innovations/hyperlane-cosmos/x/core/01_interchain_security/types"
27+
"github.com/cosmos/gogoproto/jsonpb"
2228
"github.com/noble-assets/noble/e2e"
29+
"github.com/strangelove-ventures/interchaintest/v8/chain/cosmos"
30+
"github.com/strangelove-ventures/interchaintest/v8/ibc"
31+
"github.com/stretchr/testify/require"
2332
)
2433

34+
//go:embed data/create_hyperlane_routing_ism.json
35+
var CreateHyperlaneRoutingISM []byte
36+
2537
func TestChainUpgrade(t *testing.T) {
2638
if testing.Short() {
2739
t.Skip("skipping test in short mode.")
@@ -33,8 +45,41 @@ func TestChainUpgrade(t *testing.T) {
3345
{
3446
Image: e2e.LocalImages[0],
3547
UpgradeName: "citadel",
48+
PreUpgrade: func(t *testing.T, ctx context.Context, noble *cosmos.CosmosChain, authority ibc.Wallet, _ *e2e.ICATestSuite) {
49+
val := noble.Validators[0]
50+
file := "create_hyperlane_routing_ism.json"
51+
52+
err := val.WriteFile(ctx, CreateHyperlaneRoutingISM, file)
53+
require.NoError(t, err)
54+
55+
_, err = val.ExecTx(
56+
ctx, authority.KeyName(),
57+
"authority", "execute", path.Join(val.HomeDir(), file),
58+
)
59+
require.NoError(t, err)
60+
61+
stdout, _, err := val.ExecQuery(ctx, "hyperlane", "ism", "isms")
62+
require.NoError(t, err)
63+
res := parseHyperlaneISMsResponse(stdout)
64+
require.Len(t, res.Isms, 1)
65+
},
66+
PostUpgrade: func(t *testing.T, ctx context.Context, noble *cosmos.CosmosChain, _ ibc.Wallet, _ *e2e.ICATestSuite) {
67+
val := noble.Validators[0]
68+
69+
stdout, _, err := val.ExecQuery(ctx, "hyperlane", "ism", "isms")
70+
require.NoError(t, err)
71+
res := parseHyperlaneISMsResponse(stdout)
72+
require.Len(t, res.Isms, 2)
73+
},
3674
},
3775
}
3876

3977
e2e.TestChainUpgrade(t, genesisVersion, upgrades, false)
4078
}
79+
80+
func parseHyperlaneISMsResponse(bz []byte) ismtypes.QueryIsmsResponse {
81+
var res ismtypes.QueryIsmsResponse
82+
_ = jsonpb.Unmarshal(bytes.NewReader(bz), &res)
83+
84+
return res
85+
}

upgrade/constants.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package upgrade
1818

19+
import hyperlaneutil "github.com/bcp-innovations/hyperlane-cosmos/util"
20+
1921
// UpgradeName is the name of this specific software upgrade used on-chain.
2022
const UpgradeName = "citadel"
2123

@@ -36,3 +38,6 @@ const TestnetChainID = "grand-1"
3638

3739
// MainnetChainID is the Chain ID of the Noble mainnet.
3840
const MainnetChainID = "noble-1"
41+
42+
// DefaultISM is the default Hyperlane Routing ISM ID on all Noble networks.
43+
var DefaultISM, _ = hyperlaneutil.DecodeHexAddress("0x726f757465725f69736d00000000000000000000000000010000000000000000")

upgrade/upgrade.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,25 +18,82 @@ package upgrade
1818

1919
import (
2020
"context"
21+
"fmt"
22+
"sort"
2123

2224
"cosmossdk.io/log"
2325
upgradetypes "cosmossdk.io/x/upgrade/types"
26+
ismkeeper "github.com/bcp-innovations/hyperlane-cosmos/x/core/01_interchain_security/keeper"
27+
ismtypes "github.com/bcp-innovations/hyperlane-cosmos/x/core/01_interchain_security/types"
28+
sdk "github.com/cosmos/cosmos-sdk/types"
2429
"github.com/cosmos/cosmos-sdk/types/module"
30+
authoritytypes "github.com/noble-assets/authority/types"
2531
)
2632

2733
func CreateUpgradeHandler(
2834
mm *module.Manager,
2935
cfg module.Configurator,
3036
logger log.Logger,
37+
ismKeeper ismkeeper.Keeper,
3138
) upgradetypes.UpgradeHandler {
3239
return func(ctx context.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) {
40+
sdkCtx := sdk.UnwrapSDKContext(ctx)
41+
3342
vm, err := mm.RunMigrations(ctx, cfg, vm)
3443
if err != nil {
3544
return vm, err
3645
}
3746

47+
// Because the HyperEVM default ISM has already been created on Noble's
48+
// testnet, we only need to run the logic for creating the HyperEVM
49+
// default ISM on Noble's mainnet.
50+
if sdkCtx.ChainID() == MainnetChainID {
51+
err = configureHyperlaneISM(ctx, logger, ismKeeper)
52+
if err != nil {
53+
return vm, err
54+
}
55+
}
56+
3857
logger.Info(UpgradeASCII)
3958

4059
return vm, nil
4160
}
4261
}
62+
63+
func configureHyperlaneISM(ctx context.Context, logger log.Logger, keeper ismkeeper.Keeper) error {
64+
// https://docs.hyperlane.xyz/docs/reference/addresses/validators/mainnet-default-ism-validators#hyperevm-999
65+
const domain = uint32(999)
66+
validators := []string{
67+
"0x01be14a9eceeca36c9c1d46c056ca8c87f77c26f", // Abacus Works
68+
"0xcf0211fafbb91fd9d06d7e306b30032dc3a1934f", // Merkly
69+
"0x4f977a59fdc2d9e39f6d780a84d5b4add1495a36", // Mitosis
70+
"0x04d949c615c9976f89595ddcb9008c92f8ba7278", // Luganodes
71+
}
72+
sort.Strings(validators)
73+
const threshold = uint32(3)
74+
75+
id, err := keeper.CreateMerkleRootMultisigIsm(ctx, &ismtypes.MsgCreateMerkleRootMultisigIsm{
76+
Creator: authoritytypes.ModuleAddress.String(),
77+
Validators: validators,
78+
Threshold: threshold,
79+
})
80+
if err != nil {
81+
return fmt.Errorf("unable to create default ism for domain %d: %w", domain, err)
82+
}
83+
84+
logger.Info("created default hyperlane ism for hyperevm", "domain", domain, "id", id)
85+
86+
err = keeper.SetRoutingIsmDomain(ctx, &ismtypes.MsgSetRoutingIsmDomain{
87+
IsmId: DefaultISM,
88+
Route: ismtypes.Route{
89+
Ism: id,
90+
Domain: domain,
91+
},
92+
Owner: authoritytypes.ModuleAddress.String(),
93+
})
94+
if err != nil {
95+
return fmt.Errorf("unable to set default ism in routing ism: %w", err)
96+
}
97+
98+
return nil
99+
}

0 commit comments

Comments
 (0)