The one process that holds a seed, and it re-derives before it signs
The isolated signer for the FlashyOS wallet authorization plane: verifies an Ed25519-signed SpendAuthorization, re-derives the operation from the real call, refuses on any mismatch, executes through Tether WDK, and reports settlement. Holds the seed; never holds the plane's private key.
An authorization says what may happen; a call says what is happening. The signer is where the two are compared. It verifies the plane’s signature, refuses a replay, re-derives the operation from the actual call rather than from the authorization, refuses any mismatch, and only then executes through Tether WDK and reports settlement. It never holds the plane’s private key, and its chain table is testnets only.
Every request goes through five steps in a fixed order. The authorization’s Ed25519 signature and validity window are verified against the plane’s public key. The nonce is checked against a store — in memory, or a file that survives a restart — and a repeat is refused. The `OperationRecord` is re-derived from the call itself: the transaction, the swap or bridge, the EIP-3009 typed data. It is compared with the authorization — kind, chain, asset, destination, amount at or under the cap — and any difference is a refusal with a code. Only then is the nonce marked spent, the call executed through WDK’s wallet module, and settlement reported back to the plane from a confirmed receipt rather than a hash.
Two more lines of defence sit beside that. The WDK account the backend constructs registers exactly one allow rule — the operation being executed right now — so WDK’s own policy engine makes the account deny-by-default for everything else. And an optional on-chain limit reads the Safe Allowance Module before execution so the signer refuses what the chain would refuse; the chain still decides.
The HTTP face has no authentication of its own, on purpose: the authorization is the credential, a request without a valid one does nothing, and the port is reachable only inside the deployment’s network. Exposing it is a deployment error the runbook names.
The signer is tested against a cross-package fixture: an authorization the API signed, which this package must verify, so the two sides of the boundary cannot drift apart without a red build. Its testnet table is pinned by test, and the refusal codes are the same set the spec names. It publishes with the other two wallet packages, after wallet-wdk, from one workflow.
Apache-2.0, read from the package’s own manifest. Embed it in anything, including closed software — that is what makes a spec adoptable and a verifier worth running. FlashyOS’s server side is AGPL-3.0-only instead, and a test in the monorepo asserts the direction between them: AGPL code may consume this, this may never consume AGPL code.