Searches for "fallback" in Vyper docs and in the repository return no results. If fallback functions are intentionally not allowed for security reasons, this should be mentioned in the README and/or docs.
If this feature exists or is planned, I would love to know! Its something I consider very useful in Solidity

We don't implement a fallback function because there is the gas consideration at play, and that may not be obvious to those auditing the code.
I could see potentially supporting it. It is useful for interacting with certain kinds of funding flows and what not. As long as it was properly clear what was happening, I would endorse support.
However, Python doesn't support unnamed functions, so it would have to look something a little bit more like:
spent: map(address, uint256)
# must be payable and public
@public
@payable
def __send__():
# Must not accept or return any arguments
self.spent[msg.sender] += msg.value
or something like that
I'll edit this post as a VIP later then. I know Vyper is designed around audit friendliness, and the gas consideration is reasonable, but there is such a massive utility to fallback functions I think its worth looking into further.
I like:
def __fallback__():
fallback isn't really a descriptive name for newbies, especially considering it's typical use case as the function executing during a transaction with no call data (where the only useful version of this transaction is an ether send()). That was the rationale behind my naming scheme.
Might actually be called received instead of send, because the contract receives unintended money.
Fair enough lol
Whatever name is chosen, I think it must be implemented as a built-in style e.g. __receive__()
Agreed on receive although I also like
__default__()
As discussed, we decided on __receive__.
As discussed, we decided on __receive__.
Why is that? It's possible that data would be included in the call, and that in some future version of vyper you might enable advanced developers to do something with that data. In that case __default__ makes more sense to me.
@maurelian __receive__ should make the meaning more clear as it will be triggered when the contract receives funds. It may have more sophisticated use cases in the future but this naming should make it easier for new coders to understand the meaning of the function.
I think @maurelian may have a point here, we should make it slightly more general, at least whether or not it is @payable, which is typically an optional feature for the fallback. I could also imagine it handling call data, but I'm more on the fence about this.
__default__ makes sense if you think of ethereum call handling as switch..case..default statement
Agreed, I did not consider the case of passing through call data. 馃檲
I am happy to make it __default__ to cover that scenario...
Having the option to choose if its @payable is important because it allows contracts that throw whenever they receive ETH without making an explicit function call. Although its still possible to forward these contracts ETH using selfdestruct() on other contracts.
We discussed an additional analysis step that would raise a warning whenever @payable allows Ether to enter the contract, but there is no subsequent withdrawal through send(addr, value) orraw_call(value=...) detected
By subsequent do you mean anywhere else in the contract? A fallback function that accepts ETH and mints tokens wouldn鈥檛 have a send() or raw_call() but would be following desired behavior.
@haydenadams in your use case, someone can also sell tokens to get ether back. That's the flow we're looking for.
Basically, if the contracts accepts ETH anywhere using @payable (not just in __default__()) then we expect that you should be able to "spend it" via transferring it to another party with send() or raw_call()
Otherwise that ETH would be "burned" in the contract i.e. inaccessible because there is no way of getting the funds out.
Meant to make a comment and accidentally hit close. Sorry about that lol