{"_id":"@canopy-finance/x402-rwa","name":"@canopy-finance/x402-rwa","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@canopy-finance/x402-rwa","version":"0.1.0","description":"RWA-funded x402 buyer helper: pay x402 invoices by swapping just enough tokenized RWA into the settlement stablecoin behind a validation wall. Buyer-side only, non-custodial.","license":"MIT","author":{"name":"Canopy Finance"},"homepage":"https://github.com/canopyfinance/x402-rwa#readme","repository":{"type":"git","url":"git+https://github.com/canopyfinance/x402-rwa.git"},"bugs":{"url":"https://github.com/canopyfinance/x402-rwa/issues"},"type":"module","sideEffects":false,"main":"./dist/index.cjs","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./viem":{"types":"./dist/viem.d.ts","import":"./dist/viem.js","require":"./dist/viem.cjs"}},"publishConfig":{"access":"public"},"scripts":{"build":"tsup","dev":"tsup --watch","lint":"eslint .","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest","prepublishOnly":"npm run build"},"keywords":["x402","rwa","payments","usdc","usdg","agent","uniswap","stablecoin","non-custodial"],"peerDependencies":{"viem":"^2.21.26"},"dependencies":{"x402":"^1.2.0","x402-fetch":"^1.2.0"},"devDependencies":{"@types/node":"^22.10.0","@typescript-eslint/eslint-plugin":"^8.18.0","@typescript-eslint/parser":"^8.18.0","eslint":"^9.17.0","tsup":"^8.3.5","typescript":"^5.7.2","viem":"^2.21.26","vitest":"^2.1.8"},"engines":{"node":">=18"},"gitHead":"397b6ff184ad250bfe8ff497ada035e0c153a430","_id":"@canopy-finance/x402-rwa@0.1.0","_nodeVersion":"25.6.1","_npmVersion":"11.9.0","dist":{"integrity":"sha512-F8yKpbiu/0JLvmehmT/5+jtXNxVTTJlhSwSELA1gAddPoZlHA5nVSou0MvZALrLCrTJjZB9ayJbPJgdi7FbMXA==","shasum":"c746b868cce39715bf4504521e5dd89e202a5d09","tarball":"https://registry.npmjs.org/@canopy-finance/x402-rwa/-/x402-rwa-0.1.0.tgz","fileCount":17,"unpackedSize":234159,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDOSaGvEmK4hTXiNNK08rPEyenQT44MGSyQNvEtEgz07AiAu/LJg215rnu6ABbgvSF24OOruqfg1O+8FBz1E46uSvA=="}]},"_npmUser":{"name":"canopy-finance","email":"heyagentsol@gmail.com"},"directories":{},"maintainers":[{"name":"canopy-finance","email":"heyagentsol@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/x402-rwa_0.1.0_1783798397175_0.7399033374554767"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-11T19:33:17.053Z","0.1.0":"2026-07-11T19:33:17.351Z","modified":"2026-07-11T19:33:17.557Z"},"maintainers":[{"name":"canopy-finance","email":"heyagentsol@gmail.com"}],"description":"RWA-funded x402 buyer helper: pay x402 invoices by swapping just enough tokenized RWA into the settlement stablecoin behind a validation wall. Buyer-side only, non-custodial.","homepage":"https://github.com/canopyfinance/x402-rwa#readme","keywords":["x402","rwa","payments","usdc","usdg","agent","uniswap","stablecoin","non-custodial"],"repository":{"type":"git","url":"git+https://github.com/canopyfinance/x402-rwa.git"},"author":{"name":"Canopy Finance"},"bugs":{"url":"https://github.com/canopyfinance/x402-rwa/issues"},"license":"MIT","readme":"<div align=\"center\">\n\n# `@canopy-finance/x402-rwa`\n\n### Pay [x402](https://x402.org) invoices with tokenized real-world assets — behind a validation wall.\n\nAn [x402](https://x402.org) buyer helper that lets an AI agent or app settle pay-per-request\ninvoices while holding **tokenized RWA** instead of a pre-funded stablecoin balance. On a\n`402`, it swaps *just enough* RWA into the settlement stablecoin — through a ported, non-negotiable\n**validation wall** — then completes the payment. Buyer-side only. Non-custodial.\n\n<br/>\n\n[![CI](https://github.com/canopyfinance/x402-rwa/actions/workflows/ci.yml/badge.svg)](https://github.com/canopyfinance/x402-rwa/actions/workflows/ci.yml)\n[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)\n[![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178C6?logo=typescript&logoColor=white)](./tsconfig.json)\n[![Module: ESM + CJS](https://img.shields.io/badge/module-ESM%20%2B%20CJS-f7df1e)](./package.json)\n[![Tests](https://img.shields.io/badge/tests-47%20passing-brightgreen.svg)](./src)\n[![Non-custodial](https://img.shields.io/badge/custody-none-success.svg)](#-security-model)\n[![Dependencies](https://img.shields.io/badge/runtime%20deps-x402%20only-lightgrey.svg)](./package.json)\n\n</div>\n\n---\n\n## Table of contents\n\n- [Why](#why)\n- [Install](#install)\n- [Quickstart](#quickstart)\n- [How it works](#how-it-works)\n- [Architecture](#architecture)\n- [The validation wall](#-the-validation-wall)\n- [Hard limits](#-hard-limits-fail-closed)\n- [Security model](#-security-model)\n- [API reference](#api-reference)\n- [Injected dependencies](#injected-dependencies)\n- [Errors](#errors)\n- [Testing](#testing)\n- [Limitations](#limitations-v1)\n- [FAQ](#faq)\n- [License](#license)\n\n---\n\n## Why\n\nAgents that pay for APIs usually have to pre-fund a stablecoin float and babysit it. If the balance\nruns dry mid-task, calls start failing. Meanwhile the agent may be *holding value* — tokenized\nequities, treasuries, other RWA — that it can't spend on an x402 invoice.\n\n`x402-rwa` closes that gap. It keeps your working capital in RWA and mints settlement liquidity\n**on demand, per payment**, only for the exact shortfall, and only through a swap that survives a\nstrict validation wall. If you already hold enough stablecoin, it never swaps at all.\n\n| | Pre-funded float | `x402-rwa` |\n|---|---|---|\n| Idle capital | Sits as stablecoin | Stays in yield-bearing / appreciating RWA |\n| Runs dry | Payments start failing | Swaps just-in-time to cover the shortfall |\n| Swap safety | N/A | Every swap passes an independent validation wall |\n| Overspend risk | Manual | Hard per-payment + session USD ceilings, fail-closed |\n| Custody | Depends | **None** — signs with your wallet, holds no keys/funds |\n\n---\n\n## Install\n\n```bash\nnpm install @canopy-finance/x402-rwa viem\n```\n\n- **`x402`** is the only runtime dependency (settlement is delegated to it — never reimplemented).\n- **`viem`** is a *peer* dependency, used by the optional reference `ChainAdapter` at\n  `@canopy-finance/x402-rwa/viem`.\n- Ships **dual ESM + CJS** with full type declarations. Node ≥ 18.\n\n---\n\n## Quickstart\n\nOne function wraps `fetch`. Use the result exactly like `fetch`; `402`s are handled transparently.\n\n```ts\nimport { wrapFetchWithRwaPayment } from \"@canopy-finance/x402-rwa\";\nimport { createViemChainAdapter } from \"@canopy-finance/x402-rwa/viem\";\nimport { createPublicClient, createWalletClient, http } from \"viem\";\nimport { privateKeyToAccount } from \"viem/accounts\";\n\nconst account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);\nconst walletClient = createWalletClient({ account, chain: myChain, transport: http() });\nconst publicClient = createPublicClient({ chain: myChain, transport: http() });\n\nconst fetchWithRwa = wrapFetchWithRwaPayment(walletClient, {\n  settleToken: \"USDG\",                      // settlement asset symbol (address from config)\n  fundFrom: { symbols: [\"NVDA\", \"TSLA\"] },  // RWA holdings sellable, in priority order\n  chainId: 4663,\n  maxAutoSwapUsd: 50,                        // hard per-payment ceiling; above → throw, never swap\n  slippagePct: 1,\n\n  quoter: myQuoter,                          // YOU provide (DEX / aggregator)\n  priceSource: myPriceSource,               // YOU provide (INDEPENDENT oracle) — feeds the wall\n  chain: createViemChainAdapter({ publicClient, walletClient }),\n\n  // Operator-provided, validated, checksummed address book — NO addresses ship in this package.\n  config: {\n    chainId: 4663,\n    router: \"0x…\",                          // verified DEX router that funding swaps go through\n    permit2: \"0x…\",                         // optional\n    settleTokens: { USDG: { address: \"0x…\", decimals: 6 } },\n    rwaTokens:    { NVDA: { address: \"0x…\", decimals: 18 }, TSLA: { address: \"0x…\", decimals: 18 } },\n  },\n\n  confirm: async (plan) => plan.estimatedUsd <= 25,  // optional human/agent approval hook\n});\n\nconst res  = await fetchWithRwa(\"https://api.example.com/premium\");\nconst data = await res.json();\n```\n\nRun the fully-offline demo (stubs only — no RPC, DEX, or real funds):\n\n```bash\nnode example/basic.mjs\n```\n\n```text\nScenario A: sufficient USDG → pays directly, NO swap\n  pay:     10000000 0x5fc5…d168 → 0x2222…2222\n  result: 200 { data: 'premium payload' }\n\nScenario B: short USDG → swap just enough NVDA, then pay\n  confirm: sell ~101500000000000000 NVDA for ~$10.15 (floor 10048500)\n  approve: spender=0x8876…0904 amount=101500000000000000\n  swap:    to=0x8876…0904 value=0\n  pay:     10000000 0x5fc5…d168 → 0x2222…2222\n  result: 200 { data: 'premium payload' }\n```\n\n---\n\n## How it works\n\nOn an `HTTP 402`, the wrapper runs a deterministic **fund-or-pay** decision:\n\n1. **Parse** the x402 `402` body and select the payment requirement denominated in your settlement\n   token. If the resource doesn't accept it → fail closed.\n2. **Read** the payer's settlement-token balance.\n   - **Covered?** Pay directly via x402 client primitives. **No swap.**\n   - **Short by Δ?** Continue.\n3. **Size** an RWA → stablecoin *exact-input* swap for Δ plus a small buffer, using the\n   **independent** price source (not the DEX quote).\n4. **Build** the swap with your injected `Quoter` and run it — plus any approval — through the\n   [validation wall](#-the-validation-wall). A rejection **aborts the payment**.\n5. **Enforce** the hard USD ceilings and the optional `confirm()` hook *before* any signature.\n6. **Execute** the user/agent-signed approval + swap, wait for on-chain success, and re-check the\n   balance actually covers the invoice.\n7. **Settle** the x402 payment by delegating to `x402`'s `createPaymentHeader` and retrying once.\n\n---\n\n## Architecture\n\n```mermaid\nflowchart TD\n    A[caller: fetchWithRwa url] --> B{status == 402?}\n    B -- no --> Z[return response as-is]\n    B -- yes --> C[parse 402 · select settlement requirement]\n    C --> D[read settlement-token balance]\n    D --> E{balance >= required?}\n    E -- yes --> S[settle via x402 createPaymentHeader]\n    E -- no --> F[size swap for shortfall + buffer<br/>using INDEPENDENT price source]\n    F --> G[Quoter builds RawQuote]\n    G --> H{{VALIDATION WALL<br/>router · tokens · amountIn · value ·<br/>recomputed minOut floor · impact ·<br/>deviation · price state · deadline · approval}}\n    H -- reject --> X1[throw RwaWallError · no swap · no pay]\n    H -- pass --> I{estimatedUsd <= caps?}\n    I -- no --> X2[throw RwaFundingLimitError · no swap · no pay]\n    I -- yes --> J{confirm plan?}\n    J -- false --> X3[throw RwaError CONFIRM_DECLINED]\n    J -- true --> K[send approval if needed → send swap → wait success]\n    K --> L{balance now >= required?}\n    L -- no --> X4[throw RwaError INSUFFICIENT_AFTER_SWAP]\n    L -- yes --> S\n    S --> Y[return 200 response]\n```\n\n### Payment handshake (short path)\n\n```mermaid\nsequenceDiagram\n    participant App\n    participant Wrap as wrapFetchWithRwaPayment\n    participant Chain as ChainAdapter\n    participant Wall as Validation Wall\n    participant DEX as Quoter / Router\n    participant x402 as x402 client\n    participant API as Paid API\n\n    App->>Wrap: fetch(/premium)\n    Wrap->>API: GET /premium\n    API-->>Wrap: 402 (accepts: USDG)\n    Wrap->>Chain: getErc20Balance(USDG)\n    Chain-->>Wrap: short by Δ\n    Wrap->>DEX: quote(RWA→USDG, amountIn)\n    DEX-->>Wrap: RawQuote (untrusted)\n    Wrap->>Wall: validateQuote + validateApproval\n    Wall-->>Wrap: ok · independent minOut floor\n    Note over Wrap: enforce USD caps + confirm() BEFORE signing\n    Wrap->>Chain: sendApproval → sendSwap → waitForSuccess\n    Wrap->>x402: createPaymentHeader(requirement)\n    Wrap->>API: GET /premium + X-PAYMENT\n    API-->>App: 200 OK\n```\n\nThe **core is pure and injected**: swap sizing (`planner.ts`) and the wall (`wall.ts`) have no\nnetwork, no viem, no wagmi — they're driven entirely by values and stubs, and are unit-tested in\nisolation.\n\n---\n\n## 🧱 The validation wall\n\nPorted from Canopy's on-chain trading wall and **not weakened**. Every funding swap — and its\napproval — is checked *before the wallet is ever asked to sign*. The wall **never trusts the\nquoter's slippage or `minOut`**; it recomputes an independent floor from an independently-sourced\nexpected output.\n\n| Check | Rule |\n|---|---|\n| **Router** | `tx.to` **==** the verified router from your config |\n| **Tokens** | `tokenIn` / `tokenOut` match the intended verified addresses |\n| **Amount** | `amountIn` **==** the amount the helper deterministically planned to sell |\n| **Value** | `tx.value == 0` for an ERC-20-in swap (no stray native value) |\n| **minOut** | **≥ an independently recomputed floor** — the quoter's `minOut` is *never* trusted |\n| **Impact** | `priceImpact ≤ slippagePct` **and** `≤ maxImpactPct` |\n| **Deviation** | quote's expected-out vs. the **independent** `priceSource` ≤ session threshold |\n| **Price state** | `LIVE` / `CLOSED` / `PAUSED` / `STALE_ERROR` gating — a paused/stale feed blocks execution regardless of off-hours settings |\n| **Deadline** | present, not expired, and within a sane forward window |\n| **Approval** | target is the token or verified Permit2; spender is the verified router; amount is bounded (rejects max-uint) |\n| **Coverage** | even after passing, the recomputed floor must cover the shortfall or the payment aborts |\n\n> A failing swap **aborts the payment** with `RwaWallError` (carrying `.reasons`). The helper\n> **never** force-pays with a bad swap.\n\n**Why the independent floor matters** — the DEX quote is adversarial input. A malicious or buggy\nquoter could report a generous `minOut` while the calldata guarantees far less. The wall discards\nthe quoter's number and recomputes `floor = expectedOut × (1 − slippage)` from the independent\noracle, then rejects anything below it. This is provably not the quoter's value (see the tests).\n\n---\n\n## 🔒 Hard limits (fail-closed)\n\n- **`maxAutoSwapUsd`** — an absolute per-payment ceiling. If funding a payment would exceed it, the\n  helper throws `RwaFundingLimitError` **before any swap or signature**. No swap, no payment.\n- **`maxSessionSwapUsd`** *(optional)* — a cumulative ceiling across the lifetime of the wrapped\n  fetch.\n- **Any ambiguity fails closed** — unknown token, unavailable/paused price, a floor that can't\n  cover the shortfall, or insufficient RWA all throw rather than guess.\n\n---\n\n## 🛡️ Security model\n\n- **Non-custodial.** The package never holds funds or private keys. It only ever asks the\n  `walletClient` *you* pass to sign, and broadcasts through the `ChainAdapter` *you* provide.\n- **No hardcoded addresses.** Zero mainnet addresses ship in this package. Every token, router, and\n  settlement address comes from your `config`, and is validated + **checksummed** at init.\n  Missing/invalid config throws `RwaConfigError` immediately.\n- **Adversarial-input assumption.** The quoter's output is treated as untrusted and must pass the\n  wall. The price source must be **independent** of the quoter/DEX — that independence is what makes\n  the deviation check meaningful.\n- **Pure, tested core.** The wall and planner are side-effect-free and covered by unit tests,\n  including one test per wall failure mode.\n- **Buyer-side only.** No seller middleware, so there's no server-side settlement surface here.\n\nFound a vulnerability? See [`SECURITY.md`](./SECURITY.md).\n\n---\n\n## API reference\n\n### `wrapFetchWithRwaPayment(walletClient, options) → fetch`\n\nReturns a `fetch`-compatible function.\n\n| Option | Type | Notes |\n|---|---|---|\n| `settleToken` | `string` | Settlement token **symbol**; address resolved from `config.settleTokens`. |\n| `fundFrom` | `{ symbols: string[] }` | RWA symbols sellable to fund payments, in priority order. |\n| `chainId` | `number` | Must match `config.chainId`. |\n| `maxAutoSwapUsd` | `number` | Absolute per-payment USD ceiling. Above → throw, never swap. |\n| `slippagePct` | `number` | Policy slippage `[0, 100)`; drives the recomputed `minOut` floor. |\n| `quoter` | `Quoter` | Injected DEX/aggregator. |\n| `priceSource` | `PriceSource` | Injected **independent** oracle; sizes swaps + feeds the wall. |\n| `chain` | `ChainAdapter` | Reads balances/allowances + broadcasts user-signed txs. |\n| `config` | `RwaPaymentConfig` | Validated, checksummed address book. |\n| `confirm?` | `(plan) => Promise<boolean>` | Approval hook; `false` aborts **before** signing. |\n| `maxSessionSwapUsd?` | `number` | Cumulative USD ceiling for the wrapped fetch's lifetime. |\n| `maxImpactPct?` | `number` | Max price impact (default `3`). |\n| `maxDeviationLivePct?` | `number` | Max quote-vs-oracle deviation while `LIVE` (default `2`). |\n| `maxDeviationOffhoursPct?` | `number` | Max deviation off-hours (default `5`). |\n| `executeOffhours?` | `boolean` | Allow execution while price state is `CLOSED` (default `false`). |\n| `fundingBufferBps?` | `number` | Extra headroom over slippage when sizing (default `50`). |\n| `swapDeadlineSeconds?` | `number` | Swap deadline window from now (default `600`). |\n| `maxDeadlineWindowSeconds?` | `number` | Max acceptable deadline window for the wall (default `3600`). |\n| `settler?` | `PaymentSettler` | Override the x402 settler (defaults to `createPaymentHeader`). |\n| `fetch?` | `typeof fetch` | Override the underlying fetch (defaults to `globalThis.fetch`). |\n| `now?` | `() => number` | Clock injection (ms epoch), for tests. |\n\n### Also exported\n\nPure/testable building blocks: `validateQuote`, `validateApproval`, `buildFundingPlan`,\n`computeShortfall`, `computeTargetOut`, `sizeAmountIn`, `ceilDiv`, `parse402`,\n`selectRequirementForAsset`, `createX402Settler`, `resolveConfig`, and the `StubQuoter` /\n`StubPrice` test doubles. Reference adapter: `createViemChainAdapter` from `.../viem`.\n\n---\n\n## Injected dependencies\n\n```ts\ninterface Quoter {\n  quote(req: {\n    tokenIn: TokenInfo; tokenOut: TokenInfo; amountIn: bigint;\n    recipient: string; slippagePct: number; deadlineSeconds: number;\n  }): Promise<RawQuote>;\n  // RawQuote = { tx, tokenIn, tokenOut, amountIn, expectedAmountOut,\n  //              minAmountOut, priceImpactPct, deadline, approval? }\n}\n\ninterface PriceSource { // MUST be independent of the quoter/DEX\n  impliedAmountOut(req: { tokenIn: TokenInfo; tokenOut: TokenInfo; amountIn: bigint })\n    : Promise<{ amountOut: bigint; state: \"LIVE\" | \"PAUSED\" | \"CLOSED\" | \"STALE_ERROR\" }>;\n}\n\ninterface ChainAdapter { // reads balances/allowances + broadcasts user-signed txs\n  ownerAddress(): Promise<string>;\n  getErc20Balance(token: string, owner: string): Promise<bigint>;\n  getErc20Allowance(token: string, owner: string, spender: string): Promise<bigint>;\n  sendApproval(step: ApprovalStep): Promise<string>;\n  sendSwap(tx: QuoteTx): Promise<string>;\n  waitForSuccess(hash: string): Promise<void>; // MUST reject on revert\n}\n```\n\n`StubQuoter` and `StubPrice` ship for tests/examples; `createViemChainAdapter` is a thin,\nnon-custodial reference implementation (viem is a peer dependency, not a hard one).\n\n---\n\n## Errors\n\n| Error | Thrown when | Carries |\n|---|---|---|\n| `RwaConfigError` | invalid/missing config or options (at init) | — |\n| `RwaWallError` | a funding swap/approval failed the validation wall | `.reasons: string[]` |\n| `RwaFundingLimitError` | swap would exceed `maxAutoSwapUsd` / `maxSessionSwapUsd` | `.scope`, `.requestedUsd`, `.limitUsd` |\n| `RwaError` | other failures (see `.code`) | `.code` |\n\n`RwaError.code` ∈ `UNSUPPORTED_402 · NO_FUNDING_ROUTE · WALL_REJECTED · LIMIT_EXCEEDED ·\nSESSION_LIMIT_EXCEEDED · CONFIRM_DECLINED · SWAP_FAILED · INSUFFICIENT_AFTER_SWAP · PRICE_UNAVAILABLE`.\n\n---\n\n## Testing\n\n```bash\nnpm test          # 47 unit tests, zero network\nnpm run typecheck # tsc --noEmit, strict\nnpm run lint      # eslint\nnpm run build     # tsup: ESM + CJS + .d.ts / .d.cts\n```\n\nCoverage highlights: every wall failure mode (one test each), the independently-recomputed `minOut`\nfloor (provably ≠ the quoter's), sufficient-balance direct pay (no swap), short-balance\nfund-then-pay, `maxAutoSwapUsd` / session-cap enforcement, invalid-config init throws, and the\n`confirm()` abort path — all with stubs and a mocked 402 handshake.\n\n---\n\n## Limitations (v1)\n\n- **Settlement token assumption.** USD sizing assumes the settlement token is a USD-pegged\n  stablecoin (~$1); `maxAutoSwapUsd` / `estimatedUsd` derive from the settlement amount, not an\n  independent USD oracle on the stablecoin itself.\n- **Per-payment scope.** Caps/swaps are evaluated per payment; the session cap is in-memory for the\n  wrapped fetch's lifetime (not persisted).\n- **Exact-input funding.** Swaps are sized from the oracle plus a buffer, so you may acquire\n  slightly more settlement token than owed (the remainder stays in your wallet). The recomputed\n  floor must still cover the shortfall or the payment aborts.\n- **Buyer-side only.** No seller/middleware is included.\n- **One initial request per call.** Non-402 responses pass through untouched; a 402 triggers the\n  fund-or-pay path and a single settlement retry.\n\n---\n\n## FAQ\n\n**Does it ever hold my funds or keys?** No. It's non-custodial — it signs with your wallet client\nand broadcasts through your chain adapter.\n\n**What if I already hold enough stablecoin?** It pays directly and never swaps.\n\n**Can the DEX trick it into a bad swap?** The quote is untrusted and must pass the wall, whose\n`minOut` floor is recomputed independently and whose deviation check uses a separate price source.\n\n**Which chains/DEXes are supported?** Any — everything is injected. Provide a `Quoter`,\n`PriceSource`, and `ChainAdapter` (a viem reference adapter is included).\n\n**Why is the price source required to be independent?** So the deviation check can catch a quoter\nthat misreports output. If it shared the DEX's price, the check would be meaningless.\n\n---\n\n## License\n\n[MIT](./LICENSE) © Canopy Finance\n","readmeFilename":"README.md","_rev":"1-646e2ca0019833210f6ba7772d29045e"}