Skip to content

Distribute storage rewards #27

Distribute storage rewards

Distribute storage rewards #27

Workflow file for this run

name: Distribute storage rewards
# ---------------------------------------------------------------------------
# Hourly cron + manual dispatch. Triggers ONLY on schedule and workflow_dispatch
# — never on PR events. Secrets are exposed only to runs targeting `main`.
# ---------------------------------------------------------------------------
#
# STATE LIVES ON A SEPARATE BRANCH (`state-data`).
#
# Why: `main` is protected with strict rules (require PR, CodeQL, signed
# commits). The bot can't satisfy any of those — so we write state to an
# UNPROTECTED branch instead. Two checkouts:
# • src-repo/ → main branch (source code, read-only here)
# • state-branch/ → state-data branch (state JSON, bot reads + writes)
#
# This keeps `main` maximally strict for humans while letting the cron operate
# unattended on the state branch. See docs/OPERATIONS.md "State branch setup".
# ---------------------------------------------------------------------------
on:
schedule:
- cron: "0 * * * *"
workflow_dispatch: {}
permissions:
contents: read
concurrency:
group: distribute
cancel-in-progress: false
jobs:
tick:
runs-on: ubuntu-latest
environment: production
permissions:
contents: write # for pushing to state-data branch
issues: write # for the failure-issue creation step
timeout-minutes: 20
steps:
# 1. Source code (read-only from this branch's perspective)
- name: Checkout source (main)
# actions/checkout v6.0.2 — Node 24 runtime
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
ref: main
path: src-repo
token: ${{ secrets.GITHUB_TOKEN }}
# 2. State branch — fetch separately so we can commit + push to it
# independently of main.
- name: Checkout state-data branch
id: state-checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd
with:
ref: state-data
path: state-branch
token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
continue-on-error: true
# 3. If state-data branch doesn't exist yet, fail loudly with a hint.
# The branch must be created once during setup (see OPERATIONS.md).
- name: Verify state-data branch exists
if: steps.state-checkout.outcome != 'success'
run: |
echo "::error::state-data branch is missing. Create it once with the procedure in docs/OPERATIONS.md (search for 'State branch setup')."
exit 1
- name: Setup Node
# actions/setup-node v6.4.0 — Node 24 runtime
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e
with:
node-version: "20"
cache: "npm"
cache-dependency-path: src-repo/package-lock.json
- name: Install
working-directory: src-repo
run: npm ci
- name: Run tick
working-directory: src-repo
env:
OPERATOR_PRIVATE_KEY: ${{ secrets.OPERATOR_PRIVATE_KEY }}
BASE_RPC_URL: ${{ secrets.BASE_RPC_URL }}
SKALE_RPC_URL: ${{ secrets.SKALE_RPC_URL }}
ALLOWED_SUBMITTERS: ${{ vars.ALLOWED_SUBMITTERS }}
DRY_RUN: "false"
LOG_LEVEL: ${{ vars.LOG_LEVEL || 'info' }}
# Point the tick command's STATE_DIR at the state-data checkout.
# The command's loadState/saveState/loadInbox/clearInbox honor this.
STATE_DIR: ${{ github.workspace }}/state-branch/state
run: npm run tick
- name: Commit state changes to state-data branch
if: success()
working-directory: state-branch
run: |
git config user.name "storage-reward-distributor[bot]"
git config user.email "${{ github.repository_owner }}+bot@users.noreply.github.com"
git add state/
if git diff --cached --quiet; then
echo "no state changes"
else
git commit -m "state: tick $(date -u +%Y-%m-%dT%H:%M:%SZ) [skip ci]"
for i in 1 2 3; do
if git push origin state-data; then
exit 0
fi
echo "push failed (attempt $i); pulling and retrying"
git pull --rebase --autostash origin state-data || true
sleep 5
done
echo "::error::Failed to push state changes after 3 attempts"
exit 1
fi
- name: Open failure issue
if: failure()
# actions/github-script v9.0.0 — Node 24 runtime
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
with:
script: |
const { owner, repo } = context.repo;
const title = `Distributor tick failed at ${new Date().toISOString()}`;
const body = [
`Workflow run: ${context.serverUrl}/${owner}/${repo}/actions/runs/${context.runId}`,
``,
`Investigate the log; if needed re-run the workflow manually via Actions -> Distribute storage rewards -> Run workflow.`,
].join('\n');
await github.rest.issues.create({ owner, repo, title, body, labels: ['distributor-failure'] });