Skip to content

Releases: aragon/evm-storage-proofs

v0.1.0

10 Apr 22:05
Compare
Choose a tag to compare

EVM Storage Proofs v0.1.0 🧙‍♂️

EVM Storage Proofs allow to trustlessly prove a past storage value in a contract to other contracts.

Use cases

  • Fetching a value at a past block number (i.e. ANT balance of 0xcafe1a77e... at block 5,000,000)
  • Inspecting storage values that are not exposed through a contract's public API.
  • Executing code in an EVM (or a different VM) on the EVM with real storage values.
  • More fun things 🎉

Packages

web3-proofs ✏️

Off-chain JS library for generating and locally verifying storage proofs.

Installing

npm install web3-proofs

Usage

This library can be used to generate a proof of the state of an account at a certain block height.
The current implementation uses the eth_getProof RPC method (EIP 1186) to generate proofs. To generate proofs using the JS library you can follow the next example:

const Web3Proofs = require('@aragon/web3-proofs')
const web3proofs = new Web3Proofs(web3.currentProvider)
const proof = await web3proofs.getProof(contractAddress, [slot1, slot2], blockNumber)

🚨Caveat
Bear in mind that if you're running on a live network, proof generation requires an archive node (unless the proof is being generated for the latest block). Whether proofs can be generated using the Ethereum light client protocol (LES GetProofs) is currently being researched.

You can check out more examples taking a look at the test suite for @aragon/evm-storage-proofs

evm-storage-proofs 📚

Set of contracts that allow you to verify storage proofs on-chain.

Installing

npm install evm-storage-proofs

Usage

The StorageOracle contract can be used to verify a storage proof. There are two phases for proof verification:

1. Account proof verification

In order to perform an account proof verification, the StorageOracle must be provided with the block header blob, the block number and the merkle proof for the account. If the proof is successfully verified, the storageHash for the account at that blockNumber is cached in the StorageOracle. The storageHash is the root of the storage merkle trie for the account.

storageOracle.processStorageRoot(account, blockNumber, blockHeaderRLP, accountStateProof)

🚨Caveat

Before the Constantinople hard fork, this phase of the proof can only be done for block numbers no older than 256 blocks. After 256 blocks, block hashes become unavailable to contracts, and the proof cannot be processed. After the Constantinople hard fork, some older block hashes will also be available under certain conditions. After the proof is processed in the contract, it can be used forever.

2. Using verified storage proofs

After having the storageHash verified and cached in the StorageOracle, we can now verify the merkle proofs of the account's storage trie. The storageOracle#getStorage function can be used to verify the merkle proof and get the corresponding storage value.

uint256 value = storageOracle.getStorage(account, blockNumber, slot, storageProof)

Each storage slot contains a 32 byte value (uint256 or bytes32), for more complex data structures multiple storage proofs can be done and the data structure can be composed.

3. Adapters: snapshotted token balances

The StorageOracle contract just implements the logic for trustlessly getting a past storage value on other contracts, but in order to get more interesting data, adapters can be built that use the StorageOracle for proving storage and give it extra meaning. An example adapter has been built to prove historic token balances, TokenStorageProofs, of tokens with two different internal data structures: a vanilla ERC20 token and a MiniMeToken.

The TokenStorageProofs contract exposes two functions getBalance and getTotalSupply, which provided with the correct proof, will return the historic values from the token contract storage.

Warnings

🚨 Everything in this repo is highly experimental software.

It is not secure to use any of this code in production (mainnet) until proper security audits have been conducted.

📉 Test coverage is low

There are a lot of edge cases that haven't been properly tested yet. Test contributions would be highly appreciated!

🗃 Archive node required

Generating proofs for past block heights requires having access to an archive node.

Credits and resources