# Policies \[Declare VaultKit policies from published packs, custom oracles, or a bare deployed policy.]

Every VaultKit client resolves to one `NewtonPolicy`. That policy can contain one or more policy-data oracles, or it can be a bare monolithic policy with no composable modules.

## Published Policy Packs

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

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

`definePolicy(...)` is synchronous and chainless. `createShield(...)` performs the onchain read, matches the declared modules to `NewtonPolicy.getPolicyData()`, and exposes the resolved result on `client.policy`.

```typescript
const client = await createShield({
  apiKey,
  walletClient,
  rpc,
  vault,
  policy,
  policyAddress: '0xDeployedNewtonPolicy',
})
```

A duplicate short ID is rejected because params and per-call inputs are namespaced by that ID.

## Custom Oracles

Published packs and custom `defineOracle(...)` outputs implement the same `PolicyPack` contract:

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

There is no custom-module registry gate. The same deployment matching, WASM CID checks, schema validation, and manifest encoding apply to every module.

## Policy-Level Parameters

Use `.withPolicyParams(...)` for composite-wide values that belong to the policy rather than a single oracle:

```typescript
import { z } from 'zod'

const policy = definePolicy({ chainId: '8453', env: 'prod' })
  .with(vaultsfyi)
  .withPolicyParams(
    z.object({
      allowedYieldSources: z.array(z.string()),
      maxFeeBps: z.number().int().min(0).max(10_000),
    }),
  )

await client.setParams({
  _policy: {
    allowedYieldSources: ['0xYieldSource'],
    maxFeeBps: 100,
  },
  vaultsfyi: { risk_score_floor: 80 },
})
```

The manifest stores that slice at `params._policy`; Rego reads it at `data.params.params._policy`.

## Bare Policies

Use `policyFromAddress(...)` for a deployed monolithic or calldata-only policy:

```typescript
import { policyFromAddress } from '@newton-xyz/vaultkit'

const policy = policyFromAddress({
  address: '0xNewtonPolicy',
  chainId: '8453',
  env: 'prod',
  params: {
    encode: encodeMyParams,
    decode: decodeMyParams,
  },
})
```

A bare policy has `modules: []`. Its optional codec enables `setParams(...)`, decoding, and higher verification rungs. Pass this object as `policy` and omit the separate `policyAddress`.

## Manifest Shape

`setParams(...)` writes a versioned UTF-8 JSON envelope:

```json
{
  "_manifest": { "magic": "NPM1", "version": 1 },
  "modules": [
    {
      "id": "vaultsfyi/risk-envelope/v1",
      "policyDataAddress": "0xPolicyData",
      "wasmCid": "bafy..."
    }
  ],
  "params": {
    "_policy": { "maxFeeBps": 100 },
    "vaultsfyi": { "risk_score_floor": 80 }
  }
}
```

Generate schemas and encode this format with `@newton-xyz/policy-core`; do not hand-maintain a second manifest encoder.

## Per-Call Inputs

`sendCall` takes two short-ID-keyed per-module bags. Which one a pack uses depends on whether it ships a `prepareQuery`.

```typescript
await client.sendCall({
  to,
  data,
  functionSignature,
  // INPUTS to a pack's own prepareQuery, for packs that have one.
  prepareQueryOptions: {
    vaultsfyi: { previousAllocationHash: '0x...' },
    my_oracle: { market: '0xMarket' },
  },
  // The wasmArgs THEMSELVES, for packs that ship no prepareQuery.
  wasmArgs: {
    arkham_entity: { address: '0xDestination', chain: 'ethereum' },
    pharos_treasury: { stablecoin_id: 'usdc-circle' },
  },
})
```

Each module receives only its short-ID-keyed slice. Its `prepareQuery(...)` result is checked against its `wasmArgsSchema`; a failure stops intent construction.

A pack ships no `prepareQuery` when its `wasmArgs` name something the SDK cannot read from chain state — [`balancer`](/developers/vaults/policies/balancer)'s `poolId`, [`arkham_entity`](/developers/vaults/policies/arkham-entity)'s `address`, [`pharos_treasury`](/developers/vaults/policies/pharos-treasury)'s `stablecoin_id`. Those modules take their slice from `wasmArgs` instead.

The two are separate fields rather than one because they are different things: `prepareQueryOptions` is input **to** a `prepareQuery`, `wasmArgs` is what one would have **returned**. A pack with no `prepareQuery` also carries `TOptions = unknown`, so routing its args through the options bag would compile while checking nothing; `wasmArgs` is typed per module, so a misspelled field is a compile error.

A module that ships a `prepareQuery` owns its slice outright — there is no merge, so a stray `wasmArgs` entry cannot override what the pack derived from chain state. Either way a slice its schema rejects, including the `{}` a `prepareQuery`-less module gets when nothing is supplied, throws `InvalidConfigurationError` rather than reaching the AVS.

`wasmArgs` requires `@newton-xyz/vaultkit` 2.2.0 or later.

## Verification and Introspection

The resolved client exposes objective onchain facts:

```typescript
client.policy.address
client.policy.modules
client.verification
await client.reverify()
```

For an independent report:

```typescript
import { introspectComposite } from '@newton-xyz/policy-core'

const report = await introspectComposite({
  publicClient,
  shieldAddress: client.policyClientAddress,
})
```

`introspectComposite(...)` returns comparison booleans instead of throwing on a binding mismatch. It throws only when the stored manifest cannot be decoded.

## Provenance Is Consumer-Selected

`ResolvedModule` reports objective values such as `id`, `policyDataAddress`, and `wasmCid`. It does not claim that a module is audited or trusted. Consumers can classify those facts with `classifyProvenance(...)` from `@newton-xyz/policy-core` and a registry they trust.

## Low-Level Composition

VaultKit no longer re-exports `defineComposite(...)`. Most curator integrations should use `definePolicy().with(...)`. Import `defineComposite`, `defineOracle`, manifest encoders, schema generators, and introspection helpers directly from `@newton-xyz/policy-core` when building tooling outside `createShield(...)`.

<Card title="Custom Oracles" icon="code" to="/developers/vaults/sdk/custom-oracles">
  Define schemas, query preparation, deployments, and metadata for your own oracle.
</Card>

<Card title="Policy Packs" icon="boxes" to="/developers/vaults/policy-packs">
  Browse published risk, compliance, and market-data packs.
</Card>
