-
Notifications
You must be signed in to change notification settings - Fork 182
Open
Description
I'm trying to use initializePositionAndAddLiquidityByStrategy
to open a position in the liquidity pool. The transaction returns a signature string but when I go on my wallet the balances still remain the same.
Am I doing something wrong here? Any help would be appreciated!
"use client";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { NumberInput } from "@/components/ui/number-input";
import { SGDC_DECIMALS, USDC_DECIMALS } from "@/lib/constants";
import { getConnection } from "@/lib/solana/utils";
import { zodResolver } from "@hookform/resolvers/zod";
import DLMM, { StrategyType } from "@meteora-ag/dlmm";
import { useWallet } from "@solana/wallet-adapter-react";
import {
ComputeBudgetProgram,
Keypair,
PublicKey,
Transaction,
} from "@solana/web3.js";
import { BN } from "bn.js";
import dynamic from "next/dynamic";
import { useEffect, useMemo, useState } from "react";
import { useForm } from "react-hook-form";
import { toast } from "sonner";
import * as z from "zod";
import { getPriceQuote } from "./_actions";
const WalletMultiButton = dynamic(
() =>
import("@/components/solana-wallet").then((mod) => mod.WalletMultiButton),
{ ssr: false },
);
const depositSchema = z.object({
sgdc: z.number("SGDC must be a number").min(0.01, "Minimum 0.01"),
});
type DepositFormValues = z.infer<typeof depositSchema>;
export type JitoRegion = "mainnet" | "amsterdam" | "frankfurt" | "ny" | "tokyo";
export const JitoEndpoints = {
mainnet: "https://mainnet.block-engine.jito.wtf/api/v1/transactions",
amsterdam:
"https://amsterdam.mainnet.block-engine.jito.wtf/api/v1/transactions",
frankfurt:
"https://frankfurt.mainnet.block-engine.jito.wtf/api/v1/transactions",
ny: "https://ny.mainnet.block-engine.jito.wtf/api/v1/transactions",
tokyo: "https://tokyo.mainnet.block-engine.jito.wtf/api/v1/transactions",
};
export function getJitoEndpoint(region: JitoRegion) {
return JitoEndpoints[region];
}
/**
* Send a transaction using Jito. This only supports sending a single transaction on mainnet only.
* See https://jito-labs.gitbook.io/mev/searcher-resources/json-rpc-api-reference/transactions-endpoint/sendtransaction.
* @param args.serialisedTx - A single transaction to be sent, in serialised form
* @param args.region - The region of the Jito endpoint to use
*/
export async function sendTxUsingJito(
serializedTx: Uint8Array | Buffer | number[],
) {
const rpcEndpoint = getJitoEndpoint("mainnet");
const payload = {
jsonrpc: "2.0",
id: 1,
method: "sendTransaction",
params: [serializedTx.toString("base64"), { encoding: "base64" }],
};
const res = await fetch(`${rpcEndpoint}?bundleOnly=true`, {
method: "POST",
body: JSON.stringify(payload),
headers: { "Content-Type": "application/json" },
});
const json = await res.json();
console.log("Jito response:", json);
if (json.error) {
throw new Error(json.error.message);
}
return json;
}
export default function LiquidityPage() {
const wallet = useWallet();
const [marketPrice, setMarketPrice] = useState<number | null>(null);
const [dlmmPool, setDlmmPool] = useState<DLMM | null>(null);
const form = useForm<DepositFormValues>({
resolver: zodResolver(depositSchema),
defaultValues: { sgdc: 0 },
});
useEffect(() => {
(async () => {
if (!wallet.connected) return;
const pythQuote = await getPriceQuote().catch((e) => {
console.error(e);
toast.error("Failed to fetch USD/SGD price");
});
if (!pythQuote) return;
const [pythData, price] = pythQuote;
setMarketPrice(1 / price);
DLMM.create(
getConnection(),
new PublicKey(process.env.NEXT_PUBLIC_USDC_POOL_ADDRESS!),
)
.then(setDlmmPool)
.catch((e) => {
console.error(e);
toast.error("Failed to init pool");
});
})();
}, [wallet.connected]);
// live-calc USDC needed
const sgdcVal = form.watch("sgdc") || 0;
const usdcVal = useMemo(() => {
if (!marketPrice) return 0;
return sgdcVal * marketPrice;
}, [marketPrice, sgdcVal]);
const onSubmit = form.handleSubmit(async ({ sgdc }) => {
if (!wallet.publicKey || !wallet.signTransaction) {
toast.error("Connect a wallet that can sign transactions");
return;
}
if (!dlmmPool || marketPrice === null) {
toast.error("Pool or price not ready");
return;
}
try {
const activeBin = await dlmmPool.getActiveBin();
const TOTAL_RANGE_INTERVAL = 10; // 10 bins on each side of the active bin
const minBinId = activeBin.binId - TOTAL_RANGE_INTERVAL;
const maxBinId = activeBin.binId + TOTAL_RANGE_INTERVAL;
const totalXAmount = new BN(sgdc * 10 ** SGDC_DECIMALS);
const totalYAmount = new BN(sgdc * marketPrice * 10 ** USDC_DECIMALS);
const newImbalancePosition = new Keypair();
const createPositionTx =
await dlmmPool.initializePositionAndAddLiquidityByStrategy({
positionPubKey: newImbalancePosition.publicKey,
totalXAmount,
totalYAmount,
strategy: {
maxBinId,
minBinId,
strategyType: StrategyType.Spot,
},
user: wallet.publicKey,
slippage: 50,
});
const transaction = new Transaction()
.add(ComputeBudgetProgram.setComputeUnitLimit({ units: 1_000_000 }))
.add(createPositionTx);
transaction.recentBlockhash = (
await getConnection().getLatestBlockhash()
).blockhash;
transaction.feePayer = wallet.publicKey;
transaction.sign(newImbalancePosition);
const signedTx = await wallet.signTransaction(transaction);
const txResult = await sendTxUsingJito(signedTx.serialize());
console.log("Transaction result:", txResult);
toast.success("Liquidity deposited successfully!", {
// action: {
// label: "View Tx",
// onClick: () => window.open(`https://solscan.io/tx/${txResult}`),
// },
});
form.reset();
} catch (err) {
console.error(err);
if (err instanceof Error) {
toast.error(err.message || "Deposit failed");
}
}
});
return (
<main className="relative flex flex-col items-center">
<div className="flex flex-col md:max-w-5xl w-full mt-10 gap-8 px-8 md:px-0">
<Card>
<CardHeader>
<CardTitle>Deposit Liquidity</CardTitle>
<CardDescription>
Add SGDC ↔ USDC at live SGD/USD rate
</CardDescription>
</CardHeader>
<CardContent className="space-y-6">
{!wallet.connected ? (
<WalletMultiButton className="w-full" />
) : (
<>
<div>
<p className="text-sm">Market SGD/USD:</p>
<p className="text-lg font-semibold">{marketPrice ?? "…"}</p>
</div>
<Form {...form}>
<form onSubmit={onSubmit} className="flex flex-col gap-4">
<FormField
control={form.control}
name="sgdc"
render={({ field }) => (
<FormItem>
<FormLabel>SGDC amount</FormLabel>
<FormControl>
<NumberInput
stepper={1}
thousandSeparator=","
decimalScale={2}
fixedDecimalScale
allowNegative={false}
prefix="SGDC "
min={0}
max={200_000}
{...field}
onChange={undefined}
onValueChange={(val) => {
field.onChange(val);
}}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<div>
<p className="text-sm">USDC required</p>
<p className="text-lg font-semibold">{usdcVal} USDC</p>
</div>
<Button
type="submit"
className="w-full"
disabled={!marketPrice}
>
Deposit Liquidity
</Button>
</form>
</Form>
</>
)}
</CardContent>
</Card>
</div>
</main>
);
}
Metadata
Metadata
Assignees
Labels
No labels