Rebate Selector Router

rebate-selector-router · discovery-registry · 1817 B runtime · registry-info

scores

source

pragma solidity ^0.8.13;

contract RebateSelectorRouter {
    uint256 public constant REBATE = 0.001 ether;

    struct Route {
        address payable sponsor;
        address payable agent;
        uint256 balance;
    }

    mapping(bytes4 => Route) private routes;

    event RouteRegistered(bytes4 indexed selector, address indexed sponsor, address agent);
    event RebatePaid(bytes4 indexed selector, address indexed caller, uint256 amount);
    event Forwarded(bytes4 indexed selector, address indexed agent);
    event ExcessWithdrawn(bytes4 indexed selector, address indexed sponsor, uint256 amount);

    function registerRoute(bytes4 selector, address payable agent) external payable {
        require(msg.value > 0, "fund required");
        Route storage r = routes[selector];
        if (r.agent == address(0)) {
            r.sponsor = payable(msg.sender);
            r.agent = agent;
            r.balance = msg.value;
        } else {
            require(msg.sender == r.sponsor, "not sponsor");
            r.agent = agent;
            r.balance += msg.value;
        }
        emit RouteRegistered(selector, r.sponsor, agent);
    }

    function withdrawExcess(bytes4 selector) external {
        Route storage r = routes[selector];
        require(msg.sender == r.sponsor, "not sponsor");
        uint256 amount = r.balance;
        r.balance = 0;
        (bool ok, ) = r.sponsor.call{value: amount}("");
        require(ok, "withdraw failed");
        emit ExcessWithdrawn(selector, r.sponsor, amount);
    }

    fallback() external payable {
        bytes4 selector = msg.sig;
        Route storage r = routes[selector];
        require(r.agent != address(0), "unknown selector");
        require(r.balance >= REBATE, "insufficient balance");
        r.balance -= REBATE;

        (bool rebateOk, ) = msg.sender.call{value: REBATE}("");
        require(rebateOk, "rebate failed");
        emit RebatePaid(selector, msg.sender, REBATE);

        (bool success, ) = r.agent.call{value: msg.value}(msg.data);
        require(success, "forward failed");
        emit Forwarded(selector, r.agent);

        assembly {
            returndatacopy(0, 0, returndatasize())
            return(0, returndatasize())
        }
    }
}