Abstract
Ether, other cryptocurrencies and contract-based digital assets are about money. I think that tokens, subcurrencies and other abstract calculable goods are very important part of Ethereum ecosystem.
I'd like to suggest some modifications that , I think, would help to avoid accidentally monetary losses in future.
Motivation
There are numbers of abstract digital goods on Ethereum: different tokens, unicorns etc. etc.
These abstract digital goods are transferable. This means that a transaction for the purpose of transferring goods from one account to another can be performed.
It's obvious that transaction of digital goods must be properly handled (doesn't matter Ether or any abstract asset).
Ether transactions could only be handled by @payable
functions. I think that it is important to introduce an opportunity to require payable
modifier for callable function.
Main idea: when you call a function with the @abstract_payment
modifier in contract A, which calls another contract B, then inside B only the @payable
function can be called. Each execution of the function of the contract B, which is not @ payable
, must fail.
Example
Ether transfer
We are calling @payable
function and attaching Ether to the transaction.
If there is no function with matching signature implemented in the receiver contract, then the fallback function of the receiver will be executed.
If the fallback function is not @payable
then the transaction will fail and nothing bad will happen.
Abstract asset transfer
The transferAndCall
function of the ERC20 token is calling receiveTransfer
function at the receiver contract.
If there is no receiveTransfer
function implemented in the receiver contract, then the fallback function of the receiver will be executed.
If the fallback function is implemented then it will result in accidentally lost (stuck) tokens, unlike Ether that will be thrown in this case.
Resolution
I suggest to add an @abstract_payment
modifier (decorator).
A function with the modifier @abstract_payment
can be handled only by @payable
functions. This allows contract developers to artificially require their function calls to be handled only by properly designed functions. This will reduce possibilities of mistakes and allow to avoid accidentally lost money in future.
Example
Abstract digital asset contract:
@abstract_payment
def transfer_and_call(_to : address, _value : num256) -> bool:
# this must call `on_transfer` at the receiver.
return true
Proper receiver contract implementation:
@payable
def on_transfer():
# This function will be properly called.
# I'm not familiar with the syntax yet and I didn't found
# any examples of fallback function definition
def fallback():
# Do something.
In this case fallback
function is not @payable
. This means that it must throw whenever it received Ether or any abstract goods.
@abstract_payment
requires this function call to be handled by @payable
functions only.
Optional
I think that it can be a good idea to leave @payable
functions for handling of Ether payments and introduce a new @abstract_payable
for abstract payments but it seems superfluous.
Payments can be recognized by the variable msg.value
.
If msg.value
> 0 then it is Ether payment.
If msg.value
= 0 then it is abstract payment.
At the other hand this will allow @payable
functions to receive both abstract goods payments and Ether payments.
@vbuterin what do you think about it?