← docs

Escrow: holding players' items for your game

Some games need to put a player's items at stake: a duel for each other's gear, a dungeon where what you carry can be lost, a tournament buy-in. An NFT or a token in somebody's wallet cannot be taken without their signature, so a game that wants items to change hands by its rules has the player put them in an escrow first.

An escrow is an address on the chain that holds a player's NFTs and tokens for one game:

The arcade does not know your game's rules. Whether a duel was won, whether a dropped item was picked up, who gets what: your judge decides. The escrow only holds and moves.

Setting it up: the game's JSON

Name a referee and a judge in your game inscription's JSON, next to game:

{
  "game": {"name": "My Game"},
  "escrow": {
    "referee": {"pubkey": "02…", "node": "https://…"},
    "judge": "<the inscription id of your judge>",
    "params": {"anything": "your judge reads"},
    "unlock_hours": 24
  }
}
Field What it is
referee.pubkey the referee node's key, from its /r/referee
referee.node where that node is, if it is not the arcade the player uses
judge your judge: a JavaScript inscription (see The referee)
params handed to your judge on every decision
unlock_hours the longest an escrow can stay locked: 1 to 720 hours

The judge

The same kind of judge a refereed prize pool uses: judge(seed, inputs, params), in a sandbox with no network, no clock and no randomness. For an escrow it is asked one question, may these items go to this address?, and answers:

function judge(seed, inputs, params) {
  // params.escrow: {address, owner, unlock, game, inscriptions, tokens}
  // params.to:     the address asking to receive them
  // params.items:  what it asks for
  // inputs:        whatever the page sent as `replay` (your game's evidence)
  if (provesTheWin(inputs, params)) return {release: true};
  return {release: false, why: "that duel was not won"};
}

release: true moves the items; anything else refuses them and shows why. A judge may also return to, which must match the address asked for. The seed is the escrow's address.

The page: arcade.escrow

<script src="/r/escrow.js"></script>
<script>
arcade.escrow.open({hours: 6}).then(function (e) {
  // e: {escrow, owner, owner_pubkey, unlock, referee, game}
  return arcade.escrow.deposit(e.escrow, [{inscription: swordTxid},
                                          {token: 26, amount: '50'}]);
});
</script>
Call What it does
open({hours}) this player's escrow in this game; unlocks on the hour, no later than unlock_hours. Sends nothing
deposit(escrow, items) puts things in: one card for all of them, then one transaction each
status(escrow) {inscriptions, tokens, coins, owner, unlock, open}
release({escrow, owner, owner_pubkey, unlock, to, items, replay, coins}) asks the referee; your judge decides
mine() this player's escrows in this game that still hold something

An item is {inscription: id} or {token: id, amount: "50"}.

What players can always count on

Costs

Each deposit leaves a small amount of coin with the item (0.03 coins), which pays for moving that item out again later, whichever way it goes. The rest comes back with it.