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

# guardedSubmit

> Dry-run a transaction, record a policy denial without spending gas, and submit only when allowed.

A denied action aborts on-chain and emits no event, so a chain indexer never sees it. `guardedSubmit` makes denials visible: it dry-runs the transaction first, and on a policy abort it records the denial and returns without submitting — no gas burned. An allowed transaction submits for real and the chain event indexes it.

```ts theme={null}
guardedSubmit(client, exec, sender, tx, audit): Promise<{ ok: boolean; digest?: string; reason_code?: string }>
```

| Arg      | Type                          | Notes                                                         |
| -------- | ----------------------------- | ------------------------------------------------------------- |
| `client` | `SuiJsonRpcClient`            | Used for the `devInspect` dry-run.                            |
| `exec`   | `(tx) => Promise<{ digest }>` | Submits on allow (e.g. `keypairExecutor`).                    |
| `sender` | `string`                      | The agent address (dry-run sender).                           |
| `tx`     | `Transaction`                 | A built PTB, e.g. from `buildSwap`.                           |
| `audit`  | `GuardAudit`                  | `{ baseUrl, token, agent_id, action_type, amount?, asset? }`. |

```ts theme={null}
import { buildSwap, keypairExecutor, guardedSubmit } from "@altheia-xyz/sui";

const r = await guardedSubmit(
  client,
  keypairExecutor(client, kp),
  agentAddr,
  buildSwap(refs, 50_000_000n),
  { baseUrl, token, agent_id, action_type: "deepbook_swap", amount: 0.05, asset: "SUI" },
);

if (r.ok) console.log("allowed", r.digest);
else console.log("denied", r.reason_code); // e.g. "over_per_tx_cap"
```

## What it does

1. `devInspectTransactionBlock` to dry-run the PTB as `sender`.
2. `dryRunResult` classifies the effects. On success, submit via `exec`.
3. On a **policy** abort, post a `denied` audit row with the decoded reason and return `{ ok: false, reason_code }`. The transaction is never submitted.
4. On a **non-policy** failure (DeepBook liquidity, gas), return `{ ok: false }` with no `reason_code` and no audit row. That is not a policy decision; surface it rather than recording a denial.

The audit post is best-effort and never blocks trading. A failed post is swallowed.

## `dryRunResult`

```ts theme={null}
dryRunResult(res): { ok: boolean; abort?: { code: number; reason_code: string; message: string } }
```

Pure classifier. Reads `effects.status`; on failure decodes the policy abort. Use it when you run `devInspect` yourself and want to branch on the outcome without submitting.

<Note>
  A swap that passes the dry-run is a **policy decision**, not a guaranteed fill. The agent submits a gated DeepBook order; on a thin testnet book it may fill zero. `ok: true` means the policy permitted the action and the transaction landed.
</Note>

<Card title="Reads and decodePolicyAbort" icon="arrow-right" href="/sdk/reads" horizontal>
  Read live state from chain and map abort codes to reasons.
</Card>
