// SPDX-License-Identifier: MIT OR Apache-2.0 pragma solidity >=0.8.0; /** * Format of metadata: * [ 0: 32] Merkle root * [ 32: 36] Root index * [ 36: 68] Origin mailbox address * [ 68:1092] Merkle proof * [1092:????] Validator signatures, 65 bytes each, length == Threshold */ library MultisigIsmMetadata { uint256 private constant MERKLE_ROOT_OFFSET = 0; uint256 private constant MERKLE_INDEX_OFFSET = 32; uint256 private constant ORIGIN_MAILBOX_OFFSET = 36; uint256 private constant MERKLE_PROOF_OFFSET = 68; uint256 private constant SIGNATURES_OFFSET = 1092; uint256 private constant SIGNATURE_LENGTH = 65; /** * @notice Returns the merkle root of the signed checkpoint. * @param _metadata ABI encoded Multisig ISM metadata. * @return Merkle root of the signed checkpoint */ function root(bytes calldata _metadata) internal pure returns (bytes32) { return bytes32(_metadata[MERKLE_ROOT_OFFSET:MERKLE_INDEX_OFFSET]); } /** * @notice Returns the index of the signed checkpoint. * @param _metadata ABI encoded Multisig ISM metadata. * @return Index of the signed checkpoint */ function index(bytes calldata _metadata) internal pure returns (uint32) { return uint32( bytes4(_metadata[MERKLE_INDEX_OFFSET:ORIGIN_MAILBOX_OFFSET]) ); } /** * @notice Returns the origin mailbox of the signed checkpoint as bytes32. * @param _metadata ABI encoded Multisig ISM metadata. * @return Origin mailbox of the signed checkpoint as bytes32 */ function originMailbox(bytes calldata _metadata) internal pure returns (bytes32) { return bytes32(_metadata[ORIGIN_MAILBOX_OFFSET:MERKLE_PROOF_OFFSET]); } /** * @notice Returns the merkle proof branch of the message. * @dev This appears to be more gas efficient than returning a calldata * slice and using that. * @param _metadata ABI encoded Multisig ISM metadata. * @return Merkle proof branch of the message. */ function proof(bytes calldata _metadata) internal pure returns (bytes32[32] memory) { return abi.decode( _metadata[MERKLE_PROOF_OFFSET:SIGNATURES_OFFSET], (bytes32[32]) ); } /** * @notice Returns the validator ECDSA signature at `_index`. * @dev Assumes signatures are sorted by validator * @dev Assumes `_metadata` encodes `threshold` signatures. * @dev Assumes `_index` is less than `threshold` * @param _metadata ABI encoded Multisig ISM metadata. * @param _index The index of the signature to return. * @return The validator ECDSA signature at `_index`. */ function signatureAt(bytes calldata _metadata, uint256 _index) internal pure returns (bytes calldata) { uint256 _start = SIGNATURES_OFFSET + (_index * SIGNATURE_LENGTH); uint256 _end = _start + SIGNATURE_LENGTH; return _metadata[_start:_end]; } }