Skip to main content
Morpho vault curators can route MetaMorpho manager actions through a Newton Shield before the vault receives the call. VaultKit’s Morpho overlay builds the MetaMorpho calldata with Morpho’s SDK, packages that exact call as an intent, asks Newton operators to evaluate the configured policy, and forwards the call only when the policy returns an approval attestation. This guide focuses on reallocate, a curator-only MetaMorpho action. End-user deposits and withdrawals continue through the normal Morpho vault flow.

What This Demonstrates

  • Exact calldata binding: the attestation is bound to the exact reallocate calldata your app encodes.
  • Composite policy checks: one Shield can enforce a Vaults.fyi-only policy or a Vaults.fyi + Chainalysis policy in a single evaluation.
  • Onchain policy parameters: setParams(...) writes the curator’s thresholds into the Shield-bound policy manifest.
  • Manager-action gating: the Shield clone must hold a MetaMorpho role that can call reallocate.

Target Network

The public end-to-end Morpho examples use Base Sepolia (84532) with Newton prod, also called testnet production. Base Sepolia is used because the MetaMorpho V1.1 factory is deployed there for testnet curator flows. Newton environments are separate stacks. Create the key from the Newton dashboard for the same environment your Shield uses. The public Base Sepolia example uses prod.

Install Packages

Every VaultKit Morpho integration needs VaultKit, Viem, policy-pack shared helpers, the policy packs you plan to enforce, and Morpho’s SDK:
pnpm add @newton-xyz/vaultkit @newton-xyz/policy-pack-shared viem zod
pnpm add @newton-xyz/policy-pack-vaultsfyi
pnpm add @morpho-org/blue-sdk @morpho-org/blue-sdk-viem @morpho-org/morpho-ts
For a two-module policy that also screens an address, add Chainalysis:
pnpm add @newton-xyz/policy-pack-chainalysis
The Morpho packages are optional peer dependencies of VaultKit. Curators who use the generic sendCall(...) escape hatch can encode calldata themselves, but the typed path below uses shield.morpho.reallocate(...).

Build the Composite Policy Pack

Use defineComposite(...) with the modules deployed in your Newton policy. A Vaults.fyi-only policy looks like this:
import { defineComposite } from '@newton-xyz/policy-pack-shared'
import { vaultsfyi } from '@newton-xyz/policy-pack-vaultsfyi'

const pack = await defineComposite({
  modules: [vaultsfyi],
  chainId: '84532',
  env: 'prod',
  publicClient,
  policyAddress: '0xCompositePolicyAddress',
})
For Vaults.fyi plus Chainalysis, install the Chainalysis pack and include both modules:
import { chainalysis } from '@newton-xyz/policy-pack-chainalysis'
import { defineComposite } from '@newton-xyz/policy-pack-shared'
import { vaultsfyi } from '@newton-xyz/policy-pack-vaultsfyi'

const pack = await defineComposite({
  modules: [vaultsfyi, chainalysis],
  chainId: '84532',
  env: 'prod',
  publicClient,
  policyAddress: '0xCompositePolicyAddress',
})
The module list must match the policy’s onchain getPolicyData() exactly. If the Shield is configured with a policy address that references a different module set, the SDK raises a typed configuration error before executing a vault action.

Create or Attach to a Shield

Create one Shield for the curator, vault, chain, policy pack, and version slot:
import { createShield } from '@newton-xyz/vaultkit'
import { morphoActions } from '@newton-xyz/vaultkit/vendors/morpho'

const shield = (await createShield({
  apiKey: process.env.NEWTON_API_KEY!,
  walletClient,
  rpc: process.env.BASE_SEPOLIA_RPC_URL!,
  env: 'prod',
  pack,
  vault: '0xMetaMorphoVaultAddress',
  bypassDelaySeconds: 7n * 24n * 60n * 60n,
})).extend(morphoActions)

console.log(shield.policyClientAddress)
createShield(...) is idempotent. It attaches to an existing compatible clone or deploys a new clone through ShieldFactory. If a previous run deployed a clone but did not finish writing policy params, pass a new version for a fresh clone or use skipPolicyBindingCheck only for a recovery run that immediately calls setParams(...).

Configure Params and Secrets

Write policy thresholds onchain and upload oracle secrets through Newton Gateway:
await shield.setParams({
  vaultsfyi: {
    apy_z_max: 3,
    risk_score_floor: 80,
    tvl_drawdown_24h_max_pct: 25,
    tvl_drawdown_7d_max_pct: 40,
    deny_on_allocation_change: true,
    deny_on_critical_flag: true,
    deny_on_corrupted: true,
  },
})

