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

# Dust sweep

> Split USDC 80/20, swap only the larger portion, and sweep the unused remainder back to the sender.

<Tip>
  **Featured for Wallets.** Recover unused balances automatically. Canonical wallet-cleanup pattern.
</Tip>

## Scenario

A user wants to swap 80% of a USDC balance to USDT but deliberately leave the remaining 20% untouched. In compose terms this is a `core.split` where only one of the two output handles is bound to a downstream node — the other is left dangling. Dangling resources stay on the per-signer proxy contract at the end of execution; `sweepTo` tells the backend to transfer them back to the sender (or any specified address) so nothing is stranded.

This recipe is the canonical shape for **dust recovery** — any pattern where part of an input is intentionally unused and must not be left on the proxy.

## What this recipe demonstrates

* `core.split` with `bps: 8000` (80/20) and only one of the two output handles bound downstream.
* Implicit dust tracking — the unbound handle (`b`) never becomes an input to another op; the compiler treats its balance as a terminal residual resource.
* `sweepTo: builder.context.sender` returns **all** residual balances to the sender at the end of the transaction, including the deliberately unused 20%.
* A minimal two-node flow: one split, one swap.

## Full example

Adapted from [`dustSweep.ts`](https://github.com/lifinance/composer-sdk-examples/blob/main/examples/dustSweep.ts) in the `composer-sdk-examples` repo.

```ts theme={"system"}
import {
  createComposeSdk,
  materialisers,
  resources,
} from '@lifi/composer-sdk';

const USDC = '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48';
const USDT = '0xdAC17F958D2ee523a2206206994597C13D831ec7';

const sdk = createComposeSdk({ baseUrl: 'https://composer.li.quest' });

const builder = sdk.flow(1, {
  name: 'dust-sweep',
  inputs: {
    amountIn: resources.erc20(USDC, 1),
  },
});

// Split USDC 80/20.
// Only the 80% portion (`a`) is consumed by the swap.
// The 20% portion (`b`) is intentionally left unbound — it stays on
// the proxy as dust and gets swept back to the sender.
const { a } = builder.core.split('split', {
  bind: { source: builder.inputs.amountIn },
  config: { bps: 8000 },
});

// Swap only the 80% portion to USDT.
builder.lifi.swap('swap', {
  bind: { amountIn: a },
  config: {
    resourceOut: resources.erc20(USDT, 1),
    slippage: 0.03,
  },
});

// sweepTo ensures the unused 20% USDC is transferred back to the
// sender rather than being stranded on the proxy.
// See /composer/composer-api/concepts/sweeping-and-amounts for the full semantics.
const result = await builder.compile({
  signer: '0xYourSignerAddress',
  inputs: {
    amountIn: materialisers.directDeposit({ amount: '10000000' }), // 10 USDC
  },
  sweepTo: builder.context.sender,
});
```

## What to observe

* **Inputs.** One resource input (`amountIn: USDC`).
* **Nodes.** Two: `core.split` then `lifi.swap`. Only `split.a` is referenced — `split.b` is never consumed.
* **Dangling handle.** Destructuring `const { a } = builder.core.split(...)` quietly drops `b` from the TypeScript side; on the wire, `split` still declares both outputs and the compiler knows `b` is unused.
* **Terminal resources.** Two: the swapped USDT (the intentional output) **and** the unused USDC from `split.b` (the dust). Both are swept to the sender by `sweepTo`.
* **`sweepTo` shape.** `request.run.sweepTo === { $ref: 'context.sender' }` when you pass `builder.context.sender`. You can also pass a literal address string, as in the `swap-to-recipient` recipe.
* **`producedResources[<name>].simulated?.amountOut`.** `producedResources` on the `ComposeCompileResult` lists both the USDT (from the swap) and the residual USDC amounts.
