MCN Auctions and the Juneo Hub
2024 - 2025 · Sole author of the auction contract, its delivery backends and its subgraph. I also designed and built the Juneo Hub, the portal that surfaces all of it for the ecosystem.
On-chain Dutch auctions on Juneo's EVM chain that deliver tokens on its separate UTXO chain under a 2-of-2 multisig, and the Juneo Hub, the ecosystem portal I built around them: staking, governance, soulbound tokens and analytics in one place.
What I delivered
- The UtxoDutchAuction contract (UUPS proxy), upgraded to V4 on mainnet without a redeploy
- Auctions with 1 to 10 price tiers, a cap per bidder and an optional soulbound-token gate
- Cross-chain delivery by a sender and a signer backend under a 2-of-2 multisig
- A PostgreSQL state machine that never pays the same bid twice
- A subgraph indexing every auction and bid
- A Hardhat test suite covering bids, redemption and every upgrade path
- The Juneo Hub: auctions, staking, governance, soulbound tokens and analytics behind one wallet connection
In numbers
- contract version on mainnet, upgraded without a redeploy
- V4
- price tiers per auction
- 1 to 10
- multisig: two processes sign every delivery
- 2-of-2
- states in the delivery state machine
- 6

Context
Juneo runs Dutch auctions to sell tokens, but the tokens being auctioned often live on Juneo's UTXO chain (the P-Chain), a separate ledger from the EVM chain where the auction contract runs and bids are placed. On top of that, the ecosystem needed one place where a holder could do everything at once: stake, vote in governance, bid in an auction, hold a soulbound token, check the numbers behind all of it. That place became the Juneo Hub.
The problem
An auction that settles in the EVM chain's native currency has to deliver its result somewhere else entirely, real tokens on a UTXO chain, to a UTXO address, for a bid that was placed on a different chain than the one paying out. No single backend process should be able to move those funds on its own, and no bid sale can ever pay out twice, whether from a retry, a crash mid-transaction, or a bug in the queue feeding it.
Constraints
The auction model was never going to stay fixed. Price tiers, a per-user cap and an optional soulbound-token gate all landed after the first version was already handling real bids, so the contract had to be upgradeable without breaking or re-migrating every past auction. Custody of the funds being delivered could not depend on a single machine or a single private key staying uncompromised. And because delivery runs unattended, a stuck or failed payout had to stay visible and safe to retry, never silently lost.
What I built, in detail
I built UtxoDutchAuction, a UUPS proxy contract now on its fourth version on mainnet without a redeploy. Each auction defines 1 to 10 price tiers (a price ratio, a time lock and a token threshold per tier), a cap per bidder, and an optional soulbound-token gate, and is covered by a Hardhat test suite exercising bidding, redemption and every upgrade path. Delivery runs on a pair of Node.js and TypeScript backends. The sender pulls unredeemed bid sales from a subgraph and builds the UTXO-chain payout transaction; the signer never takes its word for it, it independently re-reads the same auction straight from the contract, re-checks every output (address, amount, time lock, change returned to the multisig), and only then co-signs, under a 2-of-2 multisig the sender alone cannot spend from. A PostgreSQL state machine tracks every bid sale from queued through awaiting signature, awaiting send and completed or failed, with detection for auctions stuck mid-flow and a BidSaleAlreadyRedeemedError guarding against paying the same bid out twice. Around all of it sits the Juneo Hub, a React and Node dApp I designed and built end to end: the auction interface itself, staking, governance, soulbound tokens and ecosystem analytics, behind one wallet connection.
Decisions
- A 2-of-2 multisig between sender and signer
- The sender builds and submits the delivery transaction; the signer is a second, independent process that re-derives the same result from the contract itself and checks every output before it will co-sign. A compromised or buggy sender cannot move a single token alone, and neither can a compromised signer: both have to agree.
- Impact No single machine can move delivery funds: an attacker would need both the sender and the signer.
- A Postgres state machine instead of fire-and-forget
- Blockchain deliveries fail for ordinary reasons: a gas spike, a dropped RPC connection, a signer briefly offline. Giving every bid sale an explicit status and a guard against reprocessing one already redeemed turned a failure into a queued item to retry, not a support conversation about where someone's tokens went.
- Impact A failed delivery waits in the queue for a retry, and a bid already redeemed is refused instead of being paid twice.
- UUPS instead of a fixed contract
- Tiers, the per-user cap and the soulbound gate were all added after V1 was already live with real bids on it. UUPS let the contract reach V4 on mainnet by upgrading the logic in place, with every past auction and its history still intact.
- Impact Four versions on mainnet, with no redeploy and no migration of past auctions.
- One Hub instead of five separate apps
- Staking, governance, auctions, soulbound tokens and analytics could each have shipped as their own site with their own wallet connection. Building them as one Hub means a holder connects once, and everything they can do with their tokens lives in the same place.
- Impact One wallet connection instead of five, for staking, governance, auctions, soulbound tokens and analytics.
Result
The auction system has run on Juneo's mainnet since 2024, through four contract upgrades, moving winning bids from EVM auctions to UTXO-chain wallets without a lost or duplicated delivery. The Juneo Hub is the ecosystem's day-to-day portal today: where holders stake, vote, bid and check what they hold, all in one place.
One person built the auction contract, both delivery backends, the state machine and the subgraph behind them, plus the Hub that puts all of it in front of the ecosystem: sole author of the auction system, and the builder of the Hub around it.
Stack
- Solidity
- UUPS proxies
- Hardhat
- Node.js
- TypeScript
- PostgreSQL
- The Graph
- React