Skip to content

Commit

Permalink
refactor: convert token in bridgecall
Browse files Browse the repository at this point in the history
  • Loading branch information
zakir-code committed Oct 10, 2024
1 parent 7f95522 commit bcf92bf
Show file tree
Hide file tree
Showing 16 changed files with 146 additions and 140 deletions.
19 changes: 18 additions & 1 deletion types/target.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand All @@ -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}
Expand Down Expand Up @@ -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 {
Expand Down
68 changes: 23 additions & 45 deletions x/crosschain/keeper/bridge_call_in.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package keeper

import (
"bytes"
"context"
"fmt"
"math/big"
"strconv"
Expand All @@ -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
}
Expand All @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down
10 changes: 9 additions & 1 deletion x/crosschain/keeper/bridge_call_out.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion x/crosschain/keeper/grpc_query_v1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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})
Expand Down
15 changes: 0 additions & 15 deletions x/crosschain/keeper/hook.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand All @@ -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
}
52 changes: 43 additions & 9 deletions x/crosschain/keeper/many_to_one.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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
Expand Down
4 changes: 2 additions & 2 deletions x/crosschain/keeper/many_to_one_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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()...)
Expand Down
12 changes: 1 addition & 11 deletions x/crosschain/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down
4 changes: 2 additions & 2 deletions x/crosschain/keeper/outgoing_pool.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand Down Expand Up @@ -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
}
Expand Down
Loading

0 comments on commit bcf92bf

Please sign in to comment.