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
blsSignatureChecker_setBlsSignatureCheckerYesnone
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

blsSignatureChecker is the restaking middleware's IBLSSignatureChecker. It is the contract your target trusts to verify that a quorum of operators signed the state update, and it must be the one bound to the same operator set the router is signing with. avsAddress is the AVS service manager; it scopes the namespace and does not participate in signature verification.

For the public testnet (Sepolia, chain 11155111):

ValueAddress
Chain ID11155111
avsAddress0xdCec8ce0a03848B55989Bcc711e424Ca31d9eeD9
blsSignatureChecker0x6953fc47FC8b7568801f3fdc327bc0d9aD12E5b9
registryCoordinator0x0a032D62dde46670Ae40Ce532C97f6CE9Af72Dc4
schnorrStakeRegistry0x8A86301675ac9617895117afFE9577f5154555F9

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")
SIG_CHECKER_ADDRESS=$(jq -r .blsSignatureChecker <<<"$CONTRACTS")

schnorrStakeRegistry is published alongside them, for a target that settles under both schemes. See Migration.

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. A checker is only useful if it points at the registry coordinator the operators are actually registered in, so ask it directly and compare against registryCoordinator above:

# The checker your target actually uses, which is the thing being verified.
TARGET_CHECKER=$(cast call "$TARGET" "blsSignatureChecker()(address)" --rpc-url "$RPC_URL")

# Must equal registryCoordinator in the table above.
cast call "$TARGET_CHECKER" "registryCoordinator()(address)" --rpc-url "$RPC_URL"

If your checker resolves to a different registryCoordinator, your address is stale. The task fails with InvalidQuorumApkHash (0xe1310aed), because the router computes the quorum's aggregate-key indices against the live registry, and your checker looks them up in a different one. 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 blsSignatureChecker can point your contract at a checker 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 blsSigChecker)
        Ownable(msg.sender)
    {
        _setAvsAddress(avs);
        _setBlsSignatureChecker(blsSigChecker);
    }

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

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. 300 is a sensible default; change it only with a reason.

constructor(address avs, address blsSigChecker) {
    _setAvsAddress(avs);
    _setBlsSignatureChecker(blsSigChecker);
    _setBlockStaleMeasure(150);
}

Reading configuration back

All public, all view:

GetterReturns
avsAddress()Configured AVS service manager
blsSignatureChecker()Configured signature checker
blockStaleMeasure()Effective value, including the 300 default
namespace()abi.encodePacked(avsAddress, "gaskiller"), or empty when unset
stateTransitionCount()Transitions applied so far
inTransition()True while a transition is being applied
supportsInterface(0x93de4531)Whether the router will accept this target

namespace() is derived on read rather than stored, so setting avsAddress is a single storage write.

On this page