@newton-xyz/vaultkit
v2.1.0
Published
VaultKit — the TypeScript SDK for vault curators. Wraps every vault-management action behind a Newton Protocol policy attestation, enforced on-chain by the Shield executor.
Downloads
1,938
Readme
@newton-xyz/vaultkit
VaultKit is the TypeScript SDK for vault curators. It wraps every vault-management action behind a Newton Protocol policy attestation, so the curator's manager role is structurally incapable of executing actions that violate the policy.
Curators don't write calldata by hand and don't integrate a new vault product. They use the vendor's existing SDK (
@morpho-org/blue-sdk-viem) to produce calldata, and VaultKit plus the on-chain Shield contract handle the policy gating.
VaultKit and Shield
VaultKit is the product — the SDK you install (@newton-xyz/vaultkit) and the brand for the whole vault-protection / vault-compliance toolkit. Shield is the core on-chain mechanism it's built on: a NewtonPolicyClient executor contract that enforces the Newton policy on every call before it reaches the vault. That's why the SDK's entry point is createShield(...) and its client is ShieldClient — you're constructing and driving a Shield, the primitive that makes VaultKit protect your vault. VaultKit is the kit; Shield is the engine inside it. The naming is intentional and stable: install @newton-xyz/vaultkit, call createShield.
Highlights (target shape)
createShield({ apiKey, walletClient, rpc, policyClientAddress, policy, policyAddress, vault })- pairs a deployedShieldclone address with one policy, deploying the clone if necessary. For a composite of N policy-data oracles, declare the policy synchronously withdefinePolicy({ chainId, env }).with(vaultsfyi).with(chainalysis)(aPolicyDraft) and pass the deployedNewtonPolicyaddress aspolicyAddress;createShieldresolves the draft against on-chaingetPolicyData(). For a bare deployed policy, passpolicyFromAddress({ address, chainId, env })(aBarePolicy) and nopolicyAddress. A policy composes any mix of published packs and custom oracles (a custom oracle is authored withdefineOracle(...)from@newton-xyz/policy-core); a single-oracle curator passes one module:definePolicy({ chainId, env }).with(vaultsfyi). Add composite-level params no oracle owns (a source allowlist, a fee ceiling) with.withPolicyParams(schema). Returns aShieldClientwith setup functions (.setParams(paramsByShortId)and.uploadSecrets(secretsByShortId)) for configuring theShieldcontract and the execution entrypoint.sendCall({ to, data, functionSignature, prepareQueryOptions })that runs the policy's aggregatedprepareQuery -> wasmArgsSchema -> newt_createTask -> shield.executeDirecton every call.client.policyis aResolvedPolicy(introspect.modulesfor the resolved oracles' objective facts - id, policyDataAddress, schemas; derive a trust label with the re-exportedclassifyProvenance, injecting the audited registry you trust).- Deployment process Configuration order:
definePolicy().with() -> createShield -> setParams -> uploadSecrets -> sendCallis needed for first-time configuration ONLY. By passing a configured Shield contract, the client runs the verification ladder (client.verification), detecting and binding to the existing deployment;client.reverify()re-runs it aftersetParams. FunctionssetParamsanduploadSecretscan be called later to update configuration. Use parammustDeployto ensure not binding to existing contracts that you didn't deploy. Use paramexpectedParamsto assert the on-chain params byte-for-byte (verification rung 4);attachWithoutVerify: trueis the sole escape below rung 1, for attaching to a freshly-deployed clone beforesetParams. Incrementversionto replace unusable or abandoned shield deployments. For testing on a non-production network where an oracle's external data source has no coverage (e.g. vaults.fyi indexes mainnets only), a module may expose its own data-source override insendCall'sprepareQueryOptions(e.g.{ vaultsfyi: { network, vaultAddress } }) to point its lookup at a real mainnet target while the Shield executes on a testnet - a testing affordance only; leave it unset in production so the policy describes the same vault it gates. NewtonShield— lower-level runtime exposed via.guardedCall({ to, data, functionSignature, wasmArgs }). Use this when you want to drive intent submission yourself.- Policy packs ship as separate npm packages. Install only the ones you integrate, e.g.
pnpm add @newton-xyz/policy-pack-vaultsfyi. A pack is a ready-made policy-data oracle set; a custom oracle you author withdefineOracle(...)(from@newton-xyz/policy-core) is the same kind of thing, and a policy freely mixes them. The SDK declares@newton-xyz/policy-core(the foundational policy/policy-data contract) as a peer dep. Build the policy withdefinePolicy({ chainId, env }).with(...)(add composite-level params with.withPolicyParams(schema)), then pass the onepolicy(and itspolicyAddress) tocreateShield. The low-leveldefineCompositeresolvercreateShieldcalls internally is not re-exported from vaultkit; import it from@newton-xyz/policy-coreonly for standalone composition. - A typed error hierarchy (
PolicyDeniedError,GatewayHttpError,GatewayRpcError,GatewayTimeoutError,NewtonTaskEvaluationError,TransactionFailedError,InvalidConfigurationError,ConcurrentIntentError,UnsupportedChainError). - Browser-safe core. No
node:*imports.
Install
pnpm add @newton-xyz/vaultkit @newton-xyz/policy-core viem zod
# Plus one or more policy packs:
pnpm add @newton-xyz/policy-pack-vaultsfyi@newton-xyz/policy-core, viem, and zod are peer dependencies — the SDK uses whatever versions your application has installed. @newton-xyz/policy-core is the foundational policy/policy-data contract (the PolicyPack interface, the composite manifest wire-format, defineOracle); vaultkit and every @newton-xyz/policy-pack-* depend on it. Per-pack packages (@newton-xyz/policy-pack-vaultsfyi, @newton-xyz/policy-pack-blockaid, …) are independent: install only the packs you integrate. Vendor SDKs (@morpho-org/blue-sdk-viem, etc.) are also peer deps; install only the ones you use.
Supported chains
SUPPORTED_CHAINS (in sdk/src/chains.ts) covers two mainnets and two testnets:
| Chain | Chain id | Network | Status |
| ------------- | ----------- | ------- | ----------------------------------------------- |
| Ethereum | 1 | Mainnet | Deployed (prod) |
| Base | 8453 | Mainnet | Deployed (prod) |
| Sepolia | 11155111 | Testnet | Deployed (prod) |
| Base Sepolia | 84532 | Testnet | Deployed (prod) |
Ethereum and Base mainnet are deployed on prod (the first mainnet rollout); their audit-trail JSON lives at deployments/{1,8453}-prod.json. See docs/deployment/chains.md for the add-a-chain procedure.
The SDK's per-chain registry lives in sdk/src/deployments.ts (SHIELD_DEPLOYMENTS, keyed by (chainId, env)). The audit trail per (chainId, env) slot lives in deployments/{chainId}-{env}.json at the repo root — those JSON files travel with the source repo and are not loaded at SDK runtime. Calling createShield on an unsupported chain throws UnsupportedChainError; calling against a supported chain with no deployment recorded yet throws ShieldDeploymentNotFoundError. Either way, the SDK fails before any tx is sent.
Repository structure
sdk/
├── src/
│ ├── index.ts ← top-level exports
│ ├── builder.ts ← `createShield(...)` factory
│ ├── pack-runtime.ts ← `buildIntentArgs` / `encodePackParams` helpers
│ ├── shield.ts ← `NewtonShield` low-level runtime
│ ├── factory.ts ← `predictShieldAddress` (CREATE2 derivation)
│ ├── gateway.ts ← Newton Gateway HTTP/JSON-RPC client
│ └── vendors/<name>/ ← vendor module subpath modules
├── test/
├── package.json
├── tsconfig.json
├── tsup.config.ts ← ESM + CJS + .d.ts build
├── vitest.config.ts
└── README.mdPack code lives in newton-policy-packs; each pack publishes as its own @newton-xyz/policy-pack-<name> npm package on its own release cadence.
Local development
Requires Node ≥22 and pnpm ≥10. The SDK lives in a pnpm monorepo at the repo root.
# from repo root
pnpm install
pnpm --filter @newton-xyz/vaultkit build
pnpm --filter @newton-xyz/vaultkit typecheck
pnpm --filter @newton-xyz/vaultkit testTo test against a consumer app without publishing:
"@newton-xyz/vaultkit": "link:../vaultkit/sdk"Versioning
Changesets for semver bumps. Public-surface changes get a .changeset/*.md entry per PR via pnpm changeset.
Vendor SDK breaking changes cascade through. Peer-dep versions are tracked, and any vendor-side breaking change is treated as a VaultKit SDK semver-major.
License
Apache-2.0
