Skip to content

eth: wrapping native asset (WETH deposit/withdraw) produces no tokenTransfers — wrapped token is not auto-discovered on the address #1702

Description

@tomasklim

Summary

Wrapping the native asset (e.g. WETH.deposit()) produces no tokenTransfers entry in Blockbook, because canonical wrapped-native contracts (WETH9 and its ports) mint without emitting an ERC-20 Transfer event — they emit Deposit(address indexed dst, uint256 wad) instead. Blockbook's log parser only recognizes Transfer / TransferSingle / TransferBatch, so:

  1. the wrap transaction is indexed as a plain ETH send to the contract, with no indication the address received WETH,
  2. token auto-discovery never happens — the address↔contract association is built from token transfers only, so an address whose only WETH interaction is wrapping never gets WETH into its tokens list and its WETH balance stays invisible until some unrelated Transfer event touches the address,
  3. the same applies to unwrapping: withdraw() emits Withdrawal(address indexed src, uint256 wad), also ignored, and per-address transfers counts for WETH exclude all wraps/unwraps.

In clients this means e.g. Trezor Suite renders a wrap as nothing but an outgoing ETH payment to an unknown contract — there is no "received X WETH" line to show, while Etherscan displays the same tx as "Wrap 0.000123 ETH into 0.000123 WETH" (it parses the Deposit event itself).

Image Image

Temporary fix for Trezor Suite trezor/trezor-suite#30797, trezor/trezor-suite#29875

Examples

Both are deposit() (0xd0e30db0) calls sending ETH to WETH 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2.

/api/v2/tx-specific/0xdb59b3… shows the receipt contains exactly one log — the Deposit event, no Transfer:

"logs": [{
  "address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
  "topics": [
    "0xe1fffcc4923d04b559f4d29a8bfc6cda04eb5b0d3c460751c2402c5c5cc9109c",
    "0x0000000000000000000000009ea3721b5bf3b64b4418c38b603154d2d597fae3"
  ],
  "data": "0x00000000000000000000000000000000000000000000000000038d7ea4c68000"
}]

/api/v2/tx/… consequently returns no tokenTransfers field at all for either tx (verified on both), even though parsedData correctly identifies the call as deposit().

(The example address does show WETH in tokens today, but only because later swap/send txs emitted real Transfer events; an address that only ever wraps gets nothing.)

Root cause

contractGetTransfersFromLog dispatches solely on the three transfer topics and continues on everything else:

func contractGetTransfersFromLog(logs []*bchain.RpcLog, txid string) bchain.TokenTransfers {
var r bchain.TokenTransfers
for _, l := range logs {
tl := len(l.Topics)
if tl > 0 {
signature := l.Topics[0]
var tt *bchain.TokenTransfer
var err error
if signature == tokenTransferEventSignature {
tt, err = processTransferEvent(l)
} else if signature == tokenERC1155TransferSingleEventSignature {
tt, err = processERC1155TransferSingleEvent(l)
} else if signature == tokenERC1155TransferBatchEventSignature {
tt, err = processERC1155TransferBatchEvent(l)
} else {
continue
}
if err != nil {
glog.Warningf("contractGetTransfersFromLog: skipping unparseable log of contract %s, tx %s: %v", l.Address, txid, err)
continue
}
if tt != nil {
r = append(r, tt)
}
}
}
return r

WETH9 deposit()/withdraw() mint/burn without Transfer:

function deposit() public payable {
    balanceOf[msg.sender] += msg.value;
    Deposit(msg.sender, msg.value);
}

Suggested fix

Translate the wrapped-native contract's events into synthetic mint/burn token transfers:

  • Deposit(dst, wad)TokenTransfer{from: 0x0, to: dst, value: wad}
  • Withdrawal(src, wad)TokenTransfer{from: src, to: 0x0, value: wad}

Since any contract can emit events with these signatures (same spoofing concern as #1225), the translation should be restricted to the canonical wrapped-native contract per chain, e.g. a per-coin config field (wrappedNativeContract). That would cover WETH on Ethereum and the same WETH9-pattern contracts on other EVM chains Blockbook indexes (WBNB, WPOL, WXDAI, …).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions