diff --git a/packages/vm/core/evm/evmimpl/impl.go b/packages/vm/core/evm/evmimpl/impl.go index 6221afb1a0..8e4c2be92c 100644 --- a/packages/vm/core/evm/evmimpl/impl.go +++ b/packages/vm/core/evm/evmimpl/impl.go @@ -478,7 +478,7 @@ func newL1Deposit(ctx isc.Sandbox) dict.Dict { if !ok { continue } - logs = append(logs, makeTransferEvent(erc20Address, addr, nt.Amount)) + logs = append(logs, makeTransferEventERC20(erc20Address, addr, nt.Amount)) } for _, nftID := range assets.NFTs { // if the NFT belongs to a collection, emit a Transfer event from the corresponding ERC721NFTCollection contract @@ -488,13 +488,13 @@ func newL1Deposit(ctx isc.Sandbox) dict.Dict { erc721CollectionContractAddress := iscmagic.ERC721NFTCollectionAddress(collectionID) stateDB := emulator.NewStateDB(newEmulatorContext(ctx)) if stateDB.Exist(erc721CollectionContractAddress) { - logs = append(logs, makeTransferEvent(erc721CollectionContractAddress, addr, iscmagic.WrapNFTID(nftID).TokenID())) + logs = append(logs, makeTransferEventERC721(erc721CollectionContractAddress, addr, iscmagic.WrapNFTID(nftID).TokenID())) continue } } } // otherwise, emit a Transfer event from the ERC721NFTs contract - logs = append(logs, makeTransferEvent(iscmagic.ERC721NFTsAddress, addr, iscmagic.WrapNFTID(nftID).TokenID())) + logs = append(logs, makeTransferEventERC721(iscmagic.ERC721NFTsAddress, addr, iscmagic.WrapNFTID(nftID).TokenID())) } receipt := &types.Receipt{ @@ -515,7 +515,7 @@ func newL1Deposit(ctx isc.Sandbox) dict.Dict { var transferEventTopic = crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)")) -func makeTransferEvent(contractAddress, to common.Address, uint256Data *big.Int) *types.Log { +func makeTransferEventERC20(contractAddress, to common.Address, uint256Data *big.Int) *types.Log { var addrTopic common.Hash copy(addrTopic[len(addrTopic)-len(to):], to[:]) return &types.Log{ @@ -528,3 +528,22 @@ func makeTransferEvent(contractAddress, to common.Address, uint256Data *big.Int) Data: lo.Must((abi.Arguments{{Type: lo.Must(abi.NewType("uint256", "", nil))}}).Pack(uint256Data)), } } + +func makeTransferEventERC721(contractAddress, to common.Address, uint256Data *big.Int) *types.Log { + var addrToTopic common.Hash + copy(addrToTopic[len(addrToTopic)-len(to):], to[:]) + + tokenIDPacked := lo.Must((abi.Arguments{{Type: lo.Must(abi.NewType("uint256", "", nil))}}).Pack(uint256Data)) + var tokenIDTopic common.Hash + copy(tokenIDTopic[:], tokenIDPacked) // same len + + return &types.Log{ + Address: contractAddress, + Topics: []common.Hash{ + transferEventTopic, // event topic + {}, // indexed `from` address + addrToTopic, // indexed `to` address + tokenIDTopic, // indexed `tokenId` + }, + } +} diff --git a/packages/vm/core/evm/evmtest/evm_test.go b/packages/vm/core/evm/evmtest/evm_test.go index 08812badce..a4a949e415 100644 --- a/packages/vm/core/evm/evmtest/evm_test.go +++ b/packages/vm/core/evm/evmtest/evm_test.go @@ -925,7 +925,7 @@ func TestERC721NFTs(t *testing.T) { tx := blockTxs[0] receipt := env.evmChain.TransactionReceipt(tx.Hash()) require.Len(t, receipt.Logs, 1) - checkTransferEvent( + checkTransferEventERC721( t, receipt.Logs[0], iscmagic.ERC721NFTsAddress, @@ -1054,7 +1054,7 @@ func TestERC721NFTCollection(t *testing.T) { tx := blockTxs[0] receipt := env.evmChain.TransactionReceipt(tx.Hash()) require.Len(t, receipt.Logs, 1) - checkTransferEvent( + checkTransferEventERC721( t, receipt.Logs[0], iscmagic.ERC721NFTCollectionAddress(collection.ID), @@ -1371,7 +1371,7 @@ func TestERC20BaseTokens(t *testing.T) { } } -func checkTransferEvent( +func checkTransferEventERC721( t *testing.T, log *types.Log, contractAddress, to common.Address, @@ -1379,14 +1379,19 @@ func checkTransferEvent( ) { require.Equal(t, contractAddress, log.Address) - require.Len(t, log.Topics, 3) + require.Len(t, log.Topics, 4) require.Equal(t, crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)")), log.Topics[0]) var addrTopic common.Hash copy(addrTopic[len(addrTopic)-len(to):], to[:]) require.Equal(t, addrTopic, log.Topics[2]) - data := lo.Must((abi.Arguments{{Type: lo.Must(abi.NewType("uint256", "", nil))}}).Unpack(log.Data))[0].(*big.Int) - require.Zero(t, uint256Data.Cmp(data)) + tokenIDTopicBytes := make([]byte, common.HashLength) + copy(tokenIDTopicBytes, log.Topics[3][:]) + + tokenID := lo.Must((abi.Arguments{{Type: lo.Must(abi.NewType("uint256", "", nil))}}).Unpack(tokenIDTopicBytes))[0].(*big.Int) + require.Zero(t, uint256Data.Cmp(tokenID)) + + require.Empty(t, log.Data) } func TestERC20NativeTokens(t *testing.T) { @@ -1432,7 +1437,7 @@ func TestERC20NativeTokens(t *testing.T) { tx := blockTxs[0] receipt := env.evmChain.TransactionReceipt(tx.Hash()) require.Len(t, receipt.Logs, 1) - checkTransferEvent( + checkTransferEventERC20( t, receipt.Logs[0], iscmagic.ERC20NativeTokensAddress(foundrySN), @@ -1461,6 +1466,24 @@ func TestERC20NativeTokens(t *testing.T) { ) } +func checkTransferEventERC20( + t *testing.T, + log *types.Log, + contractAddress, to common.Address, + uint256Data *big.Int, +) { + require.Equal(t, contractAddress, log.Address) + + require.Len(t, log.Topics, 3) + require.Equal(t, crypto.Keccak256Hash([]byte("Transfer(address,address,uint256)")), log.Topics[0]) + var addrTopic common.Hash + copy(addrTopic[len(addrTopic)-len(to):], to[:]) + require.Equal(t, addrTopic, log.Topics[2]) + + data := lo.Must((abi.Arguments{{Type: lo.Must(abi.NewType("uint256", "", nil))}}).Unpack(log.Data))[0].(*big.Int) + require.Zero(t, uint256Data.Cmp(data)) +} + // helper to make sandbox calls via EVM in a more readable way func sandboxCall(t *testing.T, wallet *ecdsa.PrivateKey, sandboxContract *IscContractInstance, contract isc.Hname, entrypoint isc.Hname, params dict.Dict, allowance uint64) { evmParams := &iscmagic.ISCDict{}