# Integration Guide \[Install VaultKit 3.0, declare a Newton policy, and run a typed vault-manager action.]

VaultKit's current authoring flow is policy-first: declare the policy modules synchronously with `definePolicy(...)`, pass each module's deployed `NewtonPolicy` to `createShield(...)`, extend the returned client with a vendor module, and then call a typed action.

## Prerequisites

| Requirement | Version or purpose |
| --- | --- |
| Node.js | 22 or newer |
| pnpm | 10 or newer |
| `viem` | `^2.35.1` |
| `zod` | `^3.0.0` |
| Newton API key | Created for the chain environment you will use |
| Curator wallet | Funded on the target chain and authorized to manage the target vault |

## Install

```bash
pnpm add @newton-xyz/vaultkit @newton-xyz/policy-core viem zod
pnpm add @newton-xyz/policy-pack-vaultsfyi
```

Install only the vendor SDKs your integration needs. The typed MetaMorpho module uses:

```bash
pnpm add @morpho-org/blue-sdk @morpho-org/blue-sdk-viem @morpho-org/morpho-ts
```

`@newton-xyz/policy-pack-shared` is not part of the VaultKit 3.x flow. Policy authoring, params encoding, and policy-set introspection live in `@newton-xyz/policy-core`, a `^0.3.0` peer dependency.

## 1. Create Viem Clients

```typescript
import { createPublicClient, createWalletClient, http } from 'viem'
import { privateKeyToAccount } from 'viem/accounts'
import { base } from 'viem/chains'

const account = privateKeyToAccount(
  process.env.CURATOR_PRIVATE_KEY as `0x${string}`,
)

const publicClient = createPublicClient({
  chain: base,
  transport: http(process.env.RPC_URL),
})

const walletClient = createWalletClient({
  account,
  chain: base,
  transport: http(process.env.RPC_URL),
})
```

## 2. Declare the Policy

```typescript
import { definePolicy } from '@newton-xyz/vaultkit'
import { vaultsfyi } from '@newton-xyz/policy-pack-vaultsfyi'

const policy = definePolicy({
  chainId: '8453',
  env: 'prod',
}).with(vaultsfyi)
```

`definePolicy(...)` is synchronous and does not read the chain. Add more published packs or custom `defineOracle(...)` outputs with additional `.with(...)` calls. Module order does not need to match the Shield's policy set; when attaching, VaultKit matches the set by membership and adopts the onchain order.

Each module runs as its own `NewtonPolicy`, and packs ship no canonical one. Before creating the client, deploy one policy per module from the pack's reference Rego and its published WASM; see [Pack Policy Addresses](/developers/vaults/policy-packs#pack-policy-addresses).

## 3. Create the Client and Add a Vendor Module

```typescript
import { createShield } from '@newton-xyz/vaultkit'
import { morphoActions } from '@newton-xyz/vaultkit/vendors/morpho'

const client = (await createShield({
  apiKey: process.env.NEWTON_API_KEY!,
  walletClient,
  publicClient,
  rpc: process.env.RPC_URL!,
  vault: '0xMetaMorphoVault',
  policy,
  policies: {
    vaultsfyi: '0xVaultsfyiPolicy',
  },
})).extend(morphoActions)
```

`policies` maps each short pack ID to that module's deployed `NewtonPolicy`; the type requires an entry for every declared module. `createShield(...)` checks that each policy serves its pack's WASM for `(chainId, env)` and exposes the resolved set as `client.policy`.

VaultKit 3.0.0 publishes no Shield factory deployment yet: every `SHIELD_DEPLOYMENTS` slot is `null`, so `createShield(...)` throws `ShieldDeploymentNotFoundError` unless you attach to an existing clone with `policyClientAddress` or pass your own factory as `deployment: { factory, implementation, beacon?, timelock?, deployedAtBlock? }`. Include `beacon` for a beacon factory: without it the SDK predicts an EIP-1167 clone address, so `createShield(...)` reports the wrong address. A fresh clone is deployed with no policy set; `setParams(...)` binds it.

## 4. Configure Parameters and Secrets

```typescript
await client.setParams({
  vaultsfyi: {
    risk_score_floor: 80,
    tvl_drawdown_24h_max_pct: 25,
  },
})

await client.uploadSecrets({
  vaultsfyi: {
    VAULTS_FYI_API_KEY: process.env.VAULTSFYI_API_KEY!,
  },
})
```

`setParams(...)` binds the whole policy set through the Shield's `setPolicies(...)`, writing each module's slice as that policy's own `policyParams`. Secrets are encrypted client-side and uploaded separately, one envelope per module scoped to that module's policy; they are not written onchain.

Use `client.encodeParams(params)` to inspect the exact `PolicySpec[]` before writing it.

## 5. Verify the Attachment

```typescript
console.log(client.policy.policies)
console.log(client.policy.modules)
console.log(client.verification)
```

When attaching to an existing deployment, VaultKit verifies progressively:

1. The clone's policy set is exactly the declared policies.
2. Each module policy serves its pack's WASM.
3. Each policy's stored params decode against its schema.
4. When `expectedParams` is supplied, every policy's stored bytes exactly match the expected encoding.

Call `client.reverify()` after changing parameters. Use `attachWithoutVerify: true` only to recover an incomplete first-time setup, and remove it immediately after writing the correct configuration.

## 6. Grant the Required Vault Role

The client address must hold the manager or allocator role required by the vendor action. Role assignment is vendor-specific; VaultKit does not bypass the vendor's authorization model.

```typescript
console.log(client.policyClientAddress)
```

Grant that address the appropriate role using the vendor's normal governance process.

## 7. Execute a Typed Action

```typescript
const result = await client.morpho.reallocate(
  '0xMetaMorphoVault',
  [{ marketParams, assets: 1_000_000n }],
  {
    prepareQueryOptions: {
      vaultsfyi: {
        previousAllocationHash: '0x...',
      },
    },
  },
)

const receipt = await publicClient.waitForTransactionReceipt({
  hash: result.transactionHash,
})
```

Each policy module owns its `wasmArgs` construction. Pass module-specific inputs through `prepareQueryOptions.<shortPackId>`; VaultKit validates the resulting data before building the intent.

## 8. Handle Expected Failures

```typescript
import {
  AttestationTimeoutError,
  PolicyDeniedError,
  RpcReadError,
} from '@newton-xyz/vaultkit'

try {
  await client.morpho.reallocate('0xMetaMorphoVault', allocations)
} catch (error) {
  if (error instanceof PolicyDeniedError) {
    console.error('The policy denied this action:', error.reason)
  } else if (error instanceof AttestationTimeoutError) {
    console.error('Request a fresh task after backoff')
  } else if (error instanceof RpcReadError) {
    console.error(error.read, error.cause)
  } else {
    throw error
  }
}
```

See [Errors](/developers/vaults/sdk/errors) before adding retries. A deterministic policy or schema failure does not become valid when retried.

## Next Steps

<Card title="Policies" icon="layers" to="/developers/vaults/sdk/policies">
  Compose published packs, custom oracles, and policy-level parameters.
</Card>

<Card title="Custom Oracles" icon="code" to="/developers/vaults/sdk/custom-oracles">
  Build a typed oracle with `defineOracle(...)`.
</Card>

<Card title="Examples" icon="terminal" to="/developers/vaults/sdk/examples">
  Copy current VaultKit 3.0 recipes.
</Card>
