KeeperGasTank

0x02803a831626cd5b74d8b941961e0886df9b015c

Verification
Verified
v0.8.26+commit.8a97fa7a
Type
Contract
1,595 bytes
ABI entries
18
6 read · 2 write
License
none

Contract information

Address
0x02803a831626cd5b74d8b941961e0886df9b015c
Chain
Robinhood Chain (4663)
Compiler
v0.8.26+commit.8a97fa7a
Optimization
Enabled
Creation tx
0x7ea2e93be4…3787a79676

Token

Not a token

This contract does not expose ERC-20 metadata.

Read contract (6)

cooldown()uint256
keeper()address
lastRefillAt()uint256
maxRefill()uint256
owner()address
targetBalance()uint256

Events (3)

FundedRefilledWithdrawn

ABI

[
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "_keeper",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "_targetBalance",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "_maxRefill",
        "type": "uint256"
      },
      {
        "internalType": "uint256",
        "name": "_cooldown",
        "type": "uint256"
      },
      {
        "internalType": "address",
        "name": "_owner",
        "type": "address"
      }
    ],
    "stateMutability": "nonpayable",
    "type": "constructor"
  },
  {
    "inputs": [],
    "name": "CooldownActive",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "KeeperNotLow",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "OnlyOwner",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TankEmpty",
    "type": "error"
  },
  {
    "inputs": [],
    "name": "TransferFailed",
    "type": "error"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "from",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "Funded",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "keeperBalanceAfter",
        "type": "uint256"
      }
    ],
    "name": "Refilled",
    "type": "event"
  },
  {
    "anonymous": false,
    "inputs": [
      {
        "indexed": true,
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "indexed": false,
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "Withdrawn",
    "type": "event"
  },
  {
    "inputs": [],
    "name": "cooldown",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "keeper",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "lastRefillAt",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "maxRefill",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "owner",
    "outputs": [
      {
        "internalType": "address",
        "name": "",
        "type": "address"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "refill",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "inputs": [],
    "name": "targetBalance",
    "outputs": [
      {
        "internalType": "uint256",
        "name": "",
        "type": "uint256"
      }
    ],
    "stateMutability": "view",
    "type": "function"
  },
  {
    "inputs": [
      {
        "internalType": "address",
        "name": "to",
        "type": "address"
      },
      {
        "internalType": "uint256",
        "name": "amount",
        "type": "uint256"
      }
    ],
    "name": "withdraw",
    "outputs": [],
    "stateMutability": "nonpayable",
    "type": "function"
  },
  {
    "stateMutability": "payable",
    "type": "receive"
  }
]

Source code

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

/// @title KeeperGasTank — automatisk gass-paafyll for keeper-walleten
/// @notice Loeser "frimerke-problemet": keeperen (EOA-en som trigger
///         buybacks) maa betale gass, men skal ikke passes paa manuelt.
///         Tanken holder ETH; NAAR SOM HELST kan hvem som helst kalle
///         refill(), som fyller keeperen opp til maalniva — men aldri mer
///         enn maxRefill per cooldown-periode.
///
///         Keeper-serveren kaller refill() selv naar den ser at egen
///         balanse er lav -> helautomatisk drift. Tanken fylles fra
///         treasury-overskuddet: Safe -> withdrawSurplus(ETH, tank, beloep)
///         et par ganger i aaret. Dermed er det feene som betaler frimerkene.
///
/// @dev Sikkerhetsmodell (bevisst enkel):
///      - Mottaker er IMMUTABLE: tanken kan kun sende til keeper-adressen.
///      - Utstroem er begrenset: maks maxRefill per cooldown, og kun naar
///        keeperens balanse er under targetBalance. Lekker keeper-noekkelen,
///        er tapet avgrenset til tankens takt — og owner (Safe) kan naar som
///        helst troemme tanken med withdraw().
///      - Ingen andre funksjoner, ingen oppgradering, ingen delegatecall.
contract KeeperGasTank {
    /// @notice Keeper-EOA-en som mottar gass. Kan aldri endres.
    address public immutable keeper;
    /// @notice Fyll opp til dette nivaaet (f.eks. 0.02 ether).
    uint256 public immutable targetBalance;
    /// @notice Maks utbetaling per refill (f.eks. 0.02 ether).
    uint256 public immutable maxRefill;
    /// @notice Minste tid mellom refills (f.eks. 6 timer).
    uint256 public immutable cooldown;
    /// @notice Safe-multisigen — kan toemme/redde tanken, ingenting annet.
    address public immutable owner;

    uint256 public lastRefillAt;

    event Refilled(uint256 amount, uint256 keeperBalanceAfter);
    event Funded(address indexed from, uint256 amount);
    event Withdrawn(address indexed to, uint256 amount);

    error CooldownActive();
    error KeeperNotLow();
    error TankEmpty();
    error OnlyOwner();
    error TransferFailed();

    constructor(
        address _keeper,
        uint256 _targetBalance,
        uint256 _maxRefill,
        uint256 _cooldown,
        address _owner
    ) {
        require(_keeper != address(0) && _owner != address(0), "zero addr");
        require(_targetBalance > 0 && _maxRefill > 0, "zero amount");
        keeper = _keeper;
        targetBalance = _targetBalance;
        maxRefill = _maxRefill;
        cooldown = _cooldown;
        owner = _owner;
    }

    /// @notice Fyll tanken. Aapen for alle — Safe (via withdrawSurplus),
    ///         eier-wallet, eller hvem som helst som vil sponse driften.
    receive() external payable {
        emit Funded(msg.sender, msg.value);
    }

    /// @notice Etterfyll keeperen opp til targetBalance (begrenset av
    ///         maxRefill og cooldown). Kan kalles av hvem som helst —
    ///         pengene kan uansett bare gaa til keeper-adressen.
    function refill() external {
        // lastRefillAt == 0 betyr "aldri fylt" — foerste refill er alltid lov.
        if (lastRefillAt != 0 && block.timestamp < lastRefillAt + cooldown) {
            revert CooldownActive();
        }
        uint256 keeperBal = keeper.balance;
        if (keeperBal >= targetBalance) revert KeeperNotLow();
        if (address(this).balance == 0) revert TankEmpty();

        uint256 amount = targetBalance - keeperBal;
        if (amount > maxRefill) amount = maxRefill;
        if (amount > address(this).balance) amount = address(this).balance;

        lastRefillAt = block.timestamp;
        (bool ok,) = keeper.call{value: amount}("");
        if (!ok) revert TransferFailed();
        emit Refilled(amount, keeper.balance);
    }

    /// @notice Owner (Safe) kan toemme tanken — f.eks. ved keeper-bytte.
    function withdraw(address to, uint256 amount) external {
        if (msg.sender != owner) revert OnlyOwner();
        (bool ok,) = to.call{value: amount}("");
        if (!ok) revert TransferFailed();
        emit Withdrawn(to, amount);
    }
}
Chain explorer5440msChain node81ms