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(precompile): migrate cross-chain logic to cosmos code #741

Merged
merged 1 commit into from
Oct 14, 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
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,
nulnut marked this conversation as resolved.
Show resolved Hide resolved
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)
}
nulnut marked this conversation as resolved.
Show resolved Hide resolved
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())
nulnut marked this conversation as resolved.
Show resolved Hide resolved
}
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