Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(crosschain): simplify interface references for the erc20 module #731

Merged
merged 1 commit into from
Oct 11, 2024
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: 3 additions & 1 deletion x/crosschain/keeper/abci.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,9 @@ func (k Keeper) cleanupTimeOutBridgeCall(ctx sdk.Context) {
return true
}
// 1. handler bridge call refund
k.HandleOutgoingBridgeCallRefund(ctx, data)
if err := k.RefundOutgoingBridgeCall(ctx, data); err != nil {
panic(fmt.Sprintf("failed cancel out bridge call %d while trying to execute failed: %s", data.Nonce, err))
}

// 2. delete bridge call
k.DeleteOutgoingBridgeCallRecord(ctx, data.Nonce)
Expand Down
3 changes: 1 addition & 2 deletions x/crosschain/keeper/attestation_handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,8 @@ func (k Keeper) ExecuteClaim(ctx sdk.Context, eventNonce uint64) error {
case *types.MsgBridgeCallClaim:
return k.BridgeCallHandler(ctx, claim)
case *types.MsgBridgeCallResultClaim:
k.BridgeCallResultHandler(ctx, claim)
return k.BridgeCallResultHandler(ctx, claim)
default:
return sdkerrors.ErrInvalidRequest.Wrapf("invalid claim type: %s", claim.GetType())
}
return nil
}
122 changes: 20 additions & 102 deletions x/crosschain/keeper/bridge_call_in.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package keeper

import (
"bytes"
"fmt"
"math/big"
"strconv"
Expand All @@ -12,9 +11,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/hashicorp/go-metrics"

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) BridgeCallHandler(ctx sdk.Context, msg *types.MsgBridgeCallClaim) error {
Expand All @@ -40,13 +37,8 @@ func (k Keeper) BridgeCallHandler(ctx sdk.Context, msg *types.MsgBridgeCallClaim
}

cacheCtx, commit := sdk.UnwrapSDKContext(ctx).CacheContext()
var err error
if err = k.BridgeCallEvm(cacheCtx, msg.GetSenderAddr(), msg.GetRefundAddr(), msg.GetToAddr(),
receiverAddr, baseCoins, msg.MustData(), msg.MustMemo(), msg.Value, isMemoSendCallTo); err == nil {
commit()
return nil
}
ctx.EventManager().EmitEvent(sdk.NewEvent(types.EventTypeBridgeCallEvent, sdk.NewAttribute(types.AttributeKeyErrCause, err.Error())))
err := k.BridgeCallEvm(cacheCtx, msg.GetSenderAddr(), msg.GetRefundAddr(), msg.GetToAddr(),
receiverAddr, baseCoins, msg.MustData(), msg.MustMemo(), msg.Value, isMemoSendCallTo)
if !ctx.IsCheckTx() {
telemetry.IncrCounterWithLabels(
[]string{types.ModuleName, "bridge_call_in"},
Expand All @@ -57,7 +49,24 @@ func (k Keeper) BridgeCallHandler(ctx sdk.Context, msg *types.MsgBridgeCallClaim
},
)
}
return k.BridgeCallFailedRefund(ctx, msg.GetRefundAddr(), baseCoins, msg.EventNonce)
if err == nil {
commit()
return nil
}
// refund bridge-call case of error
ctx.EventManager().EmitEvent(sdk.NewEvent(types.EventTypeBridgeCallEvent, sdk.NewAttribute(types.AttributeKeyErrCause, err.Error())))
zakir-code marked this conversation as resolved.
Show resolved Hide resolved

refundAddr := msg.GetRefundAddr()
outCallNonce, err := k.AddOutgoingBridgeCall(ctx, refundAddr, refundAddr, baseCoins, common.Address{}, nil, nil, msg.EventNonce)
if err != nil {
return err
}
ctx.EventManager().EmitEvent(sdk.NewEvent(
types.EventTypeBridgeCallRefundOut,
sdk.NewAttribute(types.AttributeKeyEventNonce, fmt.Sprintf("%d", msg.EventNonce)),
sdk.NewAttribute(types.AttributeKeyBridgeCallNonce, fmt.Sprintf("%d", outCallNonce)),
))
return nil
}

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 {
Expand Down Expand Up @@ -100,94 +109,3 @@ func (k Keeper) BridgeCallEvm(ctx sdk.Context, sender, refundAddr, to, receiverA
}
return nil
}

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
}
ctx.EventManager().EmitEvent(sdk.NewEvent(
types.EventTypeBridgeCallRefundOut,
sdk.NewAttribute(types.AttributeKeyEventNonce, fmt.Sprintf("%d", eventNonce)),
sdk.NewAttribute(types.AttributeKeyBridgeCallNonce, fmt.Sprintf("%d", outCallNonce)),
))
return nil
}

