> ## Documentation Index
> Fetch the complete documentation index at: https://docs.socket.fi/llms.txt
> Use this file to discover all available pages before exploring further.

# Transaction Lifecycle: From Request to Confirmation

> Understand every stage a SocketFi transaction passes through, from the initial requestTransaction() call to on-chain confirmation or failure.

When you call `requestTransaction()`, the SDK doesn't immediately fire a transaction at the network. Instead, the request passes through a carefully ordered lifecycle — validation, user approval, wallet authorization, policy enforcement, fee processing, network submission, and finally execution. Understanding this lifecycle helps you build accurate UI states, handle failures correctly, and set user expectations at each step.

## Transaction status type

Throughout the lifecycle, a transaction moves through the following status values:

```ts theme={null}
type TransactionStatus =
  | "requested"
  | "preparing"
  | "awaiting_approval"
  | "approved"
  | "authorized"
  | "submitting"
  | "submitted"
  | "executing"
  | "confirmed"
  | "rejected"
  | "failed";
```

A transaction can fail or be rejected at any stage. Only a transaction that reaches `confirmed` has executed successfully on-chain.

## The ten lifecycle stages

<Steps>
  <Step title="Requested">
    Your application calls `requestTransaction()`. The SDK receives the request and begins processing. The transaction exists in memory but hasn't been validated or constructed yet.

    ```ts theme={null}
    // This call initiates the lifecycle
    await socketfi.requestTransaction({
      contractId,
      method,
      args,
    });
    ```

    **Common failure at this stage:** Missing `contractId`, null `method`, or a malformed `args` array causes the SDK to throw synchronously before any network activity occurs.
  </Step>

  <Step title="Preparing">
    The SDK validates the request inputs, encodes the method arguments into Soroban XDR format, and constructs the transaction envelope. Fee estimation also begins here.

    Activities in this stage:

    * Input validation (contract address format, method name presence)
    * Argument type encoding
    * Transaction envelope construction
    * Initial fee quote request

    **Common failure at this stage:** An invalid contract address or unsupported argument type causes an immediate SDK-level error.
  </Step>

  <Step title="Awaiting Approval">
    The transaction is ready for review. The SocketFi approval UI is presented to the user, showing the action, any assets involved, the destination, and the estimated fee.

    The entire lifecycle pauses here until the user acts. Your UI should reflect this — disable form inputs, show a waiting indicator, and communicate that action is needed.

    **Common failure at this stage:** The user dismisses the approval popup, or the popup is blocked by the browser. Both produce an error with code `USER_CANCELLED` or `POPUP_BLOCKED`.
  </Step>

  <Step title="Approved">
    The user taps or clicks **Approve**. The SDK receives the approval signal and advances to wallet authorization. The transaction has now been explicitly consented to by the user.

    No on-chain activity has occurred yet.
  </Step>

  <Step title="Authorized">
    The smart wallet evaluates the approved transaction. This involves:

    * **Ownership verification** — confirming the requesting credential matches the wallet
    * **Passkey signature validation** — verifying the cryptographic proof from the user's device
    * **Policy evaluation** — checking spending limits, contract allowlists, and any other active wallet rules
    * **Nonce validation** — ensuring the transaction nonce is sequential and hasn't been used before

    If the wallet rejects at this stage, the transaction fails with `TRANSACTION_REJECTED`. The user approved, but the wallet's own policy or verification rules blocked execution.

    **Common failure at this stage:** Policy violation (e.g., spending limit exceeded), invalid signature, or nonce conflict.
  </Step>

  <Step title="Submitting">
    The authorized transaction is being sent to the Soroban network. The SDK signs the transaction envelope and submits it to the RPC endpoint.

    **Common failure at this stage:** Network connectivity issues, RPC endpoint unavailability, or timeouts cause submission failures. These are typically transient — a retry may succeed.
  </Step>

  <Step title="Submitted">
    The network has accepted the transaction and it is now pending execution in the ledger queue. A transaction hash is available at this point.

    <Note>
      Submitted does not mean confirmed. The transaction exists on the network, but the contract has not yet executed. State changes have not occurred.
    </Note>
  </Step>

  <Step title="Executing">
    The Soroban runtime is actively processing the contract invocation. The contract method is running, state changes are being computed, and any sub-calls or asset movements are being applied.

    **Common failure at this stage:** Contract-level errors (panics, assertion failures, insufficient balance within the contract), which cause the transaction to fail even though it was submitted successfully.
  </Step>

  <Step title="Confirmed">
    The transaction executed successfully and is finalized in a closed ledger. The requested action has taken effect on-chain — token balances have moved, protocol state has updated, or governance votes have been cast.

    ```ts theme={null}
    {
      success: true,
      transactionHash: "abc123..."
    }
    ```

    It is now safe to update your application state, refresh balances, and show the user a success confirmation.
  </Step>

  <Step title="Rejected or Failed">
    The transaction did not complete. `rejected` applies when the user explicitly declined the approval; `failed` applies to all other non-success outcomes (policy violation, contract error, network error, fee block).

    ```ts theme={null}
    {
      success: false
    }
    ```

    In both cases, **no on-chain state changed**. The user's balances, positions, and wallet state are exactly as they were before the request.
  </Step>
