mETH
from the Veda BoringVault into the ITB Symbiotic PositionManager0x33272D40b247c4cd9C646582C9bbAD44e85D4fE4
0x919531146f9a25dFC161D5AB23B117FeAE2c1d36
manageVaultWithMerkleVerification (0x244b0f6a)
function call in the Manager
contract. For cmETH, the Manager address is 0xAEC02407cBC7Deb67ab1bbe4B0d49De764878bCE
manageVaultWithMerkleVerification
call. These will be more clear as we go through the example below.
manageProofs (bytes32[][])
- An array of Merkle proofs (each proof is itself an array of bytes)decodersAndSanitizers (address[])
- Array of decoderAndSanitizer addresses (each rebalance action corresponds to a decoderAndSanitizer)targets (address[])
- Array of target addressestargetData (bytes[])
- Array of encoded function target datavalues (uint256[])
- Array with information for whether native ETH is being transferred (usually just an array of 0
)mETH
is transferred to the contract, and then an action (such as depositing into Symbiotic/Eigenlayer/Karak is taken)mETH
from the BoringVault to the ITB PositionManager for Symbiotic{
"AddressArguments": ["0x919531146f9a25dFC161D5AB23B117FeAE2c1d36"],
"CanSendValue": False,
"DecoderAndSanitizerAddress": "0xa728337af7dD226B74B0b1546AA7dD54d340d5Eb",
"Description": "Transfer mETH to ITB Contract: 0x919531146f9a25dFC161D5AB23B117FeAE2c1d36",
"FunctionSelector": "0xa9059cbb",
"FunctionSignature": "transfer(address,uint256)",
"LeafDigest": "0x89cd1ab1bdfb632a52b4d7e7de0e45eed164d7e7fa9b02916e87b945e37ba94c",
"PackedArgumentAddresses": "0x919531146f9a25dfc161d5ab23b117feae2c1d36",
"TargetAddress": "0xd5F7838F5C461fefF7FE49ea5ebaF7728bB0ADfa",
}
We can see from the description that this leaf authorizes transferring mETH
to address 0x919531146f9a25dFC161D5AB23B117FeAE2c1d36
which corresponds to the ITB PositionManager for Symbiotic.
The LeafDigest
for this leaf is 0x89cd1ab1bdfb632a52b4d7e7de0e45eed164d7e7fa9b02916e87b945e37ba94c
.
This script produces the Merkle proof from the LeafDigest:
import json
from typing import List, Dict
def construct_merkle_proof(leaf_digest: str, tree_data: Dict) -> List[str]:
# Convert leaf_digest to lowercase for case-insensitive comparison
leaf_digest = leaf_digest.lower()
# Find the leaf index
leaf_index = None
for i, digest in enumerate(tree_data['MerkleTree']['6']):
if digest.lower() == leaf_digest:
leaf_index = i
break
if leaf_index is None:
raise ValueError("Leaf digest not found in the tree")
proof = []
current_index = leaf_index
# Traverse up the tree
for level in range(6, 0, -1):
is_right = current_index % 2 == 1
sibling_index = current_index - 1 if is_right else current_index + 1
if sibling_index < len(tree_data['MerkleTree'][str(level)]):
sibling_digest = tree_data['MerkleTree'][str(level)][sibling_index]
proof.append(sibling_digest)
current_index //= 2 # Move to the parent node
return proof
# Example usage:
def main():
# Load the tree data from a JSON file or string
with open('tree_data.json', 'r') as f:
tree_data = json.load(f)
# Example leaf digest
leaf_digest = "0x89cd1ab1bdfb632a52b4d7e7de0e45eed164d7e7fa9b02916e87b945e37ba94c"
try:
merkle_proof = construct_merkle_proof(leaf_digest, tree_data)
print(f"Merkle Proof for leaf {leaf_digest}:")
print(merkle_proof)
except ValueError as e:
print(f"Error: {e}")
if __name__ == "__main__":
main()
The output of the script is
[["0xd7e0a9c6d4a965ce0062e728269fe11ee10f6b82debbd2241e7363a951ac9f9c", "0x91a1565472bec1d7d1b83fa70e3940f990f60e7b1b7784adbe36a7ecf01854ae", "0xa529bcb69360978ab9ab57d087daabac89a3a07cc163755994434af4cc56e5f1", "0xef477b38d1acbe665785e8636992323a9a3ce750dcf40fd6e49d6c89d29b8119", "0x500fb7061ee25014f3761d130c907e2458e5ac555c54703e7237ef38500a2996", "0x805d86b669a6c46b9f8e66f302ed1088ce92d665a7105d7ecb0385fa352aa007"]]