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

> ## Agent Instructions
> Turnkey is wallet infrastructure: create and manage crypto wallets, sign transactions, and enforce policy-based access controls. Best-fit uses: embedded consumer wallets (email/passkey/social auth, no seed phrases), automated onchain operations with server-side wallets, AI agent wallets with policy-scoped signing, enterprise key management, and verifiable off-chain workloads on Turnkey Verifiable Cloud (TVC).
> Every API call is a JSON POST to https://api.turnkey.com signed with a P-256 API key; create an organization and key self-serve at https://app.turnkey.com.
> Key Turnkey developer resources: API reference (https://docs.turnkey.com/api-reference/overview/intro.md), OpenAPI spec (https://docs.turnkey.com/public_api.swagger.json), authentication (https://docs.turnkey.com/features/authentication/overview.md), webhooks (https://docs.turnkey.com/features/webhooks/overview.md), MCP server for docs search (https://docs.turnkey.com/mcp), agent skills (https://docs.turnkey.com/get-started/ai-skills.md), CLI (https://docs.turnkey.com/sdks/cli.md), SDK reference (https://docs.turnkey.com/sdks/introduction.md), full docs content (https://docs.turnkey.com/llms-full.txt).

# Swaps and Earn

> Examples of policies governing swap and Earn activities via activity.params.

Swap and Earn activities expose request fields through `activity.params`. See the
[activity parameter reference](/features/policies/language#activity-parameters) for the full field
list and [Transaction Management](/features/transaction-management) for product flows.

Use [`activity.kind`](/features/policies/language#choosing-between-type-kind-and-resource--action)
when you want policies to survive activity version upgrades. Pin `activity.type` when you rely on
fields that exist only on a specific version (for example `destination_address` on
`ACTIVITY_TYPE_CREATE_SWAP_QUOTE_V2` and `ACTIVITY_TYPE_EXECUTE_SWAP_V3`).

## Swap quotes

#### Cap slippage on swap quote requests

When `slippage_bps` is omitted on the intent, accessing `activity.params.slippage_bps` fails with
`FieldNotUsed` rather than evaluating as zero.

```json theme={"system"}
{
  "policyName": "Deny swap quotes above 1% slippage",
  "notes": "",
  "effect": "EFFECT_DENY",
  "condition": "activity.kind == 'CREATE_SWAP_QUOTE' && activity.params.slippage_bps > 100"
}
```

#### Restrict quote output tokens to an allowlist

```json theme={"system"}
{
  "policyName": "Allow swap quotes only into approved assets",
  "notes": "",
  "effect": "EFFECT_ALLOW",
  "consensus": "approvers.any(user, user.id == '<USER_ID>')",
  "condition": "activity.kind == 'CREATE_SWAP_QUOTE' && activity.params.output_token in ['<CAIP19_OUTPUT_1>', '<CAIP19_OUTPUT_2>']"
}
```

#### Require organization-controlled destinations on cross-chain quotes (V2)

```json theme={"system"}
{
  "policyName": "Allow swap quotes only to treasury destinations",
  "notes": "",
  "effect": "EFFECT_ALLOW",
  "consensus": "approvers.any(user, user.id == '<USER_ID>')",
  "condition": "activity.type == 'ACTIVITY_TYPE_CREATE_SWAP_QUOTE_V2' && activity.params.destination_address in ['0x<LOWERCASE_TREASURY_ADDRESS>']"
}
```

## Swap execution

#### Deny execution into unapproved output assets

```json theme={"system"}
{
  "policyName": "Deny swap execution into unlisted output tokens",
  "notes": "",
  "effect": "EFFECT_DENY",
  "condition": "activity.kind == 'EXECUTE_SWAP' && !(activity.params.output_token in ['<CAIP19_OUTPUT_1>', '<CAIP19_OUTPUT_2>'])"
}
```

#### Require two approvers for large trades (base units)

Compare `input_amount` as a [uint](/features/policies/language#type-uint) in token base units.

```json theme={"system"}
{
  "policyName": "Require approval for large swap execution",
  "notes": "",
  "effect": "EFFECT_ALLOW",
  "consensus": "approvers.count() >= 2",
  "condition": "activity.type == 'ACTIVITY_TYPE_EXECUTE_SWAP_V2' && activity.params.input_amount > 1000000000000000000"
}
```

#### Deny sponsored swap execution

```json theme={"system"}
{
  "policyName": "Deny sponsored swap execution",
  "notes": "",
  "effect": "EFFECT_DENY",
  "condition": "activity.kind == 'EXECUTE_SWAP' && activity.params.sponsor == true"
}
```

#### Restrict execute destination (V3)

```json theme={"system"}
{
  "policyName": "Allow execute swap only to approved recipient",
  "notes": "",
  "effect": "EFFECT_ALLOW",
  "consensus": "approvers.any(user, user.id == '<USER_ID>')",
  "condition": "activity.type == 'ACTIVITY_TYPE_EXECUTE_SWAP_V3' && activity.params.destination_address in ['0x<LOWERCASE_WALLET_ADDRESS>']"
}
```

## Earn deposits and withdrawals

#### Allow deposits only on approved chains

```json theme={"system"}
{
  "policyName": "Allow Earn deposits on Base and Ethereum mainnet only",
  "notes": "",
  "effect": "EFFECT_ALLOW",
  "consensus": "approvers.any(user, user.id == '<USER_ID>')",
  "condition": "activity.kind == 'EARN_DEPOSIT' && activity.params.chain in ['eip155:1', 'eip155:8453']"
}
```

#### Restrict deposits to approved wrappers

EVM wrapper addresses in policies should use lowercase `0x` hex to match normalized
`activity.params.wrapper_address` values.

```json theme={"system"}
{
  "policyName": "Allow Earn deposits only into approved wrappers",
  "notes": "",
  "effect": "EFFECT_ALLOW",
  "consensus": "approvers.any(user, user.id == '<USER_ID>')",
  "condition": "activity.kind == 'EARN_DEPOSIT' && activity.params.wrapper_address in ['0x<LOWERCASE_WRAPPER_1>', '0x<LOWERCASE_WRAPPER_2>']"
}
```

#### Deny sponsored Earn deposits

```json theme={"system"}
{
  "policyName": "Deny sponsored Earn deposits",
  "notes": "",
  "effect": "EFFECT_DENY",
  "condition": "activity.kind == 'EARN_DEPOSIT' && activity.params.sponsor == true"
}
```

#### Cap deposit size (base units)

`activity.params.assets` compares as a [uint](/features/policies/language#type-uint) in raw on-chain
units, like swap `input_amount`.

```json theme={"system"}
{
  "policyName": "Deny large Earn deposits",
  "notes": "",
  "effect": "EFFECT_DENY",
  "condition": "activity.kind == 'EARN_DEPOSIT' && activity.params.assets > 1000000000"
}
```

#### Gate full-position withdrawals

`amount_value` is a string; the API accepts the literal `MAX` to withdraw an entire position.

```json theme={"system"}
{
  "policyName": "Deny full-position Earn withdrawals",
  "notes": "",
  "effect": "EFFECT_DENY",
  "condition": "activity.kind == 'EARN_WITHDRAW' && activity.params.amount_value == 'MAX'"
}
```

## Earn administration

#### Cap client fee on wrapper deployment

`client_fee_bps` is exposed as a [uint](/features/policies/language#type-uint) in whole basis points
(the API intent carries a decimal string). `client_fee_wallet` remains a string; allowlist it for
treasury controls.

```json theme={"system"}
{
  "policyName": "Deny Earn wrapper deploy above 50 bps client fee",
  "notes": "",
  "effect": "EFFECT_DENY",
  "condition": "activity.kind == 'EARN_DEPLOY_WRAPPER' && activity.params.client_fee_bps > 50"
}
```

#### Require an approved fee recipient on wrapper deployment

```json theme={"system"}
{
  "policyName": "Allow Earn wrapper deploy only with treasury fee wallet",
  "notes": "",
  "effect": "EFFECT_ALLOW",
  "consensus": "approvers.any(user, user.id == '<USER_ID>')",
  "condition": "activity.kind == 'EARN_DEPLOY_WRAPPER' && activity.params.client_fee_wallet in ['0x<LOWERCASE_TREASURY_FEE_WALLET>']"
}
```

#### Require elevated approval to re-enable deposits

```json theme={"system"}
{
  "policyName": "Require two approvers to re-enable Earn deposits",
  "notes": "",
  "effect": "EFFECT_ALLOW",
  "consensus": "approvers.count() >= 2",
  "condition": "activity.kind == 'EARN_SET_WRAPPER_STATE' && activity.params.deposits_disabled == false"
}
```

#### Allow fee claims only for approved wrappers

```json theme={"system"}
{
  "policyName": "Allow Earn fee claims for approved wrappers only",
  "notes": "",
  "effect": "EFFECT_ALLOW",
  "consensus": "approvers.any(user, user.id == '<USER_ID>')",
  "condition": "activity.kind == 'CLAIM_EARN_FEES' && activity.params.wrapper_address in ['0x<LOWERCASE_WRAPPER_1>']"
}
```


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