</Steps>

## TransactionResult structure

`requestTransaction()` resolves with this structure regardless of outcome:

```ts theme={null}
interface TransactionResult {
  success: boolean;
  transactionHash?: string; // Only present when success === true
}
```

Use `result.success` as your primary branch condition. Never assume success based on the promise resolving — catch both the resolved `false` case and thrown exceptions.

## Common failure points by stage

| Stage             | Common Failure                       | Recommended Response                                                   |
| ----------------- | ------------------------------------ | ---------------------------------------------------------------------- |
| Preparing         | Invalid contract address or args     | Validate inputs before calling `requestTransaction()`                  |
| Awaiting Approval | User cancels, popup blocked          | Silently reset to idle for cancellation; show guidance for popup block |
| Authorized        | Policy violation, invalid signature  | Surface a descriptive error; check wallet policies                     |
| Submitting        | Network error, RPC timeout           | Offer retry with a brief delay                                         |
| Executing         | Contract panic, insufficient balance | Show contract-level error message; don't auto-retry                    |

## React status state machine example

The following example tracks transaction status through the full lifecycle and renders appropriate UI at each stage:

```tsx theme={null}
type TxStatus = "idle" | "preparing" | "awaiting_approval" | "submitting" | "confirmed" | "rejected" | "failed";

function useTransaction() {
  const [status, setStatus] = useState<TxStatus>("idle");
  const [txHash, setTxHash] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);

  const execute = async (request: TransactionRequest) => {
    setStatus("preparing");
    setError(null);

    try {
      setStatus("awaiting_approval");

      const result = await socketfi.requestTransaction(request);

      if (result.success) {
        setTxHash(result.transactionHash ?? null);
        setStatus("confirmed");
      } else {
        setStatus("failed");
        setError("Transaction could not be completed.");
      }
    } catch (err) {
      if (err.code === "USER_CANCELLED") {
        setStatus("rejected");
      } else {
        setStatus("failed");
        setError(err.message ?? "An unexpected error occurred.");
      }
    }
  };

  return { status, txHash, error, execute };
}

function StatusMessage({ status }: { status: TxStatus }) {
  const messages: Record<TxStatus, string> = {
    idle: "",
    preparing: "Preparing transaction…",
    awaiting_approval: "Waiting for your approval…",
    submitting: "Submitting to the network…",
    confirmed: "Transaction confirmed!",
    rejected: "Transaction cancelled.",
    failed: "Transaction failed.",
  };

  return <p>{messages[status]}</p>;
}
```

## Security guarantees across the lifecycle

The transaction lifecycle is not just a UX concern — each stage provides a distinct security guarantee:

* **Approval stage** ensures users are never surprised by unauthorized actions
* **Authorization stage** ensures cryptographic proof of ownership before execution
* **Nonce validation** ensures each authorization can only be used once, preventing replay attacks
* **Policy enforcement** ensures wallet-level rules cannot be bypassed by the application layer
* **Time-bound authorizations** ensure stale or delayed requests are automatically rejected
