Contracts and addresses

Reference

Contracts and addresses

Every contract rose relies on, on NEAR testnet, Base Sepolia and Solana devnet.

On this page

All addresses are testnet. Nothing is deployed on any mainnet. Live checks (engine access keys, balances, recent MPC requests) are on the status page.

NEAR testnet#

ContractAccountNotes
rose-engineengine-v2.rose-app.testnetRust, near-sdk 5.x. Classes, positions, NEP-245 units, liens, rounds, sealed bids, opening, clearing, settlement, cash ledger, foreign custody. No upgrade method, no delete-account path, no generic call method; new versions deploy to new accounts. The final engine, engine-v2.rose-app.testnet, is keyless after init (view_access_key_list returns []); the engines before it are history, see below.
rose tUSDCtusdc.rose-app.testnetNEP-141 "Test USDC", 6 decimals, public mint capped at 10,000 tUSDC per account per 24 h. The NEAR cash venue. Keyless.
NEAR MPCv1.signer-prod.testnetVersion 3.19.0 (3.18.0 when rose was built; every domain rose uses re-verified live on 3.19.0 on 14 November; Solana attestations timed out for about half an hour that day and stayed intermittent after it, a timed-out step being refunded and retried). Domains used by rose: 0 Sign, CaitSith (secp256k1); 1 Sign, Frost (Ed25519); 2 Confidential Key Derivation (BLS12-381); 3 ForeignTx, CaitSith (secp256k1). Threshold 11. Foreign chains served include Base and Solana.

Circle's USDC on NEAR testnet exists but is minted only through a captcha-gated faucet, so the NEAR cash venue is rose tUSDC.

The final engine engine-v2.rose-app.testnet was deployed keyless from the reproducible build of commit 0524b33: its access keys were deleted after init, in the same run that checked its code hash and configuration. Its RoseVault is 0xb72a42bc59ec2423ed76b56ac82cd3457a6310fe.

The engines before it are history, not the trust model. engine.rose-app.testnet (RoseVault 0x9b7182033d3f4bc017a8776c8bc55f6a261ac95f) was the first final engine, also keyless: it is superseded because an Advance funder's share of a lien never left its account index, so funders' storage deposits stayed locked. With every key deleted, an engine cannot be patched, so the fix was deployed as a new account; the old one still runs but the app no longer uses it. The staging engines (engine-s1 to engine-s5) kept a full-access key held by the team and are retired. The status page shows the live access key check of the engine the app uses.

Engine methods#

Every lifecycle transition is a public method; there is no keeper.

