Kerne Logo

Security disclosure

skUSD admin status: SAFE_ADMIN

skUSD is a live ERC-4626 wrapper for kUSD that you can deposit into today from app.kerne.fi. The vault's admin and strategist roles were rotated on May 18, 2026 from a single Trezor to the 2-of-3 Kerne Safe (admin) and the bot strategist EOA (yield-distribution authority). The Trezor that previously held both roles has renounced both, irreversibly. This page is the canonical record of the rotation, with every transaction hash linked to Basescan.

Last updated: May 18, 2026.

Current role topology (post-rotation)

The skUSD contract at 0xdEd74F7E06efc76455C07418b8b74Cc2bc009DB4 now has the following AccessControl state on Base mainnet:

Rotation execution log (2026-05-18)

Seven transactions on Base mainnet, in execution order. Click any hash to verify on Basescan.

  1. Trezor → bot: transfer 0.10 kUSD (pre-funds the smoke test)
  2. Trezor: grantRole(DEFAULT_ADMIN_ROLE, Safe)
  3. Trezor: grantRole(STRATEGIST_ROLE, bot)
  4. Bot: kUSD.approve(skUSD, 0.10 kUSD)
  5. Bot: skUSD.distributeYield(0.10 kUSD), smoke test that proves the new strategist topology works end-to-end
  6. Trezor: renounceRole(STRATEGIST_ROLE, Trezor)
  7. Trezor: renounceRole(DEFAULT_ADMIN_ROLE, Trezor). IRREVERSIBLE.

The order matters: grants land before any renounce so the contract is never admin-less. The smoke distributeYield call lands before the Trezor renounces, so the new strategist topology is proven working before the irreversible step. Pre-state and post-state assertions are embedded in the rotation scripts: scripts/skusd_rotate_phase1_grants_trezor.py, scripts/skusd_smoke_distribute_yield_bot.py, scripts/skusd_rotate_phase3_renounce_trezor.py.

What this rotation closes

The pre-rotation posture (parked-solo-admin) gave a single Trezor the ability to distributeYield() with attacker-controlled donations to manipulate share price, or to grant new roles to additional addresses. Both capabilities are now distributed: yield distribution requires the bot key, role changes require 2-of-3 Safe quorum, and the original Trezor has no authority over either path.

The skUSD source still ships the two structural defenses that were present before rotation: assets tracked via an internal _trackedAssets ledger (so a direct ERC-20 donation cannot inflate share price without an authenticated distributeYield() call) and a _decimalsOffset() = 6 that pushes the first-depositor share-rounding attack into economically prohibitive territory. Full source is Sourcify-verified (full match) and also on Blockscout.

The exit guarantee (unchanged by rotation)

skUSD is a wrapper. The underlying asset is kUSD at 0x5C2EfdF0D8D286959b42308966bc2B97f5680AA3. kUSD is administered by the 2-of-3 Kerne Safe. It is mintable 1:1 from USDC via the live mint PSM (v3) at 0x07eBb486e11BD217e6085eb5ab663e4517595993, and redeemable 1:1 for USDC via the redeem reserve at 0xFf3025ec18e301855aB0f36Ec6ECa115a29A5Fbc. Anyone holding kUSD can redeem it for USDC at the redeem reserve at any time, regardless of skUSD state.

skUSD redemption (the redeem() path on the vault) is permissionless and instant. There is no withdrawal cooldown on skUSD. Each share holder can burn their shares for their pro-rata kUSD entitlement at any time, then redeem that kUSD for USDC at the PSM.

On-chain proofs you can verify yourself

Every claim on this page is verifiable with public RPC reads. These four cast commands cover the new role state and the smoke outcome:

# Confirm Safe holds DEFAULT_ADMIN_ROLE on skUSD (should return true)
cast call 0xdEd74F7E06efc76455C07418b8b74Cc2bc009DB4 \
  "hasRole(bytes32,address)(bool)" \
  0x0000000000000000000000000000000000000000000000000000000000000000 \
  0x52d3E450bA6c299B1B07298F1E87DD74732D4877 \
  --rpc-url https://base-rpc.publicnode.com

# Confirm bot holds STRATEGIST_ROLE on skUSD (should return true)
cast call 0xdEd74F7E06efc76455C07418b8b74Cc2bc009DB4 \
  "hasRole(bytes32,address)(bool)" \
  0x17a8e30262c1f919c33056d877a3c22b95c2f5e4dac44683c1c2323cd79fbdb0 \
  0x09a2780ac8Be6D5d2d1F85A8D92b09D40C9CA37e \
  --rpc-url https://base-rpc.publicnode.com

# Confirm Trezor no longer holds DEFAULT_ADMIN_ROLE (should return false)
cast call 0xdEd74F7E06efc76455C07418b8b74Cc2bc009DB4 \
  "hasRole(bytes32,address)(bool)" \
  0x0000000000000000000000000000000000000000000000000000000000000000 \
  0x14f04cE02f35B29Af564A98544dD7e2393993946 \
  --rpc-url https://base-rpc.publicnode.com

# Confirm the smoke distributeYield landed (totalAssets >= 0.10 kUSD)
cast call 0xdEd74F7E06efc76455C07418b8b74Cc2bc009DB4 "totalAssets()(uint256)" \
  --rpc-url https://base-rpc.publicnode.com

Deployment context (for the timeline)

skUSD was deployed on Base mainnet on 2026-05-11 (tx 0x03270583, block 45,876,491) by Scofield's Trezor, which received both DEFAULT_ADMIN_ROLE and STRATEGIST_ROLE at construction time. The MintWidget on app.kerne.fi exposed a live skUSD deposit path on 2026-05-14, carrying an inline disclosure that pointed here for the full context. Rotation landed on 2026-05-18; the inline disclosure dropped the same day. skUSD is now a contract whose authority is split across a 2-of-3 hardware-wallet multisig and an operational bot key, neither of which can drain depositors and both of which are subject to the structural defenses cited above.

Audit references

skUSD was covered by the 2026-05-08 adversarial audit. The math hardening commit c082246f switched skUSD's totalAssets() from balanceOf(this) to the internal _trackedAssets ledger and added sweepDonations() so donated assets land outside the share-pricing surface. Two source-only findings remain open on skUSD: the _decimalsOffset = 6 is still attackable at approximately $1M cost (partly mitigated by the ledger), and distributeYield() has no upper bound and no event emission. Both are tracked at /security/findings-tracker.