# Starkscan Accounting Point-In-Time Balances

Use this skill when a client needs an account balance for a specific Starknet token at a calendar close or audit timestamp.

## Scope

This skill supports one workflow:

1. Resolve a timestamp to a Starknet block with Starkscan.
2. Query the token balance for one account at that exact block.
3. Return the block, balance payload, request IDs, and bracket evidence.

Do not use this skill for portfolio-wide holdings, historical tax lots, private balances, or inferred ownership. If the user asks for those, say that this skill only covers exact token-contract balances at one timestamp.

## Inputs

Ask for these values if they are missing:

- `chain`: default `SN_MAIN`
- `timestamp`: RFC3339 timestamp with timezone, for example `2025-12-31T23:59:59Z`, or Unix seconds
- `token`: Starknet token contract address
- `account`: Starknet account or contract address
- `api_key`: read key passed as `X-Starkscan-Api-Key`

Use `closest=before` for accounting "as of this instant" semantics. Only use `closest=after` when the user explicitly asks for the first block after the timestamp.

## Environment

```bash
export STARKSCAN_BASE_URL="https://starkscan.co/api"
export STARKSCAN_CHAIN="SN_MAIN"
export STARKSCAN_API_KEY="mzk_live_key_redacted"
export STARKSCAN_TIMESTAMP="2025-12-31T23:59:59Z"
export STARKSCAN_TIMESTAMP_QUERY="2025-12-31T23%3A59%3A59Z"
export STARKSCAN_TOKEN="<token_contract_address>"
export STARKSCAN_ACCOUNT="<account_address>"
```

Never paste the full API key into chat, PR comments, tickets, screenshots, or generated reports.

## Workflow

### 1. Resolve timestamp to block

```bash
curl -sS \
  -H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
  "$STARKSCAN_BASE_URL/v1/$STARKSCAN_CHAIN/block-at-timestamp?timestamp=$STARKSCAN_TIMESTAMP_QUERY&closest=before"
```

The response contains:

- `block.blockNumber`: the selected block to use as `block_tag`
- `block.timestampIso`: the selected block timestamp
- `previousBlock`: inclusive lower indexed bound
- `nextBlock`: inclusive upper indexed bound
- `source`: `indexed_blocks`

For `2025-12-31T23:59:59Z`, Starkscan's correctness gate verified block `5007537` against RPC. Treat that number as a smoke example, not as a substitute for resolving the user's requested timestamp.

### 2. Query token balance at that block

```bash
BLOCK_NUMBER="<block.blockNumber from step 1>"

curl -sS \
  -H "X-Starkscan-Api-Key: $STARKSCAN_API_KEY" \
  "$STARKSCAN_BASE_URL/v1/$STARKSCAN_CHAIN/token/$STARKSCAN_TOKEN/balance-of/$STARKSCAN_ACCOUNT?block_tag=$BLOCK_NUMBER"
```

Use a concrete block number or block hash for reproducible accounting. Do not use `latest` for calendar-close work.

### 3. Report the result

Return these fields to the user:

- requested timestamp
- selected block number and block timestamp
- previous/next bracket blocks when present
- token address
- account address
- raw balance fields from the Starkscan response
- `X-Request-Id` values from both calls

Say explicitly that Starkscan's `block-at-timestamp` request path is served from indexed block facts; RPC is used by the correctness gate, not by each user request.

## Python Smoke

```python
import json
import os
import urllib.parse
import urllib.request

base_url = os.environ.get("STARKSCAN_BASE_URL", "https://starkscan.co/api").rstrip("/")
chain = os.environ.get("STARKSCAN_CHAIN", "SN_MAIN")
api_key = os.environ["STARKSCAN_API_KEY"]
timestamp = os.environ["STARKSCAN_TIMESTAMP"]
token = os.environ["STARKSCAN_TOKEN"]
account = os.environ["STARKSCAN_ACCOUNT"]

headers = {"X-Starkscan-Api-Key": api_key}

def get_json(path: str):
    request = urllib.request.Request(f"{base_url}{path}", headers=headers)
    with urllib.request.urlopen(request, timeout=20) as response:
        return json.load(response), response.headers.get("X-Request-Id")

query = urllib.parse.urlencode({"timestamp": timestamp, "closest": "before"})
block_payload, block_request_id = get_json(f"/v1/{chain}/block-at-timestamp?{query}")
block_number = block_payload["block"]["blockNumber"]

balance_path = (
    f"/v1/{chain}/token/{urllib.parse.quote(token)}/"
    f"balance-of/{urllib.parse.quote(account)}?block_tag={block_number}"
)
balance_payload, balance_request_id = get_json(balance_path)

print(json.dumps({
    "timestamp": timestamp,
    "blockNumber": block_number,
    "blockTimestampIso": block_payload["block"]["timestampIso"],
    "previousBlock": block_payload.get("previousBlock"),
    "nextBlock": block_payload.get("nextBlock"),
    "balance": balance_payload,
    "requestIds": {
        "blockAtTimestamp": block_request_id,
        "balanceOf": balance_request_id,
    },
}, indent=2, sort_keys=True))
```

## Route Status

- `GET /v1/{chain}/token/{token}/balance-of/{address}` is a certified core API route.
- `GET /v1/{chain}/block-at-timestamp` is a stable beta accounting helper.
- If either call returns `401`, fix the API key.
- If either call returns `403`, the key does not have the required route tier.
- If either call returns `429`, honor `Retry-After` and back off.

## Refuse Unsafe Shortcuts

Do not:

- binary-search public explorer pages
- scrape HTML
- infer token identity from a ticker symbol alone
- use timezone-less date strings
- use `latest` for historical accounting close
- invent a standalone historical portfolio endpoint
