Skip to content

Commit

Permalink
refactor(precompile): migrate cross-chain logic to cosmos code (#741)
Browse files Browse the repository at this point in the history
Co-authored-by: nulnut <[email protected]>
  • Loading branch information
zakir-code and nulnut authored Oct 14, 2024
1 parent b2e11ba commit b4a9d88
Show file tree
Hide file tree
Showing 18 changed files with 303 additions and 327 deletions.
10 changes: 9 additions & 1 deletion app/keepers/keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,7 @@ func NewAppKeeper(
[]evmkeeper.CustomContractFn{
func(_ sdk.Context, _ ethparams.Rules) vm.PrecompiledContract {
return crosschainprecompile.NewPrecompiledContract(appKeepers.BankKeeper, appKeepers.Erc20Keeper,
appKeepers.IBCTransferKeeper, appKeepers.AccountKeeper, appKeepers.GovKeeper, precompileRouter)
appKeepers.GovKeeper, precompileRouter)
},
func(_ sdk.Context, _ ethparams.Rules) vm.PrecompiledContract {
return stakingprecompile.NewPrecompiledContract(appKeepers.BankKeeper, appKeepers.StakingKeeper,
Expand Down Expand Up @@ -377,6 +377,7 @@ func NewAppKeeper(
appKeepers.Erc20Keeper,
appKeepers.AccountKeeper,
appKeepers.EvmKeeper,
appKeepers.EvmKeeper,
authAddr,
)
appKeepers.PolygonKeeper = crosschainkeeper.NewKeeper(
Expand All @@ -391,6 +392,7 @@ func NewAppKeeper(
appKeepers.Erc20Keeper,
appKeepers.AccountKeeper,
appKeepers.EvmKeeper,
appKeepers.EvmKeeper,
authAddr,
)
appKeepers.AvalancheKeeper = crosschainkeeper.NewKeeper(
Expand All @@ -405,6 +407,7 @@ func NewAppKeeper(
appKeepers.Erc20Keeper,
appKeepers.AccountKeeper,
appKeepers.EvmKeeper,
appKeepers.EvmKeeper,
authAddr,
)
appKeepers.EthKeeper = crosschainkeeper.NewKeeper(
Expand All @@ -419,6 +422,7 @@ func NewAppKeeper(
appKeepers.Erc20Keeper,
appKeepers.AccountKeeper,
appKeepers.EvmKeeper,
appKeepers.EvmKeeper,
authAddr,
)
appKeepers.ArbitrumKeeper = crosschainkeeper.NewKeeper(
Expand All @@ -433,6 +437,7 @@ func NewAppKeeper(
appKeepers.Erc20Keeper,
appKeepers.AccountKeeper,
appKeepers.EvmKeeper,
appKeepers.EvmKeeper,
authAddr,
)
appKeepers.OptimismKeeper = crosschainkeeper.NewKeeper(
Expand All @@ -447,6 +452,7 @@ func NewAppKeeper(
appKeepers.Erc20Keeper,
appKeepers.AccountKeeper,
appKeepers.EvmKeeper,
appKeepers.EvmKeeper,
authAddr,
)
appKeepers.Layer2Keeper = crosschainkeeper.NewKeeper(
Expand All @@ -461,6 +467,7 @@ func NewAppKeeper(
appKeepers.Erc20Keeper,
appKeepers.AccountKeeper,
appKeepers.EvmKeeper,
appKeepers.EvmKeeper,
authAddr,
)
appKeepers.TronKeeper = crosschainkeeper.NewKeeper(
Expand All @@ -475,6 +482,7 @@ func NewAppKeeper(
appKeepers.Erc20Keeper,
appKeepers.AccountKeeper,
appKeepers.EvmKeeper,
appKeepers.EvmKeeper,
authAddr,
)

Expand Down
108 changes: 108 additions & 0 deletions x/crosschain/keeper/bridge_call_out.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,22 @@ import (
"fmt"
"math"
"strconv"
"strings"

sdkmath "cosmossdk.io/math"
storetypes "cosmossdk.io/store/types"
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
gogotypes "github.com/cosmos/gogoproto/types"
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"
)

Expand Down Expand Up @@ -226,3 +233,104 @@ func (k Keeper) IterateOutgoingBridgeCallByNonce(ctx sdk.Context, startNonce uin
}
}
}

func (k Keeper) BridgeCallBaseCoin(
ctx sdk.Context,
from, refund, to common.Address,
coins sdk.Coins,
data, memo []byte,
target string,
originTokenAmount sdkmath.Int,
) (uint64, error) {
fxTarget := fxtypes.ParseFxTarget(target)
if fxTarget.IsIBC() {
if !coins.IsValid() || len(coins) != 1 {
return 0, sdkerrors.ErrInvalidCoins.Wrapf("ibc transfer with coins: %s", coins.String())
}
amount := coins[0]
toAddr, err := fxTarget.ReceiveAddrToStr(to.Bytes())
if err != nil {
return 0, sdkerrors.ErrInvalidAddress.Wrapf("ibc transfer target %s to: %s", fxTarget.GetTarget(), to.String())
}
return k.IBCTransfer(ctx, from.Bytes(), toAddr, amount, sdk.NewCoin(amount.Denom, sdkmath.ZeroInt()), fxTarget, string(memo), originTokenAmount.IsZero())
}
// todo record origin amount
return k.AddOutgoingBridgeCall(ctx, from, refund, coins, to, data, memo, 0)
}

func (k Keeper) CrossChainBaseCoin(
ctx sdk.Context,
from sdk.AccAddress,
receipt string,
amount, fee sdk.Coin,
target string,
memo string,
originToken bool,
) error {
fxTarget := fxtypes.ParseFxTarget(target)
if fxTarget.IsIBC() {
_, err := k.IBCTransfer(ctx, from.Bytes(), receipt, amount, fee, fxTarget, memo, originToken)
return err
}
if err := types.ValidateExternalAddr(fxTarget.GetTarget(), receipt); err != nil {
return sdkerrors.ErrInvalidAddress.Wrapf("invalid receive address: %s", err)
}
batchNonce, err := k.BuildOutgoingTxBatch(ctx, from, receipt, amount, fee)
if err != nil {
return err
}
if !originToken {
k.erc20Keeper.SetOutgoingTransferRelation(ctx, fxTarget.GetTarget(), batchNonce)
}
return nil
}

func (k Keeper) IBCTransfer(
ctx sdk.Context,
from sdk.AccAddress,
to string,
amount, fee sdk.Coin,
fxTarget fxtypes.FxTarget,
memo string,
originToken bool,
) (uint64, error) {
if !fee.IsZero() {
return 0, fmt.Errorf("ibc transfer fee must be zero: %s", fee.String())
}
if strings.ToLower(fxTarget.Prefix) == contract.EthereumAddressPrefix {
if err := contract.ValidateEthereumAddress(to); err != nil {
return 0, fmt.Errorf("invalid to address: %s", to)
}
} else {
if _, err := sdk.GetFromBech32(to, fxTarget.Prefix); err != nil {
return 0, fmt.Errorf("invalid to address: %s", to)
}
}
if !originToken {
var err error
amount, err = k.BaseCoinToIBCCoin(ctx, amount, from, fxTarget.String())
if err != nil {
return 0, err
}
}
ibcTimeoutTimestamp := uint64(ctx.BlockTime().UnixNano()) + uint64(k.erc20Keeper.GetIbcTimeout(ctx))
transferResponse, err := k.ibcTransferKeeper.Transfer(ctx,
transfertypes.NewMsgTransfer(
fxTarget.SourcePort,
fxTarget.SourceChannel,
amount,
from.String(),
to,
ibcclienttypes.ZeroHeight(),
ibcTimeoutTimestamp,
memo,
),
)
if err != nil {
return 0, fmt.Errorf("ibc transfer error: %s", err.Error())
}
if !originToken {
k.erc20Keeper.SetIBCTransferRelation(ctx, fxTarget.SourceChannel, transferResponse.Sequence)
}
return transferResponse.Sequence, nil
}
30 changes: 30 additions & 0 deletions x/crosschain/keeper/bridge_token.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ import (
"fmt"
"strings"

sdkmath "cosmossdk.io/math"
storetypes "cosmossdk.io/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/ethereum/go-ethereum/common"

fxtypes "github.com/functionx/fx-core/v8/types"
"github.com/functionx/fx-core/v8/x/crosschain/types"
Expand Down Expand Up @@ -175,3 +178,30 @@ func (k Keeper) SetToken(ctx context.Context, name, symbol string, decimals uint
k.bankKeeper.SetDenomMetaData(ctx, metadata)
return nil
}

func (k Keeper) BridgeCoinSupply(ctx sdk.Context, tokenOrDenom, target string) (sdk.Coin, error) {
tokenPair, found := k.erc20Keeper.GetTokenPair(ctx, tokenOrDenom)
if !found {
return sdk.Coin{}, sdkerrors.ErrInvalidCoins.Wrapf("token pair not found: %s", tokenOrDenom)
}
if tokenPair.IsNativeERC20() {
supply, err := k.evmErc20Keeper.TotalSupply(ctx, tokenPair.GetERC20Contract())
if err != nil {
return sdk.Coin{}, err
}
return sdk.NewCoin(tokenPair.GetDenom(), sdkmath.NewIntFromBigInt(supply)), nil
}
targetDenom, err := k.ManyToOne(ctx, tokenPair.GetDenom(), target)
if err != nil {
return sdk.Coin{}, err
}
return k.bankKeeper.GetSupply(ctx, targetDenom), nil
}

func (k Keeper) GetBaseDenomByErc20(ctx sdk.Context, erc20Addr common.Address) (string, bool, error) {
tokenPair, found := k.erc20Keeper.GetTokenPair(ctx, erc20Addr.String())
if !found {
return "", false, sdkerrors.ErrInvalidAddress.Wrapf("base denom not found: %s", erc20Addr.String())
}
return tokenPair.GetDenom(), tokenPair.IsNativeCoin(), nil
}
10 changes: 1 addition & 9 deletions x/crosschain/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,18 +295,10 @@ func (k QueryServer) BridgeCoinByDenom(c context.Context, req *types.QueryBridge
if len(req.GetDenom()) == 0 {
return nil, status.Error(codes.InvalidArgument, "denom")
}
ctx := sdk.UnwrapSDKContext(c)

bridgeDenom, err := k.GetBridgeDenom(ctx, req.Denom, req.ChainName)
supply, err := k.BridgeCoinSupply(sdk.UnwrapSDKContext(c), req.GetDenom(), req.GetChainName())
if err != nil {
return nil, err
}
_, found := k.GetContractByBridgeDenom(ctx, bridgeDenom)
if !found {
return nil, status.Error(codes.NotFound, "denom")
}

supply := k.bankKeeper.GetSupply(ctx, bridgeDenom)
return &types.QueryBridgeCoinByDenomResponse{Coin: supply}, nil
}

Expand Down
4 changes: 3 additions & 1 deletion x/crosschain/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type Keeper struct {
ibcTransferKeeper types.IBCTransferKeeper
erc20Keeper types.Erc20Keeper
evmKeeper types.EVMKeeper
evmErc20Keeper types.EvmERC20Keeper

authority string
callbackFrom common.Address
Expand All @@ -37,7 +38,7 @@ type Keeper struct {
func NewKeeper(cdc codec.BinaryCodec, moduleName string, storeKey storetypes.StoreKey,
stakingKeeper types.StakingKeeper, stakingMsgServer types.StakingMsgServer, distributionKeeper types.DistributionMsgServer,
bankKeeper types.BankKeeper, ibcTransferKeeper types.IBCTransferKeeper, erc20Keeper types.Erc20Keeper, ak types.AccountKeeper,
evmKeeper types.EVMKeeper, authority string,
evmKeeper types.EVMKeeper, evmErc20Keeper types.EvmERC20Keeper, authority string,
) Keeper {
if addr := ak.GetModuleAddress(moduleName); addr == nil {
panic(fmt.Sprintf("%s module account has not been set", moduleName))
Expand All @@ -56,6 +57,7 @@ func NewKeeper(cdc codec.BinaryCodec, moduleName string, storeKey storetypes.Sto
ibcTransferKeeper: ibcTransferKeeper,
erc20Keeper: erc20Keeper,
evmKeeper: evmKeeper,
evmErc20Keeper: evmErc20Keeper,
authority: authority,
callbackFrom: common.BytesToAddress(autytypes.NewModuleAddress(types.ModuleName)),
}
Expand Down
3 changes: 3 additions & 0 deletions x/crosschain/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ type KeeperMockSuite struct {
erc20Keeper *mock.MockErc20Keeper
accountKeeper *mock.MockAccountKeeper
evmKeeper *mock.MockEVMKeeper
evmErc20Keeper *mock.MockEvmERC20Keeper
}

func TestKeeperTestSuite(t *testing.T) {
Expand Down Expand Up @@ -99,6 +100,7 @@ func (s *KeeperMockSuite) SetupTest() {
s.erc20Keeper = mock.NewMockErc20Keeper(ctrl)
s.accountKeeper = mock.NewMockAccountKeeper(ctrl)
s.evmKeeper = mock.NewMockEVMKeeper(ctrl)
s.evmErc20Keeper = mock.NewMockEvmERC20Keeper(ctrl)

s.accountKeeper.EXPECT().GetModuleAddress(s.moduleName).Return(authtypes.NewEmptyModuleAccount(s.moduleName).GetAddress()).Times(1)

Expand All @@ -114,6 +116,7 @@ func (s *KeeperMockSuite) SetupTest() {
s.erc20Keeper,
s.accountKeeper,
s.evmKeeper,
s.evmErc20Keeper,
authtypes.NewModuleAddress(govtypes.ModuleName).String(),
)

Expand Down
Loading

0 comments on commit b4a9d88

Please sign in to comment.