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

# Manage Policies

> Create, read, and remove wallet- and signer-layer policy rules for any embedded wallet.

> [!NOTE]
>
> Wallet and signer policy layers are in **early access**. [Talk to us](https://www.dynamic.xyz/talk-to-us) if you'd like to participate.

> [!NOTE]
>
> These helpers write legacy rules. A layer holds legacy rules or declarative rules, never both, and a write that would mix them is refused. To write [declarative rules](https://docs.dynamic.xyz/docs/embedded-wallets/mpc/policies/declarative-rules.md), which are in early access and must be enabled for your environment, see [Manage declarative rules](https://docs.dynamic.xyz/docs/embedded-wallets/mpc/policies/manage-policies-declarative.md) and [Rule examples](https://docs.dynamic.xyz/docs/embedded-wallets/mpc/policies/rule-examples.md).

These helpers work for any embedded wallet. A wallet's owner sets its wallet-layer rules, and a signer sets their own signer-layer rules. Business-account wallets add one more layer on top: see the [business accounts policies guide](https://docs.dynamic.xyz/docs/javascript/reference/business-accounts/policies/overview.md) for the account-layer helpers.

## Before you start

Before this: create and initialize a Dynamic client (see [Creating a Dynamic Client](https://docs.dynamic.xyz/docs/javascript/reference/client/create-dynamic-client.md), [Initializing the Dynamic Client](https://docs.dynamic.xyz/docs/javascript/reference/client/initialize-dynamic-client.md)).

The policy helpers are exported from `@dynamic-labs-sdk/client/waas`, and the matching React hooks are exported from `@dynamic-labs-sdk/react-hooks`.

## PolicyRules keys

`createPolicy` and `removePolicyRules` work with a `PolicyRules` map. Each key maps to at most one underlying `WaasPolicyRule`, so calling `createPolicy` again with the same key updates that rule in place instead of duplicating it.

| Key | Type | Description |
| - | - | - |
| `allowAddresses` | `string[]` | Only allow transactions that interact with these addresses. Combine with `maxAmountPerTransaction` to cap the same allow rule. |
| `denyAddresses` | `string[]` | Deny transactions that interact with these addresses. Independent of `allowAddresses`. |
| `blockExport` | `boolean` | When `true`, blocks exporting the wallet's private key. |
| `maxAmountPerTransaction` | `{ amount: string; asset?: string }` | Cap the value of a single transaction, in the asset's smallest unit. Omit `asset` to cap the chain's native asset. |
| `approvalRequirements` | `PolicyApprovalRequirement[]` | Require approvals before a business-account wallet signs. See [Quorum policies](https://docs.dynamic.xyz/docs/javascript/reference/business-accounts/policies/quorum-policies.md). |
| `names` | `object` | Set a custom name for each rule kind. Keys are `allowAddresses`, `blockExport`, `denyAddresses`, `maxAmountPerTransaction`, and `approvalRequirements`. |

For the raw fields these keys produce, see [Rule fields](https://docs.dynamic.xyz/docs/embedded-wallets/mpc/policies/overview.md#rule-fields).

## Create or update rules

`createPolicy` writes a `PolicyRules` map to a layer in one batch. The `scope` object decides which layer is updated: `{ walletId }` for the wallet layer, or `{ shareSetId }` for the caller's own signer layer.

### Wallet-Layer

Use `scope: { walletId }`, where `walletId` is the wallet's `verifiedCredentialId`. Only the wallet owner can set this layer.

> [tab] JavaScript
>
> ```javascript theme={"system"}
> import { createPolicy } from '@dynamic-labs-sdk/client/waas';
> import { WaasChainEnum } from '@dynamic-labs/sdk-api-core';
>
> const walletId = walletAccount.verifiedCredentialId;
>
> const layer = await createPolicy({
>   scope: { walletId },
>   chain: WaasChainEnum.Evm,
>   chainIds: [1],
>   rules: {
>     allowAddresses: ['0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'],
>     maxAmountPerTransaction: { amount: '100000000000' }, // 100 USDC
>   },
> });
> ```

> [tab] React
>
> ```tsx theme={"system"}
> import { useCreatePolicy } from '@dynamic-labs-sdk/react-hooks';
> import { WaasChainEnum } from '@dynamic-labs/sdk-api-core';
>
> const SaveWalletPolicy = ({ walletId }: { walletId: string }) => {
>   const { mutate: createPolicy, isPending } = useCreatePolicy();
>
>   return (
>     <button
>       onClick={() =>
>         createPolicy({
>           scope: { walletId },
>           chain: WaasChainEnum.Evm,
>           chainIds: [1],
>           rules: {
>             allowAddresses: ['0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48'],
>             maxAmountPerTransaction: { amount: '100000000000' },
>           },
>         })
>       }
>       disabled={isPending}
>     >
>       Save wallet policy
>     </button>
>   );
> };
> ```

### Signer-Layer

Use `scope: { shareSetId }` to set rules for the caller's own signer. A wallet account has one own share set that signs transactions, and it can also have other active share sets, such as delegated access.

> [tab] JavaScript
>
> ```javascript theme={"system"}
> import { createPolicy } from '@dynamic-labs-sdk/client/waas';
> import { WaasChainEnum } from '@dynamic-labs/sdk-api-core';
>
> const layer = await createPolicy({
>   scope: { shareSetId: walletAccount.shareSetId },
>   chain: WaasChainEnum.Evm,
>   chainIds: [1],
>   rules: { blockExport: true },
> });
> ```

> [tab] React
>
> ```tsx theme={"system"}
> import { useCreatePolicy } from '@dynamic-labs-sdk/react-hooks';
> import { WaasChainEnum } from '@dynamic-labs/sdk-api-core';
>
> const BlockExport = ({ shareSetId }: { shareSetId: string }) => {
>   const { mutate: createPolicy, isPending } = useCreatePolicy();
>
>   return (
>     <button
>       onClick={() =>
>         createPolicy({
>           scope: { shareSetId },
>           chain: WaasChainEnum.Evm,
>           chainIds: [1],
>           rules: { blockExport: true },
>         })
>       }
>       disabled={isPending}
>     >
>       Block key export
>     </button>
>   );
> };
> ```

> [!NOTE]
>
> A `shareSetId` is the current identifier for a signer. It rotates when the wallet shares are refreshed or reshared, so do not store it. Re-read `walletAccount.shareSetId` before each update.

## Read rules

`getPolicy` fetches a layer and converts the underlying rules back into a `PolicyRules` map. Rules with fields that `PolicyRules` does not include go into `unmapped`, so they are never silently dropped.

> [tab] JavaScript
>
> ```javascript theme={"system"}
> import { getPolicy } from '@dynamic-labs-sdk/client/waas';
> import { WaasChainEnum } from '@dynamic-labs/sdk-api-core';
>
> const { rules, unmapped } = await getPolicy({
>   scope: { walletId },
>   chain: WaasChainEnum.Evm,
> });
>
> // rules.allowAddresses, rules.maxAmountPerTransaction, etc.
> ```

> [tab] React
>
> ```tsx theme={"system"}
> import { useGetPolicy } from '@dynamic-labs-sdk/react-hooks';
> import { WaasChainEnum } from '@dynamic-labs/sdk-api-core';
>
> const WalletPolicy = ({ walletId }: { walletId: string }) => {
>   const { data: policy, isLoading } = useGetPolicy({
>     scope: { walletId },
>     chain: WaasChainEnum.Evm,
>   });
>
>   if (isLoading) return null;
>
>   return <pre>{JSON.stringify(policy?.rules, null, 2)}</pre>;
> };
> ```

## Remove rules

`removePolicyRules` removes the rules for one or more `PolicyRules` keys in one batch. Pass the keys to remove in the `rules` array.

> [tab] JavaScript
>
> ```javascript theme={"system"}
> import { removePolicyRules } from '@dynamic-labs-sdk/client/waas';
> import { WaasChainEnum } from '@dynamic-labs/sdk-api-core';
>
> const layer = await removePolicyRules({
>   scope: { walletId },
>   chain: WaasChainEnum.Evm,
>   chainIds: [1],
>   rules: ['maxAmountPerTransaction'],
> });
> ```

> [tab] React
>
> ```tsx theme={"system"}
> import { useRemovePolicyRules } from '@dynamic-labs-sdk/react-hooks';
> import { WaasChainEnum } from '@dynamic-labs/sdk-api-core';
>
> const RemoveCap = ({ walletId }: { walletId: string }) => {
>   const { mutate: removeRules, isPending } = useRemovePolicyRules();
>
>   return (
>     <button
>       onClick={() =>
>         removeRules({
>           scope: { walletId },
>           chain: WaasChainEnum.Evm,
>           chainIds: [1],
>           rules: ['maxAmountPerTransaction'],
>         })
>       }
>       disabled={isPending}
>     >
>       Remove cap
>     </button>
>   );
> };
> ```

## Who can update a rule

| Caller | Can update these layers |
| - | - |
| Wallet owner | Their wallet and signer layers |
| Signer | Their own signer layer |

Business accounts extend this: an owner or admin can also manage every wallet and signer in the account, plus an account-wide layer that applies to all of them. See [business account policies](https://docs.dynamic.xyz/docs/javascript/reference/business-accounts/policies/overview.md).

## Next steps

> [card] [Policy Layers](https://docs.dynamic.xyz/docs/embedded-wallets/mpc/policies/policy-layers.md)
>
> How environment, wallet, and signer rules combine.

> [card] [Business account policies](https://docs.dynamic.xyz/docs/javascript/reference/business-accounts/policies/overview.md)
>
> The extra account-layer rule for business-account wallets.


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