# Building no-loss prize staking on Sui: what the object model made easy (and what it didn't)

**URL:** <https://forums.sui.io/t/building-no-loss-prize-staking-on-sui-what-the-object-model-made-easy-and-what-it-didnt/49447>\
**Category:** General\
**Created:** [September 15, 2026, 12:24pm UTC](https://forums.sui.io/t/building-no-loss-prize-staking-on-sui-what-the-object-model-made-easy-and-what-it-didnt/49447 "2026-09-15T12:24:38Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![surgeon](https://avatars.discourse-cdn.com/v4/letter/s/ce73a5/32.png) [@surgeon](https://forums.sui.io/u/surgeon)\
**Post date:** [September 15, 2026, 12:24pm UTC](https://forums.sui.io/t/building-no-loss-prize-staking-on-sui-what-the-object-model-made-easy-and-what-it-didnt/49447/1 "2026-09-15T12:24:38Z")

</div>

I’ve been building **Surge Protocol** solo for the past few months — a no-loss prize-staking vault on Sui Mainnet. Think Premium Bonds, on-chain: you stake SUI, your principal never leaves the vault, and only the staking yield funds periodic prize draws. If you never win, you still withdraw exactly what you put in.

It’s live, the TVL is tiny (I’ll get to that), and I wanted to write up the architecture decisions while they’re still fresh — partly to share what worked, partly because I’d genuinely value having more experienced Move eyes on some of it.

## Why the object model actually mattered here

The core problem with prize-linked savings is accounting: you need to track every depositor’s principal separately from a shared yield pool, distribute prizes without touching principal, and make all of it verifiable.

On an account-based chain, this usually becomes a mess of shared mappings and careful reentrancy guards. On Sui, each piece is a distinct object:

- the **vault** holds pooled principal
- each staker holds a **receipt object** proving their position and deposit timestamp
- **draw state** is its own object with its own lifecycle
- prize pools are separate objects per tier

Reward distribution logic stops being “carefully mutate shared state” and becomes “read these objects, write those objects.” That difference is bigger than it sounds when you’re auditing your own code at 2am with no team to review it.

## The yield source: building on Haedal

Rather than running validator infrastructure, staked SUI converts to haSUI via Haedal’s liquid staking. The vault holds haSUI; as the exchange rate appreciates, the surplus above total principal is the harvestable yield that funds prizes.

This was the right call for a solo build — I get validator yield without operating validators. But it introduced a constraint I didn’t anticipate.

## The constraint nobody warns you about: unstake minimums

Haedal enforces a minimum of ~1 SUI equivalent per `request_unstake_delay` call. Perfectly reasonable for a liquid staking protocol. Brutal for a prize vault in its first weeks.

With low TVL, the yield surplus accumulates slower than that floor. So the crank computes an honest harvest gate:

```auto
haedalMinHa = ceil(1e9 * RATE_SCALE / rate) + 1_000_000n

```

and if the surplus is below it, it logs an ETA and does nothing rather than firing a transaction guaranteed to abort. Currently that ETA is around 397 days at present TVL — which shrinks roughly linearly as TVL grows.

I mention this because it’s the kind of thing you only discover after deploying: **your economics can be gated by a dependency’s operational minimums, not by your own math.** If you’re building anything that harvests yield from an LST, check the unstake floor before you design your reward cadence.

## What I’d do differently

**Testnet.** I don’t use one. I work directly on Mainnet, which means correctness before deployment is the only safety net. This is not a recommendation — it’s a confession. It works because the surface area is small and I’m paranoid, but it’s a bad default.

**UpgradeCap.** I retained it rather than burning it. The honest reason: the codebase is complex enough that bug-fix upgrades are realistically necessary, and pretending otherwise would be worse than admitting it. The commitment is open communication about any upgrade and an eventual timelock. I’d rather say that plainly than claim an immutability I can’t back up.

**JSON-RPC deprecation.** When public fullnodes dropped JSON-RPC with no grace period, everything broke at once — frontend, crank, points worker. The lesson isn’t “Sui moves fast” (that’s fine), it’s that a single RPC dependency is a single point of failure. Have a fallback strategy before you need one.

## Current state

- Live on Mainnet, verifiable on-chain
- Listed on DefiLlama under “Yield Lottery”
- TVL: genuinely tiny, three stakers
- No audit — which I’m upfront about everywhere

That last point is the one I’d most like input on. Professional audits are out of reach for a zero-budget solo build. I’ve been looking at Sui/Move Prover for formal verification of the critical vault invariants as a partial substitute. If anyone here has run the Prover against a non-trivial Move codebase, I’d genuinely appreciate hearing whether it caught anything meaningful or whether it’s mostly a box-ticking exercise.

Happy to answer questions about any of the above, and equally happy to be told where the design is wrong.
