UNYKORN WALLET
wallet.unykorn.ai · dapp surface
Open the app
Institutional custody · Real-world assets

Custody, policy, recovery and issuance — with a capability layer for agents.

UnyKorn LLC builds and runs the rail that a licensed issuer's instrument runs on — never the issuer itself. The operator's name is refused as an issuer at compile time, in uny-issuance/src/lib.rs. Qualified custody is delegated to BitGo Bank & Trust, N.A. (OCC-chartered). This page is the wallet-side app — EIP-1193 to any dapp, EIP-6963 to any wallet-selection UI, and x402 capability tokens for agent-safe treasury movement. The BitGo→SoFi shape: the platform sells the rail; the client carries the licence and the liability.

Operator UnyKorn LLC · Wyoming · EIN 42-3536633 · infrastructure vendor, not issuer
Custodian BitGo Bank & Trust, N.A. (OCC-chartered)
Signer plane 2-of-3 threshold · user key + offline backup + custodian key
Compile-time refusal Instrument::new() refuses any issuer name resolving to Unykorn — see OPERATOR_NAMES in uny-issuance/src/lib.rs
Dollar door IssuerAuthority::LicensedIssuer{institution, licence} — the only path by which a $-denominated instrument exists on this platform
Test posture 271 tests pass (235 Rust + 17 x402 + 19 vault-sdk); ~7 verify external truth (cryptographic vectors). The rest verify internal consistency. Not an audit — external security review required before any wallet holds client money.
Supply invariant An instrument's supply cannot change without a policy decision and a receipt. Not by convention — the only path that mutates supply runs both gates first, and refuses to commit if the register and the instrument disagree.
Internal review 2026-08-08 · 1 critical, 5 high, 6 medium, 4 low. See SECURITY-REVIEW-2026-08-08.md. Two operational restrictions active until remediation:
  1. Do not perform a recovery ceremony for any wallet intended to hold value (H6 — ceremony discards the decapsulation keys).
  2. Do not expose the control plane beyond loopback on any machine another party can reach (C1 — one session token authorises a transfer).

Wallet — connect

Every EIP-6963 provider the page has heard from. Click one to connect. Nothing here leaves the browser.

Scanning for EIP-6963 providers…

Try a movement — see what a custody-native response looks like

POSTs to 127.0.0.1:7331/intent if a local vault is running. If not, shows the canonical response the policy engine would produce for that amount. Reminder: allowed means policy passed. It does not mean funds moved — custodian submission is gated (see status board).

Ready. Values here are echoed from the vault, not simulated by this page.

What the policy engine says

Three real decisions from the demo run — refused, needs-two-approvers, allowed.

2,500,000 USD
to 0xA1b2C3d4…9F
POLICY DENIED

Value exceeds daily ceiling ($1.5M) and destination is not on the allowlist.

4910 · reason: ceiling_and_destination · intent_9k7fr2ab
961,021.51 USD
to 0x00000000…00dEaD
PENDING APPROVALS
1 of 2 signed

Signer plane signed. Policy officer signature outstanding.

4911 · required: 2 · current: 1 · intent_qz3f1x8k
400 USDC
to 0x00000000…00dEaD
ALLOWED (policy passed)

Under ceiling; destination on allowlist; recovery proven; single-signer wallet.

200 · receipt idx 4021 · sha fd1d77…998923 · signer 822031A6DE1DB81C

Note. "Allowed" is a decision, not a settlement. Custodian submission (BitGo Express) is gated — see status board.

Example wallet — topology

M Helen Construction Escrow Pool — wal_m-helen-escrow

2-of-3 BitGoProxy base recovery proven

User key: Unykorn signer plane.
Backup key: offline, YubiKey 5C (office safe).
Custodian key: BitGo Bank & Trust, N.A.

x402 · Capability tokensThe layer that neither BitGo nor MetaMask has.

BitGo's model assumes a human approver at the end of every chain. MetaMask's assumes a human clicking Confirm. Neither answers the question an agentic treasury actually asks: how do I let a machine spend, continuously, without giving it the keys or a human babysitter?

x402 answers with a narrow, expiring, revocable, budget-bounded grant that authorises an agent to create intents only. It can never sign. It can never approve. It cannot raise its own budget. Fully compromised, it can only spend its remaining budget to destinations already on its allowlist, and every unit of that lands on the receipt chain.

MetaMask BitGo UNYKORN x402
Human signs each tx yes yes no (agent-authorised)
Agent can spend continuously no via API keys (broad) yes (narrow, bounded)
Budget-bounded no per-key limits yes (per-tx + total)
Destination-locked no whitelists yes (allowlist per capability)
Auto-expiring no no notBefore / expiresAt
Revocable no key rotation yes (nonce revocation)
Cannot sign / cannot approve n/a n/a by construction
Blast radius if compromised full wallet key scope remaining budget → allowlist

Signature format: Ed25519 over SHA-256(domain || canonical(header) || canonical(claims)). No JWT — algorithm agility is the vulnerability (alg:none, RS256/HS256 confusion). One algorithm, one domain separator, no negotiation surface. Full implementation in packages/x402/src/capability.mjs.

Issuance railThe register, the compliance engine, the supply ceiling — the parts a bank or broker-dealer back office actually runs on.

Zero stablecoin issued by the operator. Every dollar-denominated instrument must land through IssuerAuthority::LicensedIssuer — a chartered bank or a permitted payment-stablecoin issuer under its own licence. That's the only door. What Unykorn provides is the register that holds the instrument, the compliance engine that gates its transfers, and the supply ceiling that caps its mints against a signed verifier quorum.

IssuerAuthorityMeaningTypical issuer
Reg D 506(b)Private placement, no general solicitation, up to 35 non-accreditedPrivate funds, RIA syndicates
Reg D 506(c)Private placement with general solicitation, accredited-only, verifiedMarketed RIA offerings, tokenised real estate
Reg SOffshore-only distributionNon-US issuers, non-US buyers
Reg A+Mini-IPO, up to $75M/year, accredited + retailGrowth-stage issuers pre-registration
RegisteredSEC-registered offering under S-1 / F-1 / etc.Public issuers, listed securities
LicensedIssuerThe dollar door. Chartered bank, or permitted stablecoin issuer under its own licence.Circle, First Digital, banks with trust powers
NotASecurityInstrument is not a security — counsel-memo-gated, refused without oneUtility credits, closed-loop points
SettlementVenueWhat it means for the register
BookEntryRegistrar of record, nothing touches a chain. This is what a transfer agent runs on — holders don't transfer, the intermediary does. The register is authoritative and the chain is optional. Answers the banks + broker-dealers question.
AlternativeTradingSystemATS-based settlement — venue-of-record for the trade, register still authoritative
OnChainPermissionedERC-3643 shaped. contract: Option<String> is None today because no smart contract is deployed by this repo — that leg is client-chosen and client-deployed
OmnibusCustodyPositions held omnibus by a custodian; the register maps beneficial owners under a single wallet
ComplianceRule (7)Enforcement · who may hold
RequireVerifiedRecipientRecipient identity must be verified on file before receipt.
JurisdictionAllowlistCountry / state / OFAC-level allow-list.
JurisdictionBlocklistCountry / state / OFAC-level block-list.
HoldingPeriodReg D / Reg S resale restrictions enforced by the register.
MaxHoldersOfRecordSection 12(g) 2,000-holder ceiling / 500 non-accredited ceiling.
MaxPositionPerHolderConcentration limits — beneficial-owner level.
AgentOnlyTransfersThe broker-dealer back-office primitive. Holders cannot transfer; the intermediary transfers on their behalf. Register authoritative.
CeilingPolicy · separate mechanismEnforcement · how much may exist
attestation_ceilingNot a ComplianceRule. Lives in attestation.rs, enforced inside Instrument::mint, not in the transfer path. Supply hard-capped at the median of a signed verifier quorum. Staleness halts minting automatically. Never cached — a cached ceiling keeps working after its evidence expires.
Chain supportStatus
EVM (Ethereum, Base, Arbitrum, Polygon)gated — chain adapters defined, no token contract deployed by this repo
Bitcoingated — adapter defined, no minting path here
Solanagated — adapter defined; SPL / Token-2022 client-deployed
XRPLgated — no MPT / trust-line issuance in this repo
Stellargated — no asset issuance with authorization / clawback flags in this repo

The honest sales frame. Unykorn provides the issuance register, the compliance engine, the supply ceiling and the custody rail. The client brings the licence and is the issuer of record. The platform will not let the operator's name onto an instrument — that refusal is compiled in, not policy documentation. That is a stronger position than "we issue stablecoins" and it is the one that survives a diligence meeting today.

Status boardWhat's real, what's gated, what's thin.

Every component below is labelled with the same convention used inside the codebase: real (running, verified, in the demo transcript), gated (built to a boundary, not wired past it), thin (surface exists so the interface reads honestly, no backend). A component labelled real is not the same as audited. See test-posture caveat in the header.

ComponentStatusReason
Recovery ceremony (SLIP-0039)realThreshold reconstruction rehearsed and one-share-short negative-control proven before a wallet can exist. Printable custodian cards produced.
Policy engine (refusals, approvals, ceilings)realPure evaluation; no I/O. Runs identically on control plane and signer plane by design.
Approval flow — four-eyes quorumrealMulti-signer sequencing with self-approval never counting toward quorum.
Audit record (receipt chain, offline-verifiable)realML-DSA-65 detached signatures over canonical bytes. Anyone with the signer's public key can verify the chain independently.
Phone pairing (QR)realOne-shot pair codes over the /pair/ routes.
Issuance register + attestation ceilingrealCeiling recomputed per mint — never cached, because caching outlives the evidence it depends on.
x402 capability tokensrealEd25519, domain-separated. In-process ledger tracks spend + revocation.
EIP-1193 + EIP-6963 providerrealpackages/vault-sdk/src/provider.mjs speaks EIP-1193 fully; adds the uny_* namespace.
Custodian submission (BitGo Express)gatedallowed currently means policy passed. Wire step 7 of create_intent to uny-bitgo against TEST env before shipping this claim.
Threshold signing (Tss) / HSM backendgatedBitGoProxy is the production key path. Local Tss is a placeholder trait.
Live balance feedgatedRecovery tier reports a floor and says so, rather than reading balances that might not exist.
/admin/reload endpointgatedProvisioning currently requires a service restart. Reload path documented; not written.
Card · Cover · Mesh backendsthinExtension tabs render standby. Nothing behind them yet. Honest UI is not a bug.
Issuance rail — legal + register typesreal7 IssuerAuthority variants, 4 SettlementVenue, 7 ComplianceRule, Attestation::compute_ceiling recomputed per mint. Operator name refused as issuer at compile time.
Issuance ↔ policy engine pipe (mints produce receipts, gated by policy)realuny-issuance-flow (1,808 LOC, 29 tests). Mint, burn and position transfer project into the same TransferIntent the movement engine already evaluates. One set of rules governs both paths — no second policy implementation to drift. Three receipts per action — request, decision, effect. Refusals are recorded too.
Register ↔ supply reconciliationrealA commit that would leave registry.total() != instrument.supply refuses rather than recording the break. The sharpest claim the rail can make: an instrument's supply cannot change without a policy decision and a receipt.
Smart contracts on any chain (ERC-3643, XRPL MPT, Stellar issued asset, SPL / Token-2022)thinZero .sol / on-chain deploys in this repo — by design. The chain leg is client-chosen and client-deployed under the client's own licence. SettlementVenue::OnChainPermissioned.contract is Option<String> and defaults to None.
Live attestation feed → compute_ceilinggatedThe type is real and tested; nothing pushes a real reserve balance into it. When wired, staleness halts minting automatically — the ceiling is never cached.
vault-sdk instrument surface (dapps see instruments / holders / transfer verdicts)thinvault-sdk speaks EIP-1193 + EIP-6963 today and exposes wallets and movements only. It does not yet expose uny_listInstruments / uny_transferVerdict. Next after the pipe.
make ci — fmt + clippy -D warnings + tests + release buildrealGreen for the first time as of commit fbacc68. Pre-existing clippy failures in uny-recovery, uny-bitgo, uny-store, uny-pq, uny-api are all fixed. Workspace passes clippy -D warnings.
cargo audit — dependency vulnerabilitiesreal237 dependencies against 1,190 advisories — zero vulnerabilities as of 2026-08-08.
Internal adversarial security reviewgatedCompleted 2026-08-08 to third-party standards by the author. 1 critical, 5 high, 6 medium, 4 low. Remediation window 14–19 engineer-days for critical + high, 20–29 for all. Full report at SECURITY-REVIEW-2026-08-08.md. Two operational restrictions active (see hero).
External third-party auditthinNot commissioned. Runs after remediation of critical + high findings. Named firm required before any wallet holds client money. Prereq to first paying institutional client.

Security postureWhat the code refuses, what has been found, what remains.

A control that reports itself present while absent is worse than one that is simply missing — it stops anyone looking. The 2026-08-08 internal review named four such controls and fixed the rest of the class. Every finding, every remediation step, every dependency vulnerability check is in SECURITY-REVIEW-2026-08-08.md.

1 critical · client-asserted quorum

C1. The approval quorum is asserted by the client body of /intent/{id}/approve. Approver identity, weight and the MFA flag arrive in the JSON. uny_types::Role is referenced zero times outside its own module; paired devices are never bound to sessions or approvals. Four-eyes does not exist at runtime.

Restriction: Do not expose the control plane beyond loopback on any machine another party can reach.

5 high · controls displayed as active while unenforced

  • H2 Remote process abort via UTF-8 byte slicing on attacker-controlled input.
  • H3 Recovery proof is forgeable — #[derive(Clone)] + all-pub fields; one rehearsal authorises creating any wallet.
  • H4 Unlock has no rate limit, no KDF, verifier in process env.
  • H5 Client-chosen asset bypasses every asset-scoped rule (u128::MAX with a made-up issuer → Allow).
  • H6 Ceremony discards the decapsulation keys — cards it prints cannot be opened, ever.
Restriction: Do not perform a recovery ceremony for any wallet intended to hold value.

Verified correct

cargo audit zero vulns across 237 deps. No path to Allow that skips rule evaluation. Deny absolute; AlwaysAllow never cancels a deny; empty set denies. Session token entropy 256-bit CSPRNG. Constant-time passphrase comparison. GF(2⁸) AES vectors pass. Shamir index-0 rejected, coefficients zeroized. Hybrid KEM combiner domain-separated over both secrets and both ciphertexts. Merkle avoids CVE-2012-2459 (with test). Amount arithmetic — no overflow or truncation defect. ML-DSA key handling. #![forbid(unsafe_code)] throughout.

Remediation — 14–19 engineer-days for C + H

Ten actions closing critical + all high, then all medium + low. Order after that: re-run sabotage tests → external audit → custodian against TEST → client funds. No step skipped.

14–19 days: critical + high
20–29 days: all findings
~4–8 weeks + $200K–$450K: through external audit + custodian TEST

The pattern worth remembering. Four findings share one shape — a control displayed to the operator as active while unenforced. The velocity cap is reported in /policy/{wallet} and can never fire (M8). recovery_proven: true is annotated "always true by construction" (H3). chain_verified: true is returned without checking who signed the chain (M9). The approval quorum is reported and is client-supplied (C1). A control that is absent is a gap. A control that reports itself present while absent is worse, because it stops anyone looking.

InstallBring the vault online on your own machine.

Nothing here uploads keys, seeds or recovery cards. Everything runs on your box. The control plane binds loopback-only; a non-loopback bind is refused, not merely discouraged. Push comes from your own gh.

Control plane

Rust API on 127.0.0.1:7331. Policy engine, signer plane, receipts ledger.

export UNY_PASSPHRASE_SHA256=$(printf 'pick' | sha256sum | cut -d' ' -f1)
./target/release/uny-api

Extension

Load the Genesis wallet extension from extension/ — Treasury and Pay tabs bind to the local vault.

chrome://extensions
Enable Developer mode
Load unpacked → <repo>/extension

SDK / dapp integration

Import the provider into any dapp. Speaks EIP-1193 to every existing site; announces itself via EIP-6963 to any wallet-selection UI.

import "@unykorn/vault-sdk"
// window.ethereum works
// AND EIP-6963 announce fires

Full walkthrough in START-HERE.md. Architecture in ARCHITECTURE.md. Rules that are never traded away in BUILD-PROMPT.md.