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

# useSyncOnChainTransfers

> Sync on-chain token transfers into the database. Discovers external receives not made through the SDK.

## Usage

```typescript theme={null}
const { syncTransfers, syncTransfersAsync, data, isLoading, isError, error, isSuccess, reset } =
  useSyncOnChainTransfers();
```

### Parameters

`syncTransfers` / `syncTransfersAsync` accept an object with:

| Parameter       | Type     | Required | Description                             |
| --------------- | -------- | -------- | --------------------------------------- |
| `walletAddress` | `string` | Yes      | Wallet public key to sync transfers for |
| `bearerToken`   | `string` | Yes      | Bearer token for authentication         |

### Return Value

| Property             | Type                                               | Description                    |
| -------------------- | -------------------------------------------------- | ------------------------------ |
| `syncTransfers`      | `(input) => void`                                  | Trigger sync (fire-and-forget) |
| `syncTransfersAsync` | `(input) => Promise<SyncOnChainTransfersResponse>` | Promise-based sync             |
| `data`               | `SyncOnChainTransfersResponse \| undefined`        | Sync result                    |
| `isLoading`          | `boolean`                                          | Whether sync is in progress    |
| `isError`            | `boolean`                                          | Whether an error occurred      |
| `error`              | `Error \| null`                                    | Error from last sync attempt   |
| `isSuccess`          | `boolean`                                          | Whether last sync succeeded    |
| `reset`              | `() => void`                                       | Reset mutation state           |

### SyncOnChainTransfersResponse

| Field    | Type     | Description                                    |
| -------- | -------- | ---------------------------------------------- |
| `synced` | `number` | New transactions discovered and saved to DB    |
| `total`  | `number` | Total transfers found on-chain for this wallet |

## Example Implementation

```typescript theme={null}
import { useState } from "react";
import { useAuth } from "@clerk/nextjs";
import {
  useSyncOnChainTransfers,
  useGetTransactionList,
} from "@chipi-stack/nextjs";

export function TransactionHistory({ wallet }: { wallet: { publicKey: string } }) {
  const { getToken } = useAuth();
  const { syncTransfersAsync, isLoading: isSyncing } = useSyncOnChainTransfers();
  const { data: txList, refetch } = useGetTransactionList({
    query: { walletAddress: wallet.publicKey },
    getBearerToken: getToken,
  });

  const handleSync = async () => {
    const token = await getToken();
    if (!token) return;

    // Discover external transfers (e.g., USDC received from Argent X)
    const result = await syncTransfersAsync({
      walletAddress: wallet.publicKey,
      bearerToken: token,
    });

    console.log(`Found ${result.synced} new transfers`);
    // Transaction list cache is automatically invalidated — refetch happens
  };

  return (
    <div>
      <button onClick={handleSync} disabled={isSyncing}>
        {isSyncing ? "Syncing..." : "Sync On-Chain Transfers"}
      </button>

      {txList?.data.map((tx) => (
        <div key={tx.id}>
          <span>{tx.subType === "receive" ? "Received" : "Sent"}</span>
          <span>{tx.amount} {tx.token}</span>
          <span>{tx.transactionHash.slice(0, 12)}...</span>
        </div>
      ))}
    </div>
  );
}
```

## How It Works

1. Calls `POST /transactions/sync-on-chain` on the backend
2. Backend queries Voyager API for all token transfers for the wallet
3. Compares with existing DB records by transaction hash
4. Saves new transfers to the `Transaction` table (read-through cache)
5. Returns `{ synced, total }`
6. Invalidates `useGetTransactionList` cache so new transfers appear immediately

After sync, `useGetTransactionList` returns both SDK-initiated transfers AND external receives.

## When to Use

* **On wallet load**: Sync once when user opens their wallet to discover any external receives
* **Pull-to-refresh**: Let users manually trigger sync
* **After receiving funds**: If user expects incoming funds from an external wallet

<Note>
  Synced transfers are cached in the database. Subsequent `useGetTransactionList` calls return them
  without re-querying Voyager.
</Note>

## Limitations

* Only discovers token transfers (ERC-20). Contract interactions without transfers are not synced.
* Voyager API rate limits apply. Avoid calling sync on every render.
* First sync for a wallet with many transfers may take a few seconds (paginated, max 500 transfers per sync).

## Related

* [useGetTransactionList](/sdk/nextjs/hooks/use-get-transaction-list) — Read the transaction list (includes synced transfers)
* [useGetTransaction](/sdk/nextjs/hooks/use-get-transaction) — Get a single transaction by hash
* [useGetTransactionStatus](/sdk/nextjs/hooks/use-get-transaction-status) — Poll transaction status
