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

# External deposit building blocks

Use these methods for sponsored, custom-wallet, or queue-backed transaction
flows where your integration submits the transfer itself.

Authenticate the same SDK instance with `connectAccount()` first. On a first
deposit, call setup before you submit the transfer; after the transfer, call
[`logDeposit`](/docs/sdk/api/log-deposit) with the transaction hash.

## Complete lifecycle

1. Authenticate with `connectAccount()` on the same SDK instance.
2. Run `ensureFirstDepositSetup()` before a first-deposit transfer.
3. Build ERC-20 calldata with `buildDepositTransfer()`.
4. Submit that calldata through your wallet, relayer, or transaction service,
   then wait for its on-chain receipt.
5. Register the confirmed transaction with `logDeposit()`.
6. Use `getDepositStatus()` for a one-off lifecycle check, or
   `waitForDepositCredit()` to wait until it is credited and investable.

`logDeposit()` can return `handover_pending`. Do not treat the deposit as
investable until its status is `credited` and `balanceCredited` is `true`. A
`recovered_to_eoa` status is terminal: the funds were returned to the EOA and
must not be registered or transferred again without checking the transaction
and lifecycle state first.

## `ensureFirstDepositSetup`

Idempotently configures protocols and chains for a first deposit. It does
nothing after the USDC profile has chains configured.

When setup runs, it throws if protocol configuration cannot be persisted (for
example API or pool lookup failures). Treat errors as blocking: do not submit
a transfer until setup succeeds or returns `{ applied: false }` because the
account was already configured.

```typescript theme={null}
ensureFirstDepositSetup(strategy?: Strategy): Promise<{ applied: boolean }>
```

## `buildDepositTransfer`

Resolves the user's Safe and returns standard ERC-20 `transfer` calldata.

```typescript theme={null}
buildDepositTransfer({
  userAddress: string;
  chainId: SupportedChainId;
  amount: string;
  asset: SupportedAsset;
}): Promise<{
  safeAddress: Address;
  tokenAddress: Address;
  to: Address;
  data: Hex;
  value: "0";
}>
```

## Example

```typescript theme={null}
await sdk.connectAccount(walletProvider, 8453);

await sdk.ensureFirstDepositSetup("conservative");
const transaction = await sdk.buildDepositTransfer({
  userAddress,
  chainId: 8453,
  amount: "100000000", // 100 USDC
  asset: "USDC",
});

const txHash = await transactionService.send({
  to: transaction.to,
  data: transaction.data,
});

const registration = await sdk.logDeposit(
  8453,
  txHash,
  "100000000",
  transaction.tokenAddress,
);

if (registration.deposit.status === "handover_pending") {
  // Optional one-off check for UI status or recovery handling.
  const status = await sdk.getDepositStatus(registration.deposit.id);
  console.log("Deposit status:", status.status);

  // Or wait until the deposit is investable.
  const credited = await sdk.waitForDepositCredit(registration.deposit.id, 8453);
  console.log("Deposit credited:", credited.id);
}
```

## Lifecycle helpers

| Helper                                                          | Use it when                                         | Result                                                       |
| --------------------------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------ |
| [`logDeposit`](/docs/sdk/api/log-deposit)                       | You have a confirmed external transfer hash         | Registers it and returns the initial lifecycle record        |
| [`getDepositStatus`](/docs/sdk/api/get-deposit-status)          | A UI or recovery flow needs one current state check | `handover_pending`, `credited`, or `recovered_to_eoa`        |
| [`waitForDepositCredit`](/docs/sdk/api/wait-for-deposit-credit) | The flow should pause until funds are investable    | Resolves only when `credited` and `balanceCredited` are true |
