Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
26a3aec
update docker
ljttl3q04t Feb 2, 2026
b167fd1
update port
ljttl3q04t Feb 2, 2026
075a6f5
update port
ljttl3q04t Feb 2, 2026
1c57523
init long-short server backend
ljttl3q04t Feb 3, 2026
2084e77
fix typo
ljttl3q04t Feb 4, 2026
920cdba
build long_buy
ljttl3q04t Feb 4, 2026
e1917ac
add fn address.to_hex()
ljttl3q04t Feb 4, 2026
0c95e5e
final long_buy
ljttl3q04t Feb 4, 2026
1edd46f
wip supply long
ljttl3q04t Feb 4, 2026
f289116
format
ljttl3q04t Feb 5, 2026
ea48608
add schema
ljttl3q04t Feb 5, 2026
a28e3e1
remove console.log
ljttl3q04t Feb 5, 2026
2148da2
liqwid submit
ljttl3q04t Feb 5, 2026
768b9f7
final long supply
ljttl3q04t Feb 5, 2026
1fd27ce
fix build
ljttl3q04t Feb 5, 2026
36b1418
update market_config
ljttl3q04t Feb 5, 2026
ea5bcf8
refactor
ljttl3q04t Feb 5, 2026
ea1e518
long borrow
ljttl3q04t Feb 5, 2026
5d8e8eb
buy more
ljttl3q04t Feb 5, 2026
63afdc4
adding position/close
ljttl3q04t Feb 6, 2026
b1196f7
complete long process
ljttl3q04t Feb 6, 2026
e3e7079
update config
ljttl3q04t Feb 10, 2026
33d0e5b
wip short
ljttl3q04t Feb 11, 2026
86bfbeb
update docker
ljttl3q04t Feb 11, 2026
1b2f3fa
fix
ljttl3q04t Feb 11, 2026
709d8ee
fix
ljttl3q04t Feb 11, 2026
73d53cc
fix
ljttl3q04t Feb 11, 2026
b95b2cc
fix
ljttl3q04t Feb 11, 2026
95f212d
fix + test SHORT
ljttl3q04t Feb 11, 2026
a888b9e
drop built_output_hash
ljttl3q04t Feb 11, 2026
a70a4f2
fix
ljttl3q04t Feb 11, 2026
ed306a9
add docs
ljttl3q04t Feb 12, 2026
40d2d36
update cardanoscan
ljttl3q04t Feb 25, 2026
1c1db13
update agent .md files
ljttl3q04t Feb 27, 2026
e3e80fa
update APY for borrow, supply
ljttl3q04t Feb 27, 2026
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
41 changes: 41 additions & 0 deletions .claude/SKILL.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Long-Short Backend Skills

## Database Operations

```bash
cd apps/long-short-backend

# Run migrations
DATABASE_URL=postgres://postgres:JBNGlQ9wNFLlYWc2mG@localhost:5432/margin pnpm run:migrate

# Create new migration
DATABASE_URL=postgres://postgres:JBNGlQ9wNFLlYWc2mG@localhost:5432/margin pnpm kysely migrate:make <migration_name>

# Run seeds
DATABASE_URL=postgres://postgres:JBNGlQ9wNFLlYWc2mG@localhost:5432/margin pnpm run:seed

# Regenerate database types
DATABASE_URL=postgres://postgres:JBNGlQ9wNFLlYWc2mG@localhost:5432/margin pnpm codegen
```

## Development

```bash
cd apps/long-short-backend

# Start dev server
DATABASE_URL=postgres://postgres:JBNGlQ9wNFLlYWc2mG@localhost:5432/margin pnpm dev

# Build
pnpm build
```

## Docker

```bash
docker compose build long-short-backend # Build image
docker compose up -d # Start services
docker compose logs -f long-short-backend # View logs
docker compose exec long-short-backend pnpm --filter=long-short-backend run:migrate # Migrate in Docker
docker compose exec long-short-backend pnpm --filter=long-short-backend run:seed # Seed in Docker
```
11 changes: 11 additions & 0 deletions .claude/specs/felis-build-tx.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# @minswap/felis-build-tx

