The Minswap open-source project provides a comprehensive suite of off-chain tools, including price feeds, historical data storage, and integration methods for Stableswap, AMM V1, AMM V2, and LBE V2.
- See the Minswap Example for a demonstration of how to use the SDK.
- For additional transaction-building examples, refer to the
examples/
directory in this repository.
- Pool price feed
- Historical data of pool
- Calculate trade price
- Calculate price impact
- Create orders and submit with Lucid
- Syncer to sync minswap's liquidity pool data
We provide multiple adapters to get the price and liquidity pool information.
BlockfrostAdapter
: use Blockfrost to query the data.MinswapAdapter
: use Syncer to query the data. If you want to useMinswapAdapter
you need to run syncer by yourself.MaestroAdapter
: use Maestro to query the data.
- NPM:
npm install @minswap/sdk
- Yarn:
yarn add @minswap/sdk
This package depends on @spacebudz/lucid
, which is an ESM package, so it's also an ESM package. To import from ESM package, you need to specify "type": "module"
in package.json
and configure other build flags accordingly.
Also, --experimental-wasm-modules
flag needs to be set in Node.js and @jsr:registry=https://npm.jsr.io
needs to be added to .npmrc
file.
Create an adapter using either BlockfrostAdapter
or MinswapAdapter
:
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
);
- Install docker compose.
- 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.
import { BlockFrostAPI } from "@blockfrost/blockfrost-js";
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,
});
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);
for (let i = 1; ; i++) {
const pools = await adapter.getV1Pools({
page: i,
});
if (pools.length === 0) {
// last page
break;
}
const minAdaPool = pools.find(
(p) =>
p.assetA === "lovelace" &&
p.assetB ===
"29d222ce763455e3d7a09a665ce554f00ac89d2e99a1a83d267170c64d494e"
);
if (minAdaPool) {
const [price0, price1] = await adapter.getV1PoolPrice({ pool: minAdaPool });
console.log(
`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}`);
break;
}
}
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()}`);
}
const MIN_ADA_POOL_ID =
"6aa2153e1ae896a95539c9d62f76cedcdabdcdf144e564b8955f609d660cf6a2";
const history = await adapter.getV1PoolHistory({ id: MIN_ADA_POOL_ID });
for (const historyPoint of history) {
const pool = await adapter.getV1PoolInTx({ txHash: historyPoint.txHash });
if (!pool) {
throw new Error("pool not found");
}
const [price0, price1] = await adapter.getV1PoolPrice({ pool: pool });
console.log(`${historyPoint.time}: ${price0} ADA/MIN, ${price1} MIN/ADA`);
}
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()}`
);
}
}
- Swap MIN-ADA in V2 pool on testnet:
import {
ADA, Asset,
BlockfrostAdapter,
calculateAmountWithSlippageTolerance,
DexV2,
DexV2Calculation,
getBackendBlockfrostLucidInstance,
NetworkId,
OrderV2
} from "@minswap/sdk";
import {BlockFrostAPI} from "@blockfrost/blockfrost-js";
export async function swapExactInV2TxExample() {
const networkId: NetworkId = NetworkId.TESTNET;
const blockfrostProjectId = "<YOUR_BLOCKFROST_PROJECT_ID>";
const blockfrostUrl = "https://cardano-preprod.blockfrost.io/api/v0";
const address = "<YOUR_ADDRESS";
const lucid = await getBackendBlockfrostLucidInstance(
networkId,
blockfrostProjectId,
blockfrostUrl,
address
);
const adapter = new BlockfrostAdapter(
NetworkId.TESTNET,
new BlockFrostAPI({
projectId: blockfrostProjectId,
network: "preprod",
})
);
const MIN: Asset = {
policyId: "e16c2dc8ae937e8d3790c7fd7168d7b994621ba14ca11415f39fed72",
tokenName: "4d494e",
};
const utxos = await lucid.utxosAt(address);
const assetA = ADA;
const assetB = MIN;
const pool = await adapter.getV2PoolByPair(assetA, assetB);
if (!pool) {
throw new Error("Pool not found");
}
const swapAmount = 1_000n;
const amountOut = DexV2Calculation.calculateAmountOut({
reserveIn: pool.reserveA,
reserveOut: pool.reserveB,
amountIn: swapAmount,
tradingFeeNumerator: pool.feeA[0],
});
// 20% slippage tolerance
const acceptedAmountOut = calculateAmountWithSlippageTolerance({
slippageTolerancePercent: 20,
amount: amountOut,
type: "down",
});
const txComplete = await new DexV2(lucid, adapter).createBulkOrdersTx({
sender: address,
availableUtxos: utxos,
orderOptions: [
{
type: OrderV2.StepType.SWAP_EXACT_IN,
amountIn: swapAmount,
assetIn: assetA,
direction: OrderV2.Direction.A_TO_B,
minimumAmountOut: acceptedAmountOut,
lpAsset: pool.lpAsset,
isLimitOrder: false,
killOnFailed: false,
},
],
});
const signedTx = await txComplete
.signWithPrivateKey("<YOUR_PRIVATE_KEY>")
.commit();
const txId = await signedTx.submit();
console.log(`Transaction submitted successfully: ${txId}`);
}
void swapExactInV2TxExample();
import {
ADA,
Asset,
calculateAmountWithSlippageTolerance,
DexV2,
DexV2Calculation,
getBackendMaestroLucidInstance,
MaestroAdapter,
NetworkId,
OrderV2
} from "@minswap/sdk";
import {Configuration, MaestroClient} from "@maestro-org/typescript-sdk";
export async function swapExactInV2TxExample() {
const networkId: NetworkId = NetworkId.TESTNET;
const maestroApiKey = "<YOUR_API_KEY>";
const address = "<YOUR_ADDRESS>";
const lucid = await getBackendMaestroLucidInstance(
"Preprod",
maestroApiKey,
address
);
const maestroClient = new MaestroClient(
new Configuration({
apiKey: maestroApiKey,
network: "Preprod",
})
);
const MIN: Asset = {
policyId: "e16c2dc8ae937e8d3790c7fd7168d7b994621ba14ca11415f39fed72",
tokenName: "4d494e",
};
const adapter = new MaestroAdapter(NetworkId.TESTNET, maestroClient);
const utxos = await lucid.utxosAt(address);
const assetA = ADA;
const assetB = MIN;
const pool = await adapter.getV2PoolByPair(assetA, assetB);
if (!pool) {
throw new Error("Pool not found");
}
const swapAmount = 1_000n;
const amountOut = DexV2Calculation.calculateAmountOut({
reserveIn: pool.reserveA,
reserveOut: pool.reserveB,
amountIn: swapAmount,
tradingFeeNumerator: pool.feeA[0],
});
// 20% slippage tolerance
const acceptedAmountOut = calculateAmountWithSlippageTolerance({
slippageTolerancePercent: 20,
amount: amountOut,
type: "down",
});
const txComplete = await new DexV2(lucid, adapter).createBulkOrdersTx({
sender: address,
availableUtxos: utxos,
orderOptions: [
{
type: OrderV2.StepType.SWAP_EXACT_IN,
amountIn: swapAmount,
assetIn: assetA,
direction: OrderV2.Direction.A_TO_B,
minimumAmountOut: acceptedAmountOut,
lpAsset: pool.lpAsset,
isLimitOrder: false,
killOnFailed: false,
},
],
});
const signedTx = await txComplete
.signWithPrivateKey("<YOUR_PRIVATE_KEY>")
.commit();
const txId = await signedTx.submit();
console.log(`Transaction submitted successfully: ${txId}`);
}
void swapExactInV2TxExample();
See examples/
or docs
for more details. You can run a single file like npm run exec examples/example.ts
.