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: ðTxHash, 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 }