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.
| Value | Setter | Required | Default |
|---|---|---|---|
avsAddress | _setAvsAddress | Yes | none |
blsSignatureChecker | _setBlsSignatureChecker | Yes | none |
blockStaleMeasure | _setBlockStaleMeasure | No | 300 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):
| Value | Address |
|---|---|
| Chain ID | 11155111 |
| avsAddress | 0xdCec8ce0a03848B55989Bcc711e424Ca31d9eeD9 |
| blsSignatureChecker | 0x6953fc47FC8b7568801f3fdc327bc0d9aD12E5b9 |
| registryCoordinator | 0x0a032D62dde46670Ae40Ce532C97f6CE9Af72Dc4 |
| schnorrStakeRegistry | 0x8A86301675ac9617895117afFE9577f5154555F9 |
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 .contractsThe 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.numberUnset 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:
| Getter | Returns |
|---|---|
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.
