Skip to content

Nothing crosses until you are both ready

A trade room for two on Gno.land. Put in GNOT, tokens or NFTs, both get ready on the same version, and the second ready mark swaps everything in one transaction.

Every rule, on one screen

See them step by step
Two seats
The maker opens the room. The taker is either invited by address or takes the open seat from a shared link.
Deposits
GNOT, GRC20 tokens and NFTs, up to eight per side. The realm holds them, not a person. Ordinary rooms take only verified assets.
Version
Every change to the room, a deposit, a take-back, a join or a named price, raises its version by one.
Ready
Getting ready names one version. When the room changes, earlier ready marks stop applying.
The swap
The second ready mark on the same version sends each side's deposits to the other, less a 0.5% fee on coins and tokens, in that same transaction.
Walking away
Before the swap either side can withdraw or cancel. After expiry anyone can cancel, and every deposit still goes home.

Try the whole trade without a wallet

The realm's rules in your browser, with play balances and a partner who trades back.

Open a practice room
version6

The swap is one function

This is Lock, word for word from the realm. When the other side already locked the same version, it calls settle, which sends every deposit across.

// Lock records that the caller agrees to swap the room exactly as it is at
// version. It fails if the room has changed since. When the other side
// already holds a lock on the same version, this call settles the room and
// returns "settled"; otherwise it returns "locked".
func Lock(cur realm, roomID uint64, version uint64) string {
	who := callerOf(cur)
	refuseCoins(cur)
	assertNotPaused()

	r := mustRoom(roomID)
	r.assertLive()
	mine, theirs := r.sideOf(who)
	if r.taker.owner == "" {
		panic("waiting for a counterparty to join")
	}
	if version != r.version {
		panic("the room changed: review version " + idString(r.version) + " and lock again")
	}
	if len(r.maker.assets) == 0 || len(r.taker.assets) == 0 {
		panic("both sides need at least one asset")
	}
	r.assertStillVerified()
	if mine.locked == version {
		return "locked"
	}
	mine.locked = version

	chain.Emit("Locked",
		"id", idString(r.id),
		"party", who.String(),
		"version", idString(version),
	)

	if theirs.locked == version {
		r.settle(cur, who)
		return StatusSettled
	}
	return "locked"
}