Skip to content

Commit

Permalink
[MIN-1597] Minswap syncer for query price for v1, v2 and stableswap p…
Browse files Browse the repository at this point in the history
…ool. (#40)

* init

* add dockerignore

* fix ts-node esm loading

* disable esm warning

* syncer for v1, v2 and stableswap

* fix rollback logic

* Minswap adapter

* add node-ogmios docker compose

* update minswap adapter

* update ci

* fix build

* fix jest

* fix ci

* fix test

* fix test adapter

* fix jest

* change to npm

* change to npm

* change to npm ci

* upgrade node from 18 to 20 and use pnpm instead of npm

* ci: fix node version

* add output prisma client

* fix node linker

* strict engine check

* update readme

* add v2 historical pool

* remove node-configs

* fix comment

---------

Co-authored-by: Nhat Khanh <[email protected]>
  • Loading branch information
hieupnh and lednhatkhanh authored Sep 25, 2024
1 parent 2b34342 commit c3eeee0
Show file tree
Hide file tree
Showing 31 changed files with 7,192 additions and 7,413 deletions.
4 changes: 4 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
node_modules
build
examples
.github
12 changes: 12 additions & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# "mainnet" | "testnet-preview" | "testnet-preprod"
ENVIRONMENT="testnet-preprod"

# "mainnet" | "preview" | "preprod" ref: https://ogmios.dev/getting-started/docker
OGMIOS_NETWORK="preprod"

# preprod: 7790880c9f0ff09990f253dd1bf1a55d2a2e5340bf694e5c0bb166439e513e45.10918782
# mainnet: 231d8151ca08efcdd68d05920d0622624892dd8719ddc28aef131b7f1d4315db.56553271
SYNC_START_POINT="7790880c9f0ff09990f253dd1bf1a55d2a2e5340bf694e5c0bb166439e513e45.10918782"

# prisma config database url:
DATABASE_URL="postgresql://postgres:minswap@localhost:5432/syncer?schema=public"
15 changes: 10 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,22 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
name: Install pnpm
with:
run_install: false
- uses: actions/setup-node@v4
with:
node-version: 18.x
node-version: 20.x
cache: "pnpm"
- name: Install dependencies
run: npm ci
run: pnpm install --frozen-lockfile
- name: Run build
run: npm run build
run: pnpm run build
- name: Run test
run: npm run test
run: pnpm run test
env:
BLOCKFROST_PROJECT_ID_MAINNET: ${{ secrets.BLOCKFROST_PROJECT_ID_MAINNET }}
BLOCKFROST_PROJECT_ID_TESTNET: ${{ secrets.BLOCKFROST_PROJECT_ID_TESTNET }}
- name: Check format & lint
run: npm run check-format
run: pnpm run check-format
2 changes: 2 additions & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node-linker=hoisted
engine-strict=true
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v18
v20
11 changes: 11 additions & 0 deletions Dockerfile.syncer
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM node:20
RUN apt-get update -y && \
apt-get install -y ca-certificates tzdata

WORKDIR /app

COPY package.json pnpm-lock.yaml .npmrc ./
COPY src/syncer/postgres/prisma ./src/syncer/postgres/prisma
RUN corepack enable && corepack install
RUN --mount=type=cache,id=pnpm,target=/pnpm/store pnpm install --frozen-lockfile
COPY . .
140 changes: 106 additions & 34 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
# Minswap SDK

The Minswap open-source providing a comprehensive suite of off-chain tools price feeds, historical data storage, and integration methods for: `Stableswap`, `AMM V1`, `AMM V2` and `LBE V2`.

## Features

- [x] Get current pair price
- [x] Get historical pair price
- [x] Pool price feed
- [x] Historical data of pool
- [x] Calculate trade price
- [x] Calculate price impact
- [x] Create orders and submit with Lucid
- [x] Syncer to sync minswap's liquidity pool data

We provide two adapter `BlockfrostAdapter` and `MinswapAdapter` to get the price and liquidity pool information.
- `BlockfrostAdapter`: use [Blockfrost](https://blockfrost.dev) to query the data.
- `MinswapAdapter`: use Syncer to query the data. If you want to use `MinswapAdapter` you need to run syncer by yourself.

## Install

Expand All @@ -19,74 +26,139 @@ This package depends on `lucid-cardano`, which is an ESM package, so it's also a

## Examples

### Example 1: Get current price of MIN/ADA pool
Create an adapter using either `BlockfrostAdapter` or `MinswapAdapter`:

### BlockfrostAdapter:
```ts
import { BlockFrostAPI } from "@blockfrost/blockfrost-js";
import { BlockfrostAdapter, NetworkId } from "@minswap/sdk";

const blockFrostApi = new BlockFrostAPI({
projectId: "<your_project_id>",
network: "mainnet",
})

const blockfrostAdapter = new BlockfrostAdapter(
NetworkId.MAINNET,
blockFrostApi
)
```

### MinswapAdapter:
- [Install docker compose](https://docs.docker.com/compose/install).
- Update the `.env` file to specify the exact network you want to sync.
- Run the command: `docker compose -f docker-compose.yaml up --build -d` to build.
- Run the command: `docker compose -f docker-compose.yaml logs -f` to view log.

```ts
import { BlockFrostAPI } from "@blockfrost/blockfrost-js";
import { BlockfrostAdapter } from "@minswap/sdk";

const api = new BlockfrostAdapter({
blockFrost: new BlockFrostAPI({
projectId: "<your_project_id>",
network: "mainnet",
}),
});
import { BlockfrostAdapter, MinswapAdapter, NetworkEnvironment, NetworkId, newPrismaClient, PostgresRepositoryReader } from "@minswap/sdk";

const blockFrostApi = new BlockFrostAPI({
projectId: "<your_project_id>",
network: "mainnet",
})

const prismaClient = await newPrismaClient("postgresql://postgres:minswap@postgres:5432/syncer?schema=public&connection_limit=5")

const repositoryReader = new PostgresRepositoryReader(
NetworkEnvironment.MAINNET,
prismaClient
)

const minswapAdapter = new MinswapAdapter({
networkId: NetworkId.MAINNET,
networkEnv: NetworkEnvironment.MAINNET,
blockFrostApi: blockFrostApi,
repository: repositoryReader
})
```

### Example 1: Get current price of MIN/ADA pool

#### MIN/ADA pool v1:
```ts
for (let i = 1; ; i++) {
const pools = await api.getPools({
const pools = await adapter.getV1Pools({
page: i,
});
if (pools.length === 0) {
// last page
break;
}
const minADAPool = pools.find(
const minAdaPool = pools.find(
(p) =>
p.assetA === "lovelace" &&
p.assetB ===
"29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c64d494e"
"29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c64d494e"
);
if (minADAPool) {
const [a, b] = await api.getPoolPrice({ pool: minADAPool });
if (minAdaPool) {
const [price0, price1] = await adapter.getV1PoolPrice({ pool: minAdaPool });
console.log(
`ADA/MIN price: ${a.toString()}; MIN/ADA price: ${b.toString()}`
`ADA/MIN price: ${price0.toString()}; MIN/ADA price: ${price1.toString()}`
);
// we can later use this ID to call getPoolById
console.log(`ADA/MIN pool ID: ${minADAPool.id}`);
console.log(`ADA/MIN pool ID: ${minAdaPool.id}`);
break;
}
}
```

#### MIN/ADA pool v2:
```ts
const minAdaPool = await adapter.getV2PoolByPair(
Asset.fromString("lovelace"),
Asset.fromString("29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c64d494e")
)

if (minAdaPool) {
const [a, b] = await adapter.getV2PoolPrice({ pool: minAdaPool });
console.log(
`ADA/MIN price: ${a.toString()}; MIN/ADA price: ${b.toString()}`
);
}
```

### Example 2: Get historical prices of MIN/ADA pool

#### MIN/ADA pool v1:
```ts
import { BlockFrostAPI } from "@blockfrost/blockfrost-js";
import { BlockfrostAdapter, NetworkId } from "@minswap/sdk";

const MIN_ADA_POOL_ID =
"6aa2153e1ae896a95539c9d62f76cedcdabdcdf144e564b8955f609d660cf6a2";

const api = new BlockfrostAdapter({
blockFrost: new BlockFrostAPI({
projectId: "<your_project_id>",
network: "mainnet",
}),
});
const history = await api.getPoolHistory({ id: MIN_ADA_POOL_ID });
const history = await adapter.getV1PoolHistory({ id: MIN_ADA_POOL_ID });
for (const historyPoint of history) {
const pool = await api.getPoolInTx({ txHash: historyPoint.txHash });
const pool = await adapter.getV1PoolInTx({ txHash: historyPoint.txHash });
if (!pool) {
throw new Error("pool not found");
}
const [price0, price1] = await api.getPoolPrice({
pool,
decimalsA: 6,
decimalsB: 6,
});
const [price0, price1] = await adapter.getV1PoolPrice({ pool: pool });
console.log(`${historyPoint.time}: ${price0} ADA/MIN, ${price1} MIN/ADA`);
}
```

#### MIN/ADA pool v2:
```ts
for (let i = 1; ; i++) {
const pools = await adapter.getV2PoolHistory({
assetA: Asset.fromString("lovelace"),
assetB: Asset.fromString("29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c64d494e"),
page: i,
});
if (pools.length === 0) {
// last page
break;
}

for (const pool of pools) {
const [price0, price1] = await adapter.getV2PoolPrice({ pool: pool });
console.log(
`ADA/MIN price: ${a.toString()}; MIN/ADA price: ${price1.toString()}`
);
}
}
```

### Example 3: Build Order transaction and submit

See `examples/` for more details. You can run a single file like `npm run exec examples/example.ts`.
47 changes: 47 additions & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
services:
syncer:
build:
dockerfile: Dockerfile.syncer
restart: always
environment:
ENVIRONMENT:
OGMIOS_HOST: ogmios
OGMIOS_PORT: 1337
REDIS_URL: redis://default:minswap@redis:6379
POSTGRES_URL: postgresql://postgres:minswap@postgres:5432/syncer?schema=public&connection_limit=5
SYNC_START_POINT:
command: pnpm run syncer:start

redis:
image: redis:7
restart: always
command: --requirepass minswap
ports:
- "6379:6379"
volumes:
- redis-data:/data

postgres:
image: postgres:16
restart: always
environment:
POSTGRES_DB: syncer
POSTGRES_PASSWORD: minswap
volumes:
- ./src/syncer/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql
- postgres-data:/var/lib/postgresql/data
ports:
- "5432:5432"

ogmios:
image: cardanosolutions/cardano-node-ogmios:v6.5.0_9.0.0-${OGMIOS_NETWORK}
restart: always
ports:
- 1337:1337
volumes:
- ogmios-data:/db

volumes:
redis-data: {}
ogmios-data: {}
postgres-data: {}
10 changes: 5 additions & 5 deletions examples/example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,13 @@ async function main(): Promise<void> {
address
);

const blockfrostAdapter = new BlockfrostAdapter({
networkId: NetworkId.TESTNET,
blockFrost: new BlockFrostAPI({
const blockfrostAdapter = new BlockfrostAdapter(
NetworkId.TESTNET,
new BlockFrostAPI({
projectId: blockfrostProjectId,
network: "preprod",
}),
});
})
);

const utxos = await lucid.utxosAt(address);

Expand Down
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ export default {
// snapshotSerializers: [],

// The test environment that will be used for testing
// testEnvironment: "jest-environment-node",
testEnvironment: "node",

// Options that will be passed to the testEnvironment
// testEnvironmentOptions: {},
Expand Down
Loading

0 comments on commit c3eeee0

Please sign in to comment.