Problem
When performing a read-only dry-run via ReviveApi.call, the origin parameter must be an SS58 account address. Inside the contract, msg.sender resolves to the corresponding H160 (EVM) address. This means that to read data stored under a specific user's msg.sender, the caller must first reverse-lookup the H160 → SS58 mapping via Revive.OriginalAccount storage.
This is a significant bottleneck for apps that need to enumerate data across many contracts.
Concrete example
The DotNS Store contract stores values per-user:
mapping(address user => string[] userValues) private values;
function getValues() external view returns (string[] memory) {
return values[msg.sender]; // keyed by caller's H160
}
A StoreFactory deploys one Store per user. To enumerate all values across all stores, an app must:
- Call
StoreFactory.getAllDeployedStores() → 363 store addresses
- For each store, call
Store.owner() → get the owner's H160
- For each H160, query
Revive.OriginalAccount → get the SS58 address
- Call
Store.getValues() with the SS58 as origin, so msg.sender matches
Step 3 is the bottleneck: 363 individual substrate storage queries, each requiring a state proof through the light client.
Steps 1, 2, and 4 can all be batched via Multicall3 (a single ReviveApi.call per batch). Step 3 cannot — it's a pallet storage query, not a contract call.
Possible solutions
-
Accept H160 directly as origin in ReviveApi.call — if the caller passes a 20-byte address, skip the SS58→H160 mapping and use it as msg.sender directly. This would eliminate the reverse lookup entirely for read-only dry-runs.
-
Provide a batch/multi-key query for Revive.OriginalAccount — allow querying multiple H160→SS58 mappings in a single RPC call (e.g. state_queryStorageAt with multiple keys, or a dedicated runtime API).
-
Add a ReviveApi.call_as(h160, contract, data) variant — explicit API for "call this contract as if msg.sender were this H160 address", for dry-run/simulation purposes only.
-
Expose OriginalAccount as a contract-callable precompile — so the reverse lookup can be batched through Multicall3 alongside other contract calls.
Problem
When performing a read-only dry-run via
ReviveApi.call, theoriginparameter must be an SS58 account address. Inside the contract,msg.senderresolves to the corresponding H160 (EVM) address. This means that to read data stored under a specific user'smsg.sender, the caller must first reverse-lookup the H160 → SS58 mapping viaRevive.OriginalAccountstorage.This is a significant bottleneck for apps that need to enumerate data across many contracts.
Concrete example
The DotNS
Storecontract stores values per-user:A
StoreFactorydeploys oneStoreper user. To enumerate all values across all stores, an app must:StoreFactory.getAllDeployedStores()→ 363 store addressesStore.owner()→ get the owner's H160Revive.OriginalAccount→ get the SS58 addressStore.getValues()with the SS58 as origin, somsg.sendermatchesStep 3 is the bottleneck: 363 individual substrate storage queries, each requiring a state proof through the light client.
Steps 1, 2, and 4 can all be batched via Multicall3 (a single
ReviveApi.callper batch). Step 3 cannot — it's a pallet storage query, not a contract call.Possible solutions
Accept H160 directly as origin in
ReviveApi.call— if the caller passes a 20-byte address, skip the SS58→H160 mapping and use it asmsg.senderdirectly. This would eliminate the reverse lookup entirely for read-only dry-runs.Provide a batch/multi-key query for
Revive.OriginalAccount— allow querying multiple H160→SS58 mappings in a single RPC call (e.g.state_queryStorageAtwith multiple keys, or a dedicated runtime API).Add a
ReviveApi.call_as(h160, contract, data)variant — explicit API for "call this contract as if msg.sender were this H160 address", for dry-run/simulation purposes only.Expose
OriginalAccountas a contract-callable precompile — so the reverse lookup can be batched through Multicall3 alongside other contract calls.