# Delegated Attestation Setup

Run your attester with a **cold controller wallet** that holds the stake, and a **hot operator wallet** that submits attestations. The controller's private key never touches the server.

This is the recommended setup if your staked wallet is a hardware wallet, a high-value EOA, or any key you don't want exposed on an always-online machine.

## Concept

| Role           | Wallet      | Holds                             | Signs                             | Where it lives                                                      |
| -------------- | ----------- | --------------------------------- | --------------------------------- | ------------------------------------------------------------------- |
| **Controller** | Cold wallet | Stake + rewards accrue here       | One-time delegation authorization | Hardware wallet / air-gapped / cold laptop                          |
| **Operator**   | Hot wallet  | Only enough iKAS for gas (\~5–10) | Every attestation transaction     | On the attestor server (required — the container needs the raw key) |

**What happens if the operator key leaks?** An attacker can submit (or fail to submit) attestations in your name. They **cannot** withdraw stake, claim rewards, or change the delegation — those all require the controller. You rotate by generating a new delegation to a fresh operator address.

**Rewards** always accrue to the controller address. To claim, connect the **controller** to the [attester dashboard](https://attester-dashboard.igralabs.com/?network=mainnet) — signing one claim tx, then the cold wallet can go back offline.

**The operator can be any EOA** — a fresh private key generated on the server is fine. It doesn't need a prior reputation or stake; it just needs a private key the attestor container can read.

## Pre-requisites

All the [standard pre-requisites](https://igra-labs.gitbook.io/igralabs-docs/attestor-setup-guide#pre-requisites) apply (synced node, funded kaswallet, RPC enabled), plus:

* **Controller wallet** already registered as an attester with stake
* **Operator wallet** generated (fresh EOA is fine — just need the private key)
* **5–10 iKAS on the operator wallet** for L2 gas

## Step 1 — Generate the delegation signature (on the controller side)

The signature is a standard **EIP-712** typed-data signature. It authorizes a specific operator address to attest on behalf of the controller until a given block number expires.

**EIP-712 domain:**

```
name:              "Igra Labs"
version:           "1"
chainId:           38833  (mainnet) / 38836 (testnet)
verifyingContract: 0xc24Df70E408739aeF6bF594fd41db4632dF49188
salt:              0xd6becd43d810e50afccd2f334a5834e78cf3da756977f6f8f7a8e5e97d7acf7c
```

**Message type:** `DelegationAuth(address operator, uint64 expiry)`

Any tool that can sign an EIP-712 payload will produce a valid signature. The easiest path is the attester dashboard; CLI options below cover software keys, hardware wallets, and multisigs.

### Using the attester dashboard (recommended)

The [attester dashboard](https://attester-dashboard.igralabs.com/delegate?network=mainnet) has a built-in **Sign DelegationAuth** flow that works with any connected wallet — MetaMask, Rabby, Ledger/Trezor via MetaMask, WalletConnect.

1. Open the [delegate page](https://attester-dashboard.igralabs.com/delegate?network=mainnet) and connect with your **controller** wallet
2. Enter the **operator address** and **expiry** (block number)
3. Click **Sign DelegationAuth** — your wallet prompts for an EIP-712 signature
4. The dashboard shows a **Paste into setup.sh** box with three values (`CONTROLLER_ADDRESS`, `DELEGATION_EXPIRY`, `DELEGATION_SIGNATURE`). Use **Copy all** or **Download .env** to transfer them to the attestor server.

This flow works for **any EOA controller**, including hardware wallets connected via MetaMask/Rabby.

### If the controller is a software key (CLI)

Use the official signing container on the controller's machine:

```bash
cat > delegation.env << 'EOF'
CONTROLLER_PRIVATE_KEY=0xYOUR_COLD_WALLET_KEY
OPERATOR_ADDRESS=0xYOUR_HOT_WALLET_ADDRESS
DELEGATION_EXPIRY=999999999
CHAIN_ID=38833
CONTRACT_ADDRESS=0xc24Df70E408739aeF6bF594fd41db4632dF49188
EOF
chmod 600 delegation.env

docker run --rm -it --env-file delegation.env \
  igranetwork/attestor:2.3.2 --sign-delegation

rm delegation.env
```

The command prints `CONTROLLER_ADDRESS`, `DELEGATION_EXPIRY`, and `DELEGATION_SIGNATURE` to paste on the server during `./setup.sh`.

### If the controller is a Ledger / Trezor (CLI)

The dashboard flow above is usually easier (connect hardware via MetaMask/Rabby). If you prefer CLI, use [Foundry's `cast`](https://book.getfoundry.sh/reference/cast/cast-wallet-sign) to sign the EIP-712 payload via the hardware device.

1. Save this to `delegation.json` (replace the operator and expiry):

```json
{
  "domain": {
    "name": "Igra Labs",
    "version": "1",
    "chainId": 38833,
    "verifyingContract": "0xc24Df70E408739aeF6bF594fd41db4632dF49188",
    "salt": "0xd6becd43d810e50afccd2f334a5834e78cf3da756977f6f8f7a8e5e97d7acf7c"
  },
  "primaryType": "DelegationAuth",
  "types": {
    "EIP712Domain": [
      {"name": "name", "type": "string"},
      {"name": "version", "type": "string"},
      {"name": "chainId", "type": "uint256"},
      {"name": "verifyingContract", "type": "address"},
      {"name": "salt", "type": "bytes32"}
    ],
    "DelegationAuth": [
      {"name": "operator", "type": "address"},
      {"name": "expiry", "type": "uint64"}
    ]
  },
  "message": {
    "operator": "0xYOUR_HOT_WALLET_ADDRESS",
    "expiry": "999999999"
  }
}
```

2. Sign with the hardware wallet:

```bash
# Ledger
cast wallet sign --ledger --data --from-file delegation.json

# Trezor
cast wallet sign --trezor --data --from-file delegation.json
```

The output is the 65-byte `0x…`-prefixed signature — this is your `DELEGATION_SIGNATURE`. Your `CONTROLLER_ADDRESS` is the hardware wallet's address.

### If the controller is a Safe / multisig

**Not currently supported.** The on-chain verifier uses `ECDSA.recover` (EOA signatures only) and does not accept ERC-1271 contract signatures. If your controller is a Safe, you'd need to use an EOA signer from the Safe's owners as a proxy, or wait for ERC-1271 support.

## Step 2 — Run setup.sh in delegated mode

On the attestor server:

```bash
git clone https://github.com/IgraLabs/attestor-deploy.git
cd attestor-deploy/deploy
./setup.sh mainnet
```

When prompted:

1. Choose **`2) Delegated`**
2. Paste the **controller address** (the cold wallet address)
3. Paste the **delegation expiry** (the block number you signed for)
4. Paste the **delegation signature** (`0x…` + 130 hex chars)
5. Enter the **operator private key** (the hot wallet's key — goes into `secrets/private_key.txt`)

The attestor starts and submits attestations signed by the operator, authorized by the controller's delegation.

## Step 3 — Verify

```bash
curl -s localhost:8180 | jq .
```

You should see `"status": "healthy"` and `"state": "Active"`.

Monitor status and rewards via the dashboard, pointing at the **controller** address (that's where stake and rewards live):

```
https://attester-dashboard.igralabs.com/?network=mainnet&address=CONTROLLER_ADDRESS
```

## Choosing an Expiry

`DELEGATION_EXPIRY` is a Kaspa L1 DAA score at which the delegation stops being valid. At \~10 DAA/second that's \~31,536,000 per year.

* For testing: pick a nearby future value.
* For production: pick something 6–12 months ahead and set a calendar reminder to renew.

The attestor logs warnings as expiry approaches. To renew, sign a new delegation (new expiry, same operator), then edit `deploy/.env` to update `DELEGATION_EXPIRY` and `DELEGATION_SIGNATURE` and run `docker compose down && docker compose up -d`.

## Rotating the Operator

If the operator key is ever suspected compromised:

1. Generate a fresh operator EOA.
2. Sign a new delegation from the controller (same expiry, new operator address) — the new delegation doesn't invalidate the old one on its own, but overwriting `.env` and restarting the attestor means only the new operator is active.
3. Re-run `./setup.sh mainnet` and paste the new delegation + operator key.
4. The stake, rewards history, and attester identity are unchanged — only the signing key rotates.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://igra-labs.gitbook.io/igralabs-docs/for-attesters/delegated-attestation-setup.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