func (k Keeper) bridgeCallTransferCoins(ctx sdk.Context, sender sdk.AccAddress, tokens []types.ERC20Token) (sdk.Coins, error) {
mintCoins := sdk.NewCoins()
unlockCoins := sdk.NewCoins()
for i := 0; i < len(tokens); i++ {
bridgeDenom, found := k.GetBridgeDenomByContract(ctx, tokens[i].Contract)
if !found {
return nil, types.ErrInvalid.Wrapf("bridge token is not exist")
}
if !tokens[i].Amount.IsPositive() {
continue
}
coin := sdk.NewCoin(bridgeDenom, tokens[i].Amount)
isOriginOrConverted := k.erc20Keeper.IsOriginOrConvertedDenom(ctx, bridgeDenom)
if !isOriginOrConverted {
mintCoins = mintCoins.Add(coin)
}
unlockCoins = unlockCoins.Add(coin)
}
if mintCoins.IsAllPositive() {
if err := k.bankKeeper.MintCoins(ctx, k.moduleName, mintCoins); err != nil {
return nil, err
}
}
if unlockCoins.IsAllPositive() {
if err := k.bankKeeper.SendCoinsFromModuleToAccount(ctx, k.moduleName, sender, unlockCoins); err != nil {
return nil, err
}
}

targetCoins := sdk.NewCoins()
for _, coin := range unlockCoins {
targetCoin, err := k.erc20Keeper.ConvertDenomToTarget(ctx, sender, coin, fxtypes.ParseFxTarget(fxtypes.ERC20Target))
if err != nil {
return nil, err
}
targetCoins = targetCoins.Add(targetCoin)
}
return targetCoins, nil
}

func (k Keeper) bridgeCallTransferTokens(ctx sdk.Context, sender sdk.AccAddress, receiver []byte, coins sdk.Coins) error {
for _, coin := range coins {
if coin.Denom == fxtypes.DefaultDenom {
if bytes.Equal(sender, receiver) {
continue
}
if err := k.bankKeeper.SendCoins(ctx, sender, receiver, sdk.NewCoins(coin)); err != nil {
return err
}
continue
}
if _, err := k.erc20Keeper.ConvertCoin(ctx, &erc20types.MsgConvertCoin{
Coin: coin,
Receiver: common.BytesToAddress(receiver).String(),
Sender: sender.String(),
}); err != nil {
return err
}
}
return nil
}

func (k Keeper) CoinsToBridgeCallTokens(ctx sdk.Context, coins sdk.Coins) ([]common.Address, []*big.Int) {
tokens := make([]common.Address, 0, len(coins))
amounts := make([]*big.Int, 0, len(coins))
for _, coin := range coins {
amounts = append(amounts, coin.Amount.BigInt())
if coin.Denom == fxtypes.DefaultDenom {
tokens = append(tokens, common.Address{})
continue
}
// bridgeCallTransferTokens().ConvertCoin hava already checked.
pair, _ := k.erc20Keeper.GetTokenPair(ctx, coin.Denom)
tokens = append(tokens, common.HexToAddress(pair.Erc20Address))
}
return tokens, amounts
}
47 changes: 0 additions & 47 deletions x/crosschain/keeper/bridge_call_in_test.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
package keeper_test