DEX transaction builder. Depends on `felis-ledger-core`, `felis-ledger-utils`, `felis-tx-builder`, `felis-dex-v2`.

**Location:** `packages/minswap-build-tx`

## What's here
- `DEXOrderTransaction.createBulkOrdersTx()` — main entry point, batches multiple DEX orders into one tx
- Order option types for each V2 step (SwapExactIn, SwapExactOut, Deposit, Withdraw, etc.)
- `Djed` — stablecoin protocol (mint/rate calculations)
- `MetadataMessage` — transaction label constants (DEX_MARKET_ORDER, DEX_LIMIT_ORDER, etc.)
11 changes: 11 additions & 0 deletions .claude/specs/felis-cip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# @minswap/felis-cip

Cardano Improvement Proposals. Depends on `felis-ledger-core`, `felis-ledger-utils`.

**Location:** `packages/cip`

## What's here
- `Bip32` — HD wallet key derivation, address generation, UTXO filtering
- `Bip39` — mnemonic seed to `BaseAddressWallet` / `EnterpriseAddressWallet`
- `CIP-25` — NFT metadata standard types
- `CIP-68` — reference NFT token standard (isRefNFT, isFT, isNFT, mint helpers)
10 changes: 10 additions & 0 deletions .claude/specs/felis-dex-v1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# @minswap/felis-dex-v1

Legacy DEX V1 protocol types. Depends on `felis-ledger-core`, `felis-ledger-utils`.

**Location:** `packages/minswap-dex-v1`

## What's here
- `Order` — V1 order parsing from UTXOs (SWAP_EXACT_IN, DEPOSIT, WITHDRAW, etc.)
- Compiled Plutus V1 scripts for mainnet/testnet
- Primarily consumed by the syncer for historical order parsing
13 changes: 13 additions & 0 deletions .claude/specs/felis-dex-v2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# @minswap/felis-dex-v2

DEX V2 protocol types and calculations. Depends on `felis-ledger-core`, `felis-ledger-utils`.

**Location:** `packages/minswap-dex-v2`

## What's here
- `OrderV2` — 11 step types (SWAP_EXACT_IN, STOP_LOSS, OCO, DEPOSIT, WITHDRAW, PARTIAL_SWAP, MULTI_ROUTING, etc.)
- `PoolV2` — liquidity pool state, reserves, fees (denominator=10000)
- `DexV2Calculation` — swap/deposit/withdraw math, price impact, multi-routing
- `OrderV2Datum` — Plutus serialization (fromPlutusJson/toPlutusJson, fromDataHex/toDataHex)
- Config helpers: `getDexV2Configs()`, `getDexV2PoolAddresses()`, `buildDexV2OrderAddress()`
- `BATCHER_FEE_DEX_V2` — fee schedule per step type
18 changes: 18 additions & 0 deletions .claude/specs/felis-ledger-core.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# @minswap/felis-ledger-core

Cardano blockchain primitives. Depends on `felis-ledger-utils`.

**Location:** `packages/ledger-core`

## What's here
- `Address` — bech32/hex conversion, stake address extraction, PlutusJson serialization
- `Asset` — policy ID + token name, `ADA` constant for lovelace
- `Value` — multi-asset container (get/set/add/subtract/canCover)
- `TxIn` / `TxOut` / `Utxo` — transaction inputs/outputs
- `Transaction` / `TxBody` — full transaction types
- `PrivateKey` / `PublicKey` / `PublicKeyHash` — crypto keys
- `Bytes` — hex/string/base64 wrapper
- `PlutusData` — Plutus serialization (Constr, List, Map, Int, Bytes)
- `NetworkEnvironment` — MAINNET (764824073), TESTNET_PREVIEW (2), TESTNET_PREPROD (1)
- `XJSON` — type-preserving JSON (bigint, Date, Bytes, Asset, Address, Value)
- `getTimeFromSlotMagic` / `getSlotFromTimeMagic` — slot/time conversion
15 changes: 15 additions & 0 deletions .claude/specs/felis-ledger-utils.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# @minswap/felis-ledger-utils

