Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended'
],
env: {
node: true,
jest: true
}
};
20 changes: 20 additions & 0 deletions .github/workflows/poc-staking-orchestrator-v1.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: ci

on:
push:
branches: [poc/staking-orchestrator-v1]
pull_request:
branches: [poc/staking-orchestrator-v1]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 20
- run: npm install
- run: npm run lint
- run: npm run typecheck
- run: npm test
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Goblin Services — API • Indexer • Timekeeper
[![CI](https://github.com/goblin-sh/goblin-services/actions/workflows/poc-staking-orchestrator-v1.yml/badge.svg?branch=poc/staking-orchestrator-v1)](https://github.com/goblin-sh/goblin-services/actions/workflows/poc-staking-orchestrator-v1.yml)
Off-chain smarts that connect the wallet and bots to on-chain programs.

Day-1: minimal pilot (DEV only) to exercise basic flows.
Expand All @@ -7,8 +8,24 @@ Day-1: minimal pilot (DEV only) to exercise basic flows.
- **Indexer**: reads chain → local state
- **Timekeeper**: schedules payouts/dividend policies

**Bucket:** Off-Chain Smarts (platform-agnostic)
**Bucket:** Off-Chain Smarts (platform-agnostic)
**Status:** PILOT (DEV)

- Overview → /docs/OVERVIEW.md
- Overview → /docs/OVERVIEW.md
- Runbook → /ops/RUNBOOK.md

## Staking Orchestrator POC

This proof-of-concept adds a minimal staking orchestrator.

### Run

```
npm install
npm run build
node dist/orchestrator-svc/index.js
```

### Env Vars

See [.env.example](.env.example). `DRY_RUN=true` will log driver calls without executing them.
7 changes: 7 additions & 0 deletions config/strategy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"mode": "mSOL",
"skimPeriodDays": 2.5,
"preferInstantUnstake": true,
"minProfitLamports": 10000,
"maxUnstakeFeeBps": 50
}
9 changes: 9 additions & 0 deletions docs/CONFIG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Configuration

`config/strategy.json` controls the orchestrator behaviour.

- `mode`: staking mode identifier.
- `skimPeriodDays`: number of days between skims.
- `preferInstantUnstake`: try instant unstake before delayed.
- `minProfitLamports`: minimum profit before payout.
- `maxUnstakeFeeBps`: maximum fee tolerated for instant unstake.
6 changes: 6 additions & 0 deletions docs/POC_LIMITATIONS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# POC Limitations

- Staking driver is fully mocked and does not touch the blockchain.
- Timers use `setTimeout` instead of Cloud Tasks.
- State is kept in memory; restarting the process loses progress.
- No authentication or security is implemented.
8 changes: 8 additions & 0 deletions docs/STATE_MACHINE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# State Machine

```
AWAITING_DEPOSIT -> STAKED -> SKIM_SCHEDULED -> UNSTAKING -> CLAIMABLE -> SETTLED -> PAY_PROFIT -> RESTAKE
```

Each transition only occurs on the events defined in [TOPICS.md](TOPICS.md).
Replaying an event that has already been applied leaves the state unchanged.
16 changes: 16 additions & 0 deletions docs/TOPICS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# POC Pub/Sub Topics

All topics are prefixed with `poc.` for the proof-of-concept.
Each message carries an `idempotencyKey` to allow safe retries.

| Topic | Payload | Idempotency Key |
|-------|---------|-----------------|
| `poc.stake.ordered` | `{ positionId, amount }` | `positionId:cycle:stake` |
| `poc.deposit.confirmed` | `{ positionId, user, amount }` | `positionId:cycle:deposit` |
| `poc.stake.done` | `{ positionId }` | `positionId:cycle:stake` |
| `poc.skim.due` | `{ positionId }` | `positionId:cycle:skim` |
| `poc.unstake.requested` | `{ positionId }` | `positionId:cycle:unstake` |
| `poc.unstake.claimable` | `{ positionId, out }` | `positionId:cycle:claim` |
| `poc.profit.paid` | `{ positionId, profit }` | `positionId:cycle:payout` |
| `poc.restake.done` | `{ positionId }` | `positionId:cycle:restake` |
| `poc.error` | `{ positionId, step, message }` | N/A |
5 changes: 5 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: ['**/tests/**/*.test.ts']
};
Loading