> ## 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 reads the wallet's ERC-20 `Transfer` events from Starknet (USDC, USDT, ETH and STRK), newest blocks first, then older history back to the wallet's creation
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, and the backend remembers which blocks it already
> read for each wallet. Subsequent calls only read new blocks.

## Limitations

* Only discovers USDC, USDT, ETH and STRK transfers. USDC.e and WBTC use an older event format that cannot be filtered by wallet, so they are not synced. Contract interactions without transfers are not synced either.
* One transaction is stored once, even if it moves several tokens.
* The first sync of an old wallet reads its history over several calls (each call has a time budget); new transfers show up on the first call. Avoid calling sync on every render.

## 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


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.