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
20 changes: 13 additions & 7 deletions .e2e-fixed-positions.local.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
{
"version": 1,
"accountId": "0x7d5f459101cc8076215707ef49c09789514f31a4407c4836b874c8700e6ecaf6",
"accountId": "0xab4795318525c9a6113fcba320a785345f3a8b66c523ec1a517ac040d2cd945b",
"positions": {
"BTC": 33,
"DEEP": 8,
"ETH": 11,
"SOL": 12,
"SUI": 7,
"WAL": 5
"AAPLX": 2,
"BTC": 6,
"ETH": 20,
"GOOGLX": 2,
"METAX": 2,
"NVDAX": 2,
"QQQX": 2,
"SOL": 2,
"SPYX": 2,
"SUI": 13,
"TSLAX": 2,
"WAL": 2
},
"disclaimer": "Auto-generated from public on-chain position ids. Safe to commit. Re-run preflight/bootstrap after closes/liquidations."
}
2 changes: 0 additions & 2 deletions .github/workflows/check-secrets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ name: Check Secrets

on:
pull_request:
branches:
- main

jobs:
check-secrets:
Expand Down
4 changes: 1 addition & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
# Single PR pipeline for `main`: replaces legacy `lint.yml` + `unit-test.yml` (no duplicate runs).
# PR pipeline for any base branch: replaces legacy `lint.yml` + `unit-test.yml` (no duplicate runs).
# Core: pnpm lint, typecheck, build, test:ci (unit + coverage + JUnit, then simulate / e2e + JUnit).
# Extra: Trivy, Semgrep, gitleaks, pnpm audit. Integration tests stay local (`pnpm test:integration`).

name: CI

on:
pull_request:
branches:
- main

permissions:
contents: read
Expand Down
3 changes: 1 addition & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ Each `PriceAggregator<T>` has `PythRule` set via `set_rule_weight<T, PythRule>`

SDK flow in `tx-builders.ts`: `buildOracleFeed(client, tx, tokenType, aggregatorId, priceInfoObjectId)` creates a collector, feeds Pyth (optionally preceded by Hermes update), then aggregates.

> **Legacy Supra**: dropped in v2. The SDK has no `utils/supra.ts` and no `supraRule*` / `supraOracleHolder` config fields. `scripts/clear-supra-weights.sh` removes the stale `SupraRule` weight from any v1-era collateral aggregators.
> **Legacy Supra**: dropped in v2. The SDK has no `utils/supra.ts` and no `supraRule*` / `supraOracleHolder` config fields. If an ancient deployment still had `SupraRule` weight on collateral aggregators, that had to be zeroed for Pyth-only aggregation (no helper script in-repo anymore).

## Contract Packages

Expand Down Expand Up @@ -276,7 +276,6 @@ All setup scripts are admin-gated and assume `sui client active-address` owns th
| ------ | ------- |
| `setup-markets.sh` | One PTB per market_symbol: `aggregator::new` + `set_rule_weight<T, PythRule>` + share + `pyth_rule::set_identifier` + `trading::create_market` + share. Re-runnable per row. |
| `setup-wlp-tokens.sh` | Registers USDC + USDSUI as WLP deposit tokens via `lp_pool::add_token` (stablecoin defaults). |
| `clear-supra-weights.sh` | Drops the legacy `SupraRule` weight from the USDC + USDSUI `PriceAggregator`s (Pyth-only in v2). |
| `create-markets.ts` | Admin TS wrapper around `trading::create_market` for all 13 markets (superseded by `setup-markets.sh` for greenfield setup). |
| `market-params.ts` | v2 schema: `minCollValue`, `u128` OI, no `lot_size` / `size_decimal`. |
| `setup-pyth-tolerance.sh` | Sets `pyth_rule::set_tolerance_sec<T>` per token type (crypto=310s, xStock=310s, stables=large). |
Expand Down
8 changes: 4 additions & 4 deletions MIGRATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -375,12 +375,12 @@ Off-chain event consumers MUST update parsers accordingly.
| Purpose | v1 | v2 |
|---|---|---|
| Create all markets | `create-markets.ts` (plus manual Pyth setup) | `setup-markets.sh` (one PTB per market: aggregator + Pyth weight + share + Pyth identifier + create_market + share) |
| Wire Supra + Pyth per-token | `setup-oracle.ts`, `setup-pyth-identifiers.sh`, `setup-supra-oracle.sh` | Folded into `setup-markets.sh` (Pyth-only) |
| Clear legacy Supra weights | — | `clear-supra-weights.sh` |
| Wire Pyth per-token | `setup-oracle.ts`, `setup-pyth-identifiers.sh`, legacy `setup-supra-oracle.sh` | `setup-markets.sh` + `setup-pyth-identifiers.sh` (Pyth-only); Supra setup script removed |
| Clear legacy Supra weights | — | (one-time; zero `SupraRule` weight via admin if any v1 collateral aggregators still had it — no repo script) |
| Register WLP deposit tokens | — | `setup-wlp-tokens.sh` (USDC + USDSUI via `lp_pool::add_token`) |
| Refresh Pyth prices (ops) | (manual) | `update-pyth-prices.ts` |

