Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Maestro adapter #54

Merged
merged 22 commits into from
Jan 12, 2025
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
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,7 @@ jobs:
env:
BLOCKFROST_PROJECT_ID_MAINNET: ${{ secrets.BLOCKFROST_PROJECT_ID_MAINNET }}
BLOCKFROST_PROJECT_ID_TESTNET: ${{ secrets.BLOCKFROST_PROJECT_ID_TESTNET }}
MAESTRO_API_KEY_MAINNET: ${{ secrets.MAESTRO_API_KEY_MAINNET }}
MAESTRO_API_KEY_TESTNET: ${{ secrets.MAESTRO_API_KEY_TESTNET }}
- name: Check format & lint
run: pnpm run check-format
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ build
build-tsc
coverage
.idea

package-lock.json
2 changes: 1 addition & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
@@ -1 +1 @@
build
build
67 changes: 51 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@ The Minswap open-source providing a comprehensive suite of off-chain tools price
- [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.
We provide multiple adapters 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.
- `MaestroAdapter`: use [Maestro](https://www.gomaestro.org/) to query the data.

## Install

Expand All @@ -29,54 +31,82 @@ This package depends on `lucid-cardano`, which is an ESM package, so it's also a
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, MinswapAdapter, NetworkEnvironment, NetworkId, newPrismaClient, PostgresRepositoryReader } from "@minswap/sdk";
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 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
})
repository: repositoryReader,
});
```

### Maestro Adapter:

```ts
import { MaestroAdapter } from "@minswap/sdk";
import { MaestroClient, Configuration } from "@maestro-org/typescript-sdk";

const maestroClient = new MaestroClient(
new Configuration({
apiKey: maestroApiKey,
network: cardanoNetwork,
})
);

const maestroAdapter = new MaestroAdapter(NetworkId.TESTNET, maestroClient);
```

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

#### MIN/ADA pool v1:

```ts
for (let i = 1; ; i++) {
const pools = await adapter.getV1Pools({
Expand All @@ -90,7 +120,7 @@ for (let i = 1; ; i++) {
(p) =>
p.assetA === "lovelace" &&
p.assetB ===
"29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c64d494e"
"29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c64d494e"
);
if (minAdaPool) {
const [price0, price1] = await adapter.getV1PoolPrice({ pool: minAdaPool });
Expand All @@ -105,23 +135,25 @@ for (let i = 1; ; i++) {
```

#### MIN/ADA pool v2:

```ts
const minAdaPool = await adapter.getV2PoolByPair(
Asset.fromString("lovelace"),
Asset.fromString("29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c64d494e")
)
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()}`
);
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
const MIN_ADA_POOL_ID =
"6aa2153e1ae896a95539c9d62f76cedcdabdcdf144e564b8955f609d660cf6a2";
Expand All @@ -138,11 +170,14 @@ for (const historyPoint of history) {
```

#### MIN/ADA pool v2:

```ts
for (let i = 1; ; i++) {
const pools = await adapter.getV2PoolHistory({
assetA: Asset.fromString("lovelace"),
assetB: Asset.fromString("29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c64d494e"),
assetB: Asset.fromString(
"29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c64d494e"
),
page: i,
});
if (pools.length === 0) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import BigNumber from "bignumber.js";
import {
ADA,
Asset,
BlockfrostAdapter,
calculateDeposit,
calculateSwapExactIn,
calculateSwapExactOut,
Expand All @@ -33,6 +32,8 @@ import {
StableswapCalculation,
StableswapConstant,
} from "../src";

import { BlockfrostAdapter } from "../src/adapters/blockfrost";
import { LbeV2 } from "../src/lbe-v2/lbe-v2";
import { Stableswap } from "../src/stableswap";
import { LbeV2Types } from "../src/types/lbe-v2";
Expand Down
3 changes: 2 additions & 1 deletion examples/expired-order-monitor-example.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { BlockFrostAPI } from "@blockfrost/blockfrost-js";
import { Network } from "@minswap/lucid-cardano";

import { BlockfrostAdapter, NetworkId } from "../src";
import { NetworkId } from "../src";
import { BlockfrostAdapter } from "../src/adapters/blockfrost";
import { ExpiredOrderMonitor } from "../src/expired-order-monitor";
import { getBackendLucidInstance } from "../src/utils/lucid";

Expand Down
3 changes: 2 additions & 1 deletion examples/lbe-v2-worker-example.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { BlockFrostAPI } from "@blockfrost/blockfrost-js";
import { Network } from "@minswap/lucid-cardano";

import { BlockfrostAdapter, NetworkId } from "../src";
import { NetworkId } from "../src";
import { BlockfrostAdapter } from "../src/adapters/blockfrost";
import { LbeV2Worker } from "../src/lbe-v2-worker/worker";
import { NetworkEnvironment } from "../src/types/network";
import { getBackendLucidInstance } from "../src/utils/lucid";
Expand Down
100 changes: 100 additions & 0 deletions examples/maestro-adapter-example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { Address, Lucid, Network, TxComplete } from "@minswap/lucid-cardano";
import { Asset, NetworkId, PoolV2 } from "../src";
import { getBackendMaestroLucidInstance } from "../src/utils/lucid";
import { LbeV2 } from "../src/lbe-v2/lbe-v2";
import { MaestroAdapter } from "../src/adapters/maestro";
import { MaestroClient, Configuration } from "@maestro-org/typescript-sdk";
import invariant from "@minswap/tiny-invariant";

async function main(): Promise<void> {
const cardanoNetwork: Network = "Preprod";
const maestroApiKey = "<YOUR_MAESTRO_API_KEY>";

const address =
"addr_test1qqf2dhk96l2kq4xh2fkhwksv0h49vy9exw383eshppn863jereuqgh2zwxsedytve5gp9any9jwc5hz98sd47rwfv40stc26fr";

const lucid = await getBackendMaestroLucidInstance(
cardanoNetwork,
maestroApiKey,
address
);

const maestroClient = new MaestroClient(
new Configuration({
apiKey: maestroApiKey,
network: cardanoNetwork,
})
);

const maestroAdapter = new MaestroAdapter(NetworkId.TESTNET, maestroClient);

const txComplete = await _lbeV2DepositOrderExample(
lucid,
address,
maestroAdapter
);
const signedTx = await txComplete
.signWithPrivateKey("<YOUR_PRIVATE_KEY>")
.complete();

const txId = await signedTx.submit();
console.info(`Transaction submitted successfully: ${txId}`);
}

// Example Tx: 7af5ea80b6a4a587e2c6cfce383367829f0cb68c90b65656c8198a72afc3f419
async function _lbeV2DepositOrderExample(
lucid: Lucid,
address: Address,
maestroAdapter: MaestroAdapter
): Promise<TxComplete> {
const baseAsset = Asset.fromString(
"e16c2dc8ae937e8d3790c7fd7168d7b994621ba14ca11415f39fed7243414b45"
);
const raiseAsset = Asset.fromString("lovelace");

const lbeId = PoolV2.computeLPAssetName(baseAsset, raiseAsset);
const treasury = await maestroAdapter.getLbeV2TreasuryByLbeId(lbeId);
invariant(treasury !== null, `Can not find treasury by lbeId ${lbeId}`);
const treasuryUtxos = await lucid.utxosByOutRef([
{ txHash: treasury.txIn.txHash, outputIndex: treasury.txIn.index },
]);
invariant(treasuryUtxos.length === 1, "Can not find treasury Utxo");

const seller = await maestroAdapter.getLbeV2SellerByLbeId(lbeId);
invariant(seller !== null, `Can not find seller by lbeId ${lbeId}`);
const sellerUtxos = await lucid.utxosByOutRef([
{ txHash: seller.txIn.txHash, outputIndex: seller.txIn.index },
]);
invariant(sellerUtxos.length === 1, "Can not find seller Utxo");

const orders = await maestroAdapter.getLbeV2OrdersByLbeIdAndOwner(
lbeId,
address
);
const orderUtxos =
orders.length > 0
? await lucid.utxosByOutRef(
orders.map((o) => ({
txHash: o.txIn.txHash,
outputIndex: o.txIn.index,
}))
)
: [];

invariant(
orderUtxos.length === orders.length,
"Can not find enough order Utxos"
);

const currentSlot = await maestroAdapter.currentSlot();
return new LbeV2(lucid).depositOrWithdrawOrder({
currentSlot: currentSlot,
existingOrderUtxos: orderUtxos,
treasuryUtxo: treasuryUtxos[0],
sellerUtxo: sellerUtxos[0],
owner: address,
action: { type: "deposit", additionalAmount: 1_000_000n },
});
}

void main();
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"prisma:dbpull": "prisma db pull",
"prisma:generate": "prisma generate",
"postinstall": "prisma generate",
"syncer:start": "node --no-warnings=ExperimentalWarning --loader ts-node/esm src/syncer/main.ts"
"syncer:start": "node --no-warnings=ExperimentalWarning --loader ts-node/esm src/syncer/main.ts",
"type-check": "tsc --noEmit"
},
"keywords": [
"minswap",
Expand All @@ -51,6 +52,7 @@
"@blockfrost/blockfrost-js": "^5.5.0",
"@cardano-ogmios/client": "^6.5.0",
"@cardano-ogmios/schema": "^6.5.0",
"@maestro-org/typescript-sdk": "^1.6.3",
"@minswap/lucid-cardano": "0.10.10-minswap.4",
"@minswap/tiny-invariant": "^1.2.0",
"big.js": "^6.2.1",
Expand All @@ -64,7 +66,7 @@
"@eslint/compat": "^1.1.1",
"@eslint/js": "^9.9.1",
"@jest/globals": "^29.7.0",
"@prisma/client": "^5.19.1",
"@prisma/client": "^6.0.1",
"@types/big.js": "^6.2.2",
"@types/eslint__js": "^8.42.3",
"@types/jest": "^29.5.12",
Expand All @@ -78,7 +80,7 @@
"jest": "^29.7.0",
"json-bigint": "^1.0.0",
"prettier": "3.3.3",
"prisma": "^5.19.1",
"prisma": "^6.0.1",
"rimraf": "^6.0.1",
"rollup": "^4.21.2",
"rollup-plugin-dts": "^6.1.1",
Expand Down
Loading
Loading