MethodWhoGuardEffect
bootstrapanyone, onceReads derived_public_key from the MPC contract and fills the derived foreign addresses (vault/base, vault/sol, gas/sol).
create_tender, create_exit, create_advanceissuer, anyone, holderparameters valid; closes_at at most 30 days away, key_timeout 1 min to 7 d, reveal_window 5 min to 7 d (get_limits); Tender escrow (budget + 30 bps) and Advance units availableRound Scheduled or Open, with its largest buy quantity fixed
place_bid, place_askanyoneopens_at <= now < closes_at, at most MAX_BIDS_PER_ROUND = 64 orders, one per side per account; 0.02 NEAR of storage attached; an Exit buyer's NEP-145 storage has room for the class's holding rowStores the ciphertext, escrows cash or locks units, takes the bond; an Exit bid reserves the buyer's holding row until it settles
cancel_roundcreatorbefore the first bidCancelled, everything refundable
closeanyonecloses_at <= now < closes_at + key_timeoutRequests the round key from CKD (retries unbounded, 80 Tgas attached); a round without any sealed order is cancelled instead
on_round_key (callback), submit_keyMPC, anyonekey verifies with one pairing checkRevealing from key_received_at
cancel_no_keyanyoneno key by closes_at + key_timeout, and no key request in flight (250 blocks after the last close)Cancelled, everything refundable
open_bidanyoneRevealing, inside the windowFull verification of (plaintext, sigma); the bid is opened, or void when its escrow does not cover limit * quantity plus fee, its quantity exceeds its locked units or the round's largest buy quantity, or an Advance reserve's quantity is not the claim
clearanyonewindow overUnopened bids void and slashed; orders priced above max_price left out of the clearing (not void); clearing price and fills computed and stored; Settled, or Cancelled when nothing crosses
settle_bidanyoneSettled or CancelledApplies one bid's result to the ledger (units, cash, refund, bond); idempotent
register_base_depositanyoneForeignTx Log proof at Safe, sent without expected_payload_hash; the callback recomputes the payload hashMints units for a StreamDeposited log
register_base_cashanyoneForeignTx Log proof, as above; 0.015 NEAR of record storageCredits cash in the Base venue for a CashDeposited log; a token outside the accepted list is credited too and listed by get_cash
attribute_sol_depositthe depositing NEAR accountForeignTx AccountState proof that the stream sits at the caller's deposit address; 0.015 NEAR of record storageRecords the stream as attributed to the caller, or as refused and returnable
move_sol_depositanyonestream attributed, not registered; 0.025 NEAREngine signs the vault's token account creation and transfer_recipient from the deposit address to the vault, with the caller's recent blockhash
register_sol_depositanyoneForeignTx AccountState proof at FinalizedMints units for a Streamflow stream held by the vault
claim_base_tokens, withdraw_base_cashclaimantclaimable balance; 0.025 NEARDebits, then stores an MPC-signed RoseVault Transfer authorization
claim_sol_tokensclaimantclaimable balance, proven nonce, receipt and token accounts, drawn streams more than five minutes from their end; 0.025 NEAR, 200 TgasDebits, then stores a signed durable-nonce payout transaction (Signed), drawing on streams and on the class's swept balance
confirm_sol_payout, confirm_sol_redeemanyoneForeignTx proof that the nonce advanced and of the receipt accountLanded (or Released) when the receipt holds the nonce's new value; refunded only after two proofs, 150 blocks apart, that it stayed behind
sync_sol_streamanyoneForeignTx AccountState proof of the stream metadata at Finalized; no payout or release of the stream unsettledBooks what Streamflow's auto-claim withdrew into the vault's token account in the class's swept balance (get_sol_swept)
retry_base_signature, retry_sol_payoutanyonerequest failed, or unanswered for 600 blocksSigns again (never refunds a signature request); abandons a payout still waiting for its proof
redeemunit holderholds D_p free unitsBurns the units and authorizes the release of the position; on Solana it stays Signed until confirm_sol_redeem

Units follow NEP-245 (mt_transfer, mt_transfer_call and the batch variants; token id = class id). The contract keeps a bounded, paginated event history in state so the app needs no indexer: 1,024 entries of at most 448 bytes each (free texts cut at 192 bytes), paid by nobody, so new refuses to initialize an engine whose balance does not cover its code and state, that history and the 0.5 NEAR MPC reserve (about 15.4 NEAR; the deployment script funds 17 NEAR).

Round identity#

app_id = SHA3-256("near-mpc v0.1.0 app_id derivation:" || engine_account || "," || "round/<id>"), derived by the contract from the round id.

Base Sepolia (chain id 84532)#

ContractAddressNotes
RoseVault0xb72a42bc59ec2423ed76b56ac82cd3457a6310feImmutable, no owner. Signer = the engine's MPC-derived address (path vault/base). Holds Sablier streams and Base USDC. depositStream, depositCash, attest, executeTransfer, executeRelease.
Sablier Lockup v40xA65A1ecEf02C2B9BDc604951c6A6D02335D4532eCanonical lockup (Sablier Lockup NFT, SAB-LOCKUP, release lockup@v4.0.1). Only Lockup Linear streams of this contract are accepted.
Test USDC (tUSDC)0x69fa19ad79c1c890d37cbabaa6fe99d1aa54bc01ERC-20 "Test USDC", 6 decimals, public mint capped at 10,000 tUSDC per address per 24 h.
Circle USDC0x036CbD53842c5426634e7929541eC2318f3dCF7eAlso accepted as a Base cash token when a user already has it. The demo never depends on Circle's faucet.
Demo token0x1250554fdbd8e63a75ea9ed0021f2dcae55d3f4bThe fictional issuer's token, streamed by the demo faucet.
Demo stream faucet0xf7b1302c20faab06ad5121981b3e949da24fd98d"Mint me a demo vesting position": creates a transferable, non-cancelable Lockup Linear stream of the demo token to the caller, one per class (Seed, KOL) per address per day. No owner.

EIP-712 authorizations#

  • Domain: RoseVault on chain 84532.
  • Transfer(address token, address to, uint256 amount, uint256 id): ERC-20 payout.
  • Release(address lockup, uint256 streamId, address to, bool vestedToRecipient, uint256 id): stream NFT release; lockup must be the canonical Sablier contract. The withdrawable balance goes first to the vault (vestedToRecipient = false, an in-kind redeem) or to to (true, the return of a refused stream).
  • Signature from the MPC response: v = 27 + recovery_id, r = big_R.x, s (low-s). One replay bitmap for both types, 256 ids per storage word. No deadline.

Events verified by the engine#

StreamDeposited(address sender, string nearAccount, address lockup, uint256 streamId, address token, uint8 decimals, uint128 deposited, uint128 withdrawn, uint40 start, uint40 cliff, uint40 end, uint40 granularity, uint128 startUnlock, uint128 cliffUnlock, bool cancelable, bool transferable, uint40 timestamp) with sender and streamId indexed. The engine rebuilds the log byte by byte from the values the caller provides, verifies it through ForeignTx with the block-level log index, and compares the payload hash it recomputes with the one the MPC signed. CashDeposited(address sender, address token, uint64 roundId, string nearAccount, uint128 amount, uint40 timestamp), with sender, token and roundId indexed, is verified the same way by register_base_cash.

Solana devnet#

AccountAddressNotes
Streamflow programHqDGZjaVRXJ9MGRQEw7qDc2rAr6iH1n1kAQdCZaCMfMZStreams must allow transfer_recipient for the recipient and must not be cancelable by the sender; classic SPL Token mints without a freeze authority only.
VaultEqywuZpmf7i4ycvYqwzxEiDKTq94RifUSjH9pQX1SdWCMPC-derived Ed25519 address of the engine (path vault/sol). Recipient of deposited streams, owner of the token account each payout passes through, authority of payout nonce accounts.
Gas payerHWx7jD36pAzB1Bo83bCvRYtnW5SHLcfdEZw4x4Zdn1NgMPC-derived Ed25519 address (path gas/sol), funded with devnet SOL. Fee payer of every engine-built transaction. Balance on the status page.
Deposit addressesderived per holder and classPath dep/<near_account>/<class>, derived through the MPC contract's derived_public_key.
Payout nonce accountsderived per claimant walletTwo per payout or redeem, the durable nonce and the receipt: createWithSeed(wallet, seed), the seed starting with nonce_seed_prefix_of(near_account) and adding up to 8 characters (the app uses the first 6 characters of the engine's vault/sol address for the nonce and the same followed by r for the receipt, so one wallet gets separate accounts per engine); 80 bytes each, authority = vault, reused across claims, reserved to an action until it is settled.

The engine proves a Streamflow stream with one ForeignTx AccountState read of the stream metadata account (1,104 bytes; recipient at offset 113, mint at offset 177), at deposit and in sync_sol_stream; payouts and redeems are settled on the nonce and receipt accounts alone.

Explorers#

Every transaction, account and address in the app links to a live explorer for its chain:

ChainExplorerLinks
NEAR testnetNEAR Rocks (primary)/tx/<hash>, /account/<id>, /block/<height>
NEAR testnetNear Validate (fallback, next to every NEAR transaction)/txns/<hash>?network=testnet
Base SepoliaBasescan Sepolia/tx/<hash>, /address/<address>
Solana devnetSolana Explorer/tx/<signature>?cluster=devnet, /address/<address>?cluster=devnet

NearBlocks testnet stopped indexing in September 2026, so no link points to it.

Third-party code#

  • sealwell-ibe by Sealwell (Godwin-web3/sealwell, MIT OR Apache-2.0): the Boneh-Franklin IBE implementation rose ports, with attribution.
  • Sablier Lockup v4 and Streamflow are external protocols; rose only holds positions created by them.