Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@ GRAPH_API_KEY=
# The Graph API key (required for leaderboard deposits - get from https://thegraph.com/studio/)
GRAPH_API_KEY=your-graph-api-key
# SwapKit API key (required for BTC deposits/withdrawals - get from https://docs.swapkit.dev/)
SWAPKIT_API_KEY=
SWAPKIT_API_KEY=
# Integration test config (gas sponsorship investigation)
TEST_PRIVATE_KEY=
RUN_MAINNET_INTEGRATION=
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"test:coverage": "vitest run --coverage",
"test:e2e": "playwright test",
"test:e2e:ui": "playwright test --ui",
"test": "vitest run && pnpm run test:e2e"
"test": "vitest run && pnpm run test:e2e",
"test:integration": "vitest run --config vitest.integration.config.ts"
},
"dependencies": {
"@heroicons/react": "^2.2.0",
Expand Down
6 changes: 3 additions & 3 deletions src/components/wallet/LoanSimulator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -212,8 +212,8 @@ export default function LoanSimulator({ mode = "borrow", collateralType = "WBTC"
// Simulator state - store input as string (empty for placeholder to show)
const [inputValue, setInputValue] = useState(mode === "borrow" ? String(currentBorrowedAmount) : "");

// Sandbox mode - custom collateral input (empty string allows placeholder to show)
const [sandboxCollateral, setSandboxCollateral] = useState("");
// Sandbox mode - custom collateral input (default "1" so slider is usable on load)
const [sandboxCollateral, setSandboxCollateral] = useState("1");

// Sandbox mode - custom collateral price (empty string uses live API price)
const [sandboxCollateralPrice, setSandboxCollateralPrice] = useState("");
Expand Down Expand Up @@ -398,7 +398,7 @@ export default function LoanSimulator({ mode = "borrow", collateralType = "WBTC"
const handleReset = useCallback(() => {
setInputValue(mode === "borrow" ? String(currentBorrowedAmount) : "");
if (mode === "simulate") {
setSandboxCollateral("");
setSandboxCollateral("1");
setSandboxCollateralPrice("");
}
}, [mode, currentBorrowedAmount]);
Expand Down
25 changes: 4 additions & 21 deletions src/providers/Web3Provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import {
http,
} from "viem";
import { arbitrum, mainnet } from "viem/chains";
import { boostGasFees } from "@/lib/web3/gasBoost";
// Gas boost removed — external wallets (Rabby, MetaMask, Fireblocks) handle their own gas estimation.
// Passing gas overrides through Privy's sendTransaction causes "Unknown connector error".

declare global {
interface Window {
Expand Down Expand Up @@ -389,25 +390,6 @@ export const Web3Provider: React.FC<{ children: React.ReactNode }> = ({

console.log("[TX] Sending transaction to:", params.to, "chain:", targetChainId);

// Boost gas fees by 1.5x only for Ethereum mainnet (Fluid/XAUT) — keeps Arbitrum txs untouched
const isEthereumMainnet = targetChainId === mainnet.id;
let gasOverrides: { type?: number; maxFeePerGas?: bigint; maxPriorityFeePerGas?: bigint } = {};
if (isEthereumMainnet) {
const targetClient = getPublicClient(targetChainId);
const boostedGas = await boostGasFees(targetClient);
if (boostedGas.maxFeePerGas) {
console.log("[TX] Boosted gas fees (Ethereum mainnet):", {
maxFeePerGas: boostedGas.maxFeePerGas.toString(),
maxPriorityFeePerGas: boostedGas.maxPriorityFeePerGas?.toString(),
});
gasOverrides = {
type: 2,
maxFeePerGas: boostedGas.maxFeePerGas,
maxPriorityFeePerGas: boostedGas.maxPriorityFeePerGas,
};
}
}

// Check if this is an embedded wallet (supports gas sponsorship)
const isEmbeddedWallet = activeWallet.walletClientType === "privy";

Expand Down Expand Up @@ -443,13 +425,14 @@ export const Web3Provider: React.FC<{ children: React.ReactNode }> = ({
// For external wallets, use Privy's sendTransaction without sponsorship
// Privy will show the transaction prompt where user can pay their own gas
console.log("[TX] Using regular transaction (external wallet)");
// External wallets (Rabby, MetaMask, Fireblocks) handle their own gas estimation.
// Do NOT pass gas overrides through Privy — it causes "Unknown connector error".
const txReceipt = await privySendTransaction(
{
to: params.to,
data: params.data,
value: params.value ? BigInt(params.value) : undefined,
chainId: targetChainId,
...gasOverrides,
},
{
// No sponsorship for external wallets - user pays gas
Expand Down
4 changes: 2 additions & 2 deletions src/providers/developerMode.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ export function DeveloperModeProvider({ children }: { children: React.ReactNode
const [developerMode, setDeveloperModeState] = useState<boolean>(() => {
try {
const raw = localStorage.getItem(STORAGE_KEY);
return raw == null ? true : raw === "true";
return raw == null ? false : raw === "true";
} catch {
return true;
return false;
}
});

Expand Down
73 changes: 45 additions & 28 deletions test/components/wallet/LoanSimulator.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -578,42 +578,59 @@ describe("SimulatorGauge Component", () => {

describe("LoanSimulator Collateral Input - Simulate Mode", () => {
/**
* Tests for collateral input behavior in simulate mode
* The collateral input should use a placeholder "0" instead of an actual value
* so when users tap the field, it's empty and ready for input
* Tests for collateral input behavior in simulate mode.
*
* Implementation details (LoanSimulator.tsx):
* - sandboxCollateral state should initialize to "" (empty string)
* - Input has placeholder="0" which shows when value is empty
* - handleReset should set sandboxCollateral to "" (not "0")
* The collateral input defaults to "1" so the borrow slider is usable
* immediately on page load (maxBorrow > 0 when collateral > 0).
*
* Note: Full component tests pending due to jsdom compatibility.
* Component behavior is verified via E2E tests.
* Implementation details (LoanSimulator.tsx):
* - sandboxCollateral state initializes to "1"
* - handleReset resets sandboxCollateral to "1"
* - This applies to both WBTC and XAUT collateral types
*/

it("should have empty initial value for sandbox collateral input", () => {
// sandboxCollateral state initializes to "" (empty string)
// This allows placeholder "0" to display instead of actual "0" value
// User can start typing immediately without needing to clear the field
expect(true).toBe(true);
});

it("should show placeholder '0' when collateral input is empty", () => {
// The input element has placeholder="0" attribute
// When value is empty string, browser displays placeholder
expect(true).toBe(true);
it("should default sandboxCollateral to '1' so slider is enabled on load", async () => {
const fs = await import("fs");
const path = await import("path");
const componentPath = path.resolve(
process.cwd(),
"src/components/wallet/LoanSimulator.tsx"
);
const componentCode = fs.readFileSync(componentPath, "utf-8");
// sandboxCollateral must initialize to "1" (not "" or "0")
// so parsedSandboxCollateral > 0 and maxBorrow > 0 on first render
const sandboxCollateralInit = componentCode.match(
/\[sandboxCollateral,\s*setSandboxCollateral\]\s*=\s*useState\s*\(([^)]+)\)/
);
expect(sandboxCollateralInit).not.toBeNull();
expect(sandboxCollateralInit![1].trim()).toBe('"1"');
});

it("should allow user to type value directly without clearing '0' first", () => {
// Since value starts as "" (not "0"), user typing "0.5" results in "0.5"
// Previously, value was "0" so typing "0.5" would result in "00.5"
expect(true).toBe(true);
it("should reset sandboxCollateral to '1' on reset (not empty string)", async () => {
const fs = await import("fs");
const path = await import("path");
const componentPath = path.resolve(
process.cwd(),
"src/components/wallet/LoanSimulator.tsx"
);
const componentCode = fs.readFileSync(componentPath, "utf-8");
// handleReset should set sandboxCollateral back to "1"
// so the slider remains usable after reset
expect(componentCode).toContain('setSandboxCollateral("1")');
});

it("should reset collateral input to empty string on reset", () => {
// handleReset sets sandboxCollateral to "" (not "0")
// This maintains consistent UX where placeholder shows after reset
expect(true).toBe(true);
it("should enable borrow slider when default collateral is set", async () => {
const fs = await import("fs");
const path = await import("path");
const componentPath = path.resolve(
process.cwd(),
"src/components/wallet/LoanSimulator.tsx"
);
const componentCode = fs.readFileSync(componentPath, "utf-8");
// maxBorrow calculation: collateralUsd = parsedSandboxCollateral * price
// With sandboxCollateral="1", parsedSandboxCollateral=1, so maxBorrow > 0
// The slider disabled condition checks maxBorrow <= 0
expect(componentCode).toMatch(/disabled=\{maxBorrow\s*<=\s*0\}/);
});
});

Expand Down
Loading
Loading