# NON-AUTHORITATIVE COPY — served by the canister it describes. # # You are reading a document about who controls canister idm75-kaaaa-aaaac-a67ja-cai, served BY # canister idm75-kaaaa-aaaac-a67ja-cai. That is self-attestation, and you should not take it as # proof of anything on its own. # # THE AUTHORITY IS THE IC, NOT THIS FILE. The controller set and the current # module hash live in the IC's certified state tree and are readable without # trusting this canister: # # icp canister status idm75-kaaaa-aaaac-a67ja-cai -e ic # controllers + live module hash # icp canister info idm75-kaaaa-aaaac-a67ja-cai -e ic # the recent change history # # If either disagrees with what follows, believe the IC. # # The bytes below are compiled into the wasm, so they are covered by the # module hash you just checked — this copy cannot be changed without # changing that hash. # Controllers This document states, as plainly as possible, who can change the code behind DeltaRates' attestations today, what that control concretely allows and does not allow, and the trigger under which that changes. It is the governance companion to `docs/TRUST_MODEL.md` section 5.8 ("Controller as Single Point of Trust") — read that section for the full attack analysis. This page is the summary a visitor should be able to read in two minutes. Last verified against live canister state: **2026-08-07**, via the commands in "How to verify this yourself" below. Re-run them yourself — do not take this document's word for it. --- ## 1. Who controls what, today | Canister | ID | Controller | Purpose | |---|---|---|---| | `deltarates_backend` | `idm75-kaaaa-aaaac-a67ja-cai` | `gqleh-qzmnu-avv6q-woakg-4sax2-mkvui-vsa7k-oyigl-ubdma-xqpg4-kae` | Signs every attestation. The canister that matters most. | | `deltarates_frontend` | `zhwph-eqaaa-aaaac-bdxma-cai` | `gqleh-qzmnu-avv6q-woakg-4sax2-mkvui-vsa7k-oyigl-ubdma-xqpg4-kae` | Serves the SPA. Signs nothing; certified assets prove a page came from this canister, not that the controller never changed it. | | `block_oracle` | `ylpxr-2qaaa-aaaac-bd42q-cai` | `gqleh-qzmnu-avv6q-woakg-4sax2-mkvui-vsa7k-oyigl-ubdma-xqpg4-kae` | Block-timestamp lookup used by the backend. Reads are not signed on their own; they feed into signed attestations. | | `evm_rpc` | `7hfb6-caaaa-aaaar-qadga-cai` | Not controlled by DeltaRates | Pre-built DFINITY EVM RPC canister, deployed from a published release artifact, not from this repository. A `canister status` call from the DeltaRates identity is refused with "not allowed to read the canister status" — confirmed live, 2026-08-07 — which is itself evidence this identity does not control it. | **One principal, `gqleh-qzmnu-…-xqpg4-kae`, is the sole controller of all three canisters this project owns and deploys.** There is no multi-sig, no timelock, and no DAO in front of it today. This is the single controller `TRUST_MODEL.md` §5.8 calls the documented weakness, stated here without euphemism. --- ## 2. What a controller can concretely do - **Upgrade the WASM module** on any of the three canisters it controls, at any time, without notice to anyone. - On `deltarates_backend` specifically, an upgrade can install code that **signs fabricated attestations**. The ECDSA signature would be cryptographically valid — it is the same canister, with the same chain-key-derived signing key — so signature validity alone does not prove the underlying data is honest. This is `TRUST_MODEL.md` §5.2 ("Temporary Malicious Code (Upgrade-Sign-Revert)"). - Change canister settings: freezing threshold, compute/memory allocation, log visibility, add or remove controllers. - Call every controller-only method in `lib.rs` (`require_controller()` / `assert_controller()` guard sites) — provider configuration, tracking registration, debug endpoints, cycles-ledger recovery. - Stop, start, or (with sufficient permission) delete a canister outright. ## 3. What controller access does **not** mean - **It does not mean past attestations can be retroactively altered.** A signature already produced, and the IC certificate already issued over it, do not change if the code is upgraded afterward. What a malicious upgrade can do is sign *new* false attestations going forward — it cannot rewrite history. Each attestation embeds the WASM module hash that was active *at signing time* (fetched from the IC management canister, not self-reported), so an attestation signed today carries proof of today's code regardless of what runs tomorrow. - **It does not mean DeltaRates has ever exercised this power maliciously.** No such event is recorded in `docs/UPGRADE_LOG.md`, and every entry there states what changed and why. The concern this document exists to address is capability, not a documented incident. - **It does not mean there is a multi-sig, timelock, or governance process today.** There is one controller principal. Anyone claiming otherwise about this deployment would be wrong; do not infer a stronger guarantee than the table in section 1 states. - **It does not mean the code is, or should be, blackholed.** See section 4 for why that is deliberately not the current answer. ## 4. Why not just blackhole it Blackholing (removing all controllers) is the strongest guarantee available — frozen code forever, no possible malicious upgrade — and it is the wrong answer for this codebase *right now*. The backend reads third-party smart contracts whose data layout is not under DeltaRates' control and has already changed shape once: Aave's `ReserveData` layout shifted across point releases, which is why `decode_liquidity_rate` (`yield_source_engine.rs`) refuses to sign rather than silently misinterpreting a field it can no longer prove it is reading correctly. A blackholed canister cannot ship that kind of fix — the next unannounced upstream layout change would not corrupt the signed series, but it would permanently stop it, with no way to resume. Freezing the code to eliminate the controller risk would trade the identified, monitorable risk in section 2 for an unmonitorable one: a frozen canister silently going dark the next time an integrated protocol changes its ABI. ## 5. The path forward — trigger, not a date `TRUST_MODEL.md` §5.8 lists the progression: watcher monitoring → multi-sig → timelock controller canister → SNS/DAO governance → blackholing. This document does not commit to a date for any of those steps, because a date promised without the underlying governance decision behind it is a promise this project cannot keep on schedule. **The trigger:** work on a timelock controller canister (a blackholed canister that delays every upgrade by a fixed period, giving any independent watcher guaranteed time to detect and react before a malicious upgrade takes effect) starts when a public governance commitment is made about this project's direction — not before, and not against a calendar date set in advance of that decision. Until that trigger fires, the honest position is exactly what this document states: one controller, full disclosure of what that allows, and a growing public record (section 6) of every time it has been exercised. ## 6. The module-hash history Every deployed module hash for `deltarates_backend`, with date and source revision where recorded, lives in [`module-hash-history.json`](./module-hash-history.json). It is sourced from `docs/UPGRADE_LOG.md` (a repository path — see section 8) and cross-checked against live `canister_info` / `canister_status` at the time each entry was written. That link is **relative on purpose, and it resolves in both places**: in the repository it points at the sibling file in `docs/`, and in the served copy at `/trust/v1/controllers.md` it resolves to `/trust/v1/module-hash-history.json`, which exists. Do not "fix" it to an absolute URL — that would hard-code a hostname into a document that is read from two different roots. **Why a static file, and why now:** the IC's `canister_info` query returns only the **last 20 changes** for a canister. History older than that is unrecoverable from the chain itself unless someone archived it before it rolled off. A dedicated watcher canister (`TRUST_MODEL.md` §7-§8) is the robust version of this — polling continuously and never missing a change — but it does not exist yet. `module-hash-history.json` is the zero-infrastructure version: it costs nothing to run, is honest about its own gaps (some early entries have no recorded hash at all, which the file states explicitly rather than guessing), and is appended to automatically by `scripts/deploy-backend.sh` after every successful backend deploy from now on. It is a weaker guarantee than a watcher (it depends on someone remembering to commit the update, and it starts from 2026-08-07 rather than from genesis) — say so, rather than implying otherwise. ## 7. How to verify this yourself **Split by what it costs you, because that distinction is the point.** Everything in 7.1 needs nothing from us but the canister id. 7.2 needs the source, and the source is currently private — so 7.2 is **not** independently runnable by an outsider today, and saying otherwise would be the exact overclaim this document exists to avoid. *(An earlier version of this section opened "Every claim in this document is independently checkable. No trust in DeltaRates is required for any of the following" and then listed `scripts/verify-build.sh`, which needs a checkout nobody outside can obtain. Corrected 2026-08-15, when this file started being served publicly.)* ### 7.1 What anyone can run, with no repository and no trust in us The IC itself is the authority for both the controller set and the live module hash. Neither answer comes from this canister, so neither can be faked by it: ```bash # Live controllers + module hash for each canister this project owns. icp canister status deltarates_backend -e ic icp canister status deltarates_frontend -e ic icp canister status block_oracle -e ic # The recent change history the IC keeps (last 20 changes only — see section 6). icp canister info deltarates_backend -e ic ``` The recorded history, served by the canister itself over HTTP: ```bash curl -s https://idm75-kaaaa-aaaac-a67ja-cai.raw.icp0.io/trust/v1/module-hash-history.json ``` Read that file's own header before using it. It is **not authoritative** — it is this canister describing itself — and it states two things that matter: `_live_module_hash` is `null` whenever the runtime cache is cold (after every upgrade, until the first signing call), and the embedded archive **cannot contain the deploy that shipped it**, because a build's hash is unknowable until it is installed. A mismatch between the two is therefore the expected state immediately after a deploy, **not** evidence of tampering. `icp canister info` is the independent cross-check. ### 7.2 What needs the source, which is currently private ```bash # Confirm the deployed backend module hash matches a from-source rebuild. scripts/verify-build.sh ``` `scripts/verify-build.sh` rebuilds `deltarates_backend` using the same reproducible-build flags the deploy pipeline uses (`scripts/reproducible-env.sh` — the two share one definition rather than each keeping a copy, and the quality gate enforces that) and compares the result to what `icp canister status` reports live. A match means the deployed code is the published code. **It is the strongest claim in this document and the one an outsider cannot currently check**, because running it requires the repository. Until the repository is public, or the build is reproduced by a third party who has been given access, treat "reproducible from source" as a claim we make and have verified internally — most recently on 2026-08-15, where a build in a worktree at a different path reproduced the deployed module byte for byte — rather than as something you have confirmed. The honest summary: sections 1–6 are checkable by anyone; this one is not, yet. ## 8. Where this document lives, and what that means This file is maintained in the project repository and **compiled into the backend canister's WebAssembly module**, which is what lets it be served at `/trust/v1/controllers.md`. Two consequences worth stating: - **The served copy is covered by the module hash you can check.** It cannot be altered without changing the hash `icp canister status` reports. - **The served copy therefore lags the repository by one deploy.** Editing this file changes the module, so the canister keeps serving the previous text until the next backend deploy. If you are comparing the two, that is why they can differ. **References to `docs/…` and `scripts/…` elsewhere in this document are repository paths.** They are not URLs and, while the repository is private, an external reader cannot open them. They are kept because they name the artifact precisely for anyone who does have access; the two documents that *are* public are this one and `module-hash-history.json`, both under `/trust/v1/`.