Foundation utility library. All other packages depend on this.

**Location:** `packages/ledger-utils`

## What's here
- `Result<T, E>` / `Maybe<T>` — error handling and optionals
- `Duration` — time arithmetic
- `blake2b256`, `blake2b224`, `sha3` — crypto hashes
- `encodeBech32` / `decodeBech32`
- `RustModule` — WASM loader (must call `await RustModule.load()` before any WASM ops)
- `CborHex<T>` — branded type for CBOR hex strings
- `getErrorMessage(error)` — safe stringify that handles BigInt
- `safeFreeRustObjects()` — prevents double-free on WASM objects
20 changes: 20 additions & 0 deletions .claude/specs/felis-lending-market.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# @minswap/felis-lending-market

Liqwid Finance lending protocol integration. Depends on `felis-ledger-core`, `felis-ledger-utils`.

**Location:** `packages/minswap-lending-market`

## What's here
- `LiqwidProviderV2` — namespace wrapping Liqwid V2 GraphQL API

### Namespaces
- `Transactions` — supply, withdraw, borrow, modifyBorrow, repayLoan, submit (returns CBOR hex)
- `Calculations` — loan health factor, supply/withdraw caps, net APY
- `Data` — query markets, loans, user loans, yield earned
- `signTx()` / `getTxHash()` — sign and hash Liqwid transactions

## Gotchas
- Liqwid V2 API uses `number` for amounts (not `bigint` like the rest of the codebase)
- `MarketId` is a string like "Ada", "MIN", "DJED" (not the market_id from our DB)
- `loanUtxoId` format is `"{txHash}-{outputIndex}"` (dash separator, not hash)
- API endpoints differ per network: `v2.api.liqwid.finance` (mainnet), `v2.api.preprod.liqwid.dev` (preprod), `v2.api.preview.liqwid.dev` (preview)
12 changes: 12 additions & 0 deletions .claude/specs/felis-tx-builder.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# @minswap/felis-tx-builder

High-level Cardano transaction composition. Depends on `felis-ledger-core`, `felis-ledger-utils`, `felis-cip`.

**Location:** `packages/tx-builder`

## What's here
- `TxBuilder` — fluent API: collectFrom, payTo, mintAssets, validFrom/To, attachValidator, complete()
- `TxComplete` — signing (signWithPrivateKey, partialSign, assemble)
- `CoinSelectionAlgorithm` — MINSWAP (smart + change splitting), SPEND_ALL, SPEND_ALL_V2
- `UtxoSelection` — UTXO selection and collateral selection
- `EmulatorProvider` — off-chain provider for testing
30 changes: 30 additions & 0 deletions .claude/specs/long-short-backend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# long-short-backend

Leveraged long/short trading API. Integrates Minswap DEX with Liqwid lending.

**Location:** `apps/long-short-backend`

## Key files
```
src/api/state-machine.ts -- Build/waiting functions per order type
src/services/position-service.ts -- Core business logic (create, buildTx, close)
src/api/routes/position.ts -- API route handlers
src/api/schemas.ts -- TypeBox request/response schemas
src/api/helper.ts -- CIP-8 authentication
src/repository/ -- Database access layer
src/provider/cardanoscan.ts -- On-chain transaction search
src/config/market.ts -- Market config cache
src/cmd/run-api.ts -- Entry point
```

## Order state machine (non-obvious flow)
**Open LONG:** LONG_BUY → LONG_SUPPLY → LONG_BORROW → LONG_BUY_MORE
**Close LONG:** LONG_SELL → LONG_REPAY → LONG_WITHDRAW → LONG_SELL_ALL

Each order goes through: build tx → user signs → confirm on chain → wait for output spend → next order.

## Gotchas
- LONG_SUPPLY uses LiqwidProvider V1, all other Liqwid ops use V2
- `amount_borrow = amount_in * (leverage - 1) + 4_000_000n` (fee buffer)
- Check waiting orders BEFORE finding unhandled orders in buildTx flow
- `built_valid_to` determines when to rebuild an expired transaction
122 changes: 26 additions & 96 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,117 +1,47 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
The role of this file is to describe common mistake and confusion points that agents might encounter as they work in this project. If you ever encounter something in the project that surprises you, please alert the developer working with you and indicate that this is the case in the CLAUDE.md file to help prevent future agents from having the same issue.

> **Principle:** If the info is in the codebase, it probably doesn't need to be in this file. Keep this lean.

## Project Overview

Minswap Felis is a monorepo implementing Cardano DEX infrastructure with leveraged long/short trading positions integrated with Liqwid lending protocol. Built with TypeScript, Turborepo, and pnpm workspaces.
Minswap Felis - Cardano DEX monorepo with leveraged long/short trading via Liqwid lending. TypeScript, Turborepo, pnpm workspaces.

## Commands

```bash
# Build & Development
pnpm build # Build all packages (respects turbo dependency graph)
pnpm dev # Watch mode across all packages
pnpm check-types # Run tsc --noEmit on all packages

# Testing
pnpm test # Run all tests via vitest
pnpm test:watch # Watch mode for tests
pnpm --filter=@repo/ledger-core test # Run tests for single package

# Linting & Formatting
pnpm format-and-lint # Check with biome (no changes)
pnpm build # Build all packages
pnpm check-types # Type-check all packages
pnpm test # Run all tests (vitest)
pnpm --filter=@repo/ledger-core test # Single package tests
pnpm format-and-lint:fix # Auto-fix with biome
pnpm exec turbo run check-circular-imports # Detect circular imports

# Web App
pnpm --filter=web dev # Next.js dev server (port 3001)
```

## Architecture

### Package Dependency Graph
```
ledger-utils (foundation: Result type, crypto, hex, bech32)
ledger-core (Address, Tx, UTXO, Scripts, Protocol)
├→ cip (BIP32/39, CIP-25, CIP-68)
│ ↓
└───┴→ tx-builder (high-level transaction composition)
minswap-build-tx (DEX transaction builder)
minswap-lending-market (Liqwid SDK, Nitro Wallet)
web (Next.js app)

minswap-dex-v2 (DEX V2 protocol types) → depends on ledger-core, ledger-utils
# Long-short backend
pnpm --filter=long-short-backend run migrate:latest # Apply DB migrations
pnpm --filter=long-short-backend run migrate:down # Rollback last migration
```

### Key Packages
- **ledger-utils**: `Result<T, E>` error handling, crypto utilities, `CborHex<T>` branded types
- **ledger-core**: Cardano primitives (Address, Tx, UTXO), `NetworkEnvironment` discrimination
- **tx-builder**: Transaction composition with UTXO selection
- **minswap-dex-v2**: DEX V2 protocol types and order handling
- **minswap-lending-market**: Liqwid provider SDK, Nitro Wallet (password-less signing)
## Package Dependency Graph

## Code Patterns

### Error Handling
Use `Result<T, E>` from ledger-utils:
```typescript
Result.ok(value), Result.err(error), Result.isOk()
```
Use `getErrorMessage(error)` for safe error stringification (handles BigInt).

### Class Design
- Protected constructors with static factory methods
- Immutable `readonly` properties
- Bidirectional serialization: `toHex()`, `fromHex()`, `toPlutusJson()`, `fromPlutusJson()`

### Type Conventions
- `bigint` for all amounts, slots, values (never numbers)
- `CborHex<T>` branded types for CBOR serialization
- `NetworkEnvironment` required for address/protocol operations (mainnet vs testnet)
- Type-only imports: `import type { Type } from "..."`
- Workspace imports: Always use `@repo/*` scope

### WASM Initialization
```typescript
import { RustModule } from "@repo/ledger-utils";
beforeAll(async () => {
await RustModule.load();
});
ledger-utils → ledger-core → cip → tx-builder → minswap-build-tx → minswap-lending-market → web
minswap-dex-v2 → ledger-core, ledger-utils
```

