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

# MPC Wallets

> Restrict what an MPC wallet can do on Derive

Most MPC services (Fordefi, Fireblocks, and similar) can permission over three types of actions:

* **Smart contract calls** — which contract, which function, and often which argument values.
  Fordefi expresses these as
  [ABI conditions](https://docs.fordefi.com/user-guide/policies/policy-rules-conditions-and-actions#abi),
  matching on `address`, integer, boolean, `bytes`, array, and tuple arguments.
* **Personal messages** (`personal_sign`, e.g. EIP-191) — see
  [personal messages and messages on non-EVM chains](https://docs.fordefi.com/user-guide/policies/message-policy#personal-messages-and-messages-on-non-evm-chains).
* **Typed data** (EIP-712) — see
  [typed data messages](https://docs.fordefi.com/user-guide/policies/message-policy#typed-data-messages), where you can deny signatures that match certain fields of the EIP-712 domain or message.

Derive uses all three paths for different purposes:

| Path | Medium | Scheme | Reaches |
| - | - | - | - |
| [`OnchainActionManager`](/getting-started/contracts) | Onchain | transaction | deposit, withdraw, add/remove session keys |
| [Signed actions](/authentication/action-signing) | HTTP / WS | EIP-712 | all of the above, **and trading** |
| [Session login](/authentication/session-login) | HTTP / WS | EIP-191 | **read-only** — authenticates an HTTP request or WebSocket connection |

Because the EIP-712 path can do strictly more than the contract-call path, the tightest setup is
to close it entirely and operate through contract calls only.

## Recommended policy

<Steps>
  <Step title="Block all EIP-712 signing on the MPC wallet">
    Every state-changing Derive action taken over the API is an EIP-712 signed action. Denying
    EIP-712 outright means the MPC wallet can never trade, transfer, or withdraw through the
    API — no allow-list to maintain and no new action type can slip through later.

    In Fordefi this is a [typed data message](https://docs.fordefi.com/user-guide/policies/message-policy#typed-data-messages)
    rule. Fordefi surfaces an EIP-712 message's **recipient as its `verifyingContract`**, so target
    the rule at Derive's action domain:

    | Domain field | Value |
    | - | - |
    | `name` | `Matching` |
    | `version` | `1.0` |
    | `verifyingContract` | `0xeB8d770ec18DB98Db922E9D83260A585b9F0DeAD` |
    | `chainId` | the settlement chain's id — the only field that varies by network |

    Every Derive signed action uses this same `verifyingContract` on every network, so one deny
    rule on that address covers mainnet and testnet alike.
  </Step>

  <Step title="Whitelist deposits">
    On `OnchainActionManager`, allow the two deposit entrypoints:

    ```solidity theme={null}
    function deposit(address asset, uint256 amount, uint64 subaccountId, address fallbackRecipient);
    function depositToNewSubaccount(address asset, uint256 amount, uint32 managerId, address owner);
    ```

    Pin `owner` and `fallbackRecipient` to the MPC wallet address. `owner` is what makes the MPC
    wallet the account owner; `fallbackRecipient` is where a deposit lands if it cannot be applied
    to its intended subaccount.
  </Step>

  <Step title="Whitelist session-key registration, with the scopes pinned">
    Session keys are registered from L1 through the generic entrypoint:

    ```solidity theme={null}
    function submit(uint256 actionType, bytes calldata data)
    ```

    ### Example (trade and withdraw only session key)

    In this example we're going to create a policy that will only allow your MPC wallet to create Session keys with the `trade:orderbook:perp` and `withdraw` protocol scopes. Because only `admin` scoped keys can withdraw to any recipient, this policy will only allow withdrawals to the MPC wallet's own subaccounts.

    Use the TypeScript SDK's
    [session-key codec](https://github.com/derivexyz/derive-ts/blob/master/src/codecs/sessionKey.ts),
    to produce the bytes you'll use to create an MPC policy.

    ```typescript theme={null}
    import { encodeSetSessionKeyActionData } from '@derivexyz/derive-ts/codecs';
    import { ProtocolScopeCode } from '@derivexyz/derive-ts';
    import { Interface } from 'ethers';

    const data = encodeSetSessionKeyActionData({
      sessionKey: '0x9f000000000000000000000000000000000000be',
      expirySec: 1793491200, // the KEY's lifetime; 0 deletes it
      // Exactly two scopes, in this order — the policy pins both.
      scopes: [ProtocolScopeCode.Withdraw, ProtocolScopeCode.TradeOrderbookPerp], // [1, 5]
      subaccountIds: [], // empty = all current and future subaccounts
    });

    const manager = new Interface([
      'function submit(uint256 actionType, bytes data) payable returns (uint256)',
    ]);
    // 51 = Set Session Key. `data` is the 256 bytes broken down below.
    console.log(manager.encodeFunctionData('submit', [51, data]));
    ```

    ### Which bytes to pin in your MPC policy

    | Param | Contents | Pin to |
    | - | - | - |
    | `actionType` | Set Session Key action type | `51` |
    | `data[0:32]` | `sessionKey` address | free — rotates |
    | `data[32:64]` | `expirySec` | free — rotates |
    | `data[64:96]` | offset → `scopes` | from console.log |
    | `data[96:128]` | offset → `subaccountIds` | from console.log |
    | `data[128:160]` | `scopes.length` | from console.log |
    | `data[160:192]` | `scopes[0]` = `withdraw` | from console.log |
    | `data[192:224]` | `scopes[1]` = `trade:orderbook:perp` | from console.log |
    | `data[224:256]` | `subaccountIds.length` = all | from console.log |

    You can modify what you pin depending on your needs.
  </Step>
</Steps>

<Note>
  Leave [personal messages (EIP191)](https://docs.fordefi.com/user-guide/policies/message-policy#personal-messages-and-messages-on-non-evm-chains)
  allowed so [session login](/authentication/session-login) keeps working and the MPC wallet retains
  read-only account access through UX and API.
</Note>

## Related

<CardGroup cols={2}>
  <Card title="Access scopes" icon="lock" href="/authentication/access-scopes">
    The full protocol and off-chain scope catalog.
  </Card>

  <Card title="Session keys" icon="key" href="/authentication/session-keys">
    What a session key is and how its lifecycle works.
  </Card>

  <Card title="Withdrawals" icon="money-bill-transfer" href="/trading/transfers-withdrawals">
    The withdrawal action and its recipient semantics.
  </Card>
</CardGroup>


## Related topics

- [Contracts](/getting-started/contracts.md)
- [Wallet rfqs](/api-reference/channels/walletrfqs.md)
- [public/get_wallets_from_session_key](/api-reference/session-keys/publicget_wallets_from_session_key.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.