# Examples \[VaultKit 2.1 recipes for policies, typed vendor calls, generic calls, verification, and blocked-intent assertions.]

## Declare a Published Policy

```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)
```

## Attach or Deploy Idempotently

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

const client = await createShield({
  apiKey: process.env.NEWTON_API_KEY!,
  walletClient,
  publicClient,
  rpc: process.env.RPC_URL!,
  vault: '0xVault',
  policy,
  policyAddress: '0xNewtonPolicy',
  expectedParams: {
    vaultsfyi: { risk_score_floor: 80 },
    chainalysis: { deny_on_sanctioned: true },
  },
})
```

An existing attachment must pass the verification ladder. A mismatch throws instead of silently changing the policy.

## Use a Bare Policy

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

const policy = policyFromAddress({
  address: '0xNewtonPolicy',
  chainId: '8453',
  env: 'prod',
  params: {
    encode: (value) => encodeMyPolicyParams(value),
    decode: (value) => decodeMyPolicyParams(value),
  },
})

const client = await createShield({
  apiKey,
  walletClient,
  rpc,
  vault,
  policy,
})
```

Use `policyFromAddress(...)` for a monolithic or calldata-only policy that does not use the composite module model. Do not also pass `policyAddress`; the address is already part of the bare policy.

## Add Policy-Level Parameters

```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 gate reads these composite-wide values under `data.params.params._policy`.

## Extend with a Typed Vendor Module

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

const morphoClient = client.extend(morphoActions)

await morphoClient.morpho.reallocate(
  '0xMetaMorphoVault',
  [{ marketParams, assets: 1_000_000n }],
  {
    prepareQueryOptions: {
      chainalysis: { address: curatorAddress },
    },
  },
)
```

## Use the Generic Escape Hatch

```typescript
await client.sendCall(
  {
    to: '0xTarget',
    data: encodedCalldata,
    functionSignature: 'someManagerAction(uint256)',
    prepareQueryOptions: {
      vaultsfyi: { previousAllocationHash: '0x...' },
    },
  },
  'DIRECT',
  30_000,
)
```

With `sendCall(...)`, your integration owns the target, calldata, value, and human-readable function signature. Prefer a typed vendor module when one exists.

## Inspect and Reverify

```typescript
console.log(client.policy.address)
console.table(client.policy.modules)
console.log(client.verification.achievedRung)

await client.setParams(nextParams)
const current = await client.reverify()
```

For independent manifest inspection, import `introspectComposite(...)` from `@newton-xyz/policy-core`.

## Prove a Denied Intent Is Blocked

```typescript
import {
  NotApprovedDelegateError,
  PolicyNotDeniedError,
} from '@newton-xyz/vaultkit'

try {
  const proof = await client.assertIntentBlocked({
    to: '0xTarget',
    data: noncompliantCalldata,
    functionSignature: 'someManagerAction(uint256)',
  })

  console.log(proof.blocked, proof.taskId, proof.reason)
} catch (error) {
  if (error instanceof PolicyNotDeniedError) {
    console.error('The supplied intent was allowed, so it proves no block')
  } else if (error instanceof NotApprovedDelegateError) {
    console.error('Use a wallet approved for this client')
  } else {
    throw error
  }
}
```

`assertIntentBlocked(...)` evaluates the intent and uses `eth_call` to confirm that the denied attestation reverts specifically with `InvalidAttestation`. It does not mine a transaction and does not return a transaction hash.

## Use Multiple Chains

Create one policy declaration and one client per chain. Never reuse a client while changing the wallet's active chain implicitly.

```typescript
const basePolicy = definePolicy({ chainId: '8453', env: 'prod' }).with(vaultsfyi)
const ethereumPolicy = definePolicy({ chainId: '1', env: 'prod' }).with(vaultsfyi)

const baseClient = await createShield({
  apiKey,
  walletClient: baseWalletClient,
  rpc: baseRpc,
  vault: baseVault,
  policy: basePolicy,
  policyAddress: basePolicyAddress,
})

const ethereumClient = await createShield({
  apiKey,
  walletClient: ethereumWalletClient,
  rpc: ethereumRpc,
  vault: ethereumVault,
  policy: ethereumPolicy,
  policyAddress: ethereumPolicyAddress,
})
```
