Skip to content

Commit

Permalink
feat: deploy fee contract for transaction processing (#807)
Browse files Browse the repository at this point in the history
Co-authored-by: todd <[email protected]>
  • Loading branch information
zakir-code and todd-woko authored Nov 11, 2024
1 parent 6a2f0a1 commit 08db739
Show file tree
Hide file tree
Showing 17 changed files with 5,303 additions and 509 deletions.
33 changes: 33 additions & 0 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package app

import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
Expand Down Expand Up @@ -55,6 +56,7 @@ import (

fxante "github.com/functionx/fx-core/v8/ante"
"github.com/functionx/fx-core/v8/app/keepers"
"github.com/functionx/fx-core/v8/contract"
_ "github.com/functionx/fx-core/v8/docs/statik"
fxcfg "github.com/functionx/fx-core/v8/server/config"
fxauth "github.com/functionx/fx-core/v8/server/grpc/auth"
Expand All @@ -64,6 +66,7 @@ import (
"github.com/functionx/fx-core/v8/x/crosschain"
"github.com/functionx/fx-core/v8/x/crosschain/keeper"
crosschaintypes "github.com/functionx/fx-core/v8/x/crosschain/types"
ethtypes "github.com/functionx/fx-core/v8/x/eth/types"
fxevmtypes "github.com/functionx/fx-core/v8/x/evm/types"
ibcmiddlewaretypes "github.com/functionx/fx-core/v8/x/ibc/middleware/types"
)
Expand Down Expand Up @@ -345,6 +348,36 @@ func (app *App) InitChainer(ctx sdk.Context, req *abci.RequestInitChain) (*abci.
panic(err)
}

bridgeFeeQuoteKeeper := contract.NewBridgeFeeQuoteKeeper(app.EvmKeeper, contract.BridgeFeeAddress)
bridgeFeeOracleKeeper := contract.NewBridgeFeeOracleKeeper(app.EvmKeeper, contract.BridgeFeeOracleAddress)

acc := app.AccountKeeper.GetModuleAddress(evmtypes.ModuleName)
moduleAddress := common.BytesToAddress(acc.Bytes())

delegations, err := app.StakingKeeper.GetAllDelegations(ctx)
if err != nil {
return nil, err
}
if len(delegations) == 0 {
return nil, errors.New("no delegations found")
}
bridgeDenoms := []contract.BridgeDenoms{
{
ChainName: ethtypes.ModuleName,
Denoms: []string{fxtypes.DefaultDenom},
},
}
if err = contract.DeployBridgeFeeContract(
ctx,
app.EvmKeeper,
bridgeFeeQuoteKeeper,
bridgeFeeOracleKeeper,
bridgeDenoms,
moduleAddress, moduleAddress,
common.BytesToAddress(sdk.MustAccAddressFromBech32(delegations[0].DelegatorAddress).Bytes()),
); err != nil {
return nil, err
}
return response, nil
}

Expand Down
42 changes: 42 additions & 0 deletions app/upgrades/v8/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package v8

import (
"context"
"errors"
"strings"

storetypes "cosmossdk.io/store/types"
Expand All @@ -17,10 +18,12 @@ import (
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
ibctransfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
ibcchanneltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types"
"github.com/ethereum/go-ethereum/common"
evmtypes "github.com/evmos/ethermint/x/evm/types"

"github.com/functionx/fx-core/v8/app/keepers"
"github.com/functionx/fx-core/v8/app/upgrades/store"
"github.com/functionx/fx-core/v8/contract"
fxtypes "github.com/functionx/fx-core/v8/types"
crosschaintypes "github.com/functionx/fx-core/v8/x/crosschain/types"
erc20keeper "github.com/functionx/fx-core/v8/x/erc20/keeper"
Expand Down Expand Up @@ -72,6 +75,45 @@ func CreateUpgradeHandler(cdc codec.Codec, mm *module.Manager, configurator modu

store.RemoveStoreKeys(cacheCtx, app.GetKey(erc20types.StoreKey), erc20v8.GetRemovedStoreKeys())

quoteKeeper := contract.NewBridgeFeeQuoteKeeper(app.EvmKeeper, contract.BridgeFeeAddress)
oracleKeeper := contract.NewBridgeFeeOracleKeeper(app.EvmKeeper, contract.BridgeFeeOracleAddress)
chains := crosschaintypes.GetSupportChains()
bridgeDenoms := make([]contract.BridgeDenoms, len(chains))
for index, chain := range chains {
denoms := make([]string, 0)
bridgeTokens, err := app.Erc20Keeper.GetBridgeTokens(cacheCtx, chain)
if err != nil {
return fromVM, err
}
for _, token := range bridgeTokens {
denoms = append(denoms, token.GetDenom())
}
bridgeDenoms[index] = contract.BridgeDenoms{
ChainName: chain,
Denoms: denoms,
}
}
acc := app.AccountKeeper.GetModuleAddress(evmtypes.ModuleName)
moduleAddress := common.BytesToAddress(acc.Bytes())

oracles := app.CrosschainKeepers.EthKeeper.GetAllOracles(cacheCtx, true)
if oracles.Len() <= 0 {
return fromVM, errors.New("no oracle found")
}

if err = contract.DeployBridgeFeeContract(
cacheCtx,
app.EvmKeeper,
quoteKeeper,
oracleKeeper,
bridgeDenoms,
moduleAddress,
// TODO set bridge fee contract owner address before mainnet upgrade
moduleAddress,
common.HexToAddress(oracles[0].ExternalAddress),
); err != nil {
return fromVM, err
}
commit()
cacheCtx.Logger().Info("upgrade complete", "module", "upgrade")
return toVM, nil
Expand Down
4 changes: 2 additions & 2 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ func (suite *rpcTestSuite) TestClient_Tx() {
// 0. initAccount
// 1.fee_collector + 2.distribution + 3.bonded_tokens_pool + 4.not_bonded_tokens_pool + 5.gov + 6.mint + 7.autytypes.NewModuleAddress(crosschain)
// 8.evm 9.0x..1001 10.0x..1002 11.erc20 12.wfx-contract
suite.Equal(authtypes.NewBaseAccount(toAddress, nil, uint64(15+i), 0), account)
suite.Equal(authtypes.NewBaseAccount(toAddress, nil, uint64(19+i), 0), account)
}

ethPrivKey := suite.GetPrivKeyByIndex(hd2.EthSecp256k1Type, 0)
Expand Down Expand Up @@ -224,7 +224,7 @@ func (suite *rpcTestSuite) TestClient_Tx() {

account, err := cli.QueryAccount(ethAddress.String())
suite.Require().NoError(err)
suite.Equal(authtypes.NewBaseAccount(ethAddress, nil, uint64(18), 0), account)
suite.Equal(authtypes.NewBaseAccount(ethAddress, nil, uint64(22), 0), account)
}

for i := 0; i < len(clients); i++ {
Expand Down
130 changes: 130 additions & 0 deletions contract/bridge_fee.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package contract

import (
"math/big"

sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
)

func DeployBridgeFeeContract(
ctx sdk.Context,
evmKeeper EvmKeeper,
bridgeFeeQuoteKeeper BridgeFeeQuoteKeeper,
bridgeFeeOracleKeeper BridgeFeeOracleKeeper,
bridgeDenoms []BridgeDenoms,
evmModuleAddress, owner, defaultOracleAddress common.Address,
) error {
if err := deployBridgeProxy(
ctx,
evmKeeper,
GetBridgeFeeQuote().ABI,
GetBridgeFeeQuote().Bin,
common.HexToAddress(BridgeFeeAddress),
evmModuleAddress,
); err != nil {
return err
}
if err := deployBridgeProxy(
ctx,
evmKeeper,
GetBridgeFeeOracle().ABI,
GetBridgeFeeOracle().Bin,
common.HexToAddress(BridgeFeeOracleAddress),
evmModuleAddress,
); err != nil {
return err
}

if err := initBridgeFeeOracle(ctx, bridgeFeeOracleKeeper, owner, defaultOracleAddress); err != nil {
return err
}
return initBridgeFeeQuote(ctx, bridgeFeeQuoteKeeper, bridgeDenoms, owner)
}

func deployBridgeProxy(
ctx sdk.Context,
evmKeeper EvmKeeper,
logicABI abi.ABI,
logicBin []byte,
proxyAddress, evmModuleAddress common.Address,
) error {
logicContract, err := evmKeeper.DeployContract(ctx, evmModuleAddress, logicABI, logicBin)
if err != nil {
return err
}
if err = evmKeeper.CreateContractWithCode(ctx, proxyAddress, GetBridgeProxy().Code); err != nil {
return err
}
if _, err = evmKeeper.ApplyContract(ctx, evmModuleAddress, proxyAddress, nil, GetBridgeProxy().ABI, "init", logicContract); err != nil {
return err
}
return nil
}

func initBridgeFeeOracle(
ctx sdk.Context,
bridgeFeeOracleKeeper BridgeFeeOracleKeeper,
owner, defaultOracleAddress common.Address,
) error {
if _, err := bridgeFeeOracleKeeper.Initialize(ctx); err != nil {
return err
}
role, err := bridgeFeeOracleKeeper.GetQuoteRole(ctx)
if err != nil {
return err
}
if _, err = bridgeFeeOracleKeeper.GrantRole(ctx, role, common.HexToAddress(BridgeFeeAddress)); err != nil {
return err
}
ownerRole, err := bridgeFeeOracleKeeper.GetOwnerRole(ctx)
if err != nil {
return err
}
if _, err = bridgeFeeOracleKeeper.GrantRole(ctx, ownerRole, owner); err != nil {
return err
}
upgradeRole, err := bridgeFeeOracleKeeper.GetUpgradeRole(ctx)
if err != nil {
return err
}
if _, err = bridgeFeeOracleKeeper.GrantRole(ctx, upgradeRole, owner); err != nil {
return err
}
if _, err = bridgeFeeOracleKeeper.SetDefaultOracle(ctx, defaultOracleAddress); err != nil {
return err
}
return nil
}

func initBridgeFeeQuote(
ctx sdk.Context,
bridgeFeeQuoteKeeper BridgeFeeQuoteKeeper,
bridgeDenoms []BridgeDenoms,
owner common.Address,
) error {
if _, err := bridgeFeeQuoteKeeper.Initialize(ctx, common.HexToAddress(BridgeFeeOracleAddress), big.NewInt(DefaultMaxQuoteIndex)); err != nil {
return err
}
ownerRole, err := bridgeFeeQuoteKeeper.GetOwnerRole(ctx)
if err != nil {
return err
}
if _, err = bridgeFeeQuoteKeeper.GrantRole(ctx, ownerRole, owner); err != nil {
return err
}
upgradeRole, err := bridgeFeeQuoteKeeper.GetUpgradeRole(ctx)
if err != nil {
return err
}
if _, err = bridgeFeeQuoteKeeper.GrantRole(ctx, upgradeRole, owner); err != nil {
return err
}
for _, bridgeDenom := range bridgeDenoms {
if _, err = bridgeFeeQuoteKeeper.RegisterChain(ctx, bridgeDenom.ChainName, bridgeDenom.Denoms...); err != nil {
return err
}
}
return nil
}
63 changes: 63 additions & 0 deletions contract/bridge_fee_oracle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package contract

import (
"context"

sdk "github.com/cosmos/cosmos-sdk/types"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
"github.com/ethereum/go-ethereum/accounts/abi"
"github.com/ethereum/go-ethereum/common"
"github.com/evmos/ethermint/x/evm/types"
)

type BridgeFeeOracleKeeper struct {
Caller
abi abi.ABI
from common.Address
contract common.Address
}

func NewBridgeFeeOracleKeeper(caller Caller, contract string) BridgeFeeOracleKeeper {
return BridgeFeeOracleKeeper{
Caller: caller,
abi: GetBridgeFeeOracle().ABI,
from: common.BytesToAddress(authtypes.NewModuleAddress(types.ModuleName).Bytes()),
contract: common.HexToAddress(contract),
}
}

func (k BridgeFeeOracleKeeper) Initialize(ctx context.Context) (*types.MsgEthereumTxResponse, error) {
return k.Caller.ApplyContract(ctx, k.from, k.contract, nil, k.abi, "initialize", common.HexToAddress(CrosschainAddress))
}

func (k BridgeFeeOracleKeeper) GetOwnerRole(ctx context.Context) (common.Hash, error) {
var res struct{ Role common.Hash }
if err := k.QueryContract(sdk.UnwrapSDKContext(ctx), k.from, k.contract, k.abi, "OWNER_ROLE", &res); err != nil {
return common.Hash{}, err
}
return res.Role, nil
}

func (k BridgeFeeOracleKeeper) GetUpgradeRole(ctx context.Context) (common.Hash, error) {
var res struct{ Role common.Hash }
if err := k.QueryContract(sdk.UnwrapSDKContext(ctx), k.from, k.contract, k.abi, "UPGRADE_ROLE", &res); err != nil {
return common.Hash{}, err
}
return res.Role, nil
}

func (k BridgeFeeOracleKeeper) GetQuoteRole(ctx context.Context) (common.Hash, error) {
var res struct{ Role common.Hash }
if err := k.QueryContract(sdk.UnwrapSDKContext(ctx), k.from, k.contract, k.abi, "QUOTE_ROLE", &res); err != nil {
return common.Hash{}, err
}
return res.Role, nil
}

func (k BridgeFeeOracleKeeper) GrantRole(ctx context.Context, role common.Hash, account common.Address) (*types.MsgEthereumTxResponse, error) {
return k.ApplyContract(ctx, k.from, k.contract, nil, k.abi, "grantRole", role, account)
}

func (k BridgeFeeOracleKeeper) SetDefaultOracle(ctx context.Context, oracle common.Address) (*types.MsgEthereumTxResponse, error) {
return k.ApplyContract(ctx, k.from, k.contract, nil, k.abi, "setDefaultOracle", oracle)
}
1,821 changes: 1,821 additions & 0 deletions contract/bridge_fee_oracle.sol.go

Large diffs are not rendered by default.

Loading

0 comments on commit 08db739

Please sign in to comment.