github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/x/vmbridge/keeper/evm.go (about)

     1  package keeper
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/fibonacci-chain/fbc/x/evm/watcher"
     6  	"math/big"
     7  
     8  	"github.com/ethereum/go-ethereum/common"
     9  	ethermint "github.com/fibonacci-chain/fbc/app/types"
    10  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    11  	sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors"
    12  	tmtypes "github.com/fibonacci-chain/fbc/libs/tendermint/types"
    13  	erc20types "github.com/fibonacci-chain/fbc/x/erc20/types"
    14  	evmtypes "github.com/fibonacci-chain/fbc/x/evm/types"
    15  	"github.com/fibonacci-chain/fbc/x/vmbridge/types"
    16  )
    17  
    18  // event __SendToWasmEventName(string wasmAddr,string recipient, string amount)
    19  type SendToWasmEventHandler struct {
    20  	Keeper
    21  }
    22  
    23  func NewSendToWasmEventHandler(k Keeper) *SendToWasmEventHandler {
    24  	return &SendToWasmEventHandler{k}
    25  }
    26  
    27  // EventID Return the id of the log signature it handles
    28  func (h SendToWasmEventHandler) EventID() common.Hash {
    29  	return types.SendToWasmEvent.ID
    30  }
    31  
    32  // Handle Process the log
    33  func (h SendToWasmEventHandler) Handle(ctx sdk.Context, contract common.Address, data []byte) error {
    34  	if !tmtypes.HigherThanEarth(ctx.BlockHeight()) {
    35  		errMsg := fmt.Sprintf("vmbridger not supprt at height %d", ctx.BlockHeight())
    36  		return sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg)
    37  	}
    38  
    39  	params := h.wasmKeeper.GetParams(ctx)
    40  	if !params.VmbridgeEnable {
    41  		return types.ErrVMBridgeEnable
    42  	}
    43  
    44  	logger := h.Keeper.Logger()
    45  	unpacked, err := types.SendToWasmEvent.Inputs.Unpack(data)
    46  	if err != nil {
    47  		// log and ignore
    48  		logger.Error("log signature matches but failed to decode", "error", err)
    49  		return nil
    50  	}
    51  
    52  	caller := sdk.AccAddress(contract.Bytes())
    53  	wasmAddr := unpacked[0].(string)
    54  	recipient := unpacked[1].(string)
    55  	amount := sdk.NewIntFromBigInt(unpacked[2].(*big.Int))
    56  
    57  	return h.Keeper.SendToWasm(ctx, caller, wasmAddr, recipient, amount)
    58  }
    59  
    60  // wasm call evm for erc20 exchange cw20,
    61  func (k Keeper) SendToEvm(ctx sdk.Context, caller, contract string, recipient string, amount sdk.Int) (success bool, err error) {
    62  	if !sdk.IsETHAddress(recipient) {
    63  		return false, types.ErrIsNotETHAddr
    64  	}
    65  
    66  	if !sdk.IsETHAddress(contract) {
    67  		return false, types.ErrIsNotETHAddr
    68  	}
    69  
    70  	contractAccAddr, err := sdk.AccAddressFromBech32(contract)
    71  	if err != nil {
    72  		return false, err
    73  	}
    74  	conrtractAddr := common.BytesToAddress(contractAccAddr.Bytes())
    75  
    76  	recipientAccAddr, err := sdk.AccAddressFromBech32(recipient)
    77  	if err != nil {
    78  		return false, err
    79  	}
    80  	recipientAddr := common.BytesToAddress(recipientAccAddr.Bytes())
    81  	input, err := types.GetMintERC20Input(caller, recipientAddr, amount.BigInt())
    82  	if err != nil {
    83  		return false, err
    84  	}
    85  
    86  	// k.CallEvm will call evm, so we must enable evm watch db with follow code
    87  	if watcher.IsWatcherEnabled() {
    88  		ctx.SetWatcher(watcher.NewTxWatcher())
    89  	}
    90  	_, result, err := k.CallEvm(ctx, &conrtractAddr, big.NewInt(0), input)
    91  	if err != nil {
    92  		return false, err
    93  	}
    94  	success, err = types.GetMintERC20Output(result.Ret)
    95  	if watcher.IsWatcherEnabled() && err == nil {
    96  		ctx.GetWatcher().Finalize()
    97  	}
    98  	return success, err
    99  }
   100  
   101  // callEvm execute an evm message from native module
   102  func (k Keeper) CallEvm(ctx sdk.Context, to *common.Address, value *big.Int, data []byte) (*evmtypes.ExecutionResult, *evmtypes.ResultData, error) {
   103  	callerAddr := erc20types.IbcEvmModuleETHAddr
   104  
   105  	config, found := k.evmKeeper.GetChainConfig(ctx)
   106  	if !found {
   107  		return nil, nil, types.ErrChainConfigNotFound
   108  	}
   109  
   110  	chainIDEpoch, err := ethermint.ParseChainID(ctx.ChainID())
   111  	if err != nil {
   112  		return nil, nil, err
   113  	}
   114  
   115  	acc := k.accountKeeper.GetAccount(ctx, callerAddr.Bytes())
   116  	if acc == nil {
   117  		acc = k.accountKeeper.NewAccountWithAddress(ctx, callerAddr.Bytes())
   118  	}
   119  	nonce := acc.GetSequence()
   120  	txHash := tmtypes.Tx(ctx.TxBytes()).Hash(ctx.BlockHeight())
   121  	ethTxHash := common.BytesToHash(txHash)
   122  
   123  	gasLimit := ctx.GasMeter().Limit()
   124  	if gasLimit == sdk.NewInfiniteGasMeter().Limit() {
   125  		gasLimit = k.evmKeeper.GetParams(ctx).MaxGasLimitPerTx
   126  	}
   127  
   128  	st := evmtypes.StateTransition{
   129  		AccountNonce: nonce,
   130  		Price:        big.NewInt(0),
   131  		GasLimit:     gasLimit,
   132  		Recipient:    to,
   133  		Amount:       value,
   134  		Payload:      data,
   135  		Csdb:         evmtypes.CreateEmptyCommitStateDB(k.evmKeeper.GenerateCSDBParams(), ctx),
   136  		ChainID:      chainIDEpoch,
   137  		TxHash:       &ethTxHash,
   138  		Sender:       callerAddr,
   139  		Simulate:     ctx.IsCheckTx(),
   140  		TraceTx:      false,
   141  		TraceTxLog:   false,
   142  	}
   143  
   144  	executionResult, resultData, err, _, _ := st.TransitionDb(ctx, config)
   145  	if !ctx.IsCheckTx() && !ctx.IsTraceTx() {
   146  		//TODO maybe add innertx
   147  		//k.addEVMInnerTx(ethTxHash.Hex(), innertxs, contracts)
   148  	}
   149  	if err != nil {
   150  		return nil, nil, err
   151  	}
   152  
   153  	st.Csdb.Commit(false) // write code to db
   154  	acc.SetSequence(nonce + 1)
   155  	k.accountKeeper.SetAccount(ctx, acc)
   156  
   157  	return executionResult, resultData, err
   158  }