Skip to content
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

✨ Adding ability to pack extra-data with balance in ERC20 #735

Open
Philogy opened this issue Nov 27, 2023 · 3 comments
Open

✨ Adding ability to pack extra-data with balance in ERC20 #735

Philogy opened this issue Nov 27, 2023 · 3 comments

Comments

@Philogy
Copy link
Contributor

Philogy commented Nov 27, 2023

I wanted to open this issue to discuss potential designs for how ERC20 may efficiently be extended to allow for users to set a lower total supply cap than $2^{256}-1$ and use upper (or lower) bits to pack additional information. Having such a large supply cap is mostly unnecessary and developers may often want to pack other per-address data with balances to minimize cost of initial storage modifications e.g. the ERC2612 nonce.

More critically in cases where an application that has per-address information that is frequently accessed together with balances this can allow developers to save on entire cold storage accesses e.g. permission flags.

The main problems I see is that because of Solidity's lack of generics you cannot easily support an arbitrary extra-data bit size. Furthermore such packing introduces overhead that may not be desirable for applications that do not require it, however this overhead would be minimal:

If balance is stored in the upper-most bits, extra data in the lower bits the only added overhead is a simple bit-shift of the amount e.g. in _transfer:

             mstore(0x0c, or(from_, _BALANCE_SLOT_SEED))
             let fromBalanceSlot := keccak256(0x0c, 0x20)
             let fromBalance := sload(fromBalanceSlot)
+            let balChange := shl(EXTRA_DATA_BITS, amount)
             // Revert if insufficient balance.
-            if gt(amount, fromBalance) {
+            if gt(balChange, fromBalance) {
                 mstore(0x00, 0xf4d678b8) // `InsufficientBalance()`.
                 revert(0x1c, 0x04)
             }
             // Subtract and store the updated balance.
-            sstore(fromBalanceSlot, sub(fromBalance, amount))
+            sstore(fromBalanceSlot, sub(fromBalance, balChange))
             // Compute the balance slot of `to`.
             mstore(0x00, to)
             let toBalanceSlot := keccak256(0x0c, 0x20)
             // Add and store the updated balance of `to`.
             // Will not overflow because the sum of all user balances
             // cannot exceed the maximum uint256 value.
-            sstore(toBalanceSlot, add(sload(toBalanceSlot), amount))
+            sstore(toBalanceSlot, add(sload(toBalanceSlot), balChange))
             // Emit the {Transfer} event.
             mstore(0x20, amount)
             log3(0x20, 0x20, _TRANSFER_EVENT_SIGNATURE, shr(96, from_), shr(96, mload(0x0c)))

I think 96-bits is a good candidate for the space to be allocated to balances and the total supply. It allows for a total supply of 79.2B (with decimals at 18) which is arguably for most (serious) applications. Applications that go beyond this usually do so to deflate the per-unit price of a token to take advantage of people's unit bias. 96-bits for the balance would also allow you to store up to a full address as extra-data

@Vectorized
Copy link
Owner

Vectorized commented Nov 30, 2023

I think we can abuse function overrides to allow near zero-cost abstraction.

Code will be bloat tho.

The PITA is the 2612 function.

Another way is to have a ERC20P. Probably neater.

This sounds very enticing… but might let others have the fun, since ERC20 is already audited. 🤔

I was lazy to add packing in cuz memecoins that abuse unit bias is one of the primary use cases of Ethereum.

@z0r0z
Copy link
Collaborator

z0r0z commented Dec 9, 2023

any thoughts on moving 2612 out of ERC20 base? I think a more stripped down version would be easier to work with and allow for these more custom overrides more simply.

@Vectorized
Copy link
Owner

@z0r0z The 2612 logic is quite tightly bounded to the custom storage layout.

wh173-c47 added a commit to wh173-c47/solady that referenced this issue May 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants