+
{children}
diff --git a/app/utils/__tests__/format.test.ts b/app/utils/__tests__/format.test.ts
new file mode 100644
index 0000000..4effa40
--- /dev/null
+++ b/app/utils/__tests__/format.test.ts
@@ -0,0 +1,91 @@
+import { describe, it, expect } from "vitest";
+import { formatPrice, formatPercent, formatBigNumber } from "../format";
+
+describe("formatPrice", () => {
+ it("should format very small prices with exponential notation", () => {
+ expect(formatPrice(0.0000005)).toBe(5e-7);
+ expect(formatPrice(0.00000012)).toBe(1.2e-7);
+ });
+
+ it("should format small prices (< 0.001) with 6 decimals", () => {
+ expect(formatPrice(0.0005)).toBe(0.0005);
+ expect(formatPrice(0.000123)).toBe(0.000123);
+ });
+
+ it("should format prices (< 0.01) with 5 decimals", () => {
+ expect(formatPrice(0.005)).toBe(0.005);
+ expect(formatPrice(0.00987)).toBe(0.00987);
+ });
+
+ it("should format regular prices with 4 decimals", () => {
+ expect(formatPrice(0.1444)).toBe(0.1444);
+ expect(formatPrice(1.5678)).toBe(1.5678);
+ expect(formatPrice(100.123456)).toBe(100.1235);
+ });
+});
+
+describe("formatPercent", () => {
+ it("should format positive percentages with + sign", () => {
+ expect(formatPercent(5.25)).toBe("+5.25%");
+ expect(formatPercent(0.5)).toBe("+0.50%");
+ expect(formatPercent(100)).toBe("+100.00%");
+ });
+
+ it("should format negative percentages with - sign", () => {
+ expect(formatPercent(-2.5)).toBe("-2.50%");
+ expect(formatPercent(-0.66)).toBe("-0.66%");
+ expect(formatPercent(-50)).toBe("-50.00%");
+ });
+
+ it("should round to 2 decimal places", () => {
+ expect(formatPercent(5.256)).toBe("+5.26%");
+ expect(formatPercent(-2.554)).toBe("-2.55%");
+ });
+
+ it("should handle very small numbers", () => {
+ expect(formatPercent(0.001)).toBe("+0.00%");
+ expect(formatPercent(-0.009)).toBe("-0.01%");
+ });
+});
+
+describe("formatBigNumber", () => {
+ it("should format billions with B suffix", () => {
+ expect(formatBigNumber(1000000000)).toBe("$1.00B");
+ expect(formatBigNumber(1500000000)).toBe("$1.50B");
+ expect(formatBigNumber(27792181403)).toBe("$27.79B");
+ });
+
+ it("should format millions with M suffix", () => {
+ expect(formatBigNumber(1000000)).toBe("$1.00M");
+ expect(formatBigNumber(48029742)).toBe("$48.03M");
+
+ // 0.5M should be formatted as 500.00K
+ expect(formatBigNumber(500000)).toBe("$500.00K");
+ });
+
+ it("should format thousands with K suffix", () => {
+ expect(formatBigNumber(1000)).toBe("$1.00K");
+ expect(formatBigNumber(5500)).toBe("$5.50K");
+ expect(formatBigNumber(111394)).toBe("$111.39K");
+ });
+
+ it("should format small numbers without suffix", () => {
+ expect(formatBigNumber(0)).toBe("0.00");
+ expect(formatBigNumber(50)).toBe("50.00");
+ expect(formatBigNumber(999.99)).toBe("999.99");
+ });
+
+ it("should handle edge cases at boundaries", () => {
+ expect(formatBigNumber(999)).toBe("999.00");
+ expect(formatBigNumber(1000)).toBe("$1.00K");
+ expect(formatBigNumber(999999)).toBe("$1000.00K");
+ expect(formatBigNumber(1000000)).toBe("$1.00M");
+ expect(formatBigNumber(999999999)).toBe("$1000.00M");
+ expect(formatBigNumber(1000000000)).toBe("$1.00B");
+ });
+
+ it("should round to 2 decimal places", () => {
+ expect(formatBigNumber(1234567)).toBe("$1.23M");
+ expect(formatBigNumber(1236567)).toBe("$1.24M");
+ });
+});
diff --git a/app/utils/transaction.ts b/app/utils/transaction.ts
index 7164265..ec7f7bc 100644
--- a/app/utils/transaction.ts
+++ b/app/utils/transaction.ts
@@ -4,7 +4,7 @@ import { JupiterQuote } from "@/types/JupiterQuote";
export async function prepareSwapTransaction(
quote: JupiterQuote,
- publicKey: string
+ publicKey: string,
): Promise
{
const swapResponse = await fetch(
`${process.env.NEXT_PUBLIC_JUPITER_API_HOST}/swap
@@ -19,21 +19,21 @@ export async function prepareSwapTransaction(
dynamicComputeUnitLimit: true,
prioritizationFeeLamports: "auto",
}),
- }
+ },
);
if (!swapResponse.ok) throw new Error("Failed to build swap transaction");
const { swapTransaction } = await swapResponse.json();
return VersionedTransaction.deserialize(
- Buffer.from(swapTransaction, "base64")
+ Buffer.from(swapTransaction, "base64"),
);
}
export async function executeTransaction(
transaction: VersionedTransaction,
signTransaction: (tx: VersionedTransaction) => Promise,
- connection: Connection
+ connection: Connection,
): Promise {
const signed = await signTransaction(transaction);
@@ -44,12 +44,12 @@ export async function executeTransaction(
const confirmation = await connection.confirmTransaction(
signature,
- "finalized"
+ "finalized",
);
if (confirmation.value.err) {
throw new Error(
- `Transaction failed: ${JSON.stringify(confirmation.value.err)}`
+ `Transaction failed: ${JSON.stringify(confirmation.value.err)}`,
);
}
diff --git a/package-lock.json b/package-lock.json
index 0e04f8b..c308f75 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,6 +16,7 @@
"@tanstack/react-query": "^5.90.9",
"lightweight-charts": "^5.0.9",
"next": "16.0.3",
+ "prettier-plugin-tailwindcss": "^0.7.1",
"react": "19.2.0",
"react-dom": "19.2.0"
},
@@ -16539,6 +16540,100 @@
"node": ">= 0.8.0"
}
},
+ "node_modules/prettier": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz",
+ "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==",
+ "license": "MIT",
+ "peer": true,
+ "bin": {
+ "prettier": "bin/prettier.cjs"
+ },
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/prettier/prettier?sponsor=1"
+ }
+ },
+ "node_modules/prettier-plugin-tailwindcss": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.7.1.tgz",
+ "integrity": "sha512-Bzv1LZcuiR1Sk02iJTS1QzlFNp/o5l2p3xkopwOrbPmtMeh3fK9rVW5M3neBQzHq+kGKj/4LGQMTNcTH4NGPtQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=20.19"
+ },
+ "peerDependencies": {
+ "@ianvs/prettier-plugin-sort-imports": "*",
+ "@prettier/plugin-hermes": "*",
+ "@prettier/plugin-oxc": "*",
+ "@prettier/plugin-pug": "*",
+ "@shopify/prettier-plugin-liquid": "*",
+ "@trivago/prettier-plugin-sort-imports": "*",
+ "@zackad/prettier-plugin-twig": "*",
+ "prettier": "^3.0",
+ "prettier-plugin-astro": "*",
+ "prettier-plugin-css-order": "*",
+ "prettier-plugin-jsdoc": "*",
+ "prettier-plugin-marko": "*",
+ "prettier-plugin-multiline-arrays": "*",
+ "prettier-plugin-organize-attributes": "*",
+ "prettier-plugin-organize-imports": "*",
+ "prettier-plugin-sort-imports": "*",
+ "prettier-plugin-svelte": "*"
+ },
+ "peerDependenciesMeta": {
+ "@ianvs/prettier-plugin-sort-imports": {
+ "optional": true
+ },
+ "@prettier/plugin-hermes": {
+ "optional": true
+ },
+ "@prettier/plugin-oxc": {
+ "optional": true
+ },
+ "@prettier/plugin-pug": {
+ "optional": true
+ },
+ "@shopify/prettier-plugin-liquid": {
+ "optional": true
+ },
+ "@trivago/prettier-plugin-sort-imports": {
+ "optional": true
+ },
+ "@zackad/prettier-plugin-twig": {
+ "optional": true
+ },
+ "prettier-plugin-astro": {
+ "optional": true
+ },
+ "prettier-plugin-css-order": {
+ "optional": true
+ },
+ "prettier-plugin-jsdoc": {
+ "optional": true
+ },
+ "prettier-plugin-marko": {
+ "optional": true
+ },
+ "prettier-plugin-multiline-arrays": {
+ "optional": true
+ },
+ "prettier-plugin-organize-attributes": {
+ "optional": true
+ },
+ "prettier-plugin-organize-imports": {
+ "optional": true
+ },
+ "prettier-plugin-sort-imports": {
+ "optional": true
+ },
+ "prettier-plugin-svelte": {
+ "optional": true
+ }
+ }
+ },
"node_modules/pretty-format": {
"version": "29.7.0",
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz",
diff --git a/package.json b/package.json
index 9770372..64af0cb 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,7 @@
"@tanstack/react-query": "^5.90.9",
"lightweight-charts": "^5.0.9",
"next": "16.0.3",
+ "prettier-plugin-tailwindcss": "^0.7.1",
"react": "19.2.0",
"react-dom": "19.2.0"
},
diff --git a/vitest.config.ts b/vitest.config.ts
index 9750dd1..2602af8 100644
--- a/vitest.config.ts
+++ b/vitest.config.ts
@@ -15,4 +15,3 @@ export default defineConfig({
},
},
});
-