Make an offer, connect a wallet
Your app shows a code, and a wallet connects to it. By the end of this page a wallet is connected to your account, and your app knows exactly what the wallet has let it do.
What an offer is
An offer is what your app asks for, before a wallet agrees to anything. It carries your app's name and a list of grants: things the wallet will let your app do without asking the player again, each with a cap. Send, up to so much per request and so much in all. Owns, to prove what it holds. Accept, to take objects your app issues. The wallet shows all of it to the player before they approve. Nothing in a grant is hidden, and nothing outside it runs without the player.
In code, an offer is one call:
const offer = await app.offer({
name: "My Game",
grants: [grant.send("ERA", "0.10", "1.00"), grant.owns(["ERA"]), grant.accept()],
});
console.log(offer.code);
Amounts are in the object's own units: "0.10" is a tenth of an ERA. This page makes offers two ways: on the starter's page, and from the command line.
1. The starter: your app as a page
The starter is a web app plugged into DSM, and the place to build your app from pieces. It runs in the foreground, so give it a terminal of its own, in your app's folder:
dsm-connect-starter
Open http://127.0.0.1:3000.

The page is a builder, with three kinds of pieces, in the order an app uses them:
- Objects your app issues: a coin, points, an item (supply 1 is a one-of-a-kind), a ticket; and a shop, a vault that sells one object for another.
- What the wallet lets your app do: the offer. Tick the grants (send, owns, accept, contacts, match, trade), set each cap, and press Show the connect code.
- Ask a connected wallet: send, prove what it owns, sign in, sign a statement, accept or receive an object, price or make a trade through your shop, stake on a match, decide it, collect.
Under every piece is the exact code it is, with a Copy button. The page never makes that code up: it asks the starter's server, which runs one mapping from piece to client call both to show the code and to make the call. Set the pieces up the way your app needs them, press the button to see it happen, then paste the code into your own app.


To connect the terminal wallet below to the page's code instead of the command line's, copy the code under the QR and run dsm-dev-wallet connect followed by it.
2. A wallet in the terminal
To test without a phone, start a player's wallet in the terminal:
dsm-dev-wallet up
It is a second account, made the same way dsm-app up made yours, on the same network, and funded from the faucet:
[dsm-dev-wallet] wallet account running
storage set: the beta network (carried in dsm-app-host)
ingress: http://127.0.0.1:8788 (your server calls this)
ingress secret: …/.dsm-dev/wallet/ingress/ingress-token
relay: https://127.0.0.1:8444 (wallets reach this)
recovery: …/.dsm-dev/wallet/data/RECOVERY_MNEMONIC
log: …/.dsm-dev/wallet/host.log
funded: claimed 100.00 ERA (economic position 1)
dsm-dev-wallet down stops it.
3. Make the offer from the command line
CODE=$(dsm-app offer 'My Game' ERA 0.10 1.00)
The words after offer are your app's name, the object a wallet may send it, the cap per request and the cap in all. The command line's offer asks for more than sends: to be shown what the wallet owns, to hand it objects your account issues, to see its contacts, and to referee matches it stakes ERA in (1.00 a match, 2.00 in all).
The code is now in $CODE:
echo $CODE
dsm:connect/v1:18B6GX3ME1SKMBSF64S3EBHG5RR2WC9T70T38CRJ41QXQJEH1V239MWMG2Q6RPQ5SJ4RD3XP78QK4KMD5G86Z5SCMB2MY6H0TPTDHBBYF15C78D78Z8ACYG4C5HQ0A6TAVSEY614C1D27CXRNWGG
It is long because it carries the relay's address and its certificate pin: the wallet fetches the offer itself, over TLS pinned to that certificate.
4. Connect the terminal wallet
dsm-dev-wallet connect "$CODE"
The wallet fetches the offer, checks it, and prints what My Game asks for. The terminal wallet is your test wallet, so it approves on its own, and prints the connection: its id, the app, CONNECTED, and the grants it now holds.
My Game (account 0RHS9YDRSPR9PG9WESBX7PMGAVMEJSSVSC11QSD4NG4JPKY3XQ80) asks to:
- Send this app: up to 0.10 ERA a time, 1.00 ERA in all
- Prove what you own of ERA and of objects this app issued
- Receive objects this app issues
- See which of your contacts are here: their DSM IDs, not their names
- Lock stakes for matches: up to 1.00 ERA a time, 2.00 ERA in all
- Up to 64 requests that spend nothing; after them, each waits for you
approved:
connection RKBQ40RXFBYWZCJ150X3XG32V7EQYPN1SDGV96VGGTCAQCJMCSTG My Game CONNECTED
grants: Send this app: up to 0.10 ERA a time, 1.00 ERA in all
grants: Prove what you own of ERA and of objects this app issued
grants: Receive objects this app issues
grants: See which of your contacts are here: their DSM IDs, not their names
grants: Lock stakes for matches: up to 1.00 ERA a time, 2.00 ERA in all
grants: 0 of 64 requests that spend nothing used
A player on a phone reads the same list and decides.
5. See it from your app's side
dsm-app connections
connection RKBQ40RXFBYWZCJ150X3XG32V7EQYPN1SDGV96VGGTCAQCJMCSTG wallet HA62NJZ06ZY8C79HKM39AGTC3CMX9348RJH30GZTHA00BCSP0KV0 CONNECTED
One line per wallet: the connection's id, the wallet's identity, and whether it is connected. The connection's id is what every request on the next page names. The starter lists the same, with what each connection may do:

6. On a phone
On Android, the wallet's Apps screen has Connect an app. Scan the starter's QR with Scan code, or open the code as a link on the same phone and press Read. The wallet shows the same list the terminal printed: who asks, what for, and the caps. The player approves.



The iOS Simulator has no camera, so there the code opens as a link. From the repo (building from source), this opens a code in the wallet on every phone on your machine at once, the adb devices and the booted iOS Simulators (debug builds of the wallet):
make phones-connect CODE="$CODE"




The red box says the code came from outside the wallet. Any app or web page on a phone can open such a link, so the wallet asks the player to approve only an offer they opened themselves, from the app they mean to connect.
These phones were recorded before the command line's offer asked to see contacts, so their lists are one line shorter than the one above.
What each side holds now
- The wallet holds a grant it can read and end at any time.
- Your account holds a connection to the wallet.
- No keys moved, and nothing was taken on the relay's word.
A wallet connects to an app once. To connect it again, it disconnects first (the next page ends with that), or a second wallet connects: DSM_WALLET_NAME=wallet2 dsm-dev-wallet up, then DSM_WALLET_NAME=wallet2 dsm-dev-wallet connect $CODE.
The whole page, as one script
With dsm-app up running, this makes the terminal wallet, the offer and the connection:
dsm-dev-wallet up
CODE=$(dsm-app offer 'My Game' ERA 0.10 1.00)
echo $CODE
dsm-dev-wallet connect "$CODE"
dsm-app connections
Next: Ask the wallet for things.