Skip to content
Open
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
139 changes: 139 additions & 0 deletions .claude/SKILL.MD
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
# Long-Short Backend Skills

## Database Operations

### Run Migrations
```bash
cd apps/long-short-backend
DATABASE_URL=postgres://postgres:JBNGlQ9wNFLlYWc2mG@localhost:5432/margin pnpm run:migrate
```

### Create New Migration
```bash
cd apps/long-short-backend
DATABASE_URL=postgres://postgres:JBNGlQ9wNFLlYWc2mG@localhost:5432/margin pnpm kysely migrate:make <migration_name>
```

### Run Seeds
```bash
cd apps/long-short-backend
DATABASE_URL=postgres://postgres:JBNGlQ9wNFLlYWc2mG@localhost:5432/margin pnpm run:seed
```

### Regenerate Database Types
```bash
cd apps/long-short-backend
DATABASE_URL=postgres://postgres:JBNGlQ9wNFLlYWc2mG@localhost:5432/margin pnpm codegen
```

## Development

### Start Dev Server
```bash
cd apps/long-short-backend
DATABASE_URL=postgres://postgres:JBNGlQ9wNFLlYWc2mG@localhost:5432/margin pnpm dev
```

### Build
```bash
cd apps/long-short-backend
pnpm build
```

## Docker

### Build Docker Image
```bash
docker compose build long-short-backend
```

### Start Services
```bash
docker compose up -d
```

### View Logs
```bash
docker compose logs -f long-short-backend
```

### Run Migration in Docker
```bash
docker compose exec long-short-backend pnpm --filter=long-short-backend run:migrate
```

### Run Seed in Docker
```bash
docker compose exec long-short-backend pnpm --filter=long-short-backend run:seed
```

## API Endpoints

- `GET /health` - Health check
- `GET /metadata` - Get market configurations
- `POST /position/create` - Create a new position

### Get Metadata Response
```json
{
"success": true,
"data": {
"markets": [
{
"market_id": "ADA-MIN",
"asset_a": "lovelace",
"asset_b": "29d222ce...",
"amm_lp_asset": "...",
"asset_a_q_token_ticker": "qADA",
"asset_a_q_token_raw": "...",
"asset_b_q_token_ticker": "qMIN",
"asset_b_q_token_raw": "...",
"collateral_market_id": "ADA",
"leverage": 2,
"min_collateral": "100000000"
}
]
}
}
```

### Create Position Request
```json
{
"data": {
"market": "ADA-MIN",
"side": "LONG" | "SHORT",
"amount": "100000000"
},
"user_address": "addr1...",
"witness": {
"key": "<COSEKey hex>",
"signature": "<COSESign1 hex>"
}
}
```

**Note:** The `witness` is the CIP-8 signed data of `JSON.stringify(data)`. The signature must be created by signing the hex-encoded JSON string of the `data` object. The `user_address` must match the address that signed the data.

## Database Tables

- `position` - User positions
- `order` - Trading orders
- `market_config` - Market configurations (loaded on startup)

## Market Config Fields

| Field | Type | Description |
|-------|------|-------------|
| market_id | string | Primary key (e.g., "ADA-MIN") |
| asset_a | string | First asset |
| asset_b | string | Second asset |
| amm_lp_asset | string | Minswap LP token |
| asset_a_q_token_ticker | string | Liqwid qToken ticker for asset A |
| asset_a_q_token_raw | string | Liqwid qToken raw asset for asset A |
| asset_b_q_token_ticker | string | Liqwid qToken ticker for asset B |
| asset_b_q_token_raw | string | Liqwid qToken raw asset for asset B |
| collateral_market_id | string | Liqwid market ID |
| leverage | number | Leverage multiplier |
| min_collateral | bigint | Minimum collateral in lovelace |
| enable | boolean | Market enabled |
100 changes: 100 additions & 0 deletions .claude/specs/felis-build-tx.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# @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`

## DEXOrderTransaction — DEX Order Building

### Main Entry Point
```typescript
DEXOrderTransaction.createBulkOrdersTx(options: BulkOrdersOption): TxBuilder

type BulkOrdersOption = {
networkEnv: NetworkEnvironment
sender: Address
orderOptions: MultiDEXOrderOptions[] // Array of orders to batch
outerTxb?: TxBuilder // Reuse existing builder
receiver?: Address // Optional alternate receiver
}
```

### Order Option Types
```typescript
type V2SwapExactInOptions = {
lpAsset: Asset; version: DexVersion.DEX_V2;
type: OrderV2StepType.SWAP_EXACT_IN;
assetIn: Asset; amountIn: bigint;
minimumAmountOut: bigint; direction: OrderV2Direction;
killOnFailed: boolean; isLimitOrder: boolean;
}

// Also: V2SwapExactOutOptions, V2DepositOptions, V2WithdrawOptions,
// V2StopOptions, V2OCOOptions, V2ZapOutOptions, V2PartialSwapOptions,
// V2WithdrawImbalanceOptions, V2MultiRoutingOptions
```

### Helper Functions
```typescript
DEXOrderTransaction.buildOrderValue(option): Value // Calculate UTxO value needed
DEXOrderTransaction.buildV2OrderStep(option): OrderV2Step // Convert to Plutus step
DEXOrderTransaction.getOrderMetadata(option): string // Transaction label
```

## Djed — Stablecoin Protocol

