diff --git a/app/src/app/api/bridge/status/route.ts b/app/src/app/api/bridge/status/route.ts index 118caaae..8b1cfe5a 100644 --- a/app/src/app/api/bridge/status/route.ts +++ b/app/src/app/api/bridge/status/route.ts @@ -1,6 +1,7 @@ import { rateLimited } from "@/lib/launchpad/editServer"; import { BRIDGE_PRIVATE_HEADERS, bridgeErrorResponse, getBridgeStatus } from "@/lib/bridge/relay"; import { BridgeApiError } from "@/lib/bridge/validation"; +import { getCctpStatus, parseCctpStatusRequest } from "@/lib/bridge/cctp-server"; export const dynamic = "force-dynamic"; export const runtime = "nodejs"; @@ -10,6 +11,8 @@ export async function GET(req: Request) { if (rateLimited(`bridge:status:ip:${ip}`, 100)) return bridgeErrorResponse(new BridgeApiError("Too many status requests. Please wait a moment.", 429)); try { const params = new URL(req.url).searchParams; + // A Circle burn is found by its source transaction and checked against the wallet, amount and route it was for. + if (params.has("provider")) return Response.json(await getCctpStatus(parseCctpStatusRequest(params)), { headers: BRIDGE_PRIVATE_HEADERS }); if (params.size !== 1 || !params.has("requestId")) throw new BridgeApiError("Invalid bridge request ID.", 400); return Response.json(await getBridgeStatus(params.get("requestId")!), { headers: BRIDGE_PRIVATE_HEADERS }); } catch (error) { return bridgeErrorResponse(error); } diff --git a/app/src/app/bridge/page.tsx b/app/src/app/bridge/page.tsx index 8954436d..1112c28c 100644 --- a/app/src/app/bridge/page.tsx +++ b/app/src/app/bridge/page.tsx @@ -57,7 +57,8 @@ export default async function BridgePage({ searchParams }: { searchParams: Promi
Development-only synthetic data. No wallet requests, API calls, or funds.
Base offers ETH and USDC. Arc uses USDC. Robinhood offers ETH; its USDC routes currently fail our safety checks. USDC sends use an exact-amount approval.
+{outputAmount(b.quote.amountOut)}
{needsRefresh ? "This quote expired. Refresh and review the new amounts." : "0.5% slippage limit. Arrival time and gas can change."}
- {b.approvalRequired ?First, approve only {nativeAmount(b.amount)} {inputCurrency.symbol} for Relay’s deposit contract. Then review a fresh quote and confirm the bridge separately. Approval alone does not move your funds and uses additional {origin.symbol} for gas.
: null} +{needsRefresh ? "This quote expired. Refresh and review the new amounts." : circle ? "Circle takes one fixed fee, so this is the exact amount you receive. Arrival time and gas can change." : "0.5% slippage limit. Arrival time and gas can change."}
+ {b.approvalRequired ?First, approve only {nativeAmount(b.amount)} {inputCurrency.symbol} for {circle ? "Circle’s transfer contract" : "Relay’s deposit contract"}. Then review a fresh quote and confirm the bridge separately. Approval alone does not move your funds and uses additional {origin.symbol} for gas.
: null} ) : b.quoteRejection ?Keep some {origin.symbol} on {origin.name} for gas. {convertsAsset ? "Relay converts the asset at the quoted rate. " : ""}Bridging uses Relay, a third-party protocol, and carries risk. Openlaunch does not operate Relay, holds no funds in transit, and is not responsible for delays, refunds or losses. {erc20Input ? `An unspent ${inputCurrency.symbol} approval remains until used or revoked.` : "No token approvals required."}
+Keep some {origin.symbol} on {origin.name} for gas. {convertsAsset ? "Relay converts the asset at the quoted rate. " : ""}Bridging uses {provider}, a third-party protocol, and carries risk. Openlaunch does not operate {provider}, holds no funds in transit, and is not responsible for delays, refunds or losses. {erc20Input ? `An unspent ${inputCurrency.symbol} approval remains until used or revoked.` : "No token approvals required."}
); } @@ -347,7 +354,7 @@ function ApprovalProgress({ bridge: b }: { bridge: Bridge }) {No bridge deposit has been requested. An approval permits Relay’s deposit contract to use up to this amount; it does not bridge it.
+No bridge deposit has been requested. An approval permits {approval.spender.toLowerCase() === CCTP_APPROVAL_SPENDER ? "Circle’s transfer contract" : "Relay’s deposit contract"} to use up to this amount; it does not bridge it.
{b.approvalError || b.storageError ?Relay has not seen a deposit for this transfer and nothing is confirmed on {origin.name}. If your wallet shows the transaction as dropped or cancelled, you can discard this record and start over. Keep the Transfer ID below in case you need Relay support.
+{provider} has not seen a deposit for this transfer and nothing is confirmed on {origin.name}. If your wallet shows the transaction as dropped or cancelled, you can discard this record and start over.{circle ? "" : " Keep the Transfer ID below in case you need Relay support."}
Transfer ID {transfer.requestId}
+ {circle ? null :Transfer ID {transfer.requestId}
}