Skip to content
Merged
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ An '!' indicates a state machine breaking change.
- ! [#151](https://github.com/bcp-innovations/hyperlane-cosmos/pull/151) Support 32 byte addresses in remote recv collateral.
- ! [#141](https://github.com/bcp-innovations/hyperlane-cosmos/pull/141) Corrected coin comparison.

### Improvements

- ! [#165](https://github.com/bcp-innovations/hyperlane-cosmos/pull/165) Constrain ReceiverContract to HexAddress type.

## [v1.0.1](https://github.com/bcp-innovations/hyperlane-cosmos/releases/tag/v1.0.1) - 2025-06-05

### Improvements
Expand Down
6 changes: 5 additions & 1 deletion proto/hyperlane/warp/v1/events.proto
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,11 @@ message EventEnrollRemoteRouter {
string owner = 2;

uint32 receiver_domain = 3;
string receiver_contract = 4;
string receiver_contract = 4 [
(gogoproto.customtype) =
"github.com/bcp-innovations/hyperlane-cosmos/util.HexAddress",
(gogoproto.nullable) = false
];
string gas = 5 [
(gogoproto.customtype) = "cosmossdk.io/math.Int",
(gogoproto.nullable) = false
Expand Down
8 changes: 7 additions & 1 deletion proto/hyperlane/warp/v1/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,13 @@ message HypToken {
// RemoteRouter ...
message RemoteRouter {
uint32 receiver_domain = 1;
string receiver_contract = 2;

string receiver_contract = 2 [
(gogoproto.customtype) =
"github.com/bcp-innovations/hyperlane-cosmos/util.HexAddress",
(gogoproto.nullable) = false
];

string gas = 3 [
(gogoproto.customtype) = "cosmossdk.io/math.Int",
(gogoproto.nullable) = false
Expand Down
4 changes: 2 additions & 2 deletions x/warp/client/cli/tx_enroll_remote_router.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func CmdEnrollRemoteRouter() *cobra.Command {
return err
}

_, err = util.DecodeHexAddress(args[2])
receiverContract, err := util.DecodeHexAddress(args[2])
if err != nil {
return fmt.Errorf("failed to decode receiver contract address %s", args[2])
}
Expand All @@ -53,7 +53,7 @@ func CmdEnrollRemoteRouter() *cobra.Command {
TokenId: tokenId,
RemoteRouter: &types.RemoteRouter{
ReceiverDomain: uint32(receiverDomain),
ReceiverContract: args[2],
ReceiverContract: receiverContract,
Gas: gas,
},
}
Expand Down
3 changes: 1 addition & 2 deletions x/warp/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"fmt"
"slices"
"strings"

"cosmossdk.io/math"

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

if message.Sender.String() != strings.ToLower(remoteRouter.ReceiverContract) {
if !message.Sender.Equal(remoteRouter.ReceiverContract) {
return fmt.Errorf("invalid receiver contract")
}

Expand Down
7 changes: 1 addition & 6 deletions x/warp/keeper/logic_collateral.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,6 @@ func (k *Keeper) RemoteTransferCollateral(ctx sdk.Context, token types.HypToken,
return util.HexAddress{}, fmt.Errorf("no enrolled router found for destination domain %d", destinationDomain)
}

receiverContract, err := util.DecodeHexAddress(remoteRouter.ReceiverContract)
if err != nil {
return util.HexAddress{}, fmt.Errorf("failed to decode receiver contract address %s", remoteRouter.ReceiverContract)
}

gas := remoteRouter.Gas
if !gasLimit.IsZero() {
gas = gasLimit
Expand All @@ -67,7 +62,7 @@ func (k *Keeper) RemoteTransferCollateral(ctx sdk.Context, token types.HypToken,
sdk.NewCoins(maxFee),

remoteRouter.ReceiverDomain,
receiverContract,
remoteRouter.ReceiverContract,

warpPayload.Bytes(), // message body

Expand Down
69 changes: 16 additions & 53 deletions x/warp/keeper/logic_collateral_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,10 @@ var _ = Describe("logic_collateral.go", Ordered, func() {
It("MsgRemoteTransfer (invalid) empty cosmos sender (Collateral)", func() {
// Arrange
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
remoteRouter := types.RemoteRouter{
ReceiverDomain: 1,
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
ReceiverContract: receiverContract,
Gas: math.NewInt(50000),
}

Expand Down Expand Up @@ -117,9 +118,10 @@ var _ = Describe("logic_collateral.go", Ordered, func() {
It("MsgRemoteTransfer (invalid) invalid cosmos sender (Collateral)", func() {
// Arrange
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
remoteRouter := types.RemoteRouter{
ReceiverDomain: 1,
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
ReceiverContract: receiverContract,
Gas: math.NewInt(50000),
}

Expand Down Expand Up @@ -153,9 +155,10 @@ var _ = Describe("logic_collateral.go", Ordered, func() {
It("MsgRemoteTransfer (invalid) no enrolled router for destination (Collateral)", func() {
// Arrange
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
remoteRouter := types.RemoteRouter{
ReceiverDomain: 1,
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
ReceiverContract: receiverContract,
Gas: math.NewInt(50000),
}

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

It("MsgRemoteTransfer (invalid) receiver contract (Collateral)", func() {
// Arrange
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
remoteRouter := types.RemoteRouter{
ReceiverDomain: 1,
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865de",
Gas: math.NewInt(50000),
}

amount := math.NewInt(100)
maxFee := sdk.NewCoin(denom, math.NewInt(250000))

tokenId, _, igpId, _ := createToken(s, &remoteRouter, owner.Address, sender.Address, types.HYP_TOKEN_TYPE_COLLATERAL)

err := s.MintBaseCoins(sender.Address, 1_000_000)
Expect(err).To(BeNil())

senderBalance := s.App().BankKeeper.GetBalance(s.Ctx(), sender.AccAddress, denom)

// Act
_, err = s.RunTx(&types.MsgRemoteTransfer{
Sender: sender.Address,
TokenId: tokenId,
DestinationDomain: remoteRouter.ReceiverDomain,
Recipient: receiverAddress,
Amount: amount,
CustomHookId: &igpId,
GasLimit: math.ZeroInt(),
MaxFee: maxFee,
})

// Assert
Expect(err.Error()).To(Equal(fmt.Sprintf("failed to decode receiver contract address %s", remoteRouter.ReceiverContract)))
Expect(s.App().BankKeeper.GetBalance(s.Ctx(), sender.AccAddress, denom).Amount).To(Equal(senderBalance.Amount))
})

It("MsgRemoteTransfer (invalid) insufficient funds (Collateral)", func() {
// Arrange
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
remoteRouter := types.RemoteRouter{
ReceiverDomain: 1,
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
ReceiverContract: receiverContract,
Gas: math.NewInt(50000),
}

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

It("MsgRemoteTransfer & MsgRemoteReceiveCollateral (invalid) not enough collateral (Collateral)", func() {
// Arrange
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
remoteRouter := types.RemoteRouter{
ReceiverDomain: 1,
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
ReceiverContract: receiverContract,
Gas: math.NewInt(50000),
}

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

// Act
receiverContract, err := util.DecodeHexAddress(remoteRouter.ReceiverContract)
Expect(err).To(BeNil())

warpRecipient, err := sdk.GetFromBech32(sender.Address, "hyp")
Expect(err).To(BeNil())

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

It("MsgRemoteTransfer && MsgRemoteReceiveCollateral (valid) (Collateral)", func() {
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")

// Arrange
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
remoteRouter := types.RemoteRouter{
ReceiverDomain: 1,
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
ReceiverContract: receiverContract,
Gas: math.NewInt(50000),
}

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

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

receiverContract, err := util.DecodeHexAddress(remoteRouter.ReceiverContract)
Expect(err).To(BeNil())

warpRecipient, err := sdk.GetFromBech32(sender.Address, "hyp")
Expect(err).To(BeNil())

Expand All @@ -349,7 +314,7 @@ var _ = Describe("logic_collateral.go", Ordered, func() {
Version: 3,
Nonce: 1,
Origin: remoteRouter.ReceiverDomain,
Sender: receiverContract,
Sender: remoteRouter.ReceiverContract,
Destination: 0,
Recipient: tokenId,
Body: warpPayload.Bytes(),
Expand All @@ -372,9 +337,10 @@ var _ = Describe("logic_collateral.go", Ordered, func() {
It("MsgRemoteTransfer && MsgRemoteReceiveCollateral (valid) 32-byte address (Collateral)", func() {
// Arrange
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
remoteRouter := types.RemoteRouter{
ReceiverDomain: 1,
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
ReceiverContract: receiverContract,
Gas: math.NewInt(50000),
}

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

receiverContract, err := util.DecodeHexAddress(remoteRouter.ReceiverContract)
Expect(err).To(BeNil())

warpRecipient := address.Module(types.ModuleName, []byte("collateral-receiver"))
Expect(len(warpRecipient)).To(Equal(address.Len))

Expand Down
7 changes: 1 addition & 6 deletions x/warp/keeper/logic_synthetic.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,6 @@ func (k *Keeper) RemoteTransferSynthetic(ctx sdk.Context, token types.HypToken,
return util.HexAddress{}, fmt.Errorf("no enrolled router found for destination domain %d", destinationDomain)
}

receiverContract, err := util.DecodeHexAddress(remoteRouter.ReceiverContract)
if err != nil {
return util.HexAddress{}, fmt.Errorf("failed to decode receiver contract address %s", remoteRouter.ReceiverContract)
}

gas := remoteRouter.Gas
if !gasLimit.IsZero() {
gas = gasLimit
Expand All @@ -67,7 +62,7 @@ func (k *Keeper) RemoteTransferSynthetic(ctx sdk.Context, token types.HypToken,
sdk.NewCoins(maxFee),

remoteRouter.ReceiverDomain,
receiverContract,
remoteRouter.ReceiverContract,

warpPayload.Bytes(),
util.StandardHookMetadata{
Expand Down
59 changes: 10 additions & 49 deletions x/warp/keeper/logic_synthetic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,10 @@ var _ = Describe("logic_synthetic.go", Ordered, func() {
It("MsgRemoteTransfer (invalid) empty cosmos sender (Synthetic)", func() {
// Arrange
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
remoteRouter := types.RemoteRouter{
ReceiverDomain: 1,
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
ReceiverContract: receiverContract,
Gas: math.NewInt(50000),
}

Expand Down Expand Up @@ -125,9 +126,10 @@ var _ = Describe("logic_synthetic.go", Ordered, func() {
It("MsgRemoteTransfer (invalid) invalid cosmos sender (Synthetic)", func() {
// Arrange
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
remoteRouter := types.RemoteRouter{
ReceiverDomain: 1,
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
ReceiverContract: receiverContract,
Gas: math.NewInt(50000),
}

Expand Down Expand Up @@ -166,9 +168,10 @@ var _ = Describe("logic_synthetic.go", Ordered, func() {
It("MsgRemoteTransfer (invalid) no enrolled router for destination (Synthetic)", func() {
// Arrange
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
remoteRouter := types.RemoteRouter{
ReceiverDomain: 1,
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
ReceiverContract: receiverContract,
Gas: math.NewInt(50000),
}

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

It("MsgRemoteTransfer (invalid) receiver contract (Synthetic)", func() {
// Arrange
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
remoteRouter := types.RemoteRouter{
ReceiverDomain: 1,
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865de",
Gas: math.NewInt(50000),
}

amount := math.NewInt(100)
maxFee := sdk.NewCoin(denom, math.NewInt(250000))

tokenId, _, igpId, _ := createToken(s, &remoteRouter, owner.Address, sender.Address, types.HYP_TOKEN_TYPE_SYNTHETIC)

syntheticDenom := "hyperlane/" + tokenId.String()

err := s.MintBaseCoins(sender.Address, math.NewInt(maxFee.Amount.Int64()).Uint64())
Expect(err).To(BeNil())

err = s.MintCoins(sender.Address, sdk.NewCoins(sdk.NewInt64Coin(syntheticDenom, amount.Int64())))
Expect(err).To(BeNil())

senderBalance := s.App().BankKeeper.GetBalance(s.Ctx(), sender.AccAddress, syntheticDenom)

// Act
_, err = s.RunTx(&types.MsgRemoteTransfer{
Sender: sender.Address,
TokenId: tokenId,
DestinationDomain: remoteRouter.ReceiverDomain,
Recipient: receiverAddress,
Amount: amount,
CustomHookId: &igpId,
GasLimit: math.ZeroInt(),
MaxFee: maxFee,
})

// Assert
Expect(err.Error()).To(Equal(fmt.Sprintf("failed to decode receiver contract address %s", remoteRouter.ReceiverContract)))
Expect(s.App().BankKeeper.GetBalance(s.Ctx(), sender.AccAddress, syntheticDenom).Amount).To(Equal(senderBalance.Amount))
})

It("MsgRemoteTransfer (invalid) insufficient funds (Synthetic)", func() {
// Arrange
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
remoteRouter := types.RemoteRouter{
ReceiverDomain: 1,
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
ReceiverContract: receiverContract,
Gas: math.NewInt(50000),
}

Expand Down Expand Up @@ -283,9 +246,10 @@ var _ = Describe("logic_synthetic.go", Ordered, func() {
It("MsgRemoteTransfer && MsgRemoteReceiveSynthetic (valid) (Synthetic)", func() {
// Arrange
receiverAddress, _ := util.DecodeHexAddress("0xd7194459d45619d04a5a0f9e78dc9594a0f37fd6da8382fe12ddda6f2f46d647")
receiverContract, _ := util.DecodeHexAddress("0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0")
remoteRouter := types.RemoteRouter{
ReceiverDomain: 1,
ReceiverContract: "0x934b867052ca9c65e33362112f35fb548f8732c2fe45f07b9c591958e865def0",
ReceiverContract: receiverContract,
Gas: math.NewInt(50000),
}

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

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

receiverContract, err := util.DecodeHexAddress(remoteRouter.ReceiverContract)
Expect(err).To(BeNil())

warpRecipient, err := sdk.GetFromBech32(sender.Address, "hyp")
Expect(err).To(BeNil())

Expand Down
Loading
Loading