```typescript
namespace Djed {
getConfig(networkEnv): Config // Lazy singleton
getPoolData(poolUtxo): PoolData // ADA reserve, DJED/SHEN circulation
getOracleData(oracleUtxo): OracleData // Exchange rate, price bounds

estimateMintShen(options): EstimateResult // Calculate with slippage
mintShen(options): TxBuilder // Build mint transaction

namespace Rate {
shenAdaRate(params): BigNumber
shen2ada(options): BigNumber
ada2shen(options): BigNumber
}

namespace DexFee {
getFee(amount, networkEnv): bigint // min(max(ceil(amount * pct), min), max)
}
}
```

## MetadataMessage — Transaction Labels

```typescript
// DEX: DEX_MARKET_ORDER, DEX_LIMIT_ORDER, DEX_STOP_ORDER, DEX_OCO_ORDER
// Liquidity: DEX_DEPOSIT_ORDER, DEX_WITHDRAW_ORDER, DEX_ZAP_IN_ORDER
// Advanced: DEX_PARTIAL_SWAP_ORDER, DEX_ROUTING_ORDER, DEX_MIXED_ORDERS
// Farming: STAKE_LIQUIDITY_V2, HARVEST_V2
```

## Usage Example
```typescript
const txb = DEXOrderTransaction.createBulkOrdersTx({
networkEnv: NetworkEnvironment.MAINNET,
sender: Address.fromBech32("addr1..."),
orderOptions: [{
lpAsset: Asset.fromString("..."),
version: DexVersion.DEX_V2,
type: OrderV2StepType.SWAP_EXACT_IN,
assetIn: ADA,
amountIn: 100_000_000n,
minimumAmountOut: 1n,
direction: OrderV2Direction.A_TO_B,
killOnFailed: false,
isLimitOrder: false,
}],
});

const result = await txb.complete({
changeAddress: sender,
provider,
walletUtxos,
coinSelectionAlgorithm: CoinSelectionAlgorithm.MINSWAP,
});
```
51 changes: 51 additions & 0 deletions .claude/specs/felis-cip.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# @minswap/felis-cip

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

**Location:** `packages/cip`

## Modules

### Bip32 — HD Wallet Key Derivation
```typescript
namespace Bip32 {
deriveAddress({ bip32PublicKeyHex, deriveOffsets, networkEnv }): Address[]
genPubKeyHashes(accountKey): Set<string>
filterUtxos(publicKey, utxos): Utxo[]
extractPublicKey(seed): CSLBip32PublicKey
extractBip32PrivateKey(seed): string
extractPrivateKey(options): PrivateKey
}
```

### Bip39 — Mnemonic Wallet Creation
```typescript
type BaseAddressWallet = { address: Address; rewardAddress: RewardAddress; paymentKey: PrivateKey; stakeKey: PrivateKey }
type EnterpriseAddressWallet = { address: Address; paymentKey: PrivateKey }

baseAddressWalletFromSeed(seed, networkEnv, options?): BaseAddressWallet
enterpriseAddressWalletFromSeed(seed, networkEnv, options?): EnterpriseAddressWallet
baseWalletFromEntropy(entropyHex, networkId): BaseAddressWallet
```

### CIP-25 — NFT Metadata Standard
```typescript
type CIP25NFT = { asset: Asset; name: string; image: string; mediaType?: string; files?: CIP25File[] }
type CIP25Metadata = { [policyId: string]: { [assetName: string]: Omit<CIP25NFT, "asset"> } }
```

### CIP-68 — Token Standard (Reference NFTs)
```typescript
enum Cip68UserTokenLabel { NFT = "000de140", FT = "0014df10" }

namespace CIP68 {
isRefNFT(asset): boolean
isNFT(asset): boolean
isFT(asset): boolean
isCip68(assetNameHex): boolean
fromDataHex(datum, label): Cip68UserTokenAsset
toDataHex(metadata): string
mintCip68Token(options): Cip68MintTokenResult
buildFTFromRefNFT(refNft): Maybe<Asset>
}
```
57 changes: 57 additions & 0 deletions .claude/specs/felis-dex-v1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# @minswap/felis-dex-v1

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

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

## Purpose
Handles DEX V1 order parsing and validation. V1 is the legacy DEX protocol — mainly used for backward compatibility and syncing historical orders.

## Key Exports

### Order
```typescript
class Order {
datum: OrderDatum
orderInfo: OrderInfo // { type: "SWAP", swapAsset, swapAmount, toAsset }

static fromUtxo(utxo, datum, networkEnv): Result<Order, Error>
}

type OrderDatum = {
sender: Address
receiver: Address
step: OrderStep
batcherFee: bigint
outputADA: bigint
}
```

### StepType
```typescript
enum StepType {
SWAP_EXACT_IN
SWAP_EXACT_OUT
DEPOSIT
WITHDRAW
ZAP_IN
// ... others
}
```

### Scripts
Contains compiled Plutus V1 scripts for mainnet and testnet (order validators, vesting scripts).

### Constants
DEX V1 configuration data for mainnet/testnet:
- Script hashes, addresses
- Factory tokens, pool tokens
- Batcher fee configurations

## Usage
Primarily consumed by the syncer package for parsing V1 swap orders from blockchain transactions.

```typescript
import { Order, StepType } from "@minswap/felis-dex-v1";
const orderResult = Order.fromUtxo(utxo, datum, networkEnv);
```
Loading