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

# Owner Controls

> Reclaim DUSDC and on-chain Pause/Resume. Owner-gated by Move.

The owner of a TradeAgent has four on-chain actions, all gated by `AgentOwnerCap` (Move-level) or by the server's `ownerAddress` check (hosted-fleet endpoints). Surfaced as the `OwnerControls` block on `/agents` and `/agents/:agentId`.

## Reclaim (hosted fleet)

The hosted fleet agent owns a PredictManager whose owner is the agent's ephemeral key. The user can't sign `predict_manager::withdraw` from their wallet directly. Instead:

```http theme={"system"}
POST /v1/agents/:id/reclaim
  -> { ok: true, txDigest, amount: <micro> }
```

Server decrypts the agent key, signs `predict_manager::withdraw_all<DUSDC>`, and transfers the resulting coin to the **fixed `ownerAddress` from the `agent_runtime` row**. The recipient is never user-supplied. the agent can only reclaim to its registered owner.

Frontend wiring:

```typescript theme={"system"}
// OwnerControls Reclaim button
const res = await fetch(`/v1/agents/${agentId}/reclaim`, { method: 'POST' });
if (!res.ok) throw new Error(await res.text());
const { txDigest, amount } = await res.json();
```

Demo line: "your funds, your keys. The agent never had the right to keep them."

## Reclaim (CLI / single-agent path)

For a TradeAgent registered via `pnpm agent:register`, the owner withdraws from the BalanceManager directly. `balance_manager::withdraw_all<DUSDC>` is owner-gated by Move:

```typescript theme={"system"}
const tx = new Transaction();
const [coin] = tx.moveCall({
  target: `${DEEPBOOK_PACKAGE_ID}::balance_manager::withdraw_all`,
  typeArguments: [DUSDC_TYPE],
  arguments: [tx.object(balanceManagerId)],
});
tx.transferObjects([coin], tx.pure.address(ownerAddress));
```

Renders only when `account.address === agent.owner`. Reads the BalanceManager id via `sui.getObject(TradeAgent)` (field `balance_manager_id`).

## Fund (hosted fleet)

Owner signs a `predict_manager::deposit<DUSDC>` PTB from their wallet (sponsored), then the frontend POSTs `/v1/agents/:id/sweep` so the deposited coin lands inside the agent's PredictManager via a server-signed sweep call. Two-step is required because Predict's `deposit` asserts `sender == manager.owner` and the manager is owned by the agent's ephemeral key.

```typescript theme={"system"}
// Step 1: user signs deposit + transferObjects to agent address (sponsored)
const tx = buildDepositToPredictManagerPTB({ /* user wallet */ });
const { digest } = await signer.sign(tx);

// Step 2: server sweeps the deposited coin into the manager
await fetch(`/v1/agents/${agentId}/sweep`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ txDigest: digest }),
});
```

`POST /v1/agents/:id/sweep` updates `last_funded_ms` so the auto-disable rule (3-day idle + \< \$1 PM balance) doesn't fire.

## Pause / Resume

```move theme={"system"}
public fun pause(agent: &mut TradeAgent, cap: &AgentOwnerCap);
public fun resume(agent: &mut TradeAgent, cap: &AgentOwnerCap);
```

Both abort with `ENotOwner` if `cap.agent_id != object::id(agent)`.

<Warning>
  Neither emits an event. The server `paused` column in the `agents` table is stale. The frontend `OwnerControls` and the fleet runtime's tick guard both read `is_active` live via `sui.getObject(TradeAgent)`. Do not rely on the API field.
</Warning>

Frontend wiring:

```typescript theme={"system"}
// Discover the user's AgentOwnerCap matching this agent
const caps = await sui.getOwnedObjects({
  owner: account.address,
  filter: { StructType: `${DARKPOOL_PACKAGE_ID}::agent::AgentOwnerCap` },
  options: { showContent: true },
});
const ownerCap = caps.data.find(c =>
  (c.data?.content as any)?.fields?.agent_id === agentId
);
if (!ownerCap) throw new Error('not the owner');

const tx = new Transaction();
tx.moveCall({
  target: `${DARKPOOL_PACKAGE_ID}::agent::pause`,
  arguments: [tx.object(agentId), tx.object(ownerCap.data.objectId)],
});
```

Header on `/agents/:agentId` always surfaces an **ACTIVE** (green) or **PAUSED on-chain** (warn) pill so the state is never ambiguous.

## Runtime gate

Both the legacy single-agent runtime and the hosted fleet read `is_active` at the start of every tick:

```text theme={"system"}
[fleet] tick agent 0xabc… (Mid-ITM BTC Agent)
  paused on-chain by owner. skipping (x7)
```

Defensive default = active so transient RPC hiccups don't silently halt the agent.

## Three kinds of "off"

1. **Pause on-chain.** Owner signs `agent::pause`. Runtime keeps polling but never trades. Reversible.
2. **Reclaim DUSDC.** Owner POSTs `/v1/agents/:id/reclaim` (hosted) or signs `balance_manager::withdraw_all` (CLI). Funds back in wallet.
3. **Auto-disable.** Server flips `enabled=false` if PM balance \< \$1 for > 3 days. Fleet stops ticking. Owner can reclaim, then either fund + reactivate or leave it dead.
