Skip to content
Open
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
7 changes: 7 additions & 0 deletions x/crosschain/keeper/v2_zevm_inbound.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,13 @@ func (k Keeper) getZRC20InboundDetails(
ctx.Logger().Info(fmt.Sprintf("cannot find foreign coin associated to the zrc20 address %s", zrc20.Hex()))
return InboundDetails{}, nil
}
if foreignCoin.Paused {
return InboundDetails{}, errorsmod.Wrapf(
fungibletypes.ErrPausedZRC20,
"zrc20 %s is paused",
zrc20.Hex(),
)
}

receiverChain, found := k.zetaObserverKeeper.GetSupportedChainFromChainID(ctx, foreignCoin.ForeignChainId)
if !found {
Expand Down
58 changes: 58 additions & 0 deletions x/crosschain/keeper/v2_zevm_inbound_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,35 @@ func TestKeeper_GetErc20InboundDetails(t *testing.T) {
require.Empty(t, result)
})

t.Run("fail when foreign coin is paused", func(t *testing.T) {
// ARRANGE
k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
UseFungibleMock: true,
})

zrc20 := sample.EthAddress()
callEvent := false

fungibleMock := keepertest.GetCrosschainFungibleMock(t, k)
foreignCoin := fungibletypes.ForeignCoins{
Zrc20ContractAddress: zrc20.Hex(),
Asset: "USDT",
ForeignChainId: 1,
CoinType: coin.CoinType_ERC20,
Paused: true,
}
Comment on lines +257 to +273

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 In both new paused-coin tests, foreignCoin.Zrc20ContractAddress is a freshly-sampled random address that differs from the zrc20 variable passed as input. In production, GetForeignCoins(ctx, zrc20.Hex()) returns the coin whose Zrc20ContractAddress equals zrc20.Hex(). Using zrc20.Hex() for this field aligns the test fixture with the real data shape, making it immediately clear to a reader that the coin belongs to the same address under test.

Suggested change
t.Run("fail when foreign coin is paused", func(t *testing.T) {
// ARRANGE
k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
UseFungibleMock: true,
})
zrc20 := sample.EthAddress()
callEvent := false
fungibleMock := keepertest.GetCrosschainFungibleMock(t, k)
foreignCoin := fungibletypes.ForeignCoins{
Zrc20ContractAddress: sample.EthAddress().Hex(),
Asset: "USDT",
ForeignChainId: 1,
CoinType: coin.CoinType_ERC20,
Paused: true,
}
t.Run("fail when foreign coin is paused", func(t *testing.T) {
// ARRANGE
k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
UseFungibleMock: true,
})
zrc20 := sample.EthAddress()
callEvent := false
fungibleMock := keepertest.GetCrosschainFungibleMock(t, k)
foreignCoin := fungibletypes.ForeignCoins{
Zrc20ContractAddress: zrc20.Hex(),
Asset: "USDT",
ForeignChainId: 1,
CoinType: coin.CoinType_ERC20,
Paused: true,
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: x/crosschain/keeper/v2_zevm_inbound_test.go
Line: 257-273

Comment:
In both new paused-coin tests, `foreignCoin.Zrc20ContractAddress` is a freshly-sampled random address that differs from the `zrc20` variable passed as input. In production, `GetForeignCoins(ctx, zrc20.Hex())` returns the coin whose `Zrc20ContractAddress` equals `zrc20.Hex()`. Using `zrc20.Hex()` for this field aligns the test fixture with the real data shape, making it immediately clear to a reader that the coin belongs to the same address under test.

```suggestion
	t.Run("fail when foreign coin is paused", func(t *testing.T) {
		// ARRANGE
		k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
			UseFungibleMock: true,
		})

		zrc20 := sample.EthAddress()
		callEvent := false

		fungibleMock := keepertest.GetCrosschainFungibleMock(t, k)
		foreignCoin := fungibletypes.ForeignCoins{
			Zrc20ContractAddress: zrc20.Hex(),
			Asset:                "USDT",
			ForeignChainId:       1,
			CoinType:             coin.CoinType_ERC20,
			Paused:               true,
		}
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed on the current branch: the paused-coin test now sets Zrc20ContractAddress: zrc20.Hex(), matching the lookup key used by GetForeignCoins(ctx, zrc20.Hex()).

fungibleMock.On("GetForeignCoins", ctx, zrc20.Hex()).Return(foreignCoin, true)

// ACT
result, err := k.GetERC20InboundDetails(ctx, zrc20, callEvent)

// ASSERT
require.Error(t, err)
require.ErrorIs(t, err, fungibletypes.ErrPausedZRC20)
require.Contains(t, err.Error(), "zrc20 "+zrc20.Hex()+" is paused")
require.Empty(t, result)
})

t.Run("fail when chain is not supported", func(t *testing.T) {
// ARRANGE
k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
Expand Down Expand Up @@ -322,6 +351,35 @@ func TestKeeper_GetErc20InboundDetails(t *testing.T) {
require.Contains(t, err.Error(), "gas limit query failed")
})

t.Run("fail when foreign coin is paused for call event", func(t *testing.T) {
// ARRANGE
k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
UseFungibleMock: true,
})

zrc20 := sample.EthAddress()
callEvent := true

fungibleMock := keepertest.GetCrosschainFungibleMock(t, k)
foreignCoin := fungibletypes.ForeignCoins{
Zrc20ContractAddress: zrc20.Hex(),
Asset: "USDT",
ForeignChainId: 1,
CoinType: coin.CoinType_ERC20,
Paused: true,
}
Comment on lines +354 to +370

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Same Zrc20ContractAddress mismatch in the call-event paused test. Using zrc20.Hex() matches the real data shape where GetForeignCoins(zrc20.Hex()) returns a coin whose own Zrc20ContractAddress equals the lookup key.

Suggested change
t.Run("fail when foreign coin is paused for call event", func(t *testing.T) {
// ARRANGE
k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
UseFungibleMock: true,
})
zrc20 := sample.EthAddress()
callEvent := true
fungibleMock := keepertest.GetCrosschainFungibleMock(t, k)
foreignCoin := fungibletypes.ForeignCoins{
Zrc20ContractAddress: sample.EthAddress().Hex(),
Asset: "USDT",
ForeignChainId: 1,
CoinType: coin.CoinType_ERC20,
Paused: true,
}
t.Run("fail when foreign coin is paused for call event", func(t *testing.T) {
// ARRANGE
k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
UseFungibleMock: true,
})
zrc20 := sample.EthAddress()
callEvent := true
fungibleMock := keepertest.GetCrosschainFungibleMock(t, k)
foreignCoin := fungibletypes.ForeignCoins{
Zrc20ContractAddress: zrc20.Hex(),
Asset: "USDT",
ForeignChainId: 1,
CoinType: coin.CoinType_ERC20,
Paused: true,
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: x/crosschain/keeper/v2_zevm_inbound_test.go
Line: 354-370

Comment:
Same `Zrc20ContractAddress` mismatch in the call-event paused test. Using `zrc20.Hex()` matches the real data shape where `GetForeignCoins(zrc20.Hex())` returns a coin whose own `Zrc20ContractAddress` equals the lookup key.

```suggestion
	t.Run("fail when foreign coin is paused for call event", func(t *testing.T) {
		// ARRANGE
		k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
			UseFungibleMock: true,
		})

		zrc20 := sample.EthAddress()
		callEvent := true

		fungibleMock := keepertest.GetCrosschainFungibleMock(t, k)
		foreignCoin := fungibletypes.ForeignCoins{
			Zrc20ContractAddress: zrc20.Hex(),
			Asset:                "USDT",
			ForeignChainId:       1,
			CoinType:             coin.CoinType_ERC20,
			Paused:               true,
		}
```

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed on the current branch as well: the call-event paused test now uses Zrc20ContractAddress: zrc20.Hex() so the fixture matches the production data shape.

fungibleMock.On("GetForeignCoins", ctx, zrc20.Hex()).Return(foreignCoin, true)

// ACT
result, err := k.GetERC20InboundDetails(ctx, zrc20, callEvent)

// ASSERT
require.Error(t, err)
require.ErrorIs(t, err, fungibletypes.ErrPausedZRC20)
require.Contains(t, err.Error(), "zrc20 "+zrc20.Hex()+" is paused")
require.Empty(t, result)
})

t.Run("success with call event (NoAssetCall)", func(t *testing.T) {
// ARRANGE
k, ctx, _, _ := keepertest.CrosschainKeeperWithMocks(t, keepertest.CrosschainMockOptions{
Expand Down
Loading