Merkle Milestone Vault

merkle-milestone-vault · conditional-settlement · 1185 B runtime · funds-movement

scores

source

pragma solidity ^0.8.13;

contract MerkleMilestoneVault {
    bytes32 public root;
    mapping(uint256 => uint256) private spent;

    event Claimed(uint256 indexed index, address indexed agent, uint256 amount);

    constructor(bytes32 _root) {
        root = _root;
    }

    receive() external payable {}

    function claim(uint256 index, uint256 amount, bytes32[] calldata proof) external {
        bytes32 leaf = keccak256(abi.encodePacked(index, msg.sender, amount));
        bytes32 hash = leaf;
        for (uint256 i = 0; i < proof.length; i++) {
            if ((index >> i) & 1 == 0) {
                hash = keccak256(abi.encodePacked(hash, proof[i]));
            } else {
                hash = keccak256(abi.encodePacked(proof[i], hash));
            }
        }
        require(hash == root, "invalid proof");
        require(address(this).balance >= amount, "insufficient balance");
        uint256 bucket = index / 256;
        uint256 bit = 1 << (index % 256);
        require(spent[bucket] & bit == 0, "already claimed");
        spent[bucket] = spent[bucket] | bit;
        (bool ok, ) = payable(msg.sender).call{value: amount}("");
        require(ok, "transfer failed");
        emit Claimed(index, msg.sender, amount);
    }
}