This module can be used to get information about Magicswap pools, allowing you to perform token swaps and manage pool liquidity.
Methods
interface ApiClient {
getPools(): Promise<PoolsReply>;
getPool(id: string): Promise<PoolReply>;
getRoute(body: RouteBody): Promise<RouteReply>;
swap(
body: SwapBody,
waitForCompletion?: boolean,
): Promise<CreateTransactionReply | void>;
addLiquidity(
poolId: string,
body: AddLiquidityBody,
waitForCompletion?: boolean,
): Promise<CreateTransactionReply | void>;
removeLiquidity(
poolId: string,
body: RemoveLiquidityBody,
waitForCompletion?: boolean,
): Promise<CreateTransactionReply | void>;
}
Usage
Swap and liquidity operations require the user’s smart wallet to be connected
and a started session (See Connect & Identity)
Step 1: Fetch pool and route data
const poolData = await tdk.magicswap.getPool();
const routeData = await tdk.magicswap.getRoute(
tokenInId: poolData.token0.id,
tokenOutId: poolData.token1.id,
amount: "1",
isExactOut: true
);
If isExactOut = true
then amount
is the amount out.
If isExactOut = false
then amount
is the amount in.
See this section below for details.
Step 1.1: For swaps that involve NFTs
The user must select the NFTs to swap (and their quantities)
- if the input token is NFT, select from
routeData.tokenIn.collectionTokenIds
up to routeData.amountIn
NFTs
- if the output token is NFT, select from
routeData.tokenOut.collectionTokenIds
up to routeData.amountOut
NFTs
const userSelectedNFTsOutput = [
{
id: routeData.tokenOut.collectionTokenIds[0],
quantity: 1,
},
];
const swapBody = {
tokenInId: routeData.tokenIn.id,
tokenOutId: routeData.tokenOut.id,
path: routeData.path,
amountIn: routeData.amountIn,
nftsOut: userSelectedNFTsOutput,
isExactOut: true,
};
const transaction = await tdk.magicswap.swap(swapBody);
Other types of swap
Different properties of SwapBody
can be used for different kinds of swap:
Swap type | Properties |
---|
ERC20 to NFT | amountIn & nftsOut |
ERC20 to ERC20 | amountIn & amountOut |
NFT to NFT | nftsIn & nftsOut |
NFT to ERC20 | nftsIn & amountOut |
The isExactOut
parameter
When calling getRoute
and swap
you must specify the isExactOut
parameter.
The same value should be used for both.
isExactOut = true
means that the user has specified the exact amount of tokens they want to receive.
There are a few different scenarios:
- ERC20⇔NFT swaps
- If the user is trading their NFTs,
isExactOut = false
because they must specify exactly how many NFTs they are putting in.
- If the user is trading to NFTs,
isExactOut = true
because they must specify exactly how many NFTs they are receiving.
- ERC20⇔ERC20 or NFT⇔NFT swaps;
isExactOut
depends on whatever the user specified.
- For example, if you’re swapping MAGIC to VEE, then
isExactOut = true
if you specify how much VEE you want,
and isExactOut = false
if you specify how much MAGIC you will give.
Adding Liquidity
const getQuote = (amountA: bigint, reserveA: bigint, reserveB: bigint) =>
reserveA > 0 ? (amountA * reserveB) / reserveA : 0n;
const getAmountMin = (amount: bigint, slippage: number) =>
amount - (amount * BigInt(Math.ceil(slippage * 1000))) / 1000n;
const poolData = await tdk.magicswap.getPool();
const tokenA = poolData.token1;
const tokenB = poolData.token0;
const reserveA = tokenA.reserve;
const reserveB = tokenB.reserve;
const amountA = BigInt(1);
const amountB = getQuote(
parseUnits(amountA.toString(), tokenA.decimals),
BigInt(reserveA),
BigInt(reserveB),
);
const addLiquidityBody = {
amount0: amountB.toString(),
amount0Min: getAmountMin(amountB, 0.01).toString(),
nfts1: [
{
id: tokenA.collectionTokenIds[0],
quantity: Number(amountA),
},
],
};
var transaction = await tdk.magicswap.addLiquidity(
poolData.id,
addLiquidityBody,
);
Other types of pools
Different properties of AddLiquidityBody
can be used for different kinds of pools:
Pool type | Properties |
---|
ERC20⇔NFT | amount0 & amount0Min & nfts1 |
ERC20⇔ERC20 | amount0 & amount0Min & amount1 & amount1Min |
NFT⇔NFT | nfts0 & nfts1 |
NFT⇔ERC20 | nfts0 & amount1 & amount1Min |
Removing Liquidity
const getAmountMin = (amount: bigint, slippage: number) =>
amount - (amount * BigInt(Math.ceil(slippage * 1000))) / 1000n;
const poolData = await tdk.magicswap.getPool();
const reserve0 = BigInt(poolData.token0.reserve);
const reserve1 = BigInt(poolData.token1.reserve);
const totalSupply = BigInt(poolData.totalSupply);
const rawNftsDesired = "1";
const nftsDesired = parseUnits(rawNftsDesired, poolData.token1.decimals);
const product = nftsDesired * totalSupply;
let amountLPWei = product / reserve1;
const reminder = product % reserve1;
if (reminder > 0) {
amountLPWei += BigInt(1);
}
const amount0 = (amountLPWei * reserve0) / totalSupply;
const amount0Min = getAmountMin(amount0, 0.01);
const removeLiquidityBody = {
amountLP: amountLPWei.toString(),
amount0Min: amount0Min.toString(),
amount1Min: nftsDesired.toString(),
nfts1: [
{
id: poolData.token1.collectionTokenIds[0],
quantity: Number(rawNftsDesired),
},
],
};
await tdk.magicswap.removeLiquidity(poolData.id, removeLiquidityBody);