Gas-burn micro-payment

gas-burn-micro-payment · conditional-settlement · 1249 B runtime · funds-movement

scores

source

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;

contract GasBurnMicroPayment {
    uint256 public constant MAX_GAS_TARGET = 50_000;
    uint256 private constant MIN_RESERVE_GAS = 5_000;

    address public owner;
    uint256 public threshold;
    bool private locked;

    event ThresholdSet(uint256 newThreshold);
    event Claimed(address indexed claimant, uint256 amount);

    constructor(uint256 initialThreshold) {
        require(initialThreshold > 0 && initialThreshold <= MAX_GAS_TARGET, "bad initial threshold");
        owner = msg.sender;
        threshold = initialThreshold;
    }

    modifier onlyOwner() {
        require(msg.sender == owner, "unauthorized");
        _;
    }

    modifier nonReentrant() {
        require(!locked, "reentrant");
        locked = true;
        _;
        locked = false;
    }

    receive() external payable {}

    function setThreshold(uint256 newThreshold) external onlyOwner {
        require(newThreshold > 0 && newThreshold <= MAX_GAS_TARGET, "bad threshold");
        threshold = newThreshold;
        emit ThresholdSet(newThreshold);
    }

    function claim() external nonReentrant {
        require(address(this).balance > 0, "no balance");

        uint256 startGas = gasleft();
        require(startGas >= threshold + MIN_RESERVE_GAS, "insufficient gas");

        uint256 targetGas = startGas - threshold;

        assembly {
            for { } gt(gas(), targetGas) { } {
                mstore(0, gas())
            }
        }

        uint256 gasUsed = startGas - gasleft();
        require(gasUsed >= threshold, "burn below threshold");
        require(gasleft() > MIN_RESERVE_GAS, "reserve too low");

        uint256 amount = address(this).balance;
        (bool ok, ) = msg.sender.call{value: amount}("");
        require(ok, "transfer failed");

        emit Claimed(msg.sender, amount);
    }
}