## Key Dependencies

- **@emurgo/cardano-serialization-lib (CSL)**: Cardano primitives via Rust/WASM
- **@stricahq/cbors**: CBOR encoding (Cardano serialization format)
- **json-bigint**: Preserve BigInt precision in JSON (don't use native JSON for amounts)
- **remeda**: Functional utility library (like lodash/fp)
- **@minswap/tiny-invariant**: Development-only assertions
- **dpdm**: Circular import detection (run via `check-circular-imports` script)

## Testing

- Framework: Vitest with `vitest.config.mts` per package
- Test location: `{package}/test/**/*.{test,spec}.ts`
- Property-based testing: `fast-check` available
- Environment: Node (Vitest aliases browser WASM to Node variants)

## Code Style (Biome)
## Conventions

- Line width: 120
- Quotes: Double
- Semicolons: Always
- Trailing commas: All
- Arrow parens: Always `(x) => x`
- `bigint` for all Cardano amounts, slots, IDs (never `number`)
- `Result<T, E>` from ledger-utils for error handling
- `import type` for type-only imports
- `@repo/*` scope for workspace imports
- `await RustModule.load()` required before crypto/WASM operations in tests
- `json-bigint` for JSON with BigInt values (never native `JSON.stringify`)

## Tech Stack
## Gotchas

- TypeScript 5.8, Node.js >= 22
- Turborepo + pnpm 9.0.0
- Vitest, Biome
- Next.js, React 19, Jotai, Ant Design
- Cardanoscan API: use `address.toHex()` (not bech32), header is `"apiKey"`
- DB types: update `src/database/db.d.ts` after migrations, use `Generated<T>` for defaults
- DB IDs: always `BigInt(row.id)` when mapping rows
- API fields: snake_case externally, camelCase internally
50 changes: 50 additions & 0 deletions Dockerfile.backend
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Stage 1: Base
FROM node:22-slim AS base
WORKDIR /usr/src/app

# Install pnpm and curl (for healthcheck)
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*
RUN corepack enable && corepack prepare pnpm@9.0.0 --activate

# Set pnpm global bin directory
ENV PNPM_HOME="/root/.local/share/pnpm"
ENV PATH="${PNPM_HOME}:${PATH}"

# Stage 2: Prune / Extract package.json files
# This stage filters the repo to only the files needed for installation
FROM base AS cleaner
RUN pnpm add -g turbo
COPY . .
# Generate a pruned version of the repo
ARG APP_NAME=long-short-backend
RUN turbo prune ${APP_NAME} --docker

# Stage 3: Install dependencies
FROM base AS installer
# Copy only the lockfile and the pruned package.json files from the cleaner stage
COPY --from=cleaner /usr/src/app/out/json/ .
COPY --from=cleaner /usr/src/app/out/pnpm-lock.yaml ./pnpm-lock.yaml

# Install dependencies (heavily cached)
RUN pnpm install --frozen-lockfile

# Stage 4: Build / Source
FROM base AS builder
COPY --from=installer /usr/src/app ./
# Copy the actual source code (this is what changes often)
COPY --from=cleaner /usr/src/app/out/full/ .
COPY turbo.json turbo.json

# Build the app
ARG APP_NAME=long-short-backend
RUN pnpm turbo build --filter=${APP_NAME}

# Stage 5: Production release
FROM base AS release
COPY --from=builder /usr/src/app ./

# Expose API port
EXPOSE 9999

# Command is set in docker-compose.yml
CMD ["node", "--version"]
2 changes: 1 addition & 1 deletion Dockerfile → Dockerfile.interface
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ COPY --from=builder /app/apps/web ./apps/web
RUN pnpm install --prod --frozen-lockfile

# Expose port
EXPOSE 3000
EXPOSE 3002

# Set environment to production
ENV NODE_ENV=production
Expand Down
Loading
Loading