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
- Creator
- 0x31098c0E25…659D3783Fe
- 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