Skip to content

Commit b3baa82

Browse files
authored
chore(warp): constrain ReceiverContract to HexAddress type (#165)
1 parent 55370da commit b3baa82

14 files changed

Lines changed: 185 additions & 257 deletions

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ An '!' indicates a state machine breaking change.
3333
- ! [#151](https://github.com/bcp-innovations/hyperlane-cosmos/pull/151) Support 32 byte addresses in remote recv collateral.
3434
- ! [#141](https://github.com/bcp-innovations/hyperlane-cosmos/pull/141) Corrected coin comparison.
3535

36+
### Improvements
37+
38+
- ! [#165](https://github.com/bcp-innovations/hyperlane-cosmos/pull/165) Constrain ReceiverContract to HexAddress type.
39+
3640
## [v1.0.1](https://github.com/bcp-innovations/hyperlane-cosmos/releases/tag/v1.0.1) - 2025-06-05
3741

3842
### Improvements

proto/hyperlane/warp/v1/events.proto

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,11 @@ message EventEnrollRemoteRouter {
5757
string owner = 2;
5858

5959
uint32 receiver_domain = 3;
60-
string receiver_contract = 4;
60+
string receiver_contract = 4 [
61+
(gogoproto.customtype) =
62+
"github.com/bcp-innovations/hyperlane-cosmos/util.HexAddress",
63+
(gogoproto.nullable) = false
64+
];
6165
string gas = 5 [
6266
(gogoproto.customtype) = "cosmossdk.io/math.Int",
6367
(gogoproto.nullable) = false

proto/hyperlane/warp/v1/types.proto

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,13 @@ message HypToken {
4242
// RemoteRouter ...
4343
message RemoteRouter {
4444
uint32 receiver_domain = 1;
45-
string receiver_contract = 2;
45+
46+
string receiver_contract = 2 [
47+
(gogoproto.customtype) =
48+
"github.com/bcp-innovations/hyperlane-cosmos/util.HexAddress",
49+
(gogoproto.nullable) = false
50+
];
51+
4652
string gas = 3 [
4753
(gogoproto.customtype) = "cosmossdk.io/math.Int",
4854
(gogoproto.nullable) = false

x/warp/client/cli/tx_enroll_remote_router.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func CmdEnrollRemoteRouter() *cobra.Command {
4343
return err
4444
}
4545

46-
_, err = util.DecodeHexAddress(args[2])
46+
receiverContract, err := util.DecodeHexAddress(args[2])
4747
if err != nil {
4848
return fmt.Errorf("failed to decode receiver contract address %s", args[2])
4949
}
@@ -53,7 +53,7 @@ func CmdEnrollRemoteRouter() *cobra.Command {
5353
TokenId: tokenId,
5454
RemoteRouter: &types.RemoteRouter{
5555
ReceiverDomain: uint32(receiverDomain),
56-
ReceiverContract: args[2],
56+
ReceiverContract: receiverContract,
5757
Gas: gas,
5858
},
5959
}

x/warp/keeper/keeper.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"fmt"
66
"slices"
7-
"strings"
87

98
"cosmossdk.io/math"
109

@@ -123,7 +122,7 @@ func (k *Keeper) Handle(ctx context.Context, mailboxId util.HexAddress, message
123122
return fmt.Errorf("no enrolled router found for origin %d", message.Origin)
124123
}
125124

126-
if message.Sender.String() != strings.ToLower(remoteRouter.ReceiverContract) {
125+
if !message.Sender.Equal(remoteRouter.ReceiverContract) {
127126
return fmt.Errorf("invalid receiver contract")
128127
}
129128

x/warp/keeper/logic_collateral.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,6 @@ func (k *Keeper) RemoteTransferCollateral(ctx sdk.Context, token types.HypToken,
3636
return util.HexAddress{}, fmt.Errorf("no enrolled router found for destination domain %d", destinationDomain)
3737
}
3838

39-
receiverContract, err := util.DecodeHexAddress(remoteRouter.ReceiverContract)
40-
if err != nil {
41-
return util.HexAddress{}, fmt.Errorf("failed to decode receiver contract address %s", remoteRouter.ReceiverContract)
42-
}
43-
4439
gas := remoteRouter.Gas
4540
if !gasLimit.IsZero() {
4641
gas = gasLimit
@@ -67,7 +62,7 @@ func (k *Keeper) RemoteTransferCollateral(ctx sdk.Context, token types.HypToken,
6762
sdk.NewCoins(maxFee),
6863

6964
remoteRouter.ReceiverDomain,
70-
receiverContract,
65+
remoteRouter.ReceiverContract,
7166

7267
warpPayload.Bytes(), // message body
7368

x/warp/keeper/logic_collateral_test.go

Lines changed: 16 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -81,9 +81,10 @@ var _ = Describe("logic_collateral.go", Ordered, func() {
8181
It("MsgRemoteTransfer (invalid) empty cosmos sender (Collateral)", func() {
8282
// Arrange
8383
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
84+
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
8485
remoteRouter := types.RemoteRouter{
8586
ReceiverDomain: 1,
86-
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
87+
ReceiverContract: receiverContract,
8788
Gas: math.NewInt(50000),
8889
}
8990

@@ -117,9 +118,10 @@ var _ = Describe("logic_collateral.go", Ordered, func() {
117118
It("MsgRemoteTransfer (invalid) invalid cosmos sender (Collateral)", func() {
118119
// Arrange
119120
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
121+
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
120122
remoteRouter := types.RemoteRouter{
121123
ReceiverDomain: 1,
122-
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
124+
ReceiverContract: receiverContract,
123125
Gas: math.NewInt(50000),
124126
}
125127

@@ -153,9 +155,10 @@ var _ = Describe("logic_collateral.go", Ordered, func() {
153155
It("MsgRemoteTransfer (invalid) no enrolled router for destination (Collateral)", func() {
154156
// Arrange
155157
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
158+
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
156159
remoteRouter := types.RemoteRouter{
157160
ReceiverDomain: 1,
158-
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
161+
ReceiverContract: receiverContract,
159162
Gas: math.NewInt(50000),
160163
}
161164

@@ -186,48 +189,13 @@ var _ = Describe("logic_collateral.go", Ordered, func() {
186189
Expect(s.App().BankKeeper.GetBalance(s.Ctx(), sender.AccAddress, denom).Amount).To(Equal(senderBalance.Amount))
187190
})
188191

189-
It("MsgRemoteTransfer (invalid) receiver contract (Collateral)", func() {
190-
// Arrange
191-
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
192-
remoteRouter := types.RemoteRouter{
193-
ReceiverDomain: 1,
194-
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865de",
195-
Gas: math.NewInt(50000),
196-
}
197-
198-
amount := math.NewInt(100)
199-
maxFee := sdk.NewCoin(denom, math.NewInt(250000))
200-
201-
tokenId, _, igpId, _ := createToken(s, &remoteRouter, owner.Address, sender.Address, types.HYP_TOKEN_TYPE_COLLATERAL)
202-
203-
err := s.MintBaseCoins(sender.Address, 1_000_000)
204-
Expect(err).To(BeNil())
205-
206-
senderBalance := s.App().BankKeeper.GetBalance(s.Ctx(), sender.AccAddress, denom)
207-
208-
// Act
209-
_, err = s.RunTx(&types.MsgRemoteTransfer{
210-
Sender: sender.Address,
211-
TokenId: tokenId,
212-
DestinationDomain: remoteRouter.ReceiverDomain,
213-
Recipient: receiverAddress,
214-
Amount: amount,
215-
CustomHookId: &igpId,
216-
GasLimit: math.ZeroInt(),
217-
MaxFee: maxFee,
218-
})
219-
220-
// Assert
221-
Expect(err.Error()).To(Equal(fmt.Sprintf("failed to decode receiver contract address %s", remoteRouter.ReceiverContract)))
222-
Expect(s.App().BankKeeper.GetBalance(s.Ctx(), sender.AccAddress, denom).Amount).To(Equal(senderBalance.Amount))
223-
})
224-
225192
It("MsgRemoteTransfer (invalid) insufficient funds (Collateral)", func() {
226193
// Arrange
227194
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
195+
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
228196
remoteRouter := types.RemoteRouter{
229197
ReceiverDomain: 1,
230-
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
198+
ReceiverContract: receiverContract,
231199
Gas: math.NewInt(50000),
232200
}
233201

@@ -257,9 +225,10 @@ var _ = Describe("logic_collateral.go", Ordered, func() {
257225

258226
It("MsgRemoteTransfer & MsgRemoteReceiveCollateral (invalid) not enough collateral (Collateral)", func() {
259227
// Arrange
228+
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
260229
remoteRouter := types.RemoteRouter{
261230
ReceiverDomain: 1,
262-
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
231+
ReceiverContract: receiverContract,
263232
Gas: math.NewInt(50000),
264233
}
265234

@@ -273,9 +242,6 @@ var _ = Describe("logic_collateral.go", Ordered, func() {
273242
senderBalance := s.App().BankKeeper.GetBalance(s.Ctx(), sender.AccAddress, denom)
274243

275244
// Act
276-
receiverContract, err := util.DecodeHexAddress(remoteRouter.ReceiverContract)
277-
Expect(err).To(BeNil())
278-
279245
warpRecipient, err := sdk.GetFromBech32(sender.Address, "hyp")
280246
Expect(err).To(BeNil())
281247

@@ -305,11 +271,13 @@ var _ = Describe("logic_collateral.go", Ordered, func() {
305271
})
306272

307273
It("MsgRemoteTransfer && MsgRemoteReceiveCollateral (valid) (Collateral)", func() {
274+
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
275+
308276
// Arrange
309277
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
310278
remoteRouter := types.RemoteRouter{
311279
ReceiverDomain: 1,
312-
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
280+
ReceiverContract: receiverContract,
313281
Gas: math.NewInt(50000),
314282
}
315283

@@ -336,9 +304,6 @@ var _ = Describe("logic_collateral.go", Ordered, func() {
336304

337305
Expect(s.App().BankKeeper.GetBalance(s.Ctx(), sender.AccAddress, denom).Amount).To(Equal(senderBalance.Amount.Sub(amount.Add(maxFee.Amount))))
338306

339-
receiverContract, err := util.DecodeHexAddress(remoteRouter.ReceiverContract)
340-
Expect(err).To(BeNil())
341-
342307
warpRecipient, err := sdk.GetFromBech32(sender.Address, "hyp")
343308
Expect(err).To(BeNil())
344309

@@ -349,7 +314,7 @@ var _ = Describe("logic_collateral.go", Ordered, func() {
349314
Version: 3,
350315
Nonce: 1,
351316
Origin: remoteRouter.ReceiverDomain,
352-
Sender: receiverContract,
317+
Sender: remoteRouter.ReceiverContract,
353318
Destination: 0,
354319
Recipient: tokenId,
355320
Body: warpPayload.Bytes(),
@@ -372,9 +337,10 @@ var _ = Describe("logic_collateral.go", Ordered, func() {
372337
It("MsgRemoteTransfer && MsgRemoteReceiveCollateral (valid) 32-byte address (Collateral)", func() {
373338
// Arrange
374339
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
340+
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
375341
remoteRouter := types.RemoteRouter{
376342
ReceiverDomain: 1,
377-
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
343+
ReceiverContract: receiverContract,
378344
Gas: math.NewInt(50000),
379345
}
380346

@@ -398,9 +364,6 @@ var _ = Describe("logic_collateral.go", Ordered, func() {
398364
})
399365
Expect(err).To(BeNil())
400366

401-
receiverContract, err := util.DecodeHexAddress(remoteRouter.ReceiverContract)
402-
Expect(err).To(BeNil())
403-
404367
warpRecipient := address.Module(types.ModuleName, []byte("collateral-receiver"))
405368
Expect(len(warpRecipient)).To(Equal(address.Len))
406369

x/warp/keeper/logic_synthetic.go

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,6 @@ func (k *Keeper) RemoteTransferSynthetic(ctx sdk.Context, token types.HypToken,
3636
return util.HexAddress{}, fmt.Errorf("no enrolled router found for destination domain %d", destinationDomain)
3737
}
3838

39-
receiverContract, err := util.DecodeHexAddress(remoteRouter.ReceiverContract)
40-
if err != nil {
41-
return util.HexAddress{}, fmt.Errorf("failed to decode receiver contract address %s", remoteRouter.ReceiverContract)
42-
}
43-
4439
gas := remoteRouter.Gas
4540
if !gasLimit.IsZero() {
4641
gas = gasLimit
@@ -67,7 +62,7 @@ func (k *Keeper) RemoteTransferSynthetic(ctx sdk.Context, token types.HypToken,
6762
sdk.NewCoins(maxFee),
6863

6964
remoteRouter.ReceiverDomain,
70-
receiverContract,
65+
remoteRouter.ReceiverContract,
7166

7267
warpPayload.Bytes(),
7368
util.StandardHookMetadata{

x/warp/keeper/logic_synthetic_test.go

Lines changed: 10 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,10 @@ var _ = Describe("logic_synthetic.go", Ordered, func() {
8484
It("MsgRemoteTransfer (invalid) empty cosmos sender (Synthetic)", func() {
8585
// Arrange
8686
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
87+
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
8788
remoteRouter := types.RemoteRouter{
8889
ReceiverDomain: 1,
89-
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
90+
ReceiverContract: receiverContract,
9091
Gas: math.NewInt(50000),
9192
}
9293

@@ -125,9 +126,10 @@ var _ = Describe("logic_synthetic.go", Ordered, func() {
125126
It("MsgRemoteTransfer (invalid) invalid cosmos sender (Synthetic)", func() {
126127
// Arrange
127128
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
129+
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
128130
remoteRouter := types.RemoteRouter{
129131
ReceiverDomain: 1,
130-
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
132+
ReceiverContract: receiverContract,
131133
Gas: math.NewInt(50000),
132134
}
133135

@@ -166,9 +168,10 @@ var _ = Describe("logic_synthetic.go", Ordered, func() {
166168
It("MsgRemoteTransfer (invalid) no enrolled router for destination (Synthetic)", func() {
167169
// Arrange
168170
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
171+
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
169172
remoteRouter := types.RemoteRouter{
170173
ReceiverDomain: 1,
171-
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
174+
ReceiverContract: receiverContract,
172175
Gas: math.NewInt(50000),
173176
}
174177

@@ -204,53 +207,13 @@ var _ = Describe("logic_synthetic.go", Ordered, func() {
204207
Expect(s.App().BankKeeper.GetBalance(s.Ctx(), sender.AccAddress, syntheticDenom).Amount).To(Equal(senderBalance.Amount))
205208
})
206209

207-
It("MsgRemoteTransfer (invalid) receiver contract (Synthetic)", func() {
208-
// Arrange
209-
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
210-
remoteRouter := types.RemoteRouter{
211-
ReceiverDomain: 1,
212-
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865de",
213-
Gas: math.NewInt(50000),
214-
}
215-
216-
amount := math.NewInt(100)
217-
maxFee := sdk.NewCoin(denom, math.NewInt(250000))
218-
219-
tokenId, _, igpId, _ := createToken(s, &remoteRouter, owner.Address, sender.Address, types.HYP_TOKEN_TYPE_SYNTHETIC)
220-
221-
syntheticDenom := "hyperlane/" + tokenId.String()
222-
223-
err := s.MintBaseCoins(sender.Address, math.NewInt(maxFee.Amount.Int64()).Uint64())
224-
Expect(err).To(BeNil())
225-
226-
err = s.MintCoins(sender.Address, sdk.NewCoins(sdk.NewInt64Coin(syntheticDenom, amount.Int64())))
227-
Expect(err).To(BeNil())
228-
229-
senderBalance := s.App().BankKeeper.GetBalance(s.Ctx(), sender.AccAddress, syntheticDenom)
230-
231-
// Act
232-
_, err = s.RunTx(&types.MsgRemoteTransfer{
233-
Sender: sender.Address,
234-
TokenId: tokenId,
235-
DestinationDomain: remoteRouter.ReceiverDomain,
236-
Recipient: receiverAddress,
237-
Amount: amount,
238-
CustomHookId: &igpId,
239-
GasLimit: math.ZeroInt(),
240-
MaxFee: maxFee,
241-
})
242-
243-
// Assert
244-
Expect(err.Error()).To(Equal(fmt.Sprintf("failed to decode receiver contract address %s", remoteRouter.ReceiverContract)))
245-
Expect(s.App().BankKeeper.GetBalance(s.Ctx(), sender.AccAddress, syntheticDenom).Amount).To(Equal(senderBalance.Amount))
246-
})
247-
248210
It("MsgRemoteTransfer (invalid) insufficient funds (Synthetic)", func() {
249211
// Arrange
250212
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
213+
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
251214
remoteRouter := types.RemoteRouter{
252215
ReceiverDomain: 1,
253-
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
216+
ReceiverContract: receiverContract,
254217
Gas: math.NewInt(50000),
255218
}
256219

@@ -283,9 +246,10 @@ var _ = Describe("logic_synthetic.go", Ordered, func() {
283246
It("MsgRemoteTransfer && MsgRemoteReceiveSynthetic (valid) (Synthetic)", func() {
284247
// Arrange
285248
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
249+
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
286250
remoteRouter := types.RemoteRouter{
287251
ReceiverDomain: 1,
288-
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
252+
ReceiverContract: receiverContract,
289253
Gas: math.NewInt(50000),
290254
}
291255

@@ -319,9 +283,6 @@ var _ = Describe("logic_synthetic.go", Ordered, func() {
319283

320284
Expect(s.App().BankKeeper.GetBalance(s.Ctx(), sender.AccAddress, syntheticDenom).Amount.Int64()).To(Equal(senderBalance.Amount.Sub(amount).Int64()))
321285

322-
receiverContract, err := util.DecodeHexAddress(remoteRouter.ReceiverContract)
323-
Expect(err).To(BeNil())
324-
325286
warpRecipient, err := sdk.GetFromBech32(sender.Address, "hyp")
326287
Expect(err).To(BeNil())
327288

0 commit comments

Comments
 (0)