Commit a1329f21 authored by smartcontracts's avatar smartcontracts Committed by GitHub

fix(sdk): maybe add proof node (#9663)

Fixes a bug in the SDK that would cause it to be unable to prove
certain types of withdrawals. Bug can be easily fixed on the
client side by adding an extra proof element in certain cases.
parent cee93c71
---
'@eth-optimism/sdk': patch
---
Fixes a bug in the SDK that would sometimes cause proof submission reverts.
......@@ -6,6 +6,7 @@ import {
toRpcHexString,
} from '@eth-optimism/core-utils'
import { MerkleTree } from 'merkletreejs'
import * as rlp from 'rlp'
/**
* Generates a Merkle proof (using the particular scheme we use within Lib_MerkleTree).
......@@ -44,6 +45,42 @@ export const makeMerkleTreeProof = (
return proof
}
/**
* Fix for the case where the final proof element is less than 32 bytes and the element exists
* inside of a branch node. Current implementation of the onchain MPT contract can't handle this
* natively so we instead append an extra proof element to handle it instead.
*
* @param key Key that the proof is for.
* @param proof Proof to potentially modify.
* @returns Modified proof.
*/
export const maybeAddProofNode = (key: string, proof: string[]) => {
const modifiedProof = [...proof]
const finalProofEl = modifiedProof[modifiedProof.length - 1]
const finalProofElDecoded = rlp.decode(finalProofEl) as any
if (finalProofElDecoded.length === 17) {
for (const item of finalProofElDecoded) {
// Find any nodes located inside of the branch node.
if (Array.isArray(item)) {
// Check if the key inside the node matches the key we're looking for. We remove the first
// two characters (0x) and then we remove one more character (the first nibble) since this
// is the identifier for the type of node we're looking at. In this case we don't actually
// care what type of node it is because a branch node would only ever be the final proof
// element if (1) it includes the leaf node we're looking for or (2) it stores the value
// within itself. If (1) then this logic will work, if (2) then this won't find anything
// and we won't append any proof elements, which is exactly what we would want.
const suffix = toHexString(item[0]).slice(3)
if (key.endsWith(suffix)) {
modifiedProof.push(toHexString(rlp.encode(item)))
}
}
}
}
// Return the modified proof.
return modifiedProof
}
/**
* Generates a Merkle-Patricia trie proof for a given account and storage slot.
*
......@@ -70,6 +107,11 @@ export const makeStateTrieProof = async (
toRpcHexString(blockNumber),
])
proof.storageProof[0].proof = maybeAddProofNode(
ethers.utils.keccak256(slot),
proof.storageProof[0].proof
)
return {
accountProof: proof.accountProof,
storageProof: proof.storageProof[0].proof,
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment