Abstract
On 29 October 2026 a Binance hot key was compromised and about $6.36B left the exchange's wallets in roughly 20 minutes, with an EIP-7702 delegation in the attack path. Nobody could react inside that window. The key signed, the chain executed, and the money was gone.
That is the default for every hot wallet today: whoever holds the key holds everything behind it, instantly. Uriel changes the second half of that sentence. It does not stop keys from being stolen. It stops a stolen key from emptying the wallet, by putting three things between the key and the money.
The same drain against a Sanctum on default rules yields the thief at most 10% of each asset per day, and the Sanctum can be frozen the moment a node or the owner sees the attack. We make no claim about what would have happened at Binance specifically; their wallets are not Uriel Sanctums, and the comparison is about the mechanism, not that incident.
Threat model
Uriel splits a wallet into two keys. The hot key (the Sanctum's owner) does everyday work and is assumed to be stealable. The cold key (cold) lives offline, ideally on a hardware wallet, and is assumed safe. Every guarantee below depends on that assumption.
Uriel defends against
- A stolen or phished hot key. The thief is held to the hourly and daily caps; anything above them queues for 6 hours where the cold key can cancel it.
- Malicious EIP-7702 re-delegation. If a guarded hot wallet's delegation changes away from Guard7702, nodes treat it as a compromise and freeze the Sanctum.
- Fast automated drains. Exploit bots and AI agents work in seconds. The caps are enforced by the contract per block, so speed buys an attacker nothing beyond the allowance.
- Rule loosening by the thief. The hot key cannot raise the daily cap or shorten the delay at all, and any other loosening it proposes waits at least 3 days and triggers a node panic.
Uriel does not defend against
- A stolen cold key. The cold key can change the rules, rotate both keys and lift a freeze. If it is lost, Uriel cannot help.
- Compromised signing infrastructure that also holds the cold key. One system holding both keys is one key.
- Bugs in other protocols. Funds that leave the Sanctum, or were never in it, are outside its rules.
- Approvals and permits signed outside the Sanctum. A phished
approveor permit on tokens held in a bare wallet drains that wallet, not the Sanctum.
The v1 node client panics on three signals: a guarded wallet re-delegating, the hot key proposing looser rules, and any queued transfer on a public showcase Sanctum. A thief who simply uses the stolen hot key to withdraw within the caps is not flagged automatically in v1. The caps still bound the loss to 10% of each asset per 24 hours; the owner (or cold key) is expected to notice and hit Panic. Broader behavioural detection is roadmap work, not a v1 feature.
Architecture
Five on-chain pieces carry the security model: GuardVault holds funds, Guard7702 turns a hot wallet into a funnel, GuardVaultFactory creates Sanctums and makes them discoverable, Blacklist lists addresses no Sanctum will pay, and Staking decides who counts as a node. An off-chain node client watches and acts.
GuardVault
One Sanctum per wallet, holding ETH and any ERC-20. Its rules are a five-field struct. The factory default is:
| Rule | Default | Meaning |
|---|---|---|
capBps | 500 (5%) | Max immediate outflow per asset per one-hour window, measured against the balance at the window's start. |
dayCapBps | 1000 (10%) | Max immediate outflow per asset over a rolling 24 hours, kept as 24 hourly buckets, so there is no day boundary to exploit. |
delayBps | 1000 (10%) | Transfers above this share of the balance go to the queue. |
delay | 21,600 s (6 h) | How long a queued transfer waits before it can execute. |
allowlistOn | false | When on, the Sanctum only pays addresses the cold key has allowlisted. |
The daily allowance is computed on current balance plus what left in the last 24 hours, so splitting a withdrawal into small pieces neither shrinks nor grows it. A withdrawal that the caps cannot pay right now is queued rather than reverted: the owner never hits a dead end, and a thief still has to wait out the delay.
Who can do what
| Action | Hot key | Cold key | Staked node |
|---|---|---|---|
withdraw (capped or queued) | Yes | No | No |
executeQueued after the delay | Yes | Yes | No |
cancel a queued transfer | Yes | Yes | No |
coldWithdraw: skips the queue, never the caps, blacklist or freeze | No | Yes | No |
panic: freeze 24 h | Yes | Yes | Yes, unless muted |
unfreeze | No | Yes | No |
| Change rules | Propose only, waits ≥ 3 days; daily cap and delay tighten-only | Immediately, any direction | No |
Rotate keys (setOwner, setCold), allowlist, swap blacklist | No | Yes | No |
A hot-key rule proposal applies after the longer of the current delay and 3 days. The contract rejects any proposal that raises dayCapBps or shortens delay, both when proposed and again when applied. Other loosening (a higher hourly cap, a higher queue threshold, switching the allowlist off) is possible from the hot key after the wait, which is why nodes treat any loosening proposal as a compromise signal and panic, and a panic cancels the pending proposal.
Panic
panic() sets frozenUntil to now + 24 hours, records lastPanicAt, and kills any pending hot-key rule change. While frozen, no withdraw, executeQueued or coldWithdraw goes through. Every transfer queued at or before the panic is voided permanently: a freeze alone would only postpone a thief's queued drain by a day. The owner re-queues anything legitimate after.
When the cold key calls unfreeze(), nodes are muted on that Sanctum for 24 hours, so a misbehaving or mistaken node cannot freeze the owner again straight away. The owner and cold key can still panic during the mute.
- T+0Hot key stolenAttacker re-delegates the EOA, proposes looser rules, or starts withdrawing. Capped outflow only: at most 5% this hour.
- next poll · default 10 sA staked node sees the signalDelegation code no longer points at Guard7702, or a RulesProposed event loosens the rules.
- one transactionpanic() → frozen for 24 hAll outflows blocked. Everything queued so far is voided. Any pending hot-key rule change is cancelled.
- owner, offline keyCold key resolves itcancel(id) · setOwner(newHotKey) · coldSetRules if needed
- unfreeze() → node panic muted 24 h
Guard7702
An EIP-7702 delegate for the hot wallet. The EOA calls init(Sanctum) on itself once, binding it to its Sanctum in a namespaced storage slot (ERC-7201). After that, sweep(token) moves ETH or any ERC-20 sitting in the EOA into the Sanctum, and it is permissionless: a node, a keeper or the owner can sweep the moment funds land. A third-party ETH sweep leaves 0.01 ETH behind so a griefer cannot strand the owner without gas. Calls made through the delegate's execute may only target the Sanctum.
A 7702 authorization is applied by the protocol before any code runs, and the key can still sign ordinary transactions from the EOA. No delegate can stop a stolen key from signing or from re-delegating. That is why the money lives in the Sanctum, not the EOA: Guard7702 makes the wallet a funnel, and a re-delegation becomes a signal that nodes act on.
GuardVaultFactory
create(cold) deploys a Sanctum with the defaults above; createWithRules takes custom rules. The caller becomes the hot key. Every Sanctum is wired to the shared Blacklist and to Staking as its node registry, and the factory emits VaultCreated, which is how nodes discover what to watch.
Blacklist
Every outflow checks that the destination is not flagged. In v1 the list is a team-run oracle: the owner (the deployer) appoints oracle keys, and oracles flag or unflag addresses with a reason. A cold key can point its Sanctum at a different blacklist, or at none. Replacing the oracle with a Merkle root posted by Canary nodes is planned, not shipped.
Node client
guardian-node.mjs is a single Node.js process with a staked key. Each loop (10 s by default) it:
- discovers Sanctums from the factory's
VaultCreatedlogs and re-reads each Sanctum's current hot key, since the cold key may rotate it; - marks a wallet as guarded once its code is the Guard7702 delegation and the delegate points at that Sanctum, and calls
panic()if a guarded wallet's delegation later changes; - calls
panic()when aRulesProposedevent loosens any rule; - on public showcase Sanctums (where the hot key is published on purpose), panics on any live queued transfer and logs every drain;
- logs every large queued transfer on all Sanctums, calls
poke()on Emission every 10 minutes, and claims its rewards daily.
Node network
Standing to freeze a Sanctum comes from stake. Nodes stake URIEL in the Staking contract; nothing else is accepted. isNode is true for any address staked at or above the node threshold, and every Sanctum asks the registry before accepting a node's panic.
| Parameter | Value | Notes |
|---|---|---|
| Minimum stake | 1,000 URIEL | Smallest position allowed. Below the node threshold it earns nothing. The owner can change it. |
| Node threshold | 100,000 URIEL | Standing to panic and to earn. Immutable after deploy. |
| Unbonding | 24 hours | Unstaked tokens wait 24 h and stay slashable while they wait. |
| Epoch | 10 minutes | Anyone may call poke(); staking actions also poke first. |
Seraphim tiers
Emissions are split pro rata over weighted node stake: each node's earning balance is its stake times a tier multiplier. Crossing a tier boundary checkpoints rewards, so a new weight applies only from that moment.
| Tier | Stake | Weight |
|---|---|---|
| Below threshold | 1,000 – 99,999 | 0 |
| Watcher | ≥ 100,000 | ×1.00 |
| Guardian | ≥ 500,000 | ×1.25 |
| Archangel | ≥ 2,000,000 | ×1.50 |
Only nodes earn. If no node is staked when an epoch is paid, that epoch's emission is burned rather than left to pile up for whoever stakes first. Every stake change settles the emission backlog before it applies, so a flash stake cannot claim epochs that elapsed before it existed.
Slashing
The slasher key can burn any share of a node's active and unbonding stake, with a reason string on-chain. In v1 the slasher is the deployer. That is a trusted role and we disclose it as one: there is no on-chain fault proof yet.
Token
URIEL is an ERC-20 with a hard cap of 21,000,000. 18,900,000 are minted at genesis to the deployer, who distributes them at launch. The remaining 2,100,000 can only be minted by the Emission contract. The minter is set once and then locked; there is no admin mint and no way to raise the cap.
Paired with about $5,000 of ETH (priced at deploy) on Uniswap v2. LP tokens locked in LPLocker until 1 Jan 2027.
Two lockers: 1,050,000 unlock 15 Nov 2026, 1,050,000 unlock 1 Dec 2026.
Held by the deployer wallet. Not locked.
Minted over time to staked nodes only. Burned when no node is staked.
Emission schedule
Emission starts 1 hour after deploy and pays a fixed amount per 10-minute epoch: 1,041.67 URIEL in the first week, halving every 7 days (1,008 epochs). Each week therefore emits half the previous one, and the total converges on 2,100,000. Amounts accrue per epoch and are minted into Staking when anyone calls poke().
| Week | Per epoch | Week total | Cumulative |
|---|---|---|---|
| 1 | 1,041.67 | 1,050,000 | 1,050,000 |
| 2 | 520.83 | 525,000 | 1,575,000 |
| 3 | 260.42 | 262,500 | 1,837,500 |
| 4 | 130.21 | 131,250 | 1,968,750 |
| 5 | 65.10 | 65,625 | 2,034,375 |
| 6 | 32.55 | 32,813 | 2,067,188 |
| 7 | 16.28 | 16,406 | 2,083,594 |
| 8 | 8.14 | 8,203 | 2,091,797 |
Trade tax and launch limits
Transfers to or from a registered Uniswap pair are taxed, and the tax is paid to the team wallet. Tax-exempt addresses (deployer, team, the token, Emission, Staking) are not taxed. Wallet-to-wallet transfers, staking and Sanctum deposits are never taxed: a pair can only be registered if it is a real pool holding URIEL.
| Minute | 0 | 10 | 20 | 30+ |
|---|---|---|---|---|
| Tax on pair trades | 20.0% | 14.3% | 8.7% | 3.0% |
| Max tx (pair trades) | 210,000 | 210,000 | 210,000 | none |
| Max wallet (buyers) | 210,000 | 210,000 | 210,000 | none |
Before openTrading() is called, any taxed transfer reverts, so nobody but exempt addresses can trade against the pool before open. The deploy script creates the pair and registers it as taxed before liquidity goes in, and calls openTrading() as its very last step.
Roadmap
Launch is the only date we commit to. Everything below is direction, in rough order, and none of it exists in the v1 contracts.
- Raid the SanctumA public showcase Sanctum whose hot key is published. Anyone can try to drain it; nodes panic on any queued transfer and every drain is logged. The caps either hold in public or they do not.
- Panic leaderboard and bountiesA public record of which nodes caught what, first, with bounties for valid catches.
- Canary honeypot nodesThe same nodes run bait wallets and contracts. Every address that touches them feeds the blacklist all Sanctums check, replacing the team-run oracle with a node-posted Merkle root.
- Intel feedFlagged addresses and theft signals published as a feed other wallets and protocols can consume.
- ETH fee leg for nodesA possible second reward stream for nodes, paid in ETH, so node income does not rest on emissions alone. Under consideration, not designed.
- More chainsThe Sanctum and delegate are chain-agnostic Solidity. Other EVM chains with EIP-7702 are candidates.
Risks and disclosures
URIEL is not an investment and carries no promise of yield, return or price. Emissions go only to staked nodes and fall by half every week. You can lose everything you put in.
- No external audit. The contracts have internal Foundry tests run against a mainnet fork. No third-party firm has audited them. Bugs may exist, including bugs that defeat the Sanctum's guarantees.
- Admin keys sit with the deployer. The deployer holds the slasher key (can burn node stake), the Blacklist owner and oracle keys (can flag any address, which blocks Sanctum payments to it), and the token owner role (
setPair,setTaxExempt,setTeam). The Staking owner can change the minimum stake and the slasher. None of these can mint, raise the tax or touch funds inside a Sanctum. - The tax goes to the team. The 3% trade tax (20% at open) is paid to the team wallet, not to nodes or holders.
- Thin liquidity. The pool opens with about $5,000 of ETH against 14.7M URIEL. Prices can move sharply on small trades. The LP is locked until 1 Jan 2027; after that the deployer can withdraw it.
- Unlocked treasury and team unlocks. The 2.1M treasury is not locked. Team tokens unlock on 15 Nov and 1 Dec 2026.
- Detection is narrow in v1. See the threat model: capped withdrawals by a stolen hot key are not auto-flagged, and a node panic depends on at least one honest node running.
- The cold key is a single point of failure. Lose it and you lose the ability to unfreeze or rotate; leak it and Uriel offers no protection.
- A freeze cuts both ways. A mistaken or malicious node panic blocks your own outflows for up to 24 hours (until the cold key unfreezes) and voids your queued transfers.
Contracts
Deploying 1 Nov 2026 · 19:00 UTC
All contracts are on Ethereum mainnet. Addresses appear here once the deploy script has run; until then, nothing on this page links to a contract.
| Contract | Role | Admin |
|---|---|---|
| GuardToken | URIEL ERC-20, tax, launch limits | Owner: pair, exemptions, team wallet. Minter locked to Emission. |
| Emission | 10-minute epochs, weekly halving | None |
| Staking | Node registry, tiers, rewards, slashing | Owner: min stake, slasher. Emission set once. |
| GuardVaultFactory | Creates Sanctums, emits VaultCreated | None |
| GuardVault | Per-wallet rate-limited Sanctum | Its own cold key |
| Guard7702 | EIP-7702 sweep delegate | None |
| Blacklist | Flagged destinations | Owner and oracles (deployer) |
| LPLocker ×3 | LP to 1 Jan 2027; team halves to 15 Nov and 1 Dec 2026 | None. Beneficiary withdraws after unlock. |