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

# Starknet

> Verify a Starknet call array before the account executes it.

`venue`: `starknet`. There are no aliases.

## What to send

The calls the account will execute in one multicall, as `{calls: [{contractAddress, entrypoint, calldata}]}`. Over HTTP a bare array of calls also works; over MCP, `action` must be an object, so use `{calls: [...]}`. `calldata` is an array of felt strings. It is detected without `venue` when every item has a hex `contractAddress` and a string `entrypoint`.

`actionType` is the entrypoints joined with `+`, for example `approve+swap`.

## How calls are decoded

| Call | Result | `actionFamily` |
| - | - | - |
| `transfer`, `transferFrom` or `transfer_from` on a known token | Recipient and exact u256 amount in token units | `transfer` |
| `approve` on a known token | Spender and amount. An allowance of u128::MAX or more is flagged as unlimited. | `permission` |
| `increase_allowance` or `increaseAllowance` on a known token | Spender and amount, flagged because it adds to the existing allowance and the new total is not visible | `permission` |
| An entrypoint that changes who controls an account: `upgrade`, `change_owner`, `add_owner`, `remove_owner`, `change_guardian`, `change_guardian_backup`, `set_guardian`, `trigger_escape_owner`, `trigger_escape_guardian`, `escape_owner`, `escape_guardian`, `set_public_key`, `replace_class`, `register_session`, `revoke_session` | Flagged as a custody change that moves no tokens | `permission` |
| A STRK20 privacy pool call (see below) | Declared intent, or no decode | `transfer` or `unknown` |
| Any other call | Entrypoint, contract and calldata length, flagged as unverified from calldata | `unknown` |

The known tokens are the mainnet contracts of STRK, ETH, USDC, USDC.e and USDT:

| Token | Address | Decimals |
| - | - | - |
| STRK | `0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d` | 18 |
| ETH | `0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7` | 18 |
| USDC | `0x033068f6539f8e6e6b131e6b2b814e6c34a5224bc66947c47dab9dfee93b35fb` | 6 |
| USDC.e | `0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8` | 6 |
| USDT | `0x068f5c6a61780768455de69077e07e89787839bf8166decfbf92b645209c0fb8` | 6 |

For a batch, the family is the riskiest call's: `unknown` if any call is unknown, otherwise `permission` if any call grants authority, otherwise `transfer`.

## STRK20 private operations

Calls to the STRK20 privacy pool (mainnet `0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a`, Sepolia `0x0254a6b2997ef52e9f830ce1f543f6b29768295e8d17e2267d672c552cfe0d91`) carry a zero-knowledge proof, so tokens and amounts cannot be read from the calldata.

* `apply_actions`, `compile_actions` and `execute_writes` are value-moving pool calls. The payload may carry a `strk20` object that declares what the call does: `{action: "shield" | "unshield" | "private-transfer" | "private-swap", token, amount, toToken, minReceived, recipient, venue}`. With it, the call is classified `transfer` and summarized from the declaration, which the judge is told is the client's claim and not checked against the proof. Without it, the call is classified `unknown`.
* `grant_role`, `revoke_role`, `set_open_note_screening_policy`, `set_auditor_public_key` and `set_screener_public_key` are pool administration, classified `permission` and flagged as never part of a user's transfer. Any other pool entrypoint is `unknown`.
* Calls to the anonymizer contracts (AVNU PrivacySwapHelper, the Ekubo swap anonymizer, the Endur deposit anonymizer and the Privacy Bridge in both directions) are classified `transfer`. For swaps, a note says the trade size is visible on chain: a private swap unlinks the wallet from the trade but does not hide the amount.
* A declared shield also notes that a third-party screener signs deposits and can refuse one.

Escrow proposals (`escrow_execute` and `POST /api/v1/wallets/{id}/propose`) pass only the calls, with no `strk20` declaration, so pool calls made from an escrow wallet are classified `unknown`. See [Starknet](/starknet) for escrow wallets and private balances.

## No live lookup

The adapter reads only the calldata. Escrow proposals on Starknet are also simulated with `starknet_simulateTransactions`, which supplies balance changes and events.

## Example

```ts theme={null}
const action = {
  calls: [
    {
      contractAddress: "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d", // STRK
      entrypoint: "transfer",
      // recipient, amount low, amount high: 10 STRK
      calldata: ["0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", "0x8ac7230489e80000", "0x0"],
    },
  ],
};

const res = await fetch("https://harness.chance.cc/api/v1/intent", {
  method: "POST",
  headers: { "x-api-key": process.env.CHANCE_API_KEY!, "Content-Type": "application/json" },
  body: JSON.stringify({
    intent: "Pay the design contractor in STRK, at most 50 STRK per payment.",
    venue: "starknet",
    action,
  }),
});
const result = await res.json();
if (result.verdict !== "ALLOW") throw new Error(result.reasoning ?? result.error);
// Only now execute the calls from the account.
```

The classifier's summary is `Transfer 10 STRK to 0x0123…cdef`, with `actionType: "transfer"` in the `transfer` family.

## From an MCP client

Instruct the agent to call `verify_intent` before executing any Starknet calls, with your rules as `intent`, `{ "calls": [...] }` as `action` and `venue: "starknet"`, and to act only on ALLOW.
