proposals icon indicating copy to clipboard operation
proposals copied to clipboard

Invalidate zero address

Open roman-khimov opened this issue 3 months ago • 2 comments

Neo addresses are all Uint160, they're RIPEMD(SHA256(verification_script)) which is 20 bytes of data. Theoretically, any 20 bytes can be a valid address, but practically since we're talking about cryptographic hashes here the result is pretty much random. Getting 20 bytes of zeroes in the normal process of deriving an address from verification script is highly unlikely and we don't know of the script that hashes to this address.

At the same time the default value for the respective type is 20 bytes of zeroes. Some code (and remember there is a lot of code in different languages that deal with Neo addresses) treats the type as nullable, some don't. In the latter case we have a potential problem of distinguishing unset value from valid address. A similar problem can happen in NEP-11/NEP-17 contracts, even though standards specifically mention null as the value to be used in from for mints and to for token burns some miscoded contracts can easily pass an empty Uint160 there.

The other side of the problem is users that want to burn some tokens. Neither NEP-11, nor NEP-17 have any standard means for burning tokens. Users that want to do that have to find out contract-specific ways (if they exist at all). Since transfer() to null is not possible some may try sending tokens to NKuyBkoGdZZSLyPbJEetheRhMjeznFZszf which is the stringified version of the same zero address. Most contracts will treat it as a normal transfer, so tokens won't be burned, they would just be hanging on this address.

The proposal is:

  • declare empty Uint160 as an invalid address that can not hold tokens
  • treat empty Uint160 as equal to null wrt NEP-11/NEP-17 Transfer events
  • treat transfer() to zero address as token burns and process them accordingly

This hardens the system against mistakes people can make (like https://github.com/neo-project/neo-modules/issues/344, also NKuyBkoGdZZSLyPbJEetheRhMjeznFZszf ), simplifies some processing code and adds some useful new semantics to old methods.

Refs https://explorer.onegate.space/accountprofile/0x0000000000000000000000000000000000000000, https://dora.coz.io/address/neo3/mainnet/NKuyBkoGdZZSLyPbJEetheRhMjeznFZszf/assets.

roman-khimov avatar Dec 02 '25 10:12 roman-khimov

I think it's almost impossible to get 0x0 as an address, so it should be treated as null, indeed.

shargon avatar Dec 02 '25 11:12 shargon

I don't think this restriction is necessary. Address 0 is the same as 1, 2, 3... there's no difference.

erikzhang avatar Dec 02 '25 12:12 erikzhang

It's convenient. Just like in https://datatracker.ietf.org/doc/html/rfc9562#name-nil-uuid

We made a similar change to container/object ID semantics in https://github.com/nspcc-dev/neofs-api/pull/303 and it has simplified a lot of code for us.

roman-khimov avatar Dec 22 '25 14:12 roman-khimov