Transaction status
On Arc, a transaction is final in under a second, and CrackPay waits for it before answering. So the lifecycle in your app is short:
| State | When | Show |
|---|---|---|
idle | Before the user acts | Your button |
waiting | The call is pending: CrackPay is showing its confirmation, then sending | A disabled button with progress |
done | The call resolved with a hash | Success. It is final. |
cancelled | Rejected with 4001 | "Cancelled." |
failed | Rejected with anything else | "The payment didn't go through." |
type Status = "idle" | "waiting" | "done" | "cancelled" | "failed";
async function pay() {
setStatus("waiting");
try {
const hash = await walletClient.writeContract(request);
setReceipt(hash);
setStatus("done");
} catch (error) {
console.error(error);
setStatus(isUserRejection(error) ? "cancelled" : "failed");
}
}
No polling
You do not need waitForTransactionReceipt or confirmation counts: when the call
resolves, the transaction is already final. If you want the receipt for its
events, fetch it once:
const receipt = await publicClient.getTransactionReceipt({ hash });
Its from is a bundler and its to is the ERC-4337 EntryPoint; your contract's
events are in logs.
Linking to the explorer
// `chain` from connectCrackPay(), or getArcChain(await provider.request({ method: "eth_chainId" }))
const url = `${chain.explorerUrl}/tx/${hash}`;