You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Rivet's existing SetErc20Balance solution is limited in its coverage of tokens. I propose an alternative, a lightweight and cost-effective API service that deduces storage slots for token balance mappings using heuristic analysis on call traces.
Present implementation
Rivet currently enables setting the token balance to an arbitrary value. The method involves iterating through first ten storage slots, modifying the storage slot of the targeted token, and confirming the balance change. Shown below:
thrownewBaseError('could not find storage for: `balanceOf`')
}
}
queryClient.invalidateQueries({
queryKey: getErc20BalanceQueryKey([
client.key,
{ tokenAddress, address },
]),
})
},
})
}
This method efficiently handles tokens with:
Balance mappings within slots 0 to 9.
Balance mappings and token representation within the same contract.
Storage value in the mapping being one to one to the associated balance.
For some tokens above conditions don't hold. As an example storage slot for UNI on Arbitrum is 51; SNX on Ethereum stores balances in a different contract than the token one and for stETH storage slot value to balance ratio is not one to one.
Proposed solution
Approach
Heuristic
Token balances are managed as mappings where Solidity and Vyper compilers hash the storage slot and key to determine the storage location. Analyzing the memory and stack during a balanceOf call within a trace can pinpoint the specific storage slot for balances.
Trace Availability
The major limitation of this heuristic method is the need for comprehensive traces that include instructions, stack, and memory, typically provided by Geth struct traces. Most free RPC services do not offer such detailed traces and even paid services from providers like Alchemy and Quicknode may not always support struct traces. This requires us to either deploy nodes or resort to local tracing.
Local tracing
With "local tracing" I am referring to obtaining the state of the blockchain and executing instructions locally.
Hardhat and Anvil provide this feature, however this requires spinning up a forked network each time tracing is needed. While this works just fine a more lightweight solutions is available. Under the hood Anvil uses REVM with reth-inspector to do local tracing, thus one could use just this for their tracing.
I separated the logic for local tracing using revm, AlloyDB and reth-inspector in this mini crate.
token-bss API
token-bss is a Rust tooling that is intended to find balance storage slot of Solidity and Vyper tokens. Code is available here: https://github.com/halo3mic/token-bss.
API
Its service is available via API, which you can run yourself by using the repo linked above.
The API service is lightweight and cheap. The live version uses solely public RPCs and does the tracing locally using REVM and reth-inspector under the hood. For found slot call with overrides is called to check how the slot influences balances - expressed in updateRatio output.
Using public RPCs, the API usually takes ~1 sec to find and verify the slot. Results are cached in a local database, so the latency for all subsequent requests is mostly just network propagation. I intentionally didn't cache all of the most popular tokens for the current demo, but you can imagine how that could improve the performance and reliability.
Conclusion
I believe that adopting described service would improve the functionality of Rivet at minimal cost. Using the current method as a fallback option could reduce the risks of reliance on external service for its core functionality.
Note: token-bss is not rigorously tested yet and made with a time constraint. So please let me know if you encounter a bug or have an idea for its improvment.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Summary
Rivet's existing
SetErc20Balance
solution is limited in its coverage of tokens. I propose an alternative, a lightweight and cost-effective API service that deduces storage slots for token balance mappings using heuristic analysis on call traces.Present implementation
Rivet currently enables setting the token balance to an arbitrary value. The method involves iterating through first ten storage slots, modifying the storage slot of the targeted token, and confirming the balance change. Shown below:
rivet/src/hooks/useSetErc20Balance.ts
Lines 31 to 135 in 65d03c7
This method efficiently handles tokens with:
For some tokens above conditions don't hold. As an example storage slot for UNI on Arbitrum is 51; SNX on Ethereum stores balances in a different contract than the token one and for stETH storage slot value to balance ratio is not one to one.
Proposed solution
Approach
Heuristic
Token balances are managed as mappings where Solidity and Vyper compilers hash the storage slot and key to determine the storage location. Analyzing the memory and stack during a balanceOf call within a trace can pinpoint the specific storage slot for balances.
Trace Availability
The major limitation of this heuristic method is the need for comprehensive traces that include instructions, stack, and memory, typically provided by Geth struct traces. Most free RPC services do not offer such detailed traces and even paid services from providers like Alchemy and Quicknode may not always support struct traces. This requires us to either deploy nodes or resort to local tracing.
Local tracing
With "local tracing" I am referring to obtaining the state of the blockchain and executing instructions locally.
Hardhat and Anvil provide this feature, however this requires spinning up a forked network each time tracing is needed. While this works just fine a more lightweight solutions is available. Under the hood Anvil uses REVM with reth-inspector to do local tracing, thus one could use just this for their tracing.
I separated the logic for local tracing using revm, AlloyDB and reth-inspector in this mini crate.
token-bss API
token-bss
is a Rust tooling that is intended to find balance storage slot of Solidity and Vyper tokens. Code is available here: https://github.com/halo3mic/token-bss.API
Its service is available via API, which you can run yourself by using the repo linked above.
The API is hosted http://token-bss.xyz/ so feel free to try it out:
curl http://token-bss.xyz/eth/0xae7ab96520de3a18e5e111b5eaab095312d7fe84 | jq
Supported chains are:
eth
,arb
,avax
andopt
.Performance
The API service is lightweight and cheap. The live version uses solely public RPCs and does the tracing locally using REVM and reth-inspector under the hood. For found slot call with overrides is called to check how the slot influences balances - expressed in
updateRatio
output.Using public RPCs, the API usually takes ~1 sec to find and verify the slot. Results are cached in a local database, so the latency for all subsequent requests is mostly just network propagation. I intentionally didn't cache all of the most popular tokens for the current demo, but you can imagine how that could improve the performance and reliability.
Conclusion
I believe that adopting described service would improve the functionality of Rivet at minimal cost. Using the current method as a fallback option could reduce the risks of reliance on external service for its core functionality.
Note:
token-bss
is not rigorously tested yet and made with a time constraint. So please let me know if you encounter a bug or have an idea for its improvment.Beta Was this translation helpful? Give feedback.
All reactions