Skip to content

Commit

Permalink
test: add sendToFxClaim unit test (#955)
Browse files Browse the repository at this point in the history
  • Loading branch information
zakir-code authored Jan 26, 2025
1 parent b6f8d6d commit 7639ff3
Show file tree
Hide file tree
Showing 5 changed files with 181 additions and 10 deletions.
18 changes: 11 additions & 7 deletions precompiles/crosschain/contract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,20 +116,24 @@ func (suite *CrosschainPrecompileTestSuite) GetBridgeToken(baseDenom string) erc

func (suite *CrosschainPrecompileTestSuite) AddBridgeToken(symbolOrAddr string, isNativeCoin bool, isIBC ...bool) {
keeper := suite.App.Erc20Keeper
var erc20Token erc20types.ERC20Token
var err error
var baseDenom string
isNative := false
if isNativeCoin || symbolOrAddr == fxtypes.DefaultSymbol {
erc20Token, err = keeper.RegisterNativeCoin(suite.Ctx, symbolOrAddr, symbolOrAddr, 18)
if symbolOrAddr == fxtypes.LegacyFXDenom {
baseDenom = fxtypes.FXDenom
} else if isNativeCoin || symbolOrAddr == fxtypes.DefaultSymbol {
erc20Token, err := keeper.RegisterNativeCoin(suite.Ctx, symbolOrAddr, symbolOrAddr, 18)
suite.Require().NoError(err)
baseDenom = erc20Token.Denom
} else {
isNative = true
erc20Token, err = keeper.RegisterNativeERC20(suite.Ctx, common.HexToAddress(symbolOrAddr))
erc20Token, err := keeper.RegisterNativeERC20(suite.Ctx, common.HexToAddress(symbolOrAddr))
suite.Require().NoError(err)
baseDenom = erc20Token.Denom
}
if len(isIBC) > 0 && isIBC[0] {
isNative = true
}
suite.Require().NoError(err)
err = keeper.AddBridgeToken(suite.Ctx, erc20Token.Denom, suite.chainName, helpers.GenExternalAddr(suite.chainName), isNative)
err := keeper.AddBridgeToken(suite.Ctx, baseDenom, suite.chainName, helpers.GenExternalAddr(suite.chainName), isNative)
suite.Require().NoError(err)
}

Expand Down
12 changes: 12 additions & 0 deletions precompiles/crosschain/execute_claim.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
ethtypes "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"

fxcontract "github.com/pundiai/fx-core/v8/contract"
Expand Down Expand Up @@ -93,6 +94,17 @@ func (m ExecuteClaimABI) NewExecuteClaimEvent(sender common.Address, eventNonce
return evmtypes.PackTopicData(m.Event, []common.Hash{sender.Hash()}, eventNonce, dstChain, errReason)
}

func (m ExecuteClaimABI) UnpackEvent(log *ethtypes.Log) (*fxcontract.ICrosschainExecuteClaimEvent, error) {
if log == nil {
return nil, errors.New("log is nil")
}
filterer, err := fxcontract.NewICrosschainFilterer(common.Address{}, nil)
if err != nil {
return nil, err
}
return filterer.ParseExecuteClaimEvent(*log)
}

func (m ExecuteClaimABI) PackInput(args fxcontract.ExecuteClaimArgs) ([]byte, error) {
arguments, err := m.Method.Inputs.Pack(args.Chain, args.EventNonce)
if err != nil {
Expand Down
157 changes: 157 additions & 0 deletions precompiles/crosschain/execute_claim_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,24 @@ package crosschain_test

import (
"encoding/hex"
"fmt"
"math/big"
"strings"
"testing"

sdkmath "cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/ethereum/go-ethereum/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/pundiai/fx-core/v8/contract"
"github.com/pundiai/fx-core/v8/precompiles/crosschain"
"github.com/pundiai/fx-core/v8/testutil/helpers"
fxtypes "github.com/pundiai/fx-core/v8/types"
crosschaintypes "github.com/pundiai/fx-core/v8/x/crosschain/types"
erc20types "github.com/pundiai/fx-core/v8/x/erc20/types"
ethtypes "github.com/pundiai/fx-core/v8/x/eth/types"
)

Expand All @@ -33,3 +43,150 @@ func TestExecuteClaimMethod_PackInput(t *testing.T) {
expected := "4ac3bdc30000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000036574680000000000000000000000000000000000000000000000000000000000"
assert.Equal(t, expected, hex.EncodeToString(input))
}

func (suite *CrosschainPrecompileTestSuite) TestContract_ExecuteClaim_SendToFx() {
testCases := []struct {
name string
malleate func() erc20types.BridgeToken
amount sdkmath.Int
erc20Balance *big.Int
moduleAmount sdkmath.Int
baseDenomAmount sdkmath.Int
logsLen int
}{
{
name: "native coin",
malleate: func() erc20types.BridgeToken {
symbol := helpers.NewRandSymbol()
suite.AddBridgeToken(symbol, true)

bridgeToken := suite.GetBridgeToken(strings.ToLower(symbol))
return bridgeToken
},
amount: sdkmath.NewInt(100),
erc20Balance: big.NewInt(100),
moduleAmount: sdkmath.NewInt(100),
baseDenomAmount: sdkmath.NewInt(0),
logsLen: 2,
},
{
name: "native erc20",
malleate: func() erc20types.BridgeToken {
symbol := helpers.NewRandSymbol()

erc20TokenAddr := suite.erc20TokenSuite.DeployERC20Token(suite.Ctx, symbol)
suite.AddBridgeToken(erc20TokenAddr.String(), false)

// eth module lock some tokens
bridgeToken := suite.GetBridgeToken(strings.ToLower(symbol))
suite.MintTokenToModule(suite.chainName, sdk.NewCoin(bridgeToken.BridgeDenom(), sdkmath.NewInt(100)))

// erc20 module lock some tokens
suite.MintTokenToModule(crosschaintypes.ModuleName, sdk.NewCoin(bridgeToken.Denom, sdkmath.NewInt(100)))

erc20ModuelAddr := common.BytesToAddress(authtypes.NewModuleAddress(erc20types.ModuleName))
suite.erc20TokenSuite.Mint(suite.Ctx, suite.signer.Address(), erc20ModuelAddr, big.NewInt(100))
return bridgeToken
},
amount: sdkmath.NewInt(100),
erc20Balance: big.NewInt(100),
moduleAmount: sdkmath.NewInt(0),
baseDenomAmount: sdkmath.NewInt(0),
logsLen: 2,
},
{
name: "original token",
malleate: func() erc20types.BridgeToken {
suite.AddBridgeToken(fxtypes.DefaultSymbol, false)

// eth module lock some tokens
bridgeToken := suite.GetBridgeToken(fxtypes.DefaultDenom)
suite.MintTokenToModule(ethtypes.ModuleName, sdk.NewCoin(bridgeToken.BridgeDenom(), sdkmath.NewInt(100)))

return bridgeToken
},
amount: sdkmath.NewInt(100),
erc20Balance: big.NewInt(0),
moduleAmount: sdkmath.NewInt(0),
baseDenomAmount: sdkmath.NewInt(100),
logsLen: 1,
},
{
name: "legacy FX token",
malleate: func() erc20types.BridgeToken {
suite.AddBridgeToken(fxtypes.LegacyFXDenom, false)
suite.AddBridgeToken(fxtypes.DefaultSymbol, false)

// eth module lock some tokens
bridgeToken := suite.GetBridgeToken(fxtypes.DefaultDenom)
suite.MintTokenToModule(ethtypes.ModuleName, sdk.NewCoin(bridgeToken.BridgeDenom(), sdkmath.NewInt(1)))

return suite.GetBridgeToken(fxtypes.FXDenom)
},
amount: sdkmath.NewInt(100),
erc20Balance: big.NewInt(0),
moduleAmount: sdkmath.NewInt(0),
baseDenomAmount: sdkmath.NewInt(1),
logsLen: 1,
},
}

for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
bridgeToken := tc.malleate()

receiver := helpers.GenAccAddress()
claim := &crosschaintypes.MsgSendToFxClaim{
EventNonce: 1,
BlockHeight: 100,
TokenContract: bridgeToken.Contract,
Amount: tc.amount,
Sender: helpers.GenExternalAddr(suite.chainName),
Receiver: receiver.String(),
BridgerAddress: helpers.GenAccAddress().String(),
ChainName: suite.chainName,
}
keeper := suite.App.CrosschainKeepers.GetKeeper(suite.chainName)
err := keeper.SavePendingExecuteClaim(suite.Ctx, claim)
suite.Require().NoError(err)

txResponse := suite.ExecuteClaim(suite.Ctx, suite.signer.Address(),
contract.ExecuteClaimArgs{Chain: suite.chainName, EventNonce: big.NewInt(int64(claim.EventNonce))},
)
suite.NotNil(txResponse)
suite.Len(txResponse.Logs, tc.logsLen)
event, err := crosschain.NewExecuteClaimABI().
UnpackEvent(txResponse.Logs[len(txResponse.Logs)-1].ToEthereum())
suite.Require().NoError(err)
suite.Equal(suite.GetSender(), event.Sender)
suite.Equal(claim.EventNonce, event.EventNonce.Uint64())
suite.Equal(claim.ChainName, event.Chain)
suite.Empty(event.ErrReason)

// crosschain module balance
bridgeTokenBalance := sdk.NewCoin(bridgeToken.BridgeDenom(), tc.moduleAmount)
suite.AssertBalance(authtypes.NewModuleAddress(crosschaintypes.ModuleName), bridgeTokenBalance)

// erc20 module balance
baseDenomBalance := sdk.NewCoin(bridgeToken.Denom, tc.moduleAmount)
suite.AssertBalance(authtypes.NewModuleAddress(erc20types.ModuleName), baseDenomBalance)

baseDenom := bridgeToken.Denom
if baseDenom == fxtypes.FXDenom { // swap base denom to apundiai denom
bridgeTokenBalance = sdk.NewCoin(bridgeToken.BridgeDenom(), tc.amount)
suite.AssertBalance(authtypes.NewModuleAddress(suite.chainName), bridgeTokenBalance)
baseDenom = fxtypes.DefaultDenom
}

// receiver balance
baseDenomBalance = sdk.NewCoin(baseDenom, tc.baseDenomAmount)
suite.AssertBalance(receiver, baseDenomBalance)

erc20Contract := suite.GetERC20Token(baseDenom).GetERC20Contract()
suite.erc20TokenSuite.WithContract(erc20Contract)

balance := suite.erc20TokenSuite.BalanceOf(suite.Ctx, common.BytesToAddress(receiver))
suite.Equal(tc.erc20Balance.String(), balance.String())
})
}
}
2 changes: 0 additions & 2 deletions x/crosschain/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ type KeeperMockSuite struct {
chainName string

queryClient types.QueryClient
// msgServer types.MsgServer

crosschainKeeper crosschainkeeper.Keeper
stakingKeeper *mock.MockStakingKeeper
Expand Down Expand Up @@ -106,7 +105,6 @@ func (s *KeeperMockSuite) SetupTest() {
queryHelper := baseapp.NewQueryServerTestHelper(s.ctx, myApp.InterfaceRegistry())
types.RegisterQueryServer(queryHelper, crosschainRouterKeeper)
s.queryClient = types.NewQueryClient(queryHelper)
// s.msgServer = crosschainkeeper.NewMsgServerRouterImpl(crosschainRouterKeeper)
}

func (s *KeeperMockSuite) SetupSubTest() {
Expand Down
2 changes: 1 addition & 1 deletion x/crosschain/keeper/many_to_one.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (k Keeper) SwapBridgeToken(ctx context.Context, holder sdk.AccAddress, brid
return defBridgeToken, swapAmount, nil
}
// transfer defaultDenom from eth module to holder
err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, ethtypes.ModuleName, holder, sdk.NewCoins(sdk.NewCoin(defBridgeToken.Denom, swapAmount)))
err = k.bankKeeper.SendCoinsFromModuleToAccount(ctx, ethtypes.ModuleName, holder, sdk.NewCoins(sdk.NewCoin(defBridgeToken.BridgeDenom(), swapAmount)))
return defBridgeToken, swapAmount, err
}

Expand Down

0 comments on commit 7639ff3

Please sign in to comment.