Contract Reference
Complete Solidity interface reference for all AutoLoop contracts.
Core Contracts
AutoLoop.sol
The main protocol orchestrator. Manages controller registration, loop execution, and fee distribution.
// Execute a standard loop
function performUpdate(address _autoLoopCompatibleContract) external;
// Execute a VRF loop with proof
function performVRFUpdate(
address _autoLoopCompatibleContract,
uint256[4] calldata proof,
uint256[2] calldata uPoint,
uint256[4] calldata vComponents
) external;
// Controller management
function registerController(address _controller) external;
function removeController(address _controller) external;
function isController(address _address) external view returns (bool);
// Protocol admin
function setBaseFee(uint256 _fee) external;
function setProtocolFeePortion(uint256 _portion) external;
function setMaxGas(uint256 _gas) external;
function withdrawFees(address payable _to) external;AutoLoopRegistrar.sol
Entry point for registering new contracts. Validates ERC-165 interface support.
// Register a contract and optionally deposit ETH
function registerAutoLoop(address _contract) external payable;
// Check if a contract implements a supported interface
function isCompatible(address _contract) external view returns (bool);AutoLoopRegistry.sol
State management for registered contracts, balances, and configuration.
// Registration status
function isRegistered(address _contract) external view returns (bool);
function getRegisteredContracts() external view returns (address[] memory);
// Balance management
function getBalance(address _contract) external view returns (uint256);
function deposit(address _contract) external payable;
function requestRefund(address _contract, address _to) external;
// Configuration
function getMaxGas(address _contract) external view returns (uint256);
function setMaxGas(address _contract, uint256 _gas) external;VRFVerifier.sol
Gas-efficient on-chain ECVRF proof verification using the secp256k1 curve.
// Verify an ECVRF proof and derive random output
function verify(
uint256[2] calldata publicKey, // [pkX, pkY]
uint256[4] calldata proof,
uint256[2] calldata uPoint,
uint256[4] calldata vComponents,
bytes calldata message
) external pure returns (bool valid, uint256 output);Base Contracts (For Developers)
AutoLoopCompatible
Inherit for standard automation with no randomness.
import "@luckymachines/autoloop/src/AutoLoopCompatible.sol";
contract MyGame is AutoLoopCompatible {
// Return true when the contract is ready for the next tick
function shouldProgressLoop() external view override returns (bool) {
return block.timestamp >= lastTick + INTERVAL;
}
// Execute game logic — only callable by AutoLoop
function progressLoop() external override onlyAutoLoop {
lastTick = block.timestamp;
// your logic here
}
}Interface ID: Default (no ERC-165 required) Gas per tick: ~90,000
AutoLoopHybridVRFCompatible
Inherit for selective VRF — cheap standard ticks with randomness only when requested.
import "@luckymachines/autoloop/src/AutoLoopHybridVRFCompatible.sol";
contract MyGame is AutoLoopHybridVRFCompatible {
function shouldProgressLoop() external view override returns (bool) {
return block.timestamp >= lastTick + INTERVAL;
}
// Called on standard ticks (no VRF)
function _onTick() internal override {
turnCount++;
// Set needsVRF for the NEXT tick
if (turnCount % 10 == 0) {
needsVRF = true;
}
}
// Called on VRF ticks (when needsVRF was true)
function _onVRFTick(uint256[] calldata randomWords) internal override {
needsVRF = false;
uint256 lootRoll = randomWords[0] % 100;
// use randomness
}
}Interface ID: Detected via ERC-165 Gas per standard tick: ~90,000 Gas per VRF tick: ~240,000
Key concept: Set needsVRF = true to request randomness on the next tick. Workers read this flag before executing and will generate an ECVRF proof only when it's true.
AutoLoopVRFCompatible
Inherit for full VRF — verifiable randomness on every tick.
import "@luckymachines/autoloop/src/AutoLoopVRFCompatible.sol";
contract DiceGame is AutoLoopVRFCompatible {
function shouldProgressLoop() external view override returns (bool) {
return block.timestamp >= lastTick + INTERVAL;
}
function progressLoop(uint256[] calldata randomWords) external override onlyAutoLoop {
lastTick = block.timestamp;
uint256 roll = randomWords[0] % 6 + 1;
// use roll
}
}Interface ID: Detected via ERC-165 Gas per tick: ~240,000
VRF Key Registration
For VRF and Hybrid VRF contracts, each controller must register its secp256k1 public key:
// Called by the contract owner or admin
function registerControllerKey(
address controller,
uint256 pkX,
uint256 pkY
) external;The pkX and pkY are the x and y coordinates of the controller's public key on the secp256k1 curve. Derive them from the private key:
const { secp256k1 } = require("@noble/curves/secp256k1");
const publicKey = secp256k1.getPublicKey(privateKeyHex, false);
const pkX = "0x" + Buffer.from(publicKey.slice(1, 33)).toString("hex");
const pkY = "0x" + Buffer.from(publicKey.slice(33, 65)).toString("hex");Access Control
AutoLoop uses OpenZeppelin's AccessControl for role-based permissions:
| Role | Who Has It | What It Does |
|---|---|---|
DEFAULT_ADMIN_ROLE | Protocol deployer | Can grant/revoke all roles |
CONTROLLER_ROLE | Registered workers | Can call performUpdate / performVRFUpdate |
The onlyAutoLoop modifier on base contracts ensures only the AutoLoop contract can call progressLoop() — not arbitrary addresses.
Events
AutoLoop Events
event LoopExecuted(address indexed contract, address indexed controller, uint256 gasCost, uint256 fee);
event ControllerRegistered(address indexed controller);
event ControllerRemoved(address indexed controller);
event FeesWithdrawn(address indexed to, uint256 amount);Registry Events
event ContractRegistered(address indexed contract, address indexed owner);
event Deposited(address indexed contract, uint256 amount);
event RefundRequested(address indexed contract, address indexed to, uint256 amount);Constants
| Constant | Value | Description |
|---|---|---|
BASE_FEE | 70% | Percentage of gas cost charged as protocol fee |
PROTOCOL_FEE_PORTION | 50% | Protocol's share of the base fee |
CONTROLLER_FEE_PORTION | 50% | Controller's share of the base fee |
MAX_GAS | 1,000,000 | Default maximum gas per execution |
GAS_BUFFER | 94,293 | Overhead gas for protocol operations |
CONTROLLER_REGISTRATION_FEE | 0.001 ETH | Cost to register as a controller |
Source Code
All contracts are open-source:
- autoloop on GitHub — Core contracts
- autoloop-worker on GitHub — Worker implementation