`setup-oracle.ts`, `setup-pyth-identifiers.sh`, `setup-supra-oracle.sh` were deleted.
`setup-oracle.ts` and `setup-supra-oracle.sh` were removed; `setup-pyth-identifiers.sh` remains for identifier updates.

---

Expand Down Expand Up @@ -431,5 +431,5 @@ Run `pnpm codegen` after pulling contract updates. Generated `src/generated/` is

### On-chain operational steps

- [ ] If you had `supra_rule::SupraRule` weight on any collateral aggregator, run `./scripts/clear-supra-weights.sh` (otherwise `aggregator::aggregate` aborts with `err_missing_price_source (201)`).
- [ ] If you still had `supra_rule::SupraRule` weight on any collateral aggregator from v1, zero it with an admin PTB (`aggregator::set_rule_weight`) so only `PythRule` contributes — otherwise `aggregator::aggregate` can abort with `err_missing_price_source (201)`.
- [ ] Before first WLP mint, run `./scripts/setup-wlp-tokens.sh` to register USDC + USDSUI (otherwise `mint_wlp` aborts with `err_token_not_supported (401)`).
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@
"test:coverage": "vitest run --project unit --project e2e --coverage",
"test:ci:unit": "vitest run --project unit --coverage --reporter=verbose --reporter=junit --outputFile=test-results-unit.xml",
"test:ci:simulate": "vitest run --project e2e --reporter=verbose --reporter=junit --outputFile=test-results-simulate.xml",
"test:ci:e2e": "tsx scripts/e2e-preflight.ts --allow-oracle-transient --allow-missing-positions --allow-missing-tto-split && pnpm test:ci:simulate",
"test:ci:e2e:coverage": "tsx scripts/e2e-preflight.ts --allow-oracle-transient --allow-missing-positions --allow-missing-tto-split && pnpm test:e2e -- --coverage",
"test:ci:e2e": "tsx scripts/e2e-preflight.ts --allow-oracle-transient --allow-missing-positions --allow-missing-tto-split --allow-missing-e2e-delegate && pnpm test:ci:simulate",
"test:ci:e2e:coverage": "tsx scripts/e2e-preflight.ts --allow-oracle-transient --allow-missing-positions --allow-missing-tto-split --allow-missing-e2e-delegate && pnpm test:e2e -- --coverage",
"test:ci:full": "pnpm test:ci:unit && pnpm test:ci:e2e",
"test:ci": "pnpm test:ci:full",
"diagnose:positions": "tsx scripts/diagnose-integration-positions.ts",
Expand All @@ -45,6 +45,7 @@
"rewarder:smoke": "tsx scripts/reward-distributor-smoke.ts",
"close-all-btc": "tsx scripts/close-all-my-btc-positions.ts",
"e2e:bootstrap-positions": "tsx scripts/bootstrap-e2e-lifecycle-positions.ts",
"e2e:setup-delegate": "tsx scripts/setup-e2e-delegate.ts",
"lint": "pnpm lint:eslint && pnpm lint:prettier",
"lint:eslint": "eslint \"src/**/*.ts\" \"test/**/*.ts\" \"scripts/**/*.ts\"",
"lint:prettier": "prettier --check \"src/**/*.ts\" \"test/**/*.ts\" \"scripts/**/*.ts\"",
Expand Down
107 changes: 66 additions & 41 deletions scripts/README.md
Original file line number Diff line number Diff line change
@@ -1,57 +1,82 @@
# Admin Setup Scripts
# Scripts

Scripts for deploying and configuring the WaterX Perp protocol. All require `AdminCap` ownership.
Operational and admin helpers for WaterX perp on Sui testnet. **v2 is Pyth-only** on the SDK path.

## Prerequisites

```bash
export ADMIN_SECRET_KEY=<base64-encoded-ed25519-secret-key>
```
- **Admin / listing**: `sui client active-address` must own `AdminCap` and/or `ListingCap` where noted.
- **TypeScript**: run via `pnpm exec tsx scripts/<name>.ts` or the **npm script** aliases in root `package.json`.
- **Env**: many TS scripts use `ADMIN_SECRET_KEY` (base64 ed25519 secret) or integration vars — run without secrets to see dry-run behavior where supported.

Run without the env var to see a dry-run preview.
## npm script aliases (root `package.json`)

