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

swapApi got BlockHeightExceeded #121

Closed
longlst opened this issue Jan 7, 2025 · 1 comment
Closed

swapApi got BlockHeightExceeded #121

longlst opened this issue Jan 7, 2025 · 1 comment

Comments

@longlst
Copy link

longlst commented Jan 7, 2025

`import {
SendTransactionError,
Transaction,
VersionedTransaction,
sendAndConfirmTransaction,
} from "@solana/web3.js";
import { NATIVE_MINT } from "@solana/spl-token";
import axios from "axios";
import { connection, owner, fetchTokenAccountData } from "./config";
import { API_URLS } from "@raydium-io/raydium-sdk-v2";

interface SwapCompute {
id: string;
success: true;
version: "V0" | "V1";
openTime?: undefined;
msg: undefined;
data: {
swapType: "BaseIn" | "BaseOut";
inputMint: string;
inputAmount: string;
outputMint: string;
outputAmount: string;
otherAmountThreshold: string;
slippageBps: number;
priceImpactPct: number;
routePlan: {
poolId: string;
inputMint: string;
outputMint: string;
feeMint: string;
feeRate: number;
feeAmount: string;
}[];
};
}

export const apiSwap = async () => {
try {
const inputMint = NATIVE_MINT.toBase58();
const outputMint = "4k3Dyjzvzp8eMZWUXbBCjEvwSkkk59S5iCNLY3QrkX6R"; // RAY
const amount = 100000;
const slippage = 0.5; // in percent, for this example, 0.5 means 0.5%
const txVersion: string = "LEGACY"; // or LEGACY
const isV0Tx = txVersion === "V0";

const [isInputSol, isOutputSol] = [
  inputMint === NATIVE_MINT.toBase58(),
  outputMint === NATIVE_MINT.toBase58(),
];

const tokenAccounts = await fetchTokenAccountData();
const inputTokenAcc = tokenAccounts.find(
  (a: any) => a.mint.toBase58() === inputMint
)?.publicKey;
const outputTokenAcc = tokenAccounts.find(
  (a: any) => a.mint.toBase58() === outputMint
)?.publicKey;

if (!inputTokenAcc && !isInputSol) {
  console.error("do not have input token account");
  return;
}

// get statistical transaction fee from api
/**
 * vh: very high
 * h: high
 * m: medium
 */
const { data } = await axios.get<{
  id: string;
  success: boolean;
  data: { default: { vh: number; h: number; m: number } };
}>(`${API_URLS.BASE_HOST}${API_URLS.PRIORITY_FEE}`);
console.log("axios:", data);

const { data: swapResponse } = await axios.get<SwapCompute>(
  `${
    API_URLS.SWAP_HOST
  }/compute/swap-base-out?inputMint=${inputMint}&outputMint=${outputMint}&amount=${amount}&slippageBps=${
    slippage * 100
  }&txVersion=${txVersion}`
);
console.log("swap res:", swapResponse.data);

const { data: swapTransactions } = await axios.post<{
  id: string;
  version: string;
  success: boolean;
  data: { transaction: string }[];
}>(`${API_URLS.SWAP_HOST}/transaction/swap-base-in`, {
  computeUnitPriceMicroLamports: String(data.data.default.vh),
  swapResponse,
  txVersion,
  wallet: owner.publicKey.toBase58(),
  wrapSol: isInputSol,
  unwrapSol: isOutputSol, // true means output mint receive sol, false means output mint received wsol
  inputAccount: isInputSol ? undefined : inputTokenAcc?.toBase58(),
  outputAccount: isOutputSol ? undefined : outputTokenAcc?.toBase58(),
});
console.log(swapTransactions);
console.log(data.data.default.vh);

const allTxBuf = swapTransactions.data.map((tx) =>
  Buffer.from(tx.transaction, "base64")
);
const allTransactions = allTxBuf.map((txBuf) =>
  isV0Tx ? VersionedTransaction.deserialize(txBuf) : Transaction.from(txBuf)
);

console.log(
  `total ${allTransactions.length} transactions`,
  swapTransactions
);

let idx = 0;
if (!isV0Tx) {
  for (const tx of allTransactions) {
    console.log(`${++idx} transaction sending...`);
    const transaction = tx as Transaction;
    transaction.sign(owner);
    const txId = await sendAndConfirmTransaction(
      connection,
      transaction,
      [owner],
      { skipPreflight: true }
    );
    console.log(`${++idx} transaction confirmed, txId: ${txId}`);
  }
} else {
  for (const tx of allTransactions) {
    idx++;
    const transaction = tx as VersionedTransaction;
    transaction.sign([owner]);
    const txId = await connection.sendTransaction(
      tx as VersionedTransaction,
      { skipPreflight: true }
    );
    const { lastValidBlockHeight, blockhash } =
      await connection.getLatestBlockhash({
        commitment: "finalized",
      });
    console.log(`${idx} transaction sending..., txId: ${txId}`);
    await connection.confirmTransaction(
      {
        blockhash,
        lastValidBlockHeight,
        signature: txId,
      },
      "confirmed"
    );
    console.log(`${idx} transaction confirmed`);
  }
}

} catch (error) {
if (error instanceof SendTransactionError) {
console.error("Transaction failed:", error.message);
const logs = await error.getLogs(connection);
console.error("Transaction logs:", logs);
} else {
console.error("Unexpected error:", error);
}
console.log("error:", error);
}
}`

I used paid rpc mainnet and sometimes it worked, sometimes it got BlockHeightExceeded, sometimes it got Tick Array error.

@raydium-io raydium-io deleted a comment from Alexivan4009 Jan 10, 2025
@cruzshia
Copy link
Collaborator

cruzshia commented Jan 10, 2025

BlockHeightExceeded means you need set higher priority fees, if you are swaping through high fluctuation price pool, it will have high possibility expired

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants
@cruzshia @longlst and others