await shield.uploadSecrets({
  vaultsfyi: {
    VAULTS_FYI_API_KEY: process.env.VAULTSFYI_API_KEY!,
  },
})
For a Vaults.fyi + Chainalysis composite, include the Chainalysis params and secrets required by that pack. The OFAC sanctions endpoint is public, but the policy schema may still require a non-empty secret value; use the key or placeholder required by your deployed policy.

Grant the Shield a Morpho Role

The Shield has two separate authorization gates:
  • Shield’s delegate gate controls who can call execute or executeDirect.
  • MetaMorpho’s manager roles control what the forwarded call can do on the vault.
The initial Shield owner is approved as a delegate at clone initialization. After an ownership handoff or when using a separate hot key, approve the executor explicitly:
await walletClient.writeContract({
  address: shield.policyClientAddress,
  abi: shieldAbi,
  functionName: 'setApprovedDelegate',
  args: [account.address, true],
})
MetaMorpho protects reallocate with its allocator-role check. The Shield clone must be one of:
  • the vault curator,
  • the vault owner, or
  • an approved allocator.
Grant the role from the vault owner before running the gated action. Most curator integrations use setCurator(shield.policyClientAddress) or setIsAllocator(shield.policyClientAddress, true). If the Shield can configure policy params but reallocate reverts, check this role first. Newton can approve the intent, but MetaMorpho will still reject the forwarded call if the Shield clone is not authorized on the vault.

Execute reallocate

With the Morpho overlay attached, call the typed action:
const allocations = [
  { marketParams: marketParamsA, assets: 1_000_000n },
  { marketParams: marketParamsB, assets: 0n },
]

const result = await shield.morpho.reallocate(
  '0xMetaMorphoVaultAddress',
  allocations,
  {
    prepareQueryOptions: {
      vaultsfyi: { previousAllocationHash: '0x...' },
    },
  },
)
reallocate takes positional arguments: (vault, allocations, options?). Each allocation uses Morpho’s marketParams shape plus assets. For a Vaults.fyi + Chainalysis composite, include the per-call screening input your deployed pack expects under prepareQueryOptions.chainalysis. Omit it for a Vaults.fyi-only policy. The returned result includes the onchain transaction hash and Newton task context. A successful run with allow: true means the full path worked: exact calldata, policy evaluation, attestation, and Shield execution. Use shield.sendCall(...) only as an escape hatch for vendors or actions that VaultKit does not wrap yet. With sendCall, your integration owns calldata integrity.

Read-Only Versus Full Reproduce

You can validate most of a Morpho integration before granting a vault role:
PathWhat it provesRequirements
Read-only inspectionPolicy source, params, and deployed Shield configuration are coherent.Public RPC and deployed addresses.
Type-check and encodeYour app compiles against the published package surface and produces MetaMorpho calldata.Node, package install, and Morpho SDK.
Setup stagesdefineComposite, createShield, setParams, and uploadSecrets work.Funded curator key and Newton/API secrets.
Full executionMetaMorpho accepts the Shield-forwarded reallocate.Shield clone has curator, owner, or allocator permissions.

Vaults.fyi Testnet Data

Vaults.fyi indexes production networks, not testnets. When testing a Shield on Base Sepolia, a Vaults.fyi policy can fail closed because there is no testnet vault data for the lookup target. For demos, point the Vaults.fyi lookup at a real mainnet vault through the policy pack’s data-source override fields while the Shield still executes on Base Sepolia. In production, remove the override so the policy describes the same vault the Shield gates.

Troubleshooting

SymptomLikely causeFix
401 from Newton GatewayAPI key was minted for a different Newton environment.Create a key for the same stack as env, usually prod for Base Sepolia testnet production.
UnsupportedChainErrorWallet client is not on a VaultKit-supported chain.Use a supported chain such as Base Sepolia (84532) for testnet Morpho flows.
ShieldDeploymentNotFoundErrorNo Shield factory is registered for the selected chain and environment.Check env, chain id, and RPC configuration.
Module-set mismatch or composite policy mismatchThe modules passed to defineComposite(...) do not match the policy address.Use a policy deployed with exactly the selected modules.
PolicyMismatchErrorAn existing Shield clone is bound to different policy data.Verify the clone, write the expected params in a recovery run, or use a new version.
MetaMorpho role revertThe Shield clone is not curator, owner, or allocator.Grant the clone a qualifying vault role, then rerun the action.
PolicyDeniedErrorNewton evaluated the policy and denied the intent.Inspect the error cause, adjust params, or choose inputs that satisfy the policy.
Vaults.fyi oracle errors or unexpected denialsMissing Vaults.fyi secret or no data for the lookup target.Upload the API key and use a production-network data-source override for testnet demos.
AttestationTimeoutError or GatewayErrorGateway was slow or unavailable.Retry with backoff and a fresh task.

Getting Started

Install VaultKit, configure a Shield, and execute a policy-gated vault action.

Errors

Review typed errors and retry guidance.