-
Notifications
You must be signed in to change notification settings - Fork 508
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
Add ERC: Temporary Approval Extension for ERC-20 #358
base: master
Are you sure you want to change the base?
Conversation
Co-authored-by: Andrew B Coathup <28278242+abcoathup@users.noreply.github.com>
Commit 85f7d71 removes EIP-1153 reference from the description section but it seems that EIP Walidator needs to be fixed instead: https://github.com/ethereum/ERCs/actions/runs/8536634399/job/23385573486#step:3:14
It seems that it disallows referencing any EIP in the description section. |
IMO "transient" is a technical name that refers to the underlying mechanism used here, but should not be exposed in the ABI or in the "docuementation" or this feature. I propose using "temporary allowance" instead of "transient allowance", as I believe this naming would be more user-friendly for people that have no knowledge of EIP-1153 |
This ERC should clearly mention that:
|
Co-authored-by: Hadrien Croubois <hadrien.croubois@gmail.com>
Mikhail @ZumZoom and I have collected some opinions on naming transient/temporary, with the majority leaning towards temporary as the friendlier option. So I replaced uses wherever it was appropriate. |
I left a review, thanks for pointing out @Amxx! The ERC looks good, but since it's defining an interface for a temporary approval, I don't see why to restrict this to transient storage. While it makes sense, I think the benefits of this kind of approval can be achieved regardless of transient storage support in a context where using storage may not be a big deal (e.g. an L2) I would suggest generalizing the interface and its semantics while keeping the suggestions for using transient storage if EIP-1153 is available, but I understand the intention of making a transient-approval ERC 😅 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some comments in case you're open to generalize it. Feel free to disregard.
@ernestognw Thank you for your comments!
Do you already have any ideas on how this could be implemented? |
A quick thought was another mapping with approvals per block number (or timestamp), in this way it's not needed to clean up the value at the end since it will just get invalidated immediately. Here's a quick PoC |
Co-authored-by: Ernesto García <ernestognw@gmail.com>
I prefer to keep the temporary storage for this ERC within a transaction rather than a block. |
Co-authored-by: Mikhail Melnik <by.zumzoom@gmail.com>
Update ERC-7674 based on PR comments
```solidity | ||
function temporaryApprove(address spender, uint256 value) public returns (bool success) | ||
``` | ||
Call to `temporaryApprove(spender, value)` allows `spender` to withdraw within the same transaction from `msg.sender` multiple times, up to the `value` amount. This temporary allowance is to be considered in addition to the normal (persistent) [ERC-20](./eip-20.md) allowance, the total value that spender is able to spend during the transaction is thus capped by the sum of the temporary and the normal (persistent) allowances. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This temporary allowance is to be considered in addition to the normal (persistent) ERC-20 allowance
This forces an SLOAD of the current allowance, resulting in higher costs than one would want from this feature. I think it should be a temporary allowance override instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I disagree.
If the temporary allowance takes priority (this should be mentionned somewhere if it isn't already), and if the temporary allowance is sufficient to cover the need of some function that consumes allowance (transferFrom
), then the allowance can be consumed from the temporary part without having to go consume anything in the persistent part.
You only need to lean (and update) the persistent part if the temporary part is not sufficient.
An analogy would be:
- you want to cook rice,
- you have 2kg of rice in your kitchen (fast access - eq to temporary)
- you have 50kg of rice stored in you basement (slow access - eq to persistent)
it is true that:
- you have 52kg available
- to measure how much you have available, you have to check both the kitchen and the basement
- if you need to cook diner, and that diner requires 500g of rice, the kitchen is sufficient, and you don't need to go to the basement. Rice in the basement is available if you need, but you don't need to access it unless there isn't enough in the kitchen for what you are planning to cook.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think of
Call to `temporaryApprove(spender, value)` allows `spender` to withdraw within the same transaction from `msg.sender` multiple times, up to the `value` amount. This temporary allowance is to be considered in addition to the normal (persistent) [ERC-20](./eip-20.md) allowance, the total value that spender is able to spend during the transaction is thus capped by the sum of the temporary and the normal (persistent) allowances. | |
Call to `temporaryApprove(spender, value)` allows `spender` to withdraw within the same transaction from `msg.sender` multiple times, up to the `value` amount. This temporary allowance is to be considered in addition to the normal (persistent) [ERC-20](./eip-20.md) allowance, the total value that spender is able to spend during the transaction is thus capped by the sum of the temporary and the normal (persistent) allowances. While it SHOULD be possible for a `transferFrom` operation to consume both types of allowance, the consumption of the temporary allowance SHOULD take priority over the consumption of the persistent allowance. Therefore, if the temporary allowance is sufficient for executing a `transferFrom` operation, the persistent allowance SHOULD not be loaded/updated from the storage. Consumption of persistent allowance, which implies storage accesses, SHOULD be performed only if the temporary allowance is not sufficient for the operation being executed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, my confusion was because of the effect on the allowance()
function. If the allowances have to be added, this forces allowance
to read from both. However, in the context of transferFrom
it should not be necessary to do this, as you've described.
I am not sure if the effect on allowance
is something that we should care about.
--- | ||
eip: 7674 | ||
title: Temporary Approval Extension for ERC-20 | ||
description: An interface for ephemeral ERC-20 approvals |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
description: An interface for ephemeral ERC-20 approvals | |
description: An interface for ERC-20 approvals lasting a single transaction |
|
||
## Motivation | ||
|
||
User are often require to set token approval that will only be used once. It is common to leave unexpected approvals after these interactions. [EIP-1153](./eip-1153.md) introduces a cheap way to handle temporarily allowances. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will only be used once
This is a bit misleading. This approval can be used multiple times, as long as it's in a single transaction.
|
||
Compliant contracts MUST add a temporary allowance to the permanent one when returning the allowed amount to spend in the `allowance` function. In case the sum of the temporary and permanent allowance overflow, `type(uint256).max` MUST be returned. | ||
|
||
No event is required when setting a temporary allowance, but compliant contracts MAY emit a specific event. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should specify the event, or clarify what "specific" means here. The easiest would be to define the event, but leave it optional.
``` | ||
Call to `temporaryApprove(spender, value)` allows `spender` to withdraw within the same transaction from `msg.sender` multiple times, up to the `value` amount. This temporary allowance is to be considered in addition to the normal (persistent) [ERC-20](./eip-20.md) allowance, the total value that spender is able to spend during the transaction is thus capped by the sum of the temporary and the normal (persistent) allowances. | ||
|
||
The storage for the temporary allowances MUST be different to that of the regular allowance. Compliant contracts MAY use the transient storage [EIP-1153](./eip-1153.md) to keep the temporary allowance. For each `owner` and `spender`, the slot MUST be uniquely selected to avoid slot collision. Each slot index SHOULD be derived from the base slot index for temporary allowances, `owner` and `spender` addresses. Slot MAY be derived as `keccak256(spender . keccak256(owner . p))` where `.` is concatenation and `p` is `keccak256` from the string uniquely defining temporary allowances in the namespace of the implementing contract. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is all still implementation detail. You should only specify the externally visible behaviour in the Specification section. You can put recommendations in the Reference Implementation section. How about:
The storage for the temporary allowances MUST be different to that of the regular allowance. Compliant contracts MAY use the transient storage [EIP-1153](./eip-1153.md) to keep the temporary allowance. For each `owner` and `spender`, the slot MUST be uniquely selected to avoid slot collision. Each slot index SHOULD be derived from the base slot index for temporary allowances, `owner` and `spender` addresses. Slot MAY be derived as `keccak256(spender . keccak256(owner . p))` where `.` is concatenation and `p` is `keccak256` from the string uniquely defining temporary allowances in the namespace of the implementing contract. | |
Each temporary allowance MUST persist until the end of the transaction that created it (unless overwritten by another call to `temporaryApprove`.) Each temporary allowance MUST be cleared at the end of the transaction that created it. See [Using Transient Storage](#using-transient-storage) for an example. |
Then moving this content to the Reference Implementation section under a "Using Transient Storage" heading.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(unless overwritten by another call to temporaryApprove
or consumed by a call to transferFrom
).
The commit 8a11a87 (as a parent of e167942) contains errors. |
I took the liberty of fixing your EIP/ERC links. You do need to use |
Among all cases of
ERC-20
token transactions, a popular one is when smart contracts approve token spending to other contracts. Often tokens are approved for only one transaction.Following the
ERC-20
standard, if a smart contract wants to approve the spending of tokens to another smart contract for only one transaction, this causes the allowance saved in storage to be updated and retrieved.Token allowances utilising
EIP-1153
transient storage are a cheaper alternative to the regular storage allowances.