import (
"math/big"
"strings"

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"
"go.uber.org/mock/gomock"

"github.com/functionx/fx-core/v8/testutil/helpers"
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 (suite *KeeperTestSuite) TestBridgeCallHandler() {
Expand Down Expand Up @@ -94,45 +89,3 @@ func (suite *KeeperTestSuite) BridgeCallClaimInitialize(msg types.MsgBridgeCallC
}
return baseDenoms, bridgeDenoms, erc20Addrs
}

func (s *KeeperMockSuite) Test_CoinsToBridgeCallTokens() {
input := sdk.Coins{
sdk.NewCoin(fxtypes.DefaultDenom, sdkmath.NewInt(1e18)),
sdk.NewCoin("aaa", sdkmath.NewInt(2e18)),
}
s.erc20Keeper.EXPECT().GetTokenPair(gomock.Any(), "aaa").Return(erc20types.TokenPair{
Erc20Address: "0x0000000000000000000000000000000000000001",
}, true).Times(1)
tokens, amounts := s.crosschainKeeper.CoinsToBridgeCallTokens(s.ctx, input)
s.Require().EqualValues(len(tokens), len(amounts))
s.Len(tokens, input.Len())

expectTokens := []common.Address{
common.HexToAddress("0x0000000000000000000000000000000000000000"),
common.HexToAddress("0x0000000000000000000000000000000000000001"),
}
expectAmount := []*big.Int{big.NewInt(1e18), big.NewInt(2e18)}
s.Require().EqualValues(expectTokens, tokens)
s.Require().EqualValues(expectAmount, amounts)
}

func (s *KeeperMockSuite) MockBridgeCallToken(erc20Tokens []types.ERC20Token) {
if len(erc20Tokens) == 0 {
return
}
s.accountKeeper.EXPECT().GetModuleAddress(erc20types.ModuleName).Return(authtypes.NewEmptyModuleAccount(erc20types.ModuleName).GetAddress()).AnyTimes()

s.erc20Keeper.EXPECT().IsOriginOrConvertedDenom(gomock.Any(), gomock.Any()).Return(false).Times(len(erc20Tokens))
s.bankKeeper.EXPECT().MintCoins(gomock.Any(), s.moduleName, gomock.Any()).Return(nil).Times(1)
s.bankKeeper.EXPECT().SendCoinsFromModuleToAccount(gomock.Any(), s.moduleName, gomock.Any(), gomock.Any()).Return(nil).Times(1)

for _, erc20Token := range erc20Tokens {
baseDenom := helpers.NewRandDenom()
bridgeToken := s.AddBridgeToken(erc20Token.Contract)
bridgeCoin := sdk.NewCoin(bridgeToken.Denom, erc20Token.Amount)
targetCoin := sdk.NewCoin(baseDenom, erc20Token.Amount)

s.erc20Keeper.EXPECT().ConvertDenomToTarget(gomock.Any(), gomock.Any(), bridgeCoin, gomock.Any()).Return(targetCoin, nil).Times(1)
s.erc20Keeper.EXPECT().ConvertCoin(gomock.Any(), gomock.Any()).Return(&erc20types.MsgConvertCoinResponse{}, nil).Times(1)
}
}
42 changes: 39 additions & 3 deletions x/crosschain/keeper/bridge_call_out.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,15 +87,17 @@ func (k Keeper) BuildOutgoingBridgeCall(ctx sdk.Context, sender common.Address,
return outCall, nil
}

func (k Keeper) BridgeCallResultHandler(ctx sdk.Context, claim *types.MsgBridgeCallResultClaim) {
func (k Keeper) BridgeCallResultHandler(ctx sdk.Context, claim *types.MsgBridgeCallResultClaim) error {
k.CreateBridgeAccount(ctx, claim.TxOrigin)

outgoingBridgeCall, found := k.GetOutgoingBridgeCallByNonce(ctx, claim.Nonce)
if !found {
panic(fmt.Errorf("bridge call not found for nonce %d", claim.Nonce))
return fmt.Errorf("bridge call not found for nonce %d", claim.Nonce)
zakir-code marked this conversation as resolved.
Show resolved Hide resolved
}
if !claim.Success {
k.HandleOutgoingBridgeCallRefund(ctx, outgoingBridgeCall)
if err := k.RefundOutgoingBridgeCall(ctx, outgoingBridgeCall); err != nil {
return err
zakir-code marked this conversation as resolved.
Show resolved Hide resolved
}
}
k.DeleteOutgoingBridgeCallRecord(ctx, claim.Nonce)

Expand All @@ -105,6 +107,40 @@ func (k Keeper) BridgeCallResultHandler(ctx sdk.Context, claim *types.MsgBridgeC
sdk.NewAttribute(types.AttributeKeyStateSuccess, strconv.FormatBool(claim.Success)),
sdk.NewAttribute(types.AttributeKeyErrCause, claim.Cause),
))
return nil
}

func (k Keeper) RefundOutgoingBridgeCall(ctx sdk.Context, data *types.OutgoingBridgeCall) error {
refund := types.ExternalAddrToAccAddr(k.moduleName, data.GetRefund())
baseCoins := sdk.NewCoins()
for _, token := range data.Tokens {
baseCoin, err := k.BridgeTokenToBaseCoin(ctx, token.Contract, token.Amount, refund.Bytes())
if err != nil {
return err
}
baseCoins = baseCoins.Add(baseCoin)
}

ctx.EventManager().EmitEvent(sdk.NewEvent(
types.EventTypeBridgeCallRefund,
sdk.NewAttribute(types.AttributeKeyRefund, refund.String()),
))

for _, coin := range baseCoins {
_, err := k.BaseCoinToEvm(ctx, coin, common.BytesToAddress(refund.Bytes()))
if err != nil {
return err
}
}
return nil
}

func (k Keeper) DeleteOutgoingBridgeCallRecord(ctx sdk.Context, bridgeCallNonce uint64) {
// 1. delete bridge call
k.DeleteOutgoingBridgeCall(ctx, bridgeCallNonce)

// 2. delete bridge call confirm
k.DeleteBridgeCallConfirm(ctx, bridgeCallNonce)
}

func (k Keeper) SetOutgoingBridgeCall(ctx sdk.Context, outCall *types.OutgoingBridgeCall) {
Expand Down
3 changes: 2 additions & 1 deletion x/crosschain/keeper/bridge_call_out_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ func (s *KeeperMockSuite) TestKeeper_BridgeCallResultHandler() {
Timeout: 0,
BlockHeight: 0,
})
s.crosschainKeeper.BridgeCallResultHandler(s.ctx, msg)
err := s.crosschainKeeper.BridgeCallResultHandler(s.ctx, msg)
s.Require().NoError(err)
outgoingBridgeCall, found := s.crosschainKeeper.GetOutgoingBridgeCallByNonce(s.ctx, msg.Nonce)
s.False(found)
s.Nil(outgoingBridgeCall)
Expand Down
34 changes: 0 additions & 34 deletions x/crosschain/keeper/bridge_call_refund.go

This file was deleted.

49 changes: 0 additions & 49 deletions x/crosschain/keeper/bridge_call_refund_test.go

This file was deleted.

Loading