-
Notifications
You must be signed in to change notification settings - Fork 5.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ERC: transferAndCall Token Standard #677
Comments
What calls I see the point of structuring |
The reason for not using Another reason which is less critical, but a nice feature, is that |
I would rather see an addition to tokens that allows anyone to call |
How so? User A calls transferAndCall of contract C, contract C then calls receiveTransfer of contract B. Contract B sees that msg.sender = C, and so it's a legit transfer of tokens. The reason why transferAndCall is superior is as @Arachnid says, it allows you to get rid of any expensive superfluous storage updates whatsoever - all that happens is tokens get transferred and the recipient gets notified.
This is also doable with transferAndCall: you would first call some constant function getHowMuchINeedToPay of the recipient, then send a transferAndCall with that precise amount. |
The worst case I was imagining is something like a decentralized exchange dealing with lots of tokens they can't evaluate, but just enable people to use them. In this case people could introduce malicious tokens, but as I think more about it, a malicious token contract could also sabotage the The I'm open to |
Can someone explain me what is the reason of having approves in standard tokens? As I've supposed earlier that the only purpose of So the only reason of |
@Dexaran backwards compatibility seems like the most important reason to me. Beyond that, approved withdrawal caps are a pretty standard pattern that have unique workflows that would be more difficult without the |
@MicahZoltu Interesting proposal, it looks as if it would fit the pattern proposed by EIP662. It seems like a broad pattern which may be orthogonal and complimentary to token transfer standards. |
@se3000 By the way Ether dosn't have any approves and everything is OK with it. |
@Dexaran I'm with you on wanting to remove approvals entirely. However, the workflow that is meaningful to me is the one where you have some complicated system (such as Augur) that has need to move user tokens around internally. Having the user start the interaction with a token transfer works, but it complicates the interface because it means the entrypoint for Augur is always through a token, rather than through a contract call. Since the details of the interaction are coming through via the data parameter, this means that the receiving contract needs to decode those bytes (in-contract) and then make decisions based on the data. Not only are these bytes opaque to any user looking at the transaction (which includes tools designed to show transaction details using the ABI), decoding them into something useful on-chain is hard. For the most naive case, the data could just be a number (effectively part of an enum), and this isn't too bad. However, this won't work for all cases such as an exchange where you need to send quite a few details along with the token transfer like counterparty address, token being traded for, price, etc. All of this needs to be encoded into a byte array that is totally opaque to any reader. Note: The above aren't insurmountable problems, and I'm not sure approve is really any better of a solution because it requires multiple signatures from the user (something a UI can't hide), but I do think it is something worth considering. |
Approvals have one other problem: using approvals creates a workflow where the contract that uses the approval needs to do something like: (i) call transferFrom, THEN (ii) do something else. This is an external call followed by a state change, which is generally considered a no-no because of re-entrancy issues. I now increasingly support transferAndCall as defined in #223, as the execution path is very clean - first go into the token contract, edit balances there, then go into the destination account. I previously had the objection that it complicates implementation since you would need to be able to do "ABI inside ABI", but I have since softened on this since realizing that multisig contracts and other forwarding contracts require this already. Also, stack depth attacks are irrelevant since the Tangerine Whistle hard fork (that's last October). |
Ok, thanks for the feedback so far. Based on the helpful feedback, I've switched this to At first I thought that ERC223 was sufficient to offer the transfer and call functionality. Based on further consideration it seems like not every token will want to be ERC223 compatible, as some contracts using ERC20 today do not allow for an
|
Feedback is basically the same as I provided to ERC223. |
Why specify a fixed function at all? It seems to me it would make a lot more sense to pass in a |
@Arachnid Similar argument to that over in the URI EIP. Human readability, which leads to increased security by way of allowing users to make an informed decision. When prompted to sign, if I see |
This is a standard for an ABI, though - human readability shouldn't come into it, and certainly not as an overriding consideration. Further, with Insofar as you can decode the outer call's ABI encoding to show something to the user, too, you could also decode the inner encoding in the same fashion. |
The receiving contract should know who sent the tokens and the amount sent. If that is specified in the |
Information about the transfer does not need to be contained in the message payload; the contract can identify the caller and check its balance there. |
Current balance is very different from amount received. In order for current balance to work/be useful, the contract would need to track "last known balance" for every token it receives and update it on every token receipt which means at least 5k additional gas for the state update. This also assumes that the contract isn't receiving tokens via some other means (e.g., traditional ERC20 token transfers). |
This would require tooling to directly implement support for tokens implementing this. Using the scheme I described above, the tooling only needs to be able to decode/display top level contract calls (which some tools like Parity already do). @Arachnid Is your assumption that all tools will directly support this spec and understand what the At a high level, byte arrays are a lossy interface (method name and types cannot be recovered from method hash) which is what I'm arguing against. I think the data that is lost is very important for informed signing decisions. How do you propose allowing users to re-acquire this lost information so they can make an informed signing decision? |
The current balance approach is interesting. As Micah pointed out it's expensive and not guaranteed to work if tokens are received in other ways. That is probably solvable, but would increase the complexity of writing any contract that receives tokens. Similarly, how would you determine who sent the tokens? Assuming not Stepping back a bit, I'm currently of the mind that token transfers would ideally behave as much like Ether transfers as possible. For that to remain, you should always be able to tell who sent you a token, like an equivalent to |
@se3000 do you have an example implementation yet? I assume the receiving contract will be the same as this implementation of the ERC223 token: https://github.com/Dexaran/ERC223-token-standard/blob/Recommended/Receiver_Interface.sol As a token contract author with an upcoming token sale in the coming weeks, I'm torn on whether to stick to the ERC20 standard, use this standard with |
@iam-peekay I recommend going with ERC20 for now. You can always release a new token and have users migrate once ERC223 or this is finalized. |
@MicahZoltu @se3000 Good points; being able to determine the ultimate sender and the amount they sent are critical pieces of information that have to be supplied in a trusted fashion. I withdraw my suggestion.
Ultimately, I'm a fan of representing things in the form most suited to the layer in which they reside, and of minimising unnecessary overhead inside the EVM. That means user-friendly standards for URIs, but machine-level specifications for ABIs. User insight can be provided by using a higher level encoding to determine what to display to the user, then deriving the ABI level encoding from that, rather than trying to reverse-engineer ABI encoding or embed extra metadata in it. Showing function calls to a user is a horrible user experience anyway, and for anyone other than a programmer, only marginally more meaningful than just showing them the raw ABI encoded hex data. Edit: Another alternative to consider is |
Advising people "i recommend going with ERC20 for now" is exactly the same as saying "your users will guaranteed lose money because of vulnerability of this standard but I will still recommend to use it. It's just someone else's money, you don't need to care about it." You guys cast a bad shadow on the whole cryptocurrency industry, developing tokens so that people lose money and advising other developers to do the same just because you don't think that it is serious that someone will suffer because of your inattentiveness. https://medium.com/@dexaran820/erc20-token-standard-critical-problems-3c10fd48657b |
No, it's not. ERC223 is in a state of flux, and it's far from clear that it won't lead to its own causes of lost or locked funds. Recommending people implement a standard that isn't even close to being locked down is a recipe for chaos. |
If you implement ERC20 then your users will lose money. I prefer not to do what is guaranteed to be a mistake and result in loss of money for users. |
Implementing ERC223 right now is equivalent of not implementing any standard. You are welcome to create a non-standard token, it has been done before. If you want your token to be interoperable though, you have to pick a standard and right now there is only one (ERC20). |
Again, @MicahZoltu can we consider this superseded by https://eips.ethereum.org/EIPS/eip-4524? It has nearly the exact same functionality. |
Currently, this is just an idea, not an EIP, so it cannot be superceded by anything. Separately, superseding is not something editors do because that would mean we are taking an opinionated position on which EIPs should supersede which shouldn't. If this was an actual final EIP, the authors of 4524 could mention that 4524 is meant to supersede this one but that wouldn't be any sort of official thing, just the opinion of the authors of 4524. Regarding this issue though, I am going to close it as this is no longer the right place to pursue this idea further. The correct next course of action @se3000 is to either continue discussion on Ethereum Magicians, or create a draft EIP for this idea. |
I'd like to point out that since this is already in use in many high value token contracts, it's misleading to call it a mere "idea". EIPs, even accepted ones, are full of "ideas" that never (yet) have seen practical implementation. It ought to be considered a shortcoming in the EIP process itself if it cannot stay ahead of or even closely track the state of the art; if it aspires to be normative but fails to even be exhaustively descriptive. This is not an individual failure, of course, but social/organizational one; also it's not a dramatic failure, since it's very easy to fix once there's agreement on all sides to do the standardization work. Demoting the actual state of the art to the level of "just an idea" probably doesn't help in the way of forming an agreement. |
@jtakalai The truth is, ERC-1363 went through the EIP process, got finalized, and I would argue is a better design than issue 677. |
And yes, the fact that 667 is just written down in an issue, without link to a proper discussion, and without a PR to make it actually into the repo means that 667 is definitely NOT an ERC. Calling it an idea is possibly the most accurate thing you could say about it. |
By definition, this is not an official Ethereum standard as there is no Final EIP for it. It may be a defacto standard (there are many such things in the wild), but it isn't an EIP, it doesn't have a number, it doesn't exist as an official Ethereum standard, etc. |
If you want to turn this into an actual numbered standard you are welcome to, just create a pull request against this repository adding it following the instructions in EIP-1. |
The important part is that this issue stays online so anyone googling ERC 677 gets a rough idea about its purpose. I'm one of the developers usually adding ERC 677 support to tokens as it is a relatively light-weight and convenient "standard" in comparison to the more heavy-weight proposals. For the future, what I would wish for was a convenient and light-weight standards for "permit" that can be signed offline. And by light-weight I mean low in gas fees. This could also cover some of the "transfer and call" use cases if the receiving contract supports the permits. |
I would like to point in the direction of https://eips.ethereum.org/EIPS/eip-1363, a final EIP that is effectively this proposal. |
|
Preamble
Simple Summary
Allow tokens to be transferred to contracts and have the contract trigger logic for how to respond to receiving the tokens within a single transaction.
Abstract
This adds a new function to ERC20 token contracts,
transferAndCall
which can be called to transfer tokens to a contract and then call the contract with the additional data provided. Once the token is transferred, the token contract calls the receiving contract's functiononTokenTransfer(address,uint256,bytes)
and triggers an eventTransfer(address,address,uint,bytes)
, following the convention set in ERC223.Motivation
ERC20 requires a multistep process for tokens to be transferred to a contract. First
approve
must be called on the token contract, enabling the contract to withdraw the tokens. Next, the contract needs to be informed that it has been approved to withdraw tokens. Finally, the contract has to actually withdraw the tokens, and run any code related to receiving tokens. This process typically takes two to three steps, which is inefficient and a poor user experience.While ERC223 solves the described problem with its
transfer(address,uint256,bytes)
function, it opens other problems. ERC223 changes the behavior of ERC20'stransfer(address,uint256)
, specifying that it should throw if transferring to a contract that does not implementonTokenTransfer
. This is problematic because there are deployed contracts in use that assume they can safely calltransfer(address,uint256)
to move tokens to their recipient. If one of these deployed contracts were to transfer an ERC223 token to a contract(e.g. a multisig wallet) the tokens would effectively become stuck in the transferring contract.This ERC aims to provide the helpful functionality of ERC223 without colliding with it. By giving contracts a reason to implement
onTokenTransfer
before ERC223 becomes widely implemented, a smooth transition is provided until a larger part of the Ethereum ecosystem is informed about and capable of handling ERC223 tokens.transferAndCall
behaves similarly totransfer(address,uint256,bytes)
, but allows implementers to gain the functionality without the risk of inadvertently locking up tokens in non-ERC223 compatible contracts. It is distinct from ERC223'stransfer(address,uint256,bytes)
only in name, but this distinction allows for easy distinguishability between tokens that are ERC223 and tokens that are simply ERC20 + ERC667.Specification
Token
transferAndCall
Transfers tokens to
receiver
, via ERC20'stransfer(address,uint256)
function. It then logs an eventTransfer(address,address,uint256,bytes)
. Once the transfer has succeeded and the event is logged, the token callsonTokenTransfer(address,uint256,bytes)
on thereceiver
with the sender, the amount approved, and additional bytes data as parameters.Receiving Contract
onTokenTransfer
The function is added to contracts enabling them to react to receiving tokens within a single transaction. The
from
parameter is the account which just trasferedamount
from thetoken
contract.data
is available to pass additional parameters, i.e. to indicate what the intention of the transfer is if a contract allows transfers for multiple reasons.Backwards Compatibility
This proposal is backwards compatible for all ERC20 tokens and contracts. New tokens and contracts moving forward can implement the
transferAndCall
functionality, but also still fallback to the originalapprove
-transferFrom
workflow when dealing with legacy contracts. It does not require any changes or additional steps from already deployed contracts, but enables future contracts to gain this functionality.Implementation
Example implementation.
The text was updated successfully, but these errors were encountered: