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

# User-owned execution

> Use wallet-scoped authorization with zero builder attribution and no shared builder relayer allowance.

User-owned execution is an optional trading mode for platforms whose users
should operate with credentials bound to their own signing wallets. Orders
carry zero builder attribution, and gasless wallet operations do not consume
the platform's shared builder relayer allowance.

<Note>
  Use TypeScript `polynode-sdk >= 0.14.2`, Python `polynode >= 0.14.1`, or Rust
  `polynode >= 0.17.1` with its `trading` feature. Wallet authorization requires
  an eligible paid Polynode plan and a valid `pn_live_...` API key. It is included
  in the supported SDK flow; there is no separate add-on or additional service
  URL to configure.
</Note>

Builder mode remains the default. Existing applications do not change until
they explicitly select `user_owned`.

## What changes

|                                   | `builder` (default)         | `user_owned`                           |
| --------------------------------- | --------------------------- | -------------------------------------- |
| Order attribution                 | Configured builder code     | Always zero                            |
| Gasless authorization             | Builder path                | Credential owned by the signing wallet |
| Shared builder relayer allowance  | Used by eligible operations | Not used                               |
| Builder credentials               | Supported                   | Rejected                               |
| Positive Polynode application fee | Optional                    | Rejected                               |
| First-use ownership signature     | Existing builder flow       | Required per signing wallet            |

User-owned mode removes the shared builder allowance from these operations. It
does not remove wallet balances, market rules, order API limits, or ordinary
rate limits, and it should not be presented as universally unlimited trading.

<Warning>
  Choose the execution mode before an operation begins. Never submit in builder
  mode, catch a limit or timeout, and silently replay the same intent as
  user-owned. Ask the user to opt in and complete wallet authorization first.
</Warning>

## Which integration should I use?

<CardGroup cols={2}>
  <Card title="Web application" icon="browser" href="/sdks/user-owned-web-app">
    Connect an injected wallet, authorize it, choose browser memory or an
    encrypted backend vault, and place an actual user-owned order.
  </Card>

  <Card title="Service signer" icon="key">
    Keep using `ensureReady` / `ensure_ready` with your HSM, MPC wallet, Privy
    server wallet, or controlled private-key signer.
  </Card>
</CardGroup>

For a normal multi-user platform, use the
[complete web-app guide](/sdks/user-owned-web-app). It includes the exact
Connect Wallet UX, sensitive-value table, same-origin routes, versioned vault
bundle, browser signing request, atomic one-time storage, three backend SDK
examples, canonical pre-submit order identity, exact-hash timeout
reconciliation, and security checklist.

## Credential meanings

User-owned execution uses distinct credentials for distinct purposes:

| Credential                            | Scope                             | What it can do                                      | Where to keep it                                              |
| ------------------------------------- | --------------------------------- | --------------------------------------------------- | ------------------------------------------------------------- |
| Polynode API key                      | Platform                          | Access eligible SDK services                        | Backend environment or secret manager only                    |
| Wallet-owned relayer credential       | One controlling EOA               | Authorize gasless activity for that wallet          | Encrypted backend vault; optional current-tab memory          |
| Order API key, secret, and passphrase | One trading identity              | Authenticate order and account requests             | Encrypted backend vault; optional current-tab memory          |
| Wallet signer                         | User or controlled service wallet | Sign ownership messages, orders, and wallet actions | Wallet, HSM, or MPC system; never a Polynode credential store |

The wallet-owned relayer credential is not a private key and cannot sign an
order or transfer funds by itself. It is still sensitive. Never log it, commit
it, put it in a URL, or share it across wallets.

Treat the controlling EOA as the isolation key. One user must never inherit
another user's trader, challenge, wallet-owned credential, order credentials,
prepared order, or result.

## Supported account types

* **Deposit wallet (`3`)** is the default for a new V2 user-owned browser or
  service-signer setup. The controlling EOA signs; the deposit wallet holds
  collateral and positions.
* **Existing Safe (`2`)** remains supported when it is the account identity
  already associated with that user. Do not switch an existing user to a
  different deterministic account merely because both addresses exist.
* **EOA (`0`)** can place orders directly. Initial approvals are on-chain
  transactions and require gas from that EOA.
* **Legacy proxy/Magic (`1`)** is rejected in user-owned mode.

Gasless split, merge, wrap, and unwrap operations require the appropriate
EOA-controlled smart-wallet account. A plain EOA is never silently routed
through another derived wallet.

Readiness deploys or verifies the selected account and its permissions. It does
not create collateral. Fund the returned funder address before a BUY.

## Service-signer setup

Use this model when your existing platform signer can produce both
personal-message and EIP-712 signatures. The SDK obtains the wallet-scoped
authorization during readiness and keeps it in memory. Save the returned
credential in your own encrypted store if the process must restore it later.

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    import { PolyNodeTrader } from 'polynode-sdk';

    const signer = process.env.POLYGON_PRIVATE_KEY;
    if (!signer) throw new Error('Set POLYGON_PRIVATE_KEY');

    const trader = new PolyNodeTrader({
      polynodeKey: process.env.POLYNODE_API_KEY!,
      executionMode: 'user_owned',
      exchangeVersion: 'v2',
    });

    const status = await trader.ensureReady(signer);
    console.log(status.wallet);
    console.log(status.funderAddress);
    console.log(status.userRelayerAuthorized); // true

    const result = await trader.order({
      tokenId: '...',
      side: 'BUY',
      price: 0.50,
      size: 5,
      type: 'GTC',
      postOnly: true,
    });

    trader.close();
    ```

    Use `authorizeUserOwnedExecution(signer)` when you need only the authorization
    result instead of full readiness.
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import os
    from polynode.trading import (
        ExecutionMode,
        OrderParams,
        PolyNodeTrader,
        TraderConfig,
    )

    trader = PolyNodeTrader(TraderConfig(
        polynode_key=os.environ["POLYNODE_API_KEY"],
        execution_mode=ExecutionMode.USER_OWNED,
    ))

    status = await trader.ensure_ready(os.environ["POLYGON_PRIVATE_KEY"])
    print(status.wallet)
    print(status.funder_address)
    print(status.user_relayer_authorized)  # True

    result = await trader.order(OrderParams(
        token_id="...",
        side="BUY",
        price=0.50,
        size=5,
        type="GTC",
        post_only=True,
    ))

    trader.close()
    ```

    Use `authorize_user_owned_execution(signer)` when you need only the
    authorization result. A caller-controlled `RouterSigner` may implement async
    `get_address()`, `sign_message()`, and `sign_typed_data()` instead of exposing
    a raw private key.
  </Tab>

  <Tab title="Rust">
    ```rust,no_run theme={null}
    use polynode::trading::{
        ExecutionMode, OrderParams, OrderSide, PolyNodeTrader, PrivateKeySigner,
        TraderConfig,
    };

    # async fn example() -> polynode::Result<()> {
    let signer = PrivateKeySigner::from_hex(
        &std::env::var("POLYGON_PRIVATE_KEY").unwrap(),
    )?;
    let mut trader = PolyNodeTrader::new(TraderConfig {
        polynode_key: std::env::var("POLYNODE_API_KEY").unwrap(),
        execution_mode: ExecutionMode::UserOwned,
        ..Default::default()
    })?;

    let status = trader.ensure_ready(Box::new(signer), None).await?;
    assert!(status.user_relayer_authorized);

    let result = trader.order(OrderParams {
        token_id: "...".into(),
        side: OrderSide::Buy,
        price: 0.50,
        size: 5.0,
        post_only: true,
        ..Default::default()
    }).await?;

    trader.close();
    # Ok(())
    # }
    ```

    Use `authorize_user_owned_execution(&signer)` when you need only the
    authorization result. A custom `TradingSigner` can delegate signing to an HSM
    or MPC wallet.
  </Tab>
</Tabs>

## Restore a wallet-owned credential

For a returning service signer, load only the credential saved for the active
wallet and pass it in the trader configuration. The SDK revalidates its owner
before any user-owned operation.

<Tabs>
  <Tab title="TypeScript">
    ```typescript theme={null}
    const trader = new PolyNodeTrader({
      polynodeKey: process.env.POLYNODE_API_KEY!,
      executionMode: 'user_owned',
      userRelayerCredentials: encryptedVaultRecord.userRelayerCredentials,
    });
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    trader = PolyNodeTrader(TraderConfig(
        polynode_key=os.environ["POLYNODE_API_KEY"],
        execution_mode=ExecutionMode.USER_OWNED,
        user_relayer_credentials=encrypted_vault_record.user_relayer_credentials,
    ))
    ```
  </Tab>

  <Tab title="Rust">
    ```rust theme={null}
    let trader = PolyNodeTrader::new(TraderConfig {
        polynode_key,
        execution_mode: ExecutionMode::UserOwned,
        user_relayer_credentials: Some(encrypted_vault_record.user_relayer_credentials),
        ..Default::default()
    })?;
    ```
  </Tab>
</Tabs>

The wallet-owned credential alone does not restore order API credentials or a
signer. Restore all three from the same wallet record or use the versioned
bundle flow in the web-app guide.

## Order and position behavior

User-owned mode enforces these invariants before signing or submission:

* V2 order builder attribution is exactly zero.
* Builder credentials and builder authentication are absent.
* A positive Polynode fee configuration is rejected.
* The relayer credential owner, controlling EOA, funder, account type, and
  active order credentials must describe one wallet identity.
* There is no automatic transport or attribution fallback.

`split`, `merge`, `convert`, wrap, and unwrap retain their wallet-specific
requirements. See [Trading and fees](/sdks/trading) for funding and position
methods. Use the [web-app guide](/sdks/user-owned-web-app) when the user's
injected wallet signs an order while your backend retains credentials.

## Network path

User-owned order traffic uses the SDK's direct transport by default. Approved
integrations may explicitly choose Polynode regional egress:

| SDK        | Explicit setting                                                   |
| ---------- | ------------------------------------------------------------------ |
| TypeScript | `userOwnedClobTransport: 'polynode_proxy'`                         |
| Python     | `user_owned_clob_transport=UserOwnedClobTransport.PROXY`           |
| Rust       | `user_owned_clob_transport: UserOwnedClobTransport::PolynodeProxy` |

The selected path is fixed for each request and never falls back automatically.
Regional egress changes the network path only; it does not add builder
attribution or wallet custody.

## Security checklist

1. Enable user-owned mode only after the user explicitly opts in.
2. Keep the Polynode API key on the backend.
3. Bind every credential and prepared operation to one expected controlling
   EOA.
4. Keep wallet-owned and order API credentials in an encrypted per-wallet
   vault, or explicitly accept the browser-memory risks.
5. Never log challenges, credentials, API secrets, passphrases, or signatures.
6. Do not configure builder credentials, nonzero builder attribution, or a
   positive Polynode fee on this trader.
7. Confirm the returned account type and funder before funding it.
8. Reconcile an ambiguous order result instead of retrying a signed intent.
9. Close traders and browser sessions when their request, worker job, or login
   session ends.

## Common errors

| Error                                              | Meaning                                                                                                                                                                                                                                                               |
| -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `invalid or missing X-Polynode-Key` / HTTP 401     | The backend did not send a valid current Polynode API key. Check its environment value; never move it to the frontend. If that key works on normal API calls but this error persists, contact Polynode support to check key synchronization for wallet authorization. |
| HTTP 403 during wallet authorization               | The key or plan is not eligible for user-owned authorization. Use an eligible paid plan; no separate add-on is required.                                                                                                                                              |
| `builder credentials are forbidden`                | Remove builder credentials from this trader.                                                                                                                                                                                                                          |
| `builderCode must be null or zero`                 | Remove the builder override. User-owned mode forces zero attribution.                                                                                                                                                                                                 |
| `credential does not belong to the signing wallet` | Load the credential stored for the active EOA, not another user.                                                                                                                                                                                                      |
| `does not support legacy POLY_PROXY/Magic wallets` | Keep that account on its supported path; user-owned mode accepts EOA, existing Safe, and deposit-wallet identities.                                                                                                                                                   |
| `fee ... unavailable in user_owned mode`           | Remove the positive Polynode fee configuration.                                                                                                                                                                                                                       |
| `insufficient ... collateral`                      | Fund the returned funder address, then create a new order request.                                                                                                                                                                                                    |
| `call ensureReady() first`                         | Complete wallet authorization and readiness before the operation.                                                                                                                                                                                                     |
