diff --git a/packages/vm/core/evm/evmimpl/impl.go b/packages/vm/core/evm/evmimpl/impl.go index 0310f66e4b..befdd8812c 100644 --- a/packages/vm/core/evm/evmimpl/impl.go +++ b/packages/vm/core/evm/evmimpl/impl.go @@ -44,8 +44,6 @@ var Processor = evm.Contract.Processor(nil, evm.FuncRegisterERC721NFTCollection.WithHandler(restricted(registerERC721NFTCollection)), evm.FuncNewL1Deposit.WithHandler(newL1Deposit), - evm.FuncNewL1Withdrawal.WithHandler(newL1Withdrawal), - evm.FuncNewTransferBetweenL2Accounts.WithHandler(newTransferBetweenL2Accounts), // views evm.FuncGetERC20ExternalNativeTokenAddress.WithHandler(viewERC20ExternalNativeTokenAddress), @@ -447,33 +445,7 @@ func newL1Deposit(ctx isc.Sandbox) dict.Dict { assets, err := isc.AssetsFromBytes(params.MustGetBytes(evm.FieldAssets)) ctx.RequireNoError(err, "unable to parse assets from params") txData := l1DepositOriginatorBytes - addDummyTxWithTransferEvents(ctx, fromAddress, toAddress, assets, txData) - return nil -} - -func newL1Withdrawal(ctx isc.Sandbox) dict.Dict { - // can only be called from the accounts contract - ctx.RequireCaller(isc.NewContractAgentID(ctx.ChainID(), accounts.Contract.Hname())) - params := ctx.Params() - targetL1AddressBytes := params.MustGetBytes(evm.FieldAgentIDWithdrawalTarget) - fromAddress := common.BytesToAddress(params.MustGetBytes(evm.FieldAddress)) - toAddress := common.Address{} - assets, err := isc.AssetsFromBytes(params.MustGetBytes(evm.FieldAssets)) - ctx.RequireNoError(err, "unable to parse assets from params") - txData := targetL1AddressBytes - addDummyTxWithTransferEvents(ctx, fromAddress, toAddress, assets, txData) - return nil -} - -func newTransferBetweenL2Accounts(ctx isc.Sandbox) dict.Dict { - // can only be called from the accounts contract - ctx.RequireCaller(isc.NewContractAgentID(ctx.ChainID(), accounts.Contract.Hname())) - params := ctx.Params() - fromAddress := common.BytesToAddress(params.MustGetBytes(evm.FieldFromAddress)) - toAddress := common.BytesToAddress(params.MustGetBytes(evm.FieldToAddress)) - assets, err := isc.AssetsFromBytes(params.MustGetBytes(evm.FieldAssets)) - ctx.RequireNoError(err, "unable to parse assets from params") - txData := fromAddress.Bytes() + // create a fake tx so that the operation is visible by the EVM addDummyTxWithTransferEvents(ctx, fromAddress, toAddress, assets, txData) return nil } @@ -484,8 +456,13 @@ func addDummyTxWithTransferEvents( assets *isc.Assets, txData []byte, ) { - // create a fake tx so that the operation is visible by the EVM + logs := makeTransferEvents(ctx, fromAddress, toAddress, assets) + wei := util.BaseTokensDecimalsToEthereumDecimals(assets.BaseTokens, newEmulatorContext(ctx).BaseTokensDecimals()) + if wei.Sign() == 0 && len(logs) == 0 { + return + } + nonce := uint64(0) chainInfo := ctx.ChainInfo() gasPrice := chainInfo.GasFeePolicy.DefaultGasPriceFullDecimals(parameters.L1().BaseToken.Decimals) @@ -507,6 +484,25 @@ func addDummyTxWithTransferEvents( }, ) + receipt := &types.Receipt{ + Type: types.LegacyTxType, + Logs: logs, + Status: types.ReceiptStatusSuccessful, + } + receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) + + ctx.Privileged().OnWriteReceipt(func(evmPartition kv.KVStore, gasBurned uint64) { + receipt.GasUsed = gas.ISCGasBurnedToEVM(gasBurned, &chainInfo.GasFeePolicy.EVMGasRatio) + receipt.CumulativeGasUsed = createBlockchainDB(evmPartition, chainInfo).GetPendingCumulativeGasUsed() + receipt.GasUsed + createBlockchainDB(evmPartition, ctx.ChainInfo()).AddTransaction(tx, receipt) + }) +} + +func makeTransferEvents( + ctx isc.Sandbox, + fromAddress, toAddress common.Address, + assets *isc.Assets, +) []*types.Log { logs := make([]*types.Log, 0) for _, nt := range assets.NativeTokens { if nt.Amount.Sign() == 0 { @@ -535,23 +531,7 @@ func addDummyTxWithTransferEvents( // otherwise, emit a Transfer event from the ERC721NFTs contract logs = append(logs, makeTransferEventERC721(iscmagic.ERC721NFTsAddress, fromAddress, toAddress, iscmagic.WrapNFTID(nftID).TokenID())) } - - if wei.Sign() == 0 && len(logs) == 0 { - return - } - - receipt := &types.Receipt{ - Type: types.LegacyTxType, - Logs: logs, - Status: types.ReceiptStatusSuccessful, - } - receipt.Bloom = types.CreateBloom(types.Receipts{receipt}) - - ctx.Privileged().OnWriteReceipt(func(evmPartition kv.KVStore, gasBurned uint64) { - receipt.GasUsed = gas.ISCGasBurnedToEVM(gasBurned, &chainInfo.GasFeePolicy.EVMGasRatio) - receipt.CumulativeGasUsed = createBlockchainDB(evmPartition, chainInfo).GetPendingCumulativeGasUsed() + receipt.GasUsed - createBlockchainDB(evmPartition, ctx.ChainInfo()).AddTransaction(tx, receipt) - }) + return logs } var transferEventTopic = crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)")) diff --git a/packages/vm/core/evm/evmimpl/iscmagic.go b/packages/vm/core/evm/evmimpl/iscmagic.go index 13724c8ca1..3bfd487b7d 100644 --- a/packages/vm/core/evm/evmimpl/iscmagic.go +++ b/packages/vm/core/evm/evmimpl/iscmagic.go @@ -84,7 +84,7 @@ func (c *magicContract) Run(evm *vm.EVM, caller vm.ContractRef, input []byte, va return nil, gas, ErrPayingUnpayableMethod.Create(method.Name) } - ret = callHandler(c.ctx, caller, value, method, args) + ret = callHandler(c.ctx, evm, caller, value, method, args) return ret, gas, nil } diff --git a/packages/vm/core/evm/evmimpl/iscmagic_handler.go b/packages/vm/core/evm/evmimpl/iscmagic_handler.go index a9f3cdaa42..4236bffc1f 100644 --- a/packages/vm/core/evm/evmimpl/iscmagic_handler.go +++ b/packages/vm/core/evm/evmimpl/iscmagic_handler.go @@ -23,15 +23,17 @@ import ( // correspond to a call to [GetL2NFTs]. type magicContractHandler struct { ctx isc.Sandbox + evm *vm.EVM caller vm.ContractRef callValue *uint256.Int } // callHandler finds the requested ISC magic method by reflection, and executes // it. -func callHandler(ctx isc.Sandbox, caller vm.ContractRef, callValue *uint256.Int, method *abi.Method, args []any) []byte { +func callHandler(ctx isc.Sandbox, evm *vm.EVM, caller vm.ContractRef, callValue *uint256.Int, method *abi.Method, args []any) []byte { return reflectCall(&magicContractHandler{ ctx: ctx, + evm: evm, caller: caller, callValue: callValue, }, method, args) diff --git a/packages/vm/core/evm/evmimpl/iscmagic_sandbox.go b/packages/vm/core/evm/evmimpl/iscmagic_sandbox.go index b0e1286e78..ce71482f4b 100644 --- a/packages/vm/core/evm/evmimpl/iscmagic_sandbox.go +++ b/packages/vm/core/evm/evmimpl/iscmagic_sandbox.go @@ -13,7 +13,6 @@ import ( "github.com/iotaledger/wasp/packages/kv/dict" "github.com/iotaledger/wasp/packages/parameters" "github.com/iotaledger/wasp/packages/util" - "github.com/iotaledger/wasp/packages/vm/core/accounts" "github.com/iotaledger/wasp/packages/vm/core/errors/coreerrors" "github.com/iotaledger/wasp/packages/vm/core/evm" "github.com/iotaledger/wasp/packages/vm/core/evm/iscmagic" @@ -55,17 +54,9 @@ func (h *magicContractHandler) TakeAllowedFunds(addr common.Address, allowance i assets, ) // emit ERC20 / ERC721 events for native tokens & NFTs - h.ctx.Privileged().CallOnBehalfOf( - isc.NewContractAgentID(h.ctx.ChainID(), accounts.Contract.Hname()), - evm.Contract.Hname(), - evm.FuncNewTransferBetweenL2Accounts.Hname(), - dict.Dict{ - evm.FieldFromAddress: addr.Bytes(), - evm.FieldToAddress: h.caller.Address().Bytes(), - evm.FieldAssets: assets.Bytes(), - }, - nil, - ) + for _, log := range makeTransferEvents(h.ctx, addr, h.caller.Address(), assets) { + h.evm.StateDB.AddLog(log) + } } var errInvalidAllowance = coreerrors.Register("allowance must not be greater than sent tokens").Create() @@ -118,17 +109,9 @@ func (h *magicContractHandler) Send( h.moveAssetsToCommonAccount(req.Assets) // emit ERC20 / ERC721 events for native tokens & NFTs - h.ctx.Privileged().CallOnBehalfOf( - isc.NewContractAgentID(h.ctx.ChainID(), accounts.Contract.Hname()), - evm.Contract.Hname(), - evm.FuncNewL1Withdrawal.Hname(), - dict.Dict{ - evm.FieldAgentIDWithdrawalTarget: isc.AddressToBytes(req.TargetAddress), - evm.FieldAddress: h.caller.Address().Bytes(), - evm.FieldAssets: req.Assets.Bytes(), - }, - nil, - ) + for _, log := range makeTransferEvents(h.ctx, h.caller.Address(), common.Address{}, req.Assets) { + h.evm.StateDB.AddLog(log) + } h.ctx.Privileged().SendOnBehalfOf( isc.ContractIdentityFromEVMAddress(h.caller.Address()), req, diff --git a/packages/vm/core/evm/evmnames/evmnames.go b/packages/vm/core/evm/evmnames/evmnames.go index c86db04da3..ad371796d9 100644 --- a/packages/vm/core/evm/evmnames/evmnames.go +++ b/packages/vm/core/evm/evmnames/evmnames.go @@ -17,9 +17,7 @@ const ( FuncGetERC20ExternalNativeTokenAddress = "getERC20ExternalNativeTokenAddress" FuncRegisterERC721NFTCollection = "registerERC721NFTCollection" - FuncNewL1Deposit = "newL1Deposit" - FuncNewL1Withdrawal = "newL1Withdrawal" - FuncNewTransferBetweenL2Accounts = "newTransferBetweenL2Accounts" + FuncNewL1Deposit = "newL1Deposit" FieldTransaction = "t" FieldCallMsg = "c" diff --git a/packages/vm/core/evm/evmtest/evm_test.go b/packages/vm/core/evm/evmtest/evm_test.go index 4cbeebcf96..69ae8c0687 100644 --- a/packages/vm/core/evm/evmtest/evm_test.go +++ b/packages/vm/core/evm/evmtest/evm_test.go @@ -904,33 +904,26 @@ func TestSendNFT(t *testing.T) { // 2. Transfer NFT ISCTest -> 0x0 (send to L1) { blockTxs := lo.Must(env.evmChain.BlockByNumber(nil)).Transactions() - require.Len(t, blockTxs, 3) - { - tx1 := blockTxs[0] - receipt1 := env.evmChain.TransactionReceipt(tx1.Hash()) - require.Len(t, receipt1.Logs, 1) - checkTransferEventERC721( - t, - receipt1.Logs[0], - iscmagic.ERC721NFTsAddress, - ethAddr, - iscTest.address, - iscmagic.WrapNFTID(nft.ID).TokenID(), - ) - } - { - tx2 := blockTxs[1] - receipt2 := env.evmChain.TransactionReceipt(tx2.Hash()) - require.Len(t, receipt2.Logs, 1) - checkTransferEventERC721( - t, - receipt2.Logs[0], - iscmagic.ERC721NFTsAddress, - iscTest.address, - common.Address{}, - iscmagic.WrapNFTID(nft.ID).TokenID(), - ) - } + require.Len(t, blockTxs, 1) + tx := blockTxs[0] + receipt := env.evmChain.TransactionReceipt(tx.Hash()) + require.Len(t, receipt.Logs, 2) + checkTransferEventERC721( + t, + receipt.Logs[0], + iscmagic.ERC721NFTsAddress, + ethAddr, + iscTest.address, + iscmagic.WrapNFTID(nft.ID).TokenID(), + ) + checkTransferEventERC721( + t, + receipt.Logs[1], + iscmagic.ERC721NFTsAddress, + iscTest.address, + common.Address{}, + iscmagic.WrapNFTID(nft.ID).TokenID(), + ) } } @@ -1676,7 +1669,7 @@ func TestERC20NativeTokensWithExternalFoundry(t *testing.T) { // there must be a Transfer event emitted from the foundry chain's ERC20NativeTokens contract { blockTxs := lo.Must(foundryChain.EVM().BlockByNumber(nil)).Transactions() - require.Len(t, blockTxs, 2) + require.Len(t, blockTxs, 1) tx := blockTxs[0] receipt := foundryChain.EVM().TransactionReceipt(tx.Hash()) require.Len(t, receipt.Logs, 1) diff --git a/packages/vm/core/evm/interface.go b/packages/vm/core/evm/interface.go index d962a9bb3b..da6b207d3a 100644 --- a/packages/vm/core/evm/interface.go +++ b/packages/vm/core/evm/interface.go @@ -28,9 +28,7 @@ var ( FuncGetERC20ExternalNativeTokenAddress = coreutil.ViewFunc(evmnames.FuncGetERC20ExternalNativeTokenAddress) FuncRegisterERC721NFTCollection = coreutil.Func(evmnames.FuncRegisterERC721NFTCollection) - FuncNewL1Deposit = coreutil.Func(evmnames.FuncNewL1Deposit) - FuncNewL1Withdrawal = coreutil.Func(evmnames.FuncNewL1Withdrawal) - FuncNewTransferBetweenL2Accounts = coreutil.Func(evmnames.FuncNewTransferBetweenL2Accounts) + FuncNewL1Deposit = coreutil.Func(evmnames.FuncNewL1Deposit) ) const (