mETH from the Veda BoringVault into the ITB Symbiotic PositionManager0x33272D40b247c4cd9C646582C9bbAD44e85D4fE40x919531146f9a25dFC161D5AB23B117FeAE2c1d36manageVaultWithMerkleVerification (0x244b0f6a) function call in the Manager contract. For cmETH, the Manager address is 0xAEC02407cBC7Deb67ab1bbe4B0d49De764878bCEmanageVaultWithMerkleVerification 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"]]