Gas Killer Docs
Solidity Reference

Configuration

The addresses your target must be wired to, and how to verify them.

GasKillerSDK holds its configuration in an ERC-7201 namespace, so it never collides with your contract's own storage. Two values are required; the rest have working defaults.

ValueSetterRequiredDefault
avsAddress_setAvsAddressYesnone
schnorrRegistry_setSchnorrRegistryYesnone
blockStaleMeasure_setBlockStaleMeasureNo300 blocks

All three setters are internal. The SDK deliberately ships no access control, you decide who may call them and when, by exposing them or not.

The two required addresses

schnorrRegistry is the SchnorrStakeRegistry holding the operator set's aggregate key and stake weights. It is the contract your target trusts to verify that a quorum of operators signed the state update, and it must be the one the router is signing for. avsAddress is the AVS service manager; it records which deployment the target belongs to and does not participate in signature verification.

For the public testnet (Sepolia, chain 11155111):

ValueAddress
Chain ID11155111
avsAddress0x0eF3c25243004C0F81Dc678c3411E619D61577ef
schnorrStakeRegistry0x8A86301675ac9617895117afFE9577f5154555F9
registryCoordinator0x57981e930B19C52E95Fd727Ee51923119acCeeC0
demoTarget0xCAcD6fd494cde74A84e7e5F6816ca7C87aa88aaD

Read from GET /avs-metadata on the router itself, so this table follows the deployment rather than being maintained by hand. Cached for up to an hour.

While Gas Killer is in early development on Sepolia, these addresses can change. Every target holding an old one has to be updated, so resolve them at deploy time rather than copying them into your source, and make sure your contract can be rewired afterwards.

Read them yourself the same way, in a script or a deploy pipeline:

curl -s https://testnet.gaskiller.xyz/avs-metadata | jq .contracts

The two values a target's constructor takes, resolved at the moment you deploy rather than copied from a page:

CONTRACTS=$(curl -s https://testnet.gaskiller.xyz/avs-metadata | jq .contracts)
AVS_ADDRESS=$(jq -r .avsAddress <<<"$CONTRACTS")
SCHNORR_REGISTRY_ADDRESS=$(jq -r .schnorrStakeRegistry <<<"$CONTRACTS")

The full response shape is in the API reference.

Verify your own wiring

Once your target is deployed, confirm it agrees with the published set:

# Must equal schnorrStakeRegistry in the table above.
cast call "$TARGET" "schnorrRegistry()(address)" --rpc-url "$RPC_URL"

# Non-zero: the registry actually holds an operator set.
cast call "$SCHNORR_REGISTRY_ADDRESS" "totalWeight()(uint256)" --rpc-url "$RPC_URL"

If your target points at a different registry, its address is stale. Its tasks fail with InvalidQuorumSignature (0x68477238), because the aggregate key it checks against is not the one the operators signed with, or with NotRegistered (0xbfc6c337) when a non-signer the router lists is unknown to it. See the error table.

Stay reconfigurable

Gas Killer is not production-ready. It is unaudited and under active development, so treat this section as required rather than optional. Because the addresses above can change, a contract you can reconfigure follows a migration, while one you cannot has to be redeployed with its state moved across. Guard the setter like the upgrade key it is, with a multisig or a timelock: whoever can change schnorrRegistry can point your contract at a registry they control.

Because the setters are internal, a contract that only calls them in its constructor can never be rewired, whether an address changed or you simply got one wrong.

Expose a guarded setter:

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {GasKillerSDK} from "gas-killer-sdk/GasKillerSDK.sol";

contract Counter is GasKillerSDK, Ownable {
    constructor(address avs, address schnorrRegistry)
        Ownable(msg.sender)
    {
        _setAvsAddress(avs);
        _setSchnorrRegistry(schnorrRegistry);
    }

    /// Lets the deployment follow an operator-set migration without redeploying.
    function setGasKillerConfig(address avs, address schnorrRegistry) external onlyOwner {
        _setAvsAddress(avs);
        _setSchnorrRegistry(schnorrRegistry);
    }
}

blockStaleMeasure

The maximum age, in blocks, of the referenceBlockNumber a payload may carry. verifyAndUpdate requires:

referenceBlockNumber < block.number
referenceBlockNumber + blockStaleMeasure >= block.number

Unset means 300 blocks, roughly an hour on Sepolia. Below that floor a payload expires before a client can reasonably submit it; well above it, a payload stays applicable long after the state it was computed against.

Lowering it tightens the window in which a signed transition can land. Raising it widens the period during which an operator-set change can invalidate an already-assembled signature. The registry schedules operator changes behind a notice window (600 blocks on the public testnet) sized to exceed this value plus a signing round, so raising it past that window loses the guarantee that a payload settles under the operator set that signed it. 300 is a sensible default; change it only with a reason.

constructor(address avs, address schnorrRegistry) {
    _setAvsAddress(avs);
    _setSchnorrRegistry(schnorrRegistry);
    _setBlockStaleMeasure(150);
}

Reading configuration back

All public, all view:

GetterReturns
avsAddress()Configured AVS service manager
schnorrRegistry()Configured stake registry
blockStaleMeasure()Effective value, including the 300 default
stateTransitionCount()Transitions applied so far
inTransition()True while a transition is being applied
supportsInterface(0x82b35a01)Whether the router will accept this target

On this page