## Deployment Order
| pnpm script | Script file |
| ----------- | ----------- |
| `codegen` | runs `fix-generated-imports.ts` after codegen |
| `e2e:preflight` | `e2e-preflight.ts` |
| `e2e:prepare` | `e2e-prepare.ts` |
| `e2e:bootstrap-positions` | `bootstrap-e2e-lifecycle-positions.ts` |
| `e2e:setup-delegate` | `setup-e2e-delegate.ts` — pinned `addDelegate` / `updateDelegatePermissions` (see `trading-config` `e2eDelegate`) |
| `diagnose:positions` | `diagnose-integration-positions.ts` |
| `oracle:aggregates` | `print-oracle-aggregates.ts` |
| `query-output` | `query-output.ts` |
| `create-testnet-account` | `create-testnet-user-account.ts` |
| `rewarder:smoke` | `reward-distributor-smoke.ts` |
| `close-all-btc` | `close-all-my-btc-positions.ts` |

After publishing the Move packages, run these scripts in order:
CI also chains `e2e-preflight.ts` before simulate tests (`test:ci:e2e`).

```bash
# 1. Add USDC (and other tokens) to the WLP pool
npx tsx scripts/add-token-pool.ts
## By category

# 2. Create all trading markets (BTC, ETH, SOL, SUI, DEEP, WAL)
npx tsx scripts/create-markets.ts
# → Copy the created Market object IDs into TESTNET_MARKETS in constants.ts
### Admin / on-chain setup (bash + TS)

# 3. Set up Pyth + Supra oracle feeds (identifiers, pair IDs, aggregator weights)
ADMIN_SECRET_KEY=<base64> npx tsx scripts/setup-oracle.ts
# Or Supra-only via CLI (no secret key needed):
./scripts/setup-supra-oracle.sh
| File | Purpose |
| ---- | ------- |
| `setup-markets.sh` | Per-market PTB: aggregator + Pyth rule weight + `pyth_rule::set_identifier` + `create_market`. |
| `setup-wlp-tokens.sh` | `lp_pool::add_token` for USDC / USDSUI. |
| `setup-pyth-identifiers.sh` | `pyth_rule::set_identifier` for base + collateral types (`market_symbol::*_USD`). |
| `setup-pyth-tolerance.sh` | `pyth_rule::set_tolerance_sec` per token. |
| `set-min-coll-value.sh` | `update_market_config` min collateral value across markets. |
| `create-markets.ts` | TS helper to create markets (params from `market-params.ts`). |
| `market-params.ts` | Shared market creation params (imported by tests + `create-markets.ts`). |
| `setup-keepers.ts` | Register keepers on `GlobalConfig`. |

# 4. Add keeper addresses for order matching / liquidation / funding
npx tsx scripts/setup-keepers.ts
### E2E / integration ergonomics

# 5. (Optional) Add USDSUI token pool + rebalance weights
./scripts/add-usdsui-pool.sh
```
| File | Purpose |
| ---- | ------- |
| `e2e-preflight.ts` | Wallet / account / **required on-chain position per lifecycle base** + cooldown + oracle simulate, before `test:e2e`. |
| `e2e-prepare.ts` | TTO split (pre + post open), persistent perp slots, cooldown, collateral / WLP top-up; optional `--ensure-delegate` (needs integration key). A single run leaves the account in a state that satisfies `e2e:preflight`. |
| `bootstrap-e2e-lifecycle-positions.ts` | Open small persistent perp slots per `test/fixtures/trading/trading-config.json`. |
| `diagnose-integration-positions.ts` | Inspect reference account positions / refresh local fixed-position hints. |

## Scripts
### Oracle ops

| Script | Description |
| ----------------------- | --------------------------------------------------------------------------------------- |
| `create-markets.ts` | Create `Market<BASE_TOKEN, LP_TOKEN>` for all assets |
| `add-token-pool.ts` | Add collateral token (USDC) to WLP pool |
| `setup-oracle.ts` | Configure Pyth identifiers + Supra pair IDs + SupraRule aggregator weights (all-in-one) |
| `setup-supra-oracle.sh` | Supra-only setup via `sui client call` (no secret key, uses active CLI address) |
| `setup-keepers.ts` | Authorize keeper addresses in GlobalConfig |
| `market-params.ts` | Market creation parameters (imported by create-markets) |
| `add-usdsui-pool.sh` | Add USDSUI to WLP pool + rebalance USDC weight to 50/50 |
| File | Purpose |
| ---- | ------- |
| `print-oracle-aggregates.ts` | Hermes + simulate oracle PTB; `--format pretty` or `raw`. |
| `update-pyth-prices.ts` | Push Hermes updates to on-chain Pyth price objects. |

## Adding a New Market
### WLP / rewarder / accounts

1. Add the asset to `BaseAsset` type in `src/constants.ts`
2. Add creation params to `scripts/market-params.ts`
3. Add base token type to `BASE_TYPES` in `scripts/create-markets.ts`
4. Add token feed to `TOKEN_FEEDS` in `scripts/setup-oracle.ts`
5. Run `create-markets.ts`, `setup-oracle.ts`, and `setup-supra-oracle.sh`
6. Add the new market entry to `TESTNET_MARKETS` in `src/constants.ts`
7. Add Supra pair ID to `SUPRA_PAIR_IDS` in `src/constants.ts` (if available)
| File | Purpose |
| ---- | ------- |
| `test-cancel-redeem-wlp.ts` | `cancel_redeem` scenarios (simulate; optional `--execute`). |
| `reward-distributor-smoke.ts` | Stake / claim / redeem smoke on reward distributor. |
| `create-testnet-user-account.ts` | Create `UserAccount` for integration testing. |
| `close-all-my-btc-positions.ts` | Close all BTC positions for configured account (`--dry-run` supported). |

### Dev utilities

| File | Purpose |
| ---- | ------- |
| `fix-generated-imports.ts` | Post-`sui-ts-codegen` import normalization (used by `pnpm codegen`). |
| `query-output.ts` | Dump SDK query results to `query-output/*.json`. |

## Adding a new market (high level)

1. Extend `BaseAsset` / `TESTNET_MARKETS` in `src/constants.ts`.
2. Add params in `market-params.ts` and run `setup-markets.sh` (or `create-markets.ts`) plus Pyth identifier / tolerance scripts.
3. Update **`test/fixtures/trading/trading-config.json`** for e2e tables (`lifecycleMarkets`, `enabledE2eBases`, `persistentPerp` as needed).

See root [CLAUDE.md](../CLAUDE.md) for protocol details.
43 changes: 39 additions & 4 deletions scripts/bootstrap-e2e-lifecycle-positions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ import {
} from "../test/helpers/e2e-persistent-perp-slots.ts";
import {
activeE2ePersistentPerpBases,
e2ePersistentMinAccountUsdcRough,
e2ePersistentMinAccountCollateralRough,
} from "../test/helpers/e2e-persistent-state.ts";
import { INTEGRATION_REFERENCE_WALLET_ADDRESS } from "../test/helpers/integration-reference-wallet.ts";
import {
buildDepositCollateralFromWalletTx,
buildDepositUsdcFromWalletTx,
ensureUserAccountForIntegration,
} from "../test/integration/helpers/account-bootstrap.ts";
Expand Down Expand Up @@ -60,8 +61,8 @@ function parseArgs(argv: string[]) {
};
}

function bootstrapMinAccountUsdc(): bigint {
return e2ePersistentMinAccountUsdcRough();
function bootstrapMinAccountRough() {
return e2ePersistentMinAccountCollateralRough();
}

async function main() {
Expand All @@ -83,7 +84,10 @@ async function main() {

const { accountId } = await ensureUserAccountForIntegration(client, trader, execTx);
const usdcType = client.config.collaterals.USDC.type;
const minUsdc = bootstrapMinAccountUsdc();
const usdsuiType = client.config.collaterals.USDSUI.type;
const rough = bootstrapMinAccountRough();
const minUsdc = rough.minUsdc;
const minUsdsui = rough.minUsdsui;
let balance = await getAccountBalance(client, accountId, usdcType);

if (balance < minUsdc) {
Expand All @@ -107,6 +111,37 @@ async function main() {
throw new Error(`Account USDC still below ${minUsdc} after deposit attempt (have ${balance}).`);
}

if (minUsdsui > 0n) {
let balSui = await getAccountBalance(client, accountId, usdsuiType);
if (balSui < minUsdsui) {
const need = minUsdsui - balSui;
if (dryRun) {
console.log(
`[dry-run] Would deposit ${need} USDSUI (raw); account has ${balSui}, need ${minUsdsui}.`,
);
} else {
console.log(
`Depositing ${need} USDSUI (raw) from wallet into account ${accountId.slice(0, 12)}…`,
);
const depTx = await buildDepositCollateralFromWalletTx(
client,
owner,
accountId,
need,
"USDSUI",
);
const depResult = await execTx(depTx, trader, { gasBudget: 50_000_000 });
assertSuccess(depResult);
balSui = await getAccountBalance(client, accountId, usdsuiType);
}
}
if (!dryRun && balSui < minUsdsui) {
throw new Error(
`Account USDSUI still below ${minUsdsui} after deposit attempt (have ${balSui}).`,
);
}
}

const bases = activeE2ePersistentPerpBases();
console.log(
`Account ${accountId.slice(0, 14)}… | USDC balance ${balance} | markets: ${bases.join(", ")}`,
Expand Down
52 changes: 0 additions & 52 deletions scripts/clear-supra-weights.sh

This file was deleted.

Loading
Loading