EIP-5920: PAY opcode

The zero address should not have a nonzero balance.

It already does. And adding a single special case for reversion just replaces one class of potential bugs with another. If an address gets set to zero and is unchangeable, then any function that calls PAY on that address will always revert and effectively be uncallable. If that function needs to be called as some necessary phase of the contract, then your contract is now permanently frozen and the ETH is inaccessible.

E.g. imagine a lottery contract where people can set their payout address when they buy a ticket. A function called startNewRound() checks if the last round is over, PAYs out ETH to the winner, and starts the next round anew. If the winner sets their payout address to 0, then startNewRound() will always revert when attempting to make the payout, and the lottery is now frozen with no future rounds possible.

It makes PAY a lot easier to reason about if it succeeds no matter what, as long as you pass in a valid address and ETH amount. If you want your contract to prevent payouts to the zero address, just add in some custom check like require(addr != address(0)). This is semantically equivalent to how people already make payouts with call(), transfer(), and send(), and there is no reason to change it for just this single opcode. Even less so, in fact, since the point of PAY is pretty much to bypass any checks and force an address to receive ETH.

That makes sense. What’s currently written probably makes more sense then.

burning for payments to address(0) is still a bad idea for a few reasons:

  1. when a contract PAYs to some address, it might operate under the assumption that the balance of that address will increase. E.g. the contract PAYs some amount ether to some receiving address, then at a later point checks that the receiving address’s balance has increased by that amount. If the receiver is address(0), then that check will fail, even though the payment was made.
  2. the existing CALL opcode does not burn ETH when the recipient is address(0); changing the semantics of ETH transfers for this new opcode will be confusing
  3. it’s pointless; the only reason I can think of for someone to burn ETH is executing a malicious attack using the situation described in (1)

Again, it’s best for no exceptions to be made for the zero address.

Why would that possibly need to be done?

The call still fails.

The call still fails.

Just checked on Goerli, and CALL does not fail when the receiver is address(0). Here’s my tx sending 0.01 ETH there from a contract:
And it increased the balance of address(0) from “11,090.383…” to “11,090.393…”, so no burn. So to bring the opcodes semantically in-line would require not giving address(0) any special treatment.

Why would that possibly need to be done?

Dunno, but someone might still end up doing it. Like, if there’s a bunch of complicated conditional code that decides whether or not to make a payment, so the dev decides that the simplest way to check whether or not the payment was made is just to query the receiver’s balance. My point stands that a burn is pointless, and (hypothetically at least) could lead to bugs.

Never mind then. It seems that the special case is not needed.

1 Like