From bcf92bf73b8c81f3811668a7b627e332662c0690 Mon Sep 17 00:00:00 2001 From: zakir <80246097+zakir-code@users.noreply.github.com> Date: Thu, 10 Oct 2024 15:47:37 +0800 Subject: [PATCH] refactor: convert token in bridgecall --- types/target.go | 19 +++++- x/crosschain/keeper/bridge_call_in.go | 68 +++++++-------------- x/crosschain/keeper/bridge_call_out.go | 10 ++- x/crosschain/keeper/grpc_query_v1_test.go | 2 +- x/crosschain/keeper/hook.go | 15 ----- x/crosschain/keeper/many_to_one.go | 52 +++++++++++++--- x/crosschain/keeper/many_to_one_test.go | 4 +- x/crosschain/keeper/msg_server.go | 12 +--- x/crosschain/keeper/outgoing_pool.go | 4 +- x/crosschain/keeper/send_to_fx.go | 40 +++--------- x/crosschain/mock/expected_keepers_mocks.go | 15 +++++ x/crosschain/precompile/bridge_call.go | 16 +++-- x/crosschain/precompile/expected_keepers.go | 5 +- x/crosschain/types/expected_keepers.go | 6 +- x/crosschain/types/msgs.go | 4 ++ x/crosschain/types/types.go | 14 ----- 16 files changed, 146 insertions(+), 140 deletions(-) diff --git a/types/target.go b/types/target.go index 43d38302..d4487d69 100644 --- a/types/target.go +++ b/types/target.go @@ -6,8 +6,13 @@ import ( "fmt" "strings" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/bech32" ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + "github.com/ethereum/go-ethereum/common" + + "github.com/functionx/fx-core/v8/contract" ) const ( @@ -28,7 +33,12 @@ type FxTarget struct { SourceChannel string } -func ParseFxTarget(targetStr string) FxTarget { +func ParseFxTarget(targetStr string, isHex ...bool) FxTarget { + if len(isHex) > 0 && isHex[0] { + // ignore hex decode error + targetByte, _ := hex.DecodeString(targetStr) + targetStr = string(targetByte) + } // module evm if targetStr == LegacyERC20Target { return FxTarget{isIBC: false, target: ERC20Target} @@ -114,6 +124,13 @@ func (i FxTarget) IBCValidate() bool { return true } +func (i FxTarget) ReceiveAddrToStr(receive sdk.AccAddress) (receiveAddrStr string, err error) { + if strings.ToLower(i.Prefix) == contract.EthereumAddressPrefix { + return common.BytesToAddress(receive.Bytes()).String(), nil + } + return bech32.ConvertAndEncode(i.Prefix, receive) +} + func GetIbcDenomTrace(denom string, channelIBC string) (ibctransfertypes.DenomTrace, error) { channelPath, err := hex.DecodeString(channelIBC) if err != nil { diff --git a/x/crosschain/keeper/bridge_call_in.go b/x/crosschain/keeper/bridge_call_in.go index 30ede8f3..2b6a5f6d 100644 --- a/x/crosschain/keeper/bridge_call_in.go +++ b/x/crosschain/keeper/bridge_call_in.go @@ -2,7 +2,6 @@ package keeper import ( "bytes" - "context" "fmt" "math/big" "strconv" @@ -25,25 +24,25 @@ func (k Keeper) BridgeCallHandler(ctx sdk.Context, msg *types.MsgBridgeCallClaim return types.ErrInvalid.Wrap("sender is module account") } } - isMemoSendCallTo := types.IsMemoSendCallTo(msg.MustMemo()) - receiverTokenAddr := msg.GetToAddr() + isMemoSendCallTo := msg.IsMemoSendCallTo() + receiverAddr := msg.GetToAddr() if isMemoSendCallTo { - receiverTokenAddr = msg.GetSenderAddr() + receiverAddr = msg.GetSenderAddr() } - erc20Token, err := types.NewERC20Tokens(k.moduleName, msg.GetTokensAddr(), msg.GetAmounts()) - if err != nil { - return err - } - - _, tokenAddrs, tokenAmounts, err := k.BridgeTokenToERC20(ctx, receiverTokenAddr.Bytes(), erc20Token...) - if err != nil { - return err + baseCoins := sdk.NewCoins() + for i, address := range msg.TokenContracts { + baseCoin, err := k.BridgeTokenToBaseCoin(ctx, address, msg.Amounts[i], receiverAddr.Bytes()) + if err != nil { + return err + } + baseCoins = baseCoins.Add(baseCoin) } cacheCtx, commit := sdk.UnwrapSDKContext(ctx).CacheContext() + var err error if err = k.BridgeCallEvm(cacheCtx, msg.GetSenderAddr(), msg.GetRefundAddr(), msg.GetToAddr(), - tokenAddrs, tokenAmounts, msg.MustData(), msg.MustMemo(), msg.Value, isMemoSendCallTo); err == nil { + receiverAddr, baseCoins, msg.MustData(), msg.MustMemo(), msg.Value, isMemoSendCallTo); err == nil { commit() return nil } @@ -58,42 +57,21 @@ func (k Keeper) BridgeCallHandler(ctx sdk.Context, msg *types.MsgBridgeCallClaim }, ) } - return k.BridgeCallFailedRefund(ctx, msg.GetRefundAddr(), erc20Token, msg.EventNonce) + return k.BridgeCallFailedRefund(ctx, msg.GetRefundAddr(), baseCoins, msg.EventNonce) } -func (k Keeper) BridgeTokenToERC20(ctx context.Context, holder sdk.AccAddress, tokens ...types.ERC20Token) (sdk.Coins, []common.Address, []*big.Int, error) { - baseCoins := sdk.NewCoins() - tokenAddrs := make([]common.Address, 0, len(tokens)) - tokenAmounts := make([]*big.Int, 0, len(tokens)) - - for _, token := range tokens { - coin, err := k.BridgeTokenToBaseCoin(ctx, token.Contract, token.Amount.BigInt(), holder) +func (k Keeper) BridgeCallEvm(ctx sdk.Context, sender, refundAddr, to, receiverAddr common.Address, baseCoins sdk.Coins, data, memo []byte, value sdkmath.Int, isMemoSendCallTo bool) error { + tokens := make([]common.Address, 0, baseCoins.Len()) + amounts := make([]*big.Int, 0, baseCoins.Len()) + for _, coin := range baseCoins { + tokenContract, err := k.BaseCoinToEvm(ctx, coin, receiverAddr) if err != nil { - return nil, nil, nil, err - } - baseCoins = baseCoins.Add(coin) - - tokenAmounts = append(tokenAmounts, coin.Amount.BigInt()) - if coin.Denom == fxtypes.DefaultDenom { - tokenAddrs = append(tokenAddrs, common.Address{}) - continue - } - // todo replace convert coin, return token pair - if _, err = k.erc20Keeper.ConvertCoin(ctx, &erc20types.MsgConvertCoin{ - Coin: coin, - Receiver: common.BytesToAddress(holder.Bytes()).String(), - Sender: holder.String(), - }); err != nil { - return nil, nil, nil, err + return err } - // NOTE: convert coin already checked - pair, _ := k.erc20Keeper.GetTokenPair(sdk.UnwrapSDKContext(ctx), coin.Denom) - tokenAddrs = append(tokenAddrs, pair.GetERC20Contract()) + tokens = append(tokens, common.HexToAddress(tokenContract)) + amounts = append(amounts, coin.Amount.BigInt()) } - return baseCoins, tokenAddrs, tokenAmounts, nil -} -func (k Keeper) BridgeCallEvm(ctx sdk.Context, sender, refundAddr, to common.Address, tokens []common.Address, amounts []*big.Int, data, memo []byte, value sdkmath.Int, isMemoSendCallTo bool) error { if !k.evmKeeper.IsContract(ctx, to) { return nil } @@ -123,8 +101,8 @@ func (k Keeper) BridgeCallEvm(ctx sdk.Context, sender, refundAddr, to common.Add return nil } -func (k Keeper) BridgeCallFailedRefund(ctx sdk.Context, refundAddr common.Address, erc20Token []types.ERC20Token, eventNonce uint64) error { - outCallNonce, err := k.AddOutgoingBridgeCall(ctx, refundAddr, refundAddr, erc20Token, common.Address{}, nil, nil, eventNonce) +func (k Keeper) BridgeCallFailedRefund(ctx sdk.Context, refundAddr common.Address, baseCoins sdk.Coins, eventNonce uint64) error { + outCallNonce, err := k.AddOutgoingBridgeCall(ctx, refundAddr, refundAddr, baseCoins, common.Address{}, nil, nil, eventNonce) if err != nil { return err } diff --git a/x/crosschain/keeper/bridge_call_out.go b/x/crosschain/keeper/bridge_call_out.go index 6e070352..3b6a4bbd 100644 --- a/x/crosschain/keeper/bridge_call_out.go +++ b/x/crosschain/keeper/bridge_call_out.go @@ -37,7 +37,15 @@ func (k Keeper) BridgeCallCoinsToERC20Token(ctx sdk.Context, sender sdk.AccAddre return tokens, nil } -func (k Keeper) AddOutgoingBridgeCall(ctx sdk.Context, sender, refundAddr common.Address, tokens []types.ERC20Token, to common.Address, data, memo []byte, eventNonce uint64) (uint64, error) { +func (k Keeper) AddOutgoingBridgeCall(ctx sdk.Context, sender, refundAddr common.Address, baseCoins sdk.Coins, to common.Address, data, memo []byte, eventNonce uint64) (uint64, error) { + tokens := make([]types.ERC20Token, 0, len(baseCoins)) + for _, coin := range baseCoins { + tokenContract, err := k.BaseCoinToBridgeToken(ctx, coin, sender.Bytes()) + if err != nil { + return 0, err + } + tokens = append(tokens, types.NewERC20Token(coin.Amount, tokenContract)) + } outCall, err := k.BuildOutgoingBridgeCall(ctx, sender, refundAddr, tokens, to, data, memo, eventNonce) if err != nil { return 0, err diff --git a/x/crosschain/keeper/grpc_query_v1_test.go b/x/crosschain/keeper/grpc_query_v1_test.go index 8404d642..773de8be 100644 --- a/x/crosschain/keeper/grpc_query_v1_test.go +++ b/x/crosschain/keeper/grpc_query_v1_test.go @@ -39,7 +39,7 @@ type CrossChainGrpcTestSuite struct { // func TestCrossChainGrpcTestSuite_bsc(t *testing.T) { // suite.Run(t, &CrossChainGrpcTestSuite{KeeperTestSuite: KeeperTestSuite{chainName: bsctypes.ModuleName}, chainName: bsctypes.ModuleName}) -//} +// } func TestCrossChainGrpcTestSuite_eth(t *testing.T) { suite.Run(t, &CrossChainGrpcTestSuite{KeeperTestSuite: KeeperTestSuite{chainName: ethtypes.ModuleName}, chainName: ethtypes.ModuleName}) diff --git a/x/crosschain/keeper/hook.go b/x/crosschain/keeper/hook.go index 7b5df083..f3d02aec 100644 --- a/x/crosschain/keeper/hook.go +++ b/x/crosschain/keeper/hook.go @@ -3,7 +3,6 @@ package keeper import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" - "github.com/ethereum/go-ethereum/common" "github.com/functionx/fx-core/v8/x/crosschain/types" ) @@ -26,17 +25,3 @@ func (k Keeper) TransferAfter(ctx sdk.Context, sender sdk.AccAddress, receive st } return nil } - -func (k Keeper) PrecompileBridgeCall(ctx sdk.Context, sender, refund common.Address, coins sdk.Coins, to common.Address, data, memo []byte) (nonce uint64, err error) { - tokens, err := k.BridgeCallCoinsToERC20Token(ctx, sender.Bytes(), coins) - if err != nil { - return 0, err - } - - outCallNonce, err := k.AddOutgoingBridgeCall(ctx, sender, refund, tokens, to, data, memo, 0) - if err != nil { - return 0, err - } - - return outCallNonce, nil -} diff --git a/x/crosschain/keeper/many_to_one.go b/x/crosschain/keeper/many_to_one.go index 0f09ca88..e17fa0ea 100644 --- a/x/crosschain/keeper/many_to_one.go +++ b/x/crosschain/keeper/many_to_one.go @@ -13,15 +13,49 @@ import ( "github.com/ethereum/go-ethereum/common" fxtypes "github.com/functionx/fx-core/v8/types" + "github.com/functionx/fx-core/v8/x/crosschain/types" erc20types "github.com/functionx/fx-core/v8/x/erc20/types" ) -func (k Keeper) BridgeTokenToBaseCoin(ctx context.Context, tokenAddr string, amount *big.Int, holder sdk.AccAddress) (sdk.Coin, error) { +func (k Keeper) EvmToBaseCoin(ctx context.Context, tokenAddr string, amount *big.Int, holder common.Address) (sdk.Coin, error) { + _, err := k.erc20Keeper.ConvertERC20(ctx, &erc20types.MsgConvertERC20{ + ContractAddress: tokenAddr, + Amount: sdkmath.NewIntFromBigInt(amount), + Receiver: sdk.AccAddress(holder.Bytes()).String(), + Sender: holder.String(), + }) + if err != nil { + return sdk.Coin{}, err + } + tokenPair, ok := k.erc20Keeper.GetTokenPair(sdk.UnwrapSDKContext(ctx), tokenAddr) + if !ok { + return sdk.Coin{}, types.ErrInvalid.Wrapf("not found %s token pair", tokenAddr) + } + return sdk.NewCoin(tokenPair.Denom, sdkmath.NewIntFromBigInt(amount)), nil +} + +func (k Keeper) BaseCoinToEvm(ctx context.Context, coin sdk.Coin, holder common.Address) (string, error) { + _, err := k.erc20Keeper.ConvertCoin(ctx, &erc20types.MsgConvertCoin{ + Coin: coin, + Receiver: holder.String(), + Sender: sdk.AccAddress(holder.Bytes()).String(), + }) + if err != nil { + return "", err + } + tokenPair, ok := k.erc20Keeper.GetTokenPair(sdk.UnwrapSDKContext(ctx), coin.Denom) + if !ok { + return "", types.ErrInvalid.Wrapf("not found %s token pair", coin.Denom) + } + return tokenPair.Erc20Address, nil +} + +func (k Keeper) BridgeTokenToBaseCoin(ctx context.Context, tokenAddr string, amount sdkmath.Int, holder sdk.AccAddress) (sdk.Coin, error) { bridgeDenom, found := k.GetBridgeDenomByContract(sdk.UnwrapSDKContext(ctx), tokenAddr) if !found { return sdk.Coin{}, sdkerrors.ErrInvalidCoins.Wrapf("bridge denom not found %s", tokenAddr) } - bridgeToken := sdk.NewCoin(bridgeDenom, sdkmath.NewIntFromBigInt(amount)) + bridgeToken := sdk.NewCoin(bridgeDenom, amount) if err := k.DepositBridgeToken(ctx, bridgeToken, holder); err != nil { return sdk.Coin{}, err } @@ -35,22 +69,22 @@ func (k Keeper) BridgeTokenToBaseCoin(ctx context.Context, tokenAddr string, amo return sdk.NewCoin(baseDenom, bridgeToken.Amount), nil } -func (k Keeper) BaseCoinToBridgeToken(ctx context.Context, module string, coin sdk.Coin, holder sdk.AccAddress) (string, *big.Int, error) { - bridgeDenom, err := k.ManyToOne(ctx, coin.Denom, module) +func (k Keeper) BaseCoinToBridgeToken(ctx context.Context, coin sdk.Coin, holder sdk.AccAddress) (string, error) { + bridgeDenom, err := k.ManyToOne(ctx, coin.Denom, k.moduleName) if err != nil { - return "", nil, err + return "", err } if err = k.ConversionCoin(ctx, holder, coin, coin.Denom, bridgeDenom); err != nil { - return "", nil, err + return "", err } if err = k.WithdrawBridgeToken(ctx, sdk.NewCoin(bridgeDenom, coin.Amount), holder); err != nil { - return "", nil, err + return "", err } tokenAddr, found := k.GetContractByBridgeDenom(sdk.UnwrapSDKContext(ctx), bridgeDenom) if !found { - return "", nil, sdkerrors.ErrInvalidRequest.Wrapf("bridge token not found %s", bridgeDenom) + return "", sdkerrors.ErrInvalidRequest.Wrapf("bridge token not found %s", bridgeDenom) } - return tokenAddr, coin.Amount.BigInt(), nil + return tokenAddr, nil } // DepositBridgeToken get bridge token from crosschain module diff --git a/x/crosschain/keeper/many_to_one_test.go b/x/crosschain/keeper/many_to_one_test.go index d414a38b..2e1b0253 100644 --- a/x/crosschain/keeper/many_to_one_test.go +++ b/x/crosschain/keeper/many_to_one_test.go @@ -370,7 +370,7 @@ func (suite *KeeperTestSuite) TestBridgeTokenToBaseCoin() { suite.MintTokenToModule(suite.chainName, sdk.NewCoin(tc.BridgeDenom, amount)) } - _, err := suite.Keeper().BridgeTokenToBaseCoin(suite.Ctx, tc.TokenAddr, amount.BigInt(), acc) + _, err := suite.Keeper().BridgeTokenToBaseCoin(suite.Ctx, tc.TokenAddr, amount, acc) if tc.Success { suite.NoError(err) suite.CheckAllBalance(acc, sdk.NewCoin(tc.BaseDenom, amount)) @@ -437,7 +437,7 @@ func (suite *KeeperTestSuite) TestBaseCoinToBridgeToken() { suite.MintTokenToModule(suite.chainName, sdk.NewCoin(tc.BridgeDenom, amount)) } - _, _, err := suite.Keeper().BaseCoinToBridgeToken(suite.Ctx, suite.chainName, tc.Coin, acc) + _, err := suite.Keeper().BaseCoinToBridgeToken(suite.Ctx, tc.Coin, acc) if tc.Success { suite.NoError(err) suite.CheckAllBalance(acc, sdk.NewCoins()...) diff --git a/x/crosschain/keeper/msg_server.go b/x/crosschain/keeper/msg_server.go index 9c671fd4..e97138d8 100644 --- a/x/crosschain/keeper/msg_server.go +++ b/x/crosschain/keeper/msg_server.go @@ -464,18 +464,8 @@ func (s MsgServer) BridgeCallConfirm(c context.Context, msg *types.MsgBridgeCall } func (s MsgServer) BridgeCall(c context.Context, msg *types.MsgBridgeCall) (*types.MsgBridgeCallResponse, error) { - sender, err := sdk.AccAddressFromBech32(msg.Sender) - if err != nil { - return nil, types.ErrInvalid.Wrapf("sender address") - } - ctx := sdk.UnwrapSDKContext(c) - tokens, err := s.BridgeCallCoinsToERC20Token(ctx, sender, msg.Coins) - if err != nil { - return nil, err - } - - outCallNonce, err := s.AddOutgoingBridgeCall(ctx, msg.GetSenderAddr(), msg.GetRefundAddr(), tokens, msg.GetToAddr(), msg.MustData(), msg.MustMemo(), 0) + outCallNonce, err := s.AddOutgoingBridgeCall(ctx, msg.GetSenderAddr(), msg.GetRefundAddr(), msg.Coins, msg.GetToAddr(), msg.MustData(), msg.MustMemo(), 0) if err != nil { return nil, err } diff --git a/x/crosschain/keeper/outgoing_pool.go b/x/crosschain/keeper/outgoing_pool.go index 78b0872f..667abb1c 100644 --- a/x/crosschain/keeper/outgoing_pool.go +++ b/x/crosschain/keeper/outgoing_pool.go @@ -26,7 +26,7 @@ func (k Keeper) AddToOutgoingPool(ctx sdk.Context, sender sdk.AccAddress, receiv // - persists an OutgoingTx // - adds the TX to the `available` TX pool via a second index func (k Keeper) addToOutgoingPool(ctx sdk.Context, sender sdk.AccAddress, receiver string, amount sdk.Coin, fee sdk.Coin, txID uint64) error { - tokenContract, _, err := k.BaseCoinToBridgeToken(ctx, k.moduleName, amount.Add(fee), sender) + tokenContract, err := k.BaseCoinToBridgeToken(ctx, amount.Add(fee), sender) if err != nil { return err } @@ -218,7 +218,7 @@ func (k Keeper) handleRemoveFromOutgoingPoolAndRefund(ctx sdk.Context, tx *types func (k Keeper) handleCancelRefund(ctx sdk.Context, txId uint64, sender sdk.AccAddress, tokenContract string, refundAmount sdkmath.Int) (sdk.Coin, error) { // 1. handler refund and convert to base coin - baseCoin, err := k.BridgeTokenToBaseCoin(ctx, tokenContract, refundAmount.BigInt(), sender) + baseCoin, err := k.BridgeTokenToBaseCoin(ctx, tokenContract, refundAmount, sender) if err != nil { return sdk.Coin{}, err } diff --git a/x/crosschain/keeper/send_to_fx.go b/x/crosschain/keeper/send_to_fx.go index b5c1ec76..0d0a6288 100644 --- a/x/crosschain/keeper/send_to_fx.go +++ b/x/crosschain/keeper/send_to_fx.go @@ -1,21 +1,16 @@ package keeper import ( - "encoding/hex" "fmt" - "strings" "time" - sdkmath "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/telemetry" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/types/bech32" transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types" ibcclienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" "github.com/ethereum/go-ethereum/common" "github.com/hashicorp/go-metrics" - "github.com/functionx/fx-core/v8/contract" fxtelemetry "github.com/functionx/fx-core/v8/telemetry" fxtypes "github.com/functionx/fx-core/v8/types" "github.com/functionx/fx-core/v8/x/crosschain/types" @@ -44,52 +39,37 @@ func (k Keeper) SendToFxExecuted(ctx sdk.Context, claim *types.MsgSendToFxClaim) return types.ErrInvalid.Wrapf("receiver address") } - baseCoin, err := k.BridgeTokenToBaseCoin(ctx, claim.TokenContract, claim.Amount.BigInt(), receiveAddr) + baseCoin, err := k.BridgeTokenToBaseCoin(ctx, claim.TokenContract, claim.Amount, receiveAddr) if err != nil { return err } - return k.RelayTransferHandler(ctx, claim.EventNonce, claim.TargetIbc, receiveAddr, baseCoin) -} - -func (k Keeper) RelayTransferHandler(ctx sdk.Context, eventNonce uint64, targetHex string, receiver sdk.AccAddress, coin sdk.Coin) error { - // ignore hex decode error - targetByte, _ := hex.DecodeString(targetHex) - fxTarget := fxtypes.ParseFxTarget(string(targetByte)) - + fxTarget := fxtypes.ParseFxTarget(claim.TargetIbc, true) if fxTarget.IsIBC() { - // transfer to ibc - // todo convert to ibc token - return k.transferIBCHandler(ctx, eventNonce, receiver, coin, fxTarget) + return k.transferIBCHandler(ctx, claim.EventNonce, receiveAddr, baseCoin, fxTarget) } if fxTarget.GetTarget() == fxtypes.ERC20Target { - // transfer to evm - if err := k.erc20Keeper.TransferAfter(ctx, receiver, common.BytesToAddress(receiver.Bytes()).String(), coin, sdk.NewCoin(coin.Denom, sdkmath.ZeroInt()), false); err != nil { + _, err = k.BaseCoinToEvm(ctx, baseCoin, common.BytesToAddress(receiveAddr.Bytes())) + if err != nil { return err } ctx.EventManager().EmitEvent(sdk.NewEvent( types.EventTypeEvmTransfer, sdk.NewAttribute(sdk.AttributeKeyModule, k.moduleName), - sdk.NewAttribute(types.AttributeKeyEventNonce, fmt.Sprint(eventNonce)), + sdk.NewAttribute(types.AttributeKeyEventNonce, fmt.Sprint(claim.EventNonce)), )) } return nil } func (k Keeper) transferIBCHandler(ctx sdk.Context, eventNonce uint64, receive sdk.AccAddress, coin sdk.Coin, target fxtypes.FxTarget) error { - var ibcReceiveAddress string - if strings.ToLower(target.Prefix) == contract.EthereumAddressPrefix { - ibcReceiveAddress = common.BytesToAddress(receive.Bytes()).String() - } else { - var err error - ibcReceiveAddress, err = bech32.ConvertAndEncode(target.Prefix, receive) - if err != nil { - return err - } + ibcCoin, err := k.BaseCoinToIBCCoin(ctx, coin, receive, target.String()) + if err != nil { + return err } - ibcCoin, err := k.BaseCoinToIBCCoin(ctx, coin, receive, target.String()) + ibcReceiveAddress, err := target.ReceiveAddrToStr(receive) if err != nil { return err } diff --git a/x/crosschain/mock/expected_keepers_mocks.go b/x/crosschain/mock/expected_keepers_mocks.go index 4cc04f9f..d4dab0de 100644 --- a/x/crosschain/mock/expected_keepers_mocks.go +++ b/x/crosschain/mock/expected_keepers_mocks.go @@ -428,6 +428,21 @@ func (mr *MockErc20KeeperMockRecorder) ConvertDenomToTarget(ctx, from, coin, fxT return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConvertDenomToTarget", reflect.TypeOf((*MockErc20Keeper)(nil).ConvertDenomToTarget), ctx, from, coin, fxTarget) } +// ConvertERC20 mocks base method. +func (m *MockErc20Keeper) ConvertERC20(goCtx context.Context, msg *types6.MsgConvertERC20) (*types6.MsgConvertERC20Response, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ConvertERC20", goCtx, msg) + ret0, _ := ret[0].(*types6.MsgConvertERC20Response) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// ConvertERC20 indicates an expected call of ConvertERC20. +func (mr *MockErc20KeeperMockRecorder) ConvertERC20(goCtx, msg any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ConvertERC20", reflect.TypeOf((*MockErc20Keeper)(nil).ConvertERC20), goCtx, msg) +} + // DeleteIBCTransferRelation mocks base method. func (m *MockErc20Keeper) DeleteIBCTransferRelation(ctx types.Context, channel string, sequence uint64) bool { m.ctrl.T.Helper() diff --git a/x/crosschain/precompile/bridge_call.go b/x/crosschain/precompile/bridge_call.go index aa25f94f..c9d4c011 100644 --- a/x/crosschain/precompile/bridge_call.go +++ b/x/crosschain/precompile/bridge_call.go @@ -57,24 +57,28 @@ func (m *BridgeCallMethod) Run(evm *vm.EVM, contract *vm.Contract) ([]byte, erro var result []byte err = stateDB.ExecuteNativeAction(contract.Address(), nil, func(ctx sdk.Context) error { sender := contract.Caller() - coins := make([]sdk.Coin, 0, len(args.Tokens)+1) + baseCoins := make([]sdk.Coin, 0, len(args.Tokens)+1) value := contract.Value() if value.Cmp(big.NewInt(0)) == 1 { - totalCoin, err := m.handlerOriginToken(ctx, evm, sender, value) + coin, err := m.handlerOriginToken(ctx, evm, sender, value) if err != nil { return err } - coins = append(coins, totalCoin) + baseCoins = append(baseCoins, coin) } for i, token := range args.Tokens { - coin, err := m.handlerERC20Token(ctx, evm, sender, token, args.Amounts[i]) + crosschainKeeper, ok := m.router.GetRoute(args.DstChain) + if !ok { + return errors.New("invalid dstChain") + } + coin, err := crosschainKeeper.EvmToBaseCoin(ctx, token.String(), args.Amounts[i], sender) if err != nil { return err } - coins = append(coins, coin) + baseCoins = append(baseCoins, coin) } - bridgeCallNonce, err := route.PrecompileBridgeCall(ctx, sender, args.Refund, coins, args.To, args.Data, args.Memo) + bridgeCallNonce, err := route.AddOutgoingBridgeCall(ctx, sender, args.Refund, baseCoins, args.To, args.Data, args.Memo, 0) if err != nil { return err } diff --git a/x/crosschain/precompile/expected_keepers.go b/x/crosschain/precompile/expected_keepers.go index 303e8199..4c499918 100644 --- a/x/crosschain/precompile/expected_keepers.go +++ b/x/crosschain/precompile/expected_keepers.go @@ -2,6 +2,7 @@ package precompile import ( "context" + "math/big" "time" sdk "github.com/cosmos/cosmos-sdk/types" @@ -48,7 +49,9 @@ type CrosschainKeeper interface { TransferAfter(ctx sdk.Context, sender sdk.AccAddress, receive string, coins, fee sdk.Coin, originToken bool) error RemoveFromOutgoingPoolAndRefund(ctx sdk.Context, txID uint64, sender sdk.AccAddress) (sdk.Coin, error) AddUnbatchedTxBridgeFee(ctx sdk.Context, txID uint64, sender sdk.AccAddress, addBridgeFee sdk.Coin) error - PrecompileBridgeCall(ctx sdk.Context, sender, refund common.Address, coins sdk.Coins, to common.Address, data, memo []byte) (uint64, error) + + AddOutgoingBridgeCall(ctx sdk.Context, sender, refundAddr common.Address, baseCoins sdk.Coins, to common.Address, data, memo []byte, eventNonce uint64) (uint64, error) + EvmToBaseCoin(ctx context.Context, tokenAddr string, amount *big.Int, holder common.Address) (sdk.Coin, error) ExecuteClaim(ctx sdk.Context, eventNonce uint64) error HasOracleAddrByExternalAddr(ctx sdk.Context, externalAddress string) bool diff --git a/x/crosschain/types/expected_keepers.go b/x/crosschain/types/expected_keepers.go index 10997fc2..7c6480cd 100644 --- a/x/crosschain/types/expected_keepers.go +++ b/x/crosschain/types/expected_keepers.go @@ -50,8 +50,11 @@ type BankKeeper interface { } type Erc20Keeper interface { - TransferAfter(ctx sdk.Context, sender sdk.AccAddress, receive string, coin, fee sdk.Coin, _ bool) error + GetTokenPair(ctx sdk.Context, tokenOrDenom string) (erc20types.TokenPair, bool) ConvertCoin(ctx context.Context, msg *erc20types.MsgConvertCoin) (*erc20types.MsgConvertCoinResponse, error) + ConvertERC20(goCtx context.Context, msg *erc20types.MsgConvertERC20) (*erc20types.MsgConvertERC20Response, error) + + TransferAfter(ctx sdk.Context, sender sdk.AccAddress, receive string, coin, fee sdk.Coin, _ bool) error ConvertDenomToTarget(ctx sdk.Context, from sdk.AccAddress, coin sdk.Coin, fxTarget fxtypes.FxTarget) (sdk.Coin, error) HookOutgoingRefund(ctx sdk.Context, moduleName string, txID uint64, sender sdk.AccAddress, totalCoin sdk.Coin) error SetOutgoingTransferRelation(ctx sdk.Context, moduleName string, txID uint64) @@ -59,7 +62,6 @@ type Erc20Keeper interface { DeleteOutgoingTransferRelation(ctx sdk.Context, moduleName string, txID uint64) IsOriginOrConvertedDenom(ctx sdk.Context, denom string) bool ToTargetDenom(ctx sdk.Context, denom, base string, aliases []string, fxTarget fxtypes.FxTarget) string - GetTokenPair(ctx sdk.Context, tokenOrDenom string) (erc20types.TokenPair, bool) IbcRefund(ctx sdk.Context, channel string, sequence uint64, sender sdk.AccAddress, amount sdk.Coin) error DeleteIBCTransferRelation(ctx sdk.Context, channel string, sequence uint64) bool } diff --git a/x/crosschain/types/msgs.go b/x/crosschain/types/msgs.go index 8a2c481e..a95dc282 100644 --- a/x/crosschain/types/msgs.go +++ b/x/crosschain/types/msgs.go @@ -483,6 +483,10 @@ func (m *MsgBridgeCallClaim) GetToAddr() common.Address { return ExternalAddrToHexAddr(m.ChainName, m.To) } +func (m *MsgBridgeCallClaim) IsMemoSendCallTo() bool { + return IsMemoSendCallTo(m.MustMemo()) +} + func (m *MsgBridgeCallClaim) MustData() []byte { if len(m.Data) == 0 { return []byte{} diff --git a/x/crosschain/types/types.go b/x/crosschain/types/types.go index ba30d144..2f18c569 100644 --- a/x/crosschain/types/types.go +++ b/x/crosschain/types/types.go @@ -505,20 +505,6 @@ func BridgeDenomToContract(moduleName string, bridgeDenom string) string { return strings.TrimPrefix(bridgeDenom, moduleName) } -func NewERC20Tokens(module string, tokenAddrs []gethcommon.Address, tokenAmounts []*big.Int) ([]ERC20Token, error) { - if len(tokenAddrs) != len(tokenAmounts) { - return nil, fmt.Errorf("invalid length") - } - tokens := make([]ERC20Token, 0, len(tokenAddrs)) - for i := 0; i < len(tokenAddrs); i++ { - tokens = append(tokens, ERC20Token{ - Contract: ExternalAddrToStr(module, tokenAddrs[i].Bytes()), - Amount: sdkmath.NewIntFromBigInt(tokenAmounts[i]), - }) - } - return tokens, nil -} - func (m *MsgBridgeCallClaim) GetERC20Tokens() []ERC20Token { erc20Tokens := make([]ERC20Token, 0, len(m.TokenContracts)) for i, tokenContract := range m.TokenContracts {