---
# System prepended metadata

title: 'Demo for Magmo '

---

## Setup

* Clone `go-nitro` repo and checkout to the required branch:
    ```bash
    git clone git@github.com:cerc-io/go-nitro.git
    
    # In go-nitro
    cd go-nitro
    git checkout ts-interop
    ```

* Install dependencies:
    ```bash
    # In go-nitro
    go mod tidy
    ```

* Clone `mobymask-ui` repo, checkout to v3 branch and install dependencies:
    ```bash
    git clone git@github.com:cerc-io/mobymask-ui.git
    cd mobymask-ui
    git checkout lxdao-v3
    yarn install
    ```

* Run a script to fix modules in `mobymask-ui`:
    ```bash
    # In mobymask-ui
    yarn build:fix-modules
    ```

* Clone `ts-nitro` for browser setup and install dependencies:
    ```bash
    git clone git@github.com:cerc-io/ts-nitro.git browser-ts-nitro

    cd browser-ts-nitro
    yarn install
    ```

* Run the hardhat chain:
    ```bash
    # In browser-ts-nitro
    yarn chain
    ```

* Deploy the Nitro protocol contracts and copy over the generated JSON file to required places:
    ```bash
    # In browser-ts-nitro (another window)
    yarn test:deploy-contracts

    yarn test:copy-addresses
    ```

* Build packages in `browser-ts-nitro`:
    ```bash
    # In browser-ts-nitro
    yarn build:browser --ignore @cerc-io/example-web-app
    ```

* Copy over the contract addresses to the `mobymask-ui` repo:
    ```bash
    # In browser-ts-nitro
    cp packages/nitro-util/nitro-addresses.json ../mobymask-ui/src/utils/nitro-addresses.json
    ```

* Clone `mobymask-v2-watcher-ts` to `mobymask-v3-watcher-ts` and checkout to `v3` branch for running v3 watcher with nitro client

    ```bash
    git clone git@github.com:cerc-io/mobymask-v2-watcher-ts.git mobymask-v3-watcher-ts
    cd mobymask-v3-watcher-ts
    git checkout v3
    ```

* Copy over the contract addresses deployed:
    ```bash
    # In mobymask-v3-watcher-ts
    cp ../browser-ts-nitro/packages/nitro-util/nitro-addresses.json ./src/nitro-addresses.json
    ```

* Install dependencies and build:
    ```bash
    # In mobymask-v3-watcher-ts
    yarn && yarn build
    ```

* Setup postgres databases for the watcher servers:
    ```bash
    sudo su - postgres
    createdb mobymask-v2-watcher
    createdb mobymask-v2-watcher-job-queue
    ```

* Create a JSON file `relay-id.json` in `mobymask-v3-watcher-ts` for relay node's peer id:
    ```json
    {
      "id": "12D3KooWJmiEGTzqBpLSmjNkux1aaHZfara47ggQGsvAC9atfJC8",
      "privKey": "CAESQKxvh6+M84l1u28rNdYf/a/FjWpplmiGjVSl+oIdiIVQhQsfZtQnpJzcdTFE4sirkmxvMuy8pbee8Om28YCqyCk=",
      "pubKey": "CAESIIULH2bUJ6Sc3HUxROLIq5JsbzLsvKW3nvDptvGAqsgp"
    }
    ```
    
* Create a JSON file `peer-id.json` in `mobymask-v3-watcher-ts` for watcher peer's peer id:
    ```json
    {
      "id": "12D3KooWGEaoVcaFMwZve8ReXQgiucoPrjdwHPVbBgc35acHpL9u",
      "privKey": "CAESQMbtIzsdVa6il9JamQeA1xM2UB5u/qcUwB/Pg4Sm90LLX1pYiakFrxUIa3Wg07evhaPwVXAaCNDQDY9xrQ/GQyg=",
      "pubKey": "CAESIF9aWImpBa8VCGt1oNO3r4Wj8FVwGgjQ0A2Pca0PxkMo"
    }
    ```

* Update the watcher config (`environments/local.toml`) to update the following fields:
    ```toml
    ...
    [server.p2p]
        enablePeer = true
        ...
        [server.p2p.relay]
            ...
            peerIdFile = './relay-id.json'
            ...
        [server.p2p.peer]
            relayMultiaddr = '/ip4/127.0.0.1/tcp/9090/ws/p2p/12D3KooWJmiEGTzqBpLSmjNkux1aaHZfara47ggQGsvAC9atfJC8'
            ...
            peerIdFile = './peer-id.json'
            ...
        [server.p2p.nitro]
            store = './out/erin-db'
            privateKey = '0aca28ba64679f63d71e671ab4dbb32aaa212d4789988e6ca47da47601c18fe2'
            chainPrivateKey = '7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6'
            ...
            [server.p2p.nitro.payments]
                ratesFile = './environments/rates.toml'
    ```

* Clone `mobymask-v2-watcher-ts` to `watcher-relay` for running a watcher relay node:
    ```bash
    git clone git@github.com:cerc-io/mobymask-v2-watcher-ts.git watcher-relay
    cd watcher-relay
    ```

* Install dependencies and build packages in `watcher-relay`:
    ```bash
    # In watcher-relay
    yarn && yarn build
    ```

* Copy over the `relay-id.json` file:
    ```bash
    # In watcher-relay
    cp ../mobymask-v3-watcher-ts/relay-id.json ./relay-id.json
    ```

* Set `peerIdFile` for relay node in `environments/local.toml`:
    ```toml
    ...
    [server.p2p]
        enablePeer = false
        ...
        ...
    [server.p2p.relay]
        ...
        peerIdFile = './relay-id.json'
    ```

* Run the watcher server which will also run the relay node:
    ```bash
    # In watcher-relay
    yarn server
    
    # Expected output:
    # laconic:relay Listening on: +0ms
    # laconic:relay /ip4/127.0.0.1/tcp/9090/ws/p2p/12D3KooWJmiEGTzqBpLSmjNkux1aaHZfara47ggQGsvAC9atfJC8 +1ms
    ```

* Set the relay address, chain ID and chain URL in mobymask-ui app config (`mobymask-ui/src/utils/config.json`) with the relay node address:
    ```json    
    {        
        ...  
        "chainId": 31337,
        "chainURL": "http://localhost:8545",
        "relayNodes": ["/ip4/127.0.0.1/tcp/9090/ws/p2p/12D3KooWJmiEGTzqBpLSmjNkux1aaHZfara47ggQGsvAC9atfJC8"],
        ...
    }
    ```
* Set watcher URL `mobymask-ui/.env` file 
    ```bash
    # In mobymask-ui
    REACT_APP_WATCHER_URI=http://localhost:3010/graphql
    ```

* Set the relay address in browser-ts-nitro .env file (`browser-ts-nitro/packages/example-web-app/.env`):
    ```bash
    # In browser-ts-nitro/packages/example-web-app/.env
    REACT_APP_RELAY_MULTIADDR=/ip4/127.0.0.1/tcp/9090/ws/p2p/12D3KooWJmiEGTzqBpLSmjNkux1aaHZfara47ggQGsvAC9atfJC8
    ```
    

* Run the browser app in dev mode:
    ```bash
    # In browser-ts-nitro
    cd packages/example-web-app
    yarn start
    ```

## Run

### browser <-> browser

* Open the [app](http://localhost:3000) in a browser tab; open the console in browser inspect and enable debug logs
    ```bash
    localStorage.debug = 'ts-nitro:*'
    # Refresh the tab for taking effect
    ```

* Setup a client:
    ```bash
    const nitro = await setupClient('alice')
    ```

* Open the [app](http://localhost:3000) for another client in a different browser and enable logs:
    ```bash
    localStorage.debug = 'ts-nitro:*'
    # Refresh the tab for taking effect
    ```

* Setup a client:
    ```bash
    const nitro = await setupClient('bob')
    ```

* Wait for `New peer found` log in console

* Check if Bob's client is dialable from Alice’s browser:
    ```bash
    await nitro.isPeerDialable('0xBBB676f9cFF8D242e9eaC39D063848807d3D1D94')
    # Expected output:
    # [true, 'Peer with address 0xBBB676f9cFF8D242e9eaC39D063848807d3D1D94 is dialable']
    ```

* From Alice, create a ledger channel by calling the `directFund` method:
    ```bash
    await nitro.directFund('0xBBB676f9cFF8D242e9eaC39D063848807d3D1D94', 1_000_000_000_000_000_000)
    
    # Expected output:
    # ..
    # ts-nitro:engine Objective DirectFunding-0x0a59b50c2869d6952906d7ee295423adfdd1659cc8f48f9087ca7cfd629f3eae is complete & returned to API +12ms
    # ts-nitro:util:nitro Ledger channel created with id 0x0a59b50c2869d6952906d7ee295423adfdd1659cc8f48f9087ca7cfd629f3eae +0ms
    ```

* Assign ledger channel id from the log above to a variable in the console:
    ```bash
    let LEDGER_CHANNEL_ID = "<LEDGER_CHANNEL_ID>"
    ```

* Check the ledger channel's status:
    ```bash
    out(await nitro.getLedgerChannel(LEDGER_CHANNEL_ID))
    ```

* The funding amount can be seen deducted from the chain accounts; check chain account balances:
    ```bash
    # In browser-ts-nitro/packages/nitro-util
    export ALICE_CHAIN_PK=ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80
    export BOB_CHAIN_PK=59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d

    yarn balance --key $ALICE_CHAIN_PK
    # Expected output:
    # ts-nitro:util Balance of account 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 is 9998990425919170977798 +0ms

    yarn balance --key $BOB_CHAIN_PK
    # Expected output:
    # ts-nitro:util Balance of account 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 is 9998999938277338495680 +0ms
    ```

* Create a virtual payment channel by calling the `virtualFund` method:
    ```bash
    await nitro.virtualFund('0xBBB676f9cFF8D242e9eaC39D063848807d3D1D94', 1_000)
    
    # Expected output:
    # ...
    # ts-nitro:engine Objective VirtualFund-0x7cc3065fa683647b3ae38178fb4b32ad1584b524772bd442252d108be8b194f5 is complete & returned to API +1ms
    # ts-nitro:util:nitro Virtual payment channel created with id 0x7cc3065fa683647b3ae38178fb4b32ad1584b524772bd442252d108be8b194f5 +4m
    ```

* Assign payment channel id from the log above to a variable in the console:
    ```bash
    let PAYMENT_CHANNEL_ID = "<PAYMENT_CHANNEL_ID>"
    ```

* Check the payment channel's status:
    ```bash
    out(await nitro.getPaymentChannel(PAYMENT_CHANNEL_ID))

    # Expected output:
    # {
    #   "ID": "0x7cc3065fa683647b3ae38178fb4b32ad1584b524772bd442252d108be8b194f5",
    #   "Status": "Open",
    #   "Balance": {
    #     "AssetAddress": "0x0000000000000000000000000000000000000000",
    #     "Payee": "0xbbb676f9cff8d242e9eac39d063848807d3d1d94",
    #     "Payer": "0xaaa6628ec44a8a742987ef3a114ddfe2d4f7adce",
    #     "PaidSoFar": 0,
    #     "RemainingFunds": 1000
    #   }
    # }
    ```

* Make a payment on the created payment channel:
    ```bash
    await nitro.pay(PAYMENT_CHANNEL_ID, 50)

    # The payment can be done multiple times
    ```

* Check status of the payment channel:
    ```bash
    out(await nitro.getPaymentChannel(PAYMENT_CHANNEL_ID))

    # Expected output:
    # {
    #   "ID": "0x7cc3065fa683647b3ae38178fb4b32ad1584b524772bd442252d108be8b194f5",
    #   "Status": "Open",
    #   "Balance": {
    #     "AssetAddress": "0x0000000000000000000000000000000000000000",
    #     "Payee": "0xbbb676f9cff8d242e9eac39d063848807d3d1d94",
    #     "Payer": "0xaaa6628ec44a8a742987ef3a114ddfe2d4f7adce",
    #     "PaidSoFar": 50,
    #     "RemainingFunds": 950
    #   }
    # }
    ```

* Close the virtual payment channel:
    ```bash
    await nitro.virtualDefund(PAYMENT_CHANNEL_ID)
    
    # Expected output:
    # ts-nitro:util:nitro Virtual payment channel with id 0xba0d64f7a0e91cf1aecb70a90ebf7341286f9f840785b4360675d44c8d5fd55e closed +49s
    ```

* Check status of the payment and ledger channels:
    ```bash
    out(await nitro.getPaymentChannel(PAYMENT_CHANNEL_ID))
    # Expected output:
    # {
    #   "ID": "0x7cc3065fa683647b3ae38178fb4b32ad1584b524772bd442252d108be8b194f5",
    #   "Status": "Complete",
    #   "Balance": {
    #     "AssetAddress": "0x0000000000000000000000000000000000000000",
    #     "Payee": "0xbbb676f9cff8d242e9eac39d063848807d3d1d94",
    #     "Payer": "0xaaa6628ec44a8a742987ef3a114ddfe2d4f7adce",
    #     "PaidSoFar": 50,
    #     "RemainingFunds": 950
    #   }
    # }

    out(await nitro.getLedgerChannel(LEDGER_CHANNEL_ID))
    # Expected output:
    # {
    #   "ID": "0x0a59b50c2869d6952906d7ee295423adfdd1659cc8f48f9087ca7cfd629f3eae",
    #   "Status": "Open",
    #   "Balance": {
    #     "AssetAddress": "0x0000000000000000000000000000000000000000",
    #     "Hub": "0xbbb676f9cff8d242e9eac39d063848807d3d1d94",
    #     "Client": "0xaaa6628ec44a8a742987ef3a114ddfe2d4f7adce",
    #     "HubBalance": 1000000000000000050,
    #     "ClientBalance": 999999999999999950
    #   }
    # }
    ```

* Close the ledger channel:
    ```bash
    await nitro.directDefund(LEDGER_CHANNEL_ID)
    
    # Expected output:
    # ts-nitro:util:nitro Ledger channel with id 0x0a1d20c9574bd61e75e6ae44fb2b67e8ede5f08dea9ff2e62cb22cbfb88631fd closed +1m
    ```

* Check balance of accounts on chain
    ```bash
    # In browser-ts-nitro/packages/nitro-util
    export ALICE_ADDRESS=0xAAA6628Ec44A8a742987EF3A114dDFE2D4F7aDCE
    export BOB_ADDRESS=0xBBB676f9cFF8D242e9eaC39D063848807d3D1D94

    # Alice's (browser peer) balance
    yarn balance --address $ALICE_ADDRESS
    # Expected output:
    # ts-nitro:util Balance of account 0xAAA6628Ec44A8a742987EF3A114dDFE2D4F7aDCE is 999999999999999950 +0ms

    # Bob's (watcher) balance
    yarn balance --address $BOB_ADDRESS
    # Expected output:
    # ts-nitro:util Balance of account 0xBBB676f9cFF8D242e9eaC39D063848807d3D1D94 is 1000000000000000050 +0ms
    ```

* Close Alice's browser client and keep Bob's open for further demonstration

### browser <-> go-nitro

* In go-nitro repo, assign private keys for Charlie and contract addresses to variables:
    ```bash
    # In go-nitro
    export CHARLIE_PK=58368d20ff12f17669c06158c21d885897aa56f9be430edc789614bf9851d53f
    export CHARLIE_CHAIN_PK=47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a
    
    export NA_ADDRESS=0x5FbDB2315678afecb367f032d93F642f64180aa3
    export VPA_ADDRESS=0xe7f1725E7734CE288F8367e1Bb143E90bb3F0512
    export CA_ADDRESS=0x9fE46736679d2D9a65F0992F2272dE9f3c7fa6e0
    ```

* Run a client for Charlie:
    ```bash
    # In go-nitro
    go run . -msgport 3006 -wsmsgport 5006 -rpcport 4006 -pk $CHARLIE_PK -chainpk $CHARLIE_CHAIN_PK -naaddress $NA_ADDRESS -vpaaddress $VPA_ADDRESS -caaddress $CA_ADDRESS

    # Expected output:
    # Initialising mem store...
    # Initializing chain service and connecting to ws://127.0.0.1:8545...
    # Initializing message service on tcp port 3006 and websocket port 5006...
    # P2PMessageService started with Peer Id: 16Uiu2HAmRKvrFMTFYr7bocpsyZhBaTx6wLLa8D9VnkiEvAmUZimm
    # Address: 0x67D5b55604d1aF90074FcB69b8C51838FFF84f8d
    # {"level":"debug","engine":"0x67D5b5","time":1689317732882,"caller":"engine.go:151","message":"Constructed Engine"}
    # Initializing websocket RPC transport...
    # Nitro as a Service listening on port 4006
    ```

* Check that Charlie's client is not dialable from Bob’s browser:
    ```bash
    await nitro.isPeerDialable('0x67D5b55604d1aF90074FcB69b8C51838FFF84f8d')
    # Expected output:
    # [false, 'Not able to dial peer with address 0x67D5b55604d1aF90074FcB69b8C51838FFF84f8d: peer info not found']
    ```

* In Bob's browser console, call the `nitro.addPeerByMultiaddr` method to connect to Charlie's go-nitro client:
    ```bash
    await nitro.addPeerByMultiaddr('0x67D5b55604d1aF90074FcB69b8C51838FFF84f8d', '/ip4/127.0.0.1/tcp/5006/ws/p2p/16Uiu2HAmRKvrFMTFYr7bocpsyZhBaTx6wLLa8D9VnkiEvAmUZimm')
    ```

* Check if Charlie's client is dialable from Bob’s browser now:
    ```bash
    await nitro.isPeerDialable('0x67D5b55604d1aF90074FcB69b8C51838FFF84f8d')
    # Expected output:
    # [true, 'Peer with address 0x67D5b55604d1aF90074FcB69b8C51838FFF84f8d is dialable']
    ```

* Create a ledger channel by calling the `directFund` method:
    ```bash
    await nitro.directFund('0x67D5b55604d1aF90074FcB69b8C51838FFF84f8d', 1_000_000_000_000_000_000)
    
    # Expected output:
    # ..
    # ts-nitro:engine Objective DirectFunding-0x0a59b50c2869d6952906d7ee295423adfdd1659cc8f48f9087ca7cfd629f3eae is complete & returned to API +12ms
    # ts-nitro:util:nitro Ledger channel created with id 0x0a59b50c2869d6952906d7ee295423adfdd1659cc8f48f9087ca7cfd629f3eae +0ms
    ```

* Assign ledger channel id from the log above to a variable in the console:
    ```bash
    let LEDGER_CHANNEL_ID = "<LEDGER_CHANNEL_ID>"
    ```

* Check the ledger channel's status:
    ```bash
    out(await nitro.getLedgerChannel(LEDGER_CHANNEL_ID))
    ```

* The funding amount can be seen deducted from the chain accounts; check chain account balances:
    ```bash
    # In browser-ts-nitro/packages/nitro-util
    export BOB_CHAIN_PK=59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d
    export CHARLIE_CHAIN_PK=47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a

    yarn balance --key $BOB_CHAIN_PK
    # Expected output:
    # ts-nitro:util Balance of account 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 is 9997999847780203211120 +0ms

    yarn balance --key $CHARLIE_CHAIN_PK
    # Expected output:
    # ts-nitro:util Balance of account 0x15d34AAf54267DB7D7c367839AAf71A00a2C6A65 is 9998999957217078558360 +0ms
    ```

* Create a virtual payment channel by calling the `virtualFund` method:
    ```bash
    await nitro.virtualFund('0x67D5b55604d1aF90074FcB69b8C51838FFF84f8d', 1_000)
    
    # Expected output:
    # ...
    # ts-nitro:engine Objective VirtualFund-0x7cc3065fa683647b3ae38178fb4b32ad1584b524772bd442252d108be8b194f5 is complete & returned to API +1ms
    # ts-nitro:util:nitro Virtual payment channel created with id 0x7cc3065fa683647b3ae38178fb4b32ad1584b524772bd442252d108be8b194f5 +4m
    ```

* Assign payment channel id from the log above to a variable in the console:
    ```bash
    let PAYMENT_CHANNEL_ID = "<PAYMENT_CHANNEL_ID>"
    ```

* Check the payment channel's status:
    ```bash
    out(await nitro.getPaymentChannel(PAYMENT_CHANNEL_ID))
    
    # Expected output:
    # {
    #   "ID": "0xcad9f588ab79e3e50cd8f5738b01c9c07747bf75c6c9eb2fa02ca620dba5ec34",
    #   "Status": "Open",
    #   "Balance": {
    #     "AssetAddress": "0x0000000000000000000000000000000000000000",
    #     "Payee": "0x67d5b55604d1af90074fcb69b8c51838fff84f8d",
    #     "Payer": "0xbbb676f9cff8d242e9eac39d063848807d3d1d94",
    #     "PaidSoFar": 0,
    #     "RemainingFunds": 1000
    #   }
    # }
    ```

* Make a payment on the created payment channel:
    ```bash
    await nitro.pay(PAYMENT_CHANNEL_ID, 50)

    # The payment can be done multiple times
    ```

* Check status of the payment channel:
    ```bash
    out(await nitro.getPaymentChannel(PAYMENT_CHANNEL_ID))
    
    # Expected output:
    # {
    #   "ID": "0xcad9f588ab79e3e50cd8f5738b01c9c07747bf75c6c9eb2fa02ca620dba5ec34",
    #   "Status": "Open",
    #   "Balance": {
    #     "AssetAddress": "0x0000000000000000000000000000000000000000",
    #     "Payee": "0x67d5b55604d1af90074fcb69b8c51838fff84f8d",
    #     "Payer": "0xbbb676f9cff8d242e9eac39d063848807d3d1d94",
    #     "PaidSoFar": 50,
    #     "RemainingFunds": 950
    #   }
    # }
    ```

* Close the virtual payment channel:
    ```bash
    await nitro.virtualDefund(PAYMENT_CHANNEL_ID)
    ```

* Check status of the payment and ledger channels:
    ```bash
    out(await nitro.getPaymentChannel(PAYMENT_CHANNEL_ID))
    # Expected output:
    # {
    #   "ID": "0xcad9f588ab79e3e50cd8f5738b01c9c07747bf75c6c9eb2fa02ca620dba5ec34",
    #   "Status": "Complete",
    #   "Balance": {
    #     "AssetAddress": "0x0000000000000000000000000000000000000000",
    #     "Payee": "0x67d5b55604d1af90074fcb69b8c51838fff84f8d",
    #     "Payer": "0xbbb676f9cff8d242e9eac39d063848807d3d1d94",
    #     "PaidSoFar": 50,
    #     "RemainingFunds": 950
    #   }
    # }

    out(await nitro.getLedgerChannel(LEDGER_CHANNEL_ID))
    # Expected output:
    # {
    #   "ID": "0xba6312502c3efaeafa861b7d9ef520fda9de3eaba77916dff38b64b74875bbde",
    #   "Status": "Open",
    #   "Balance": {
    #     "AssetAddress": "0x0000000000000000000000000000000000000000",
    #     "Hub": "0x67d5b55604d1af90074fcb69b8c51838fff84f8d",
    #     "Client": "0xbbb676f9cff8d242e9eac39d063848807d3d1d94",
    #     "HubBalance": 1000000000000000050,
    #     "ClientBalance": 999999999999999950
    #   }
    # }
    ```

* Close the ledger channel:
    ```bash
    await nitro.directDefund(LEDGER_CHANNEL_ID)
    ```

* Check balance of accounts on chain
    ```bash
    # In browser-ts-nitro/packages/nitro-util
    export BOB_ADDRESS=0xBBB676f9cFF8D242e9eaC39D063848807d3D1D94
    export CHARLIE_ADDRESS=0x67D5b55604d1aF90074FcB69b8C51838FFF84f8d

    # Bob's (browser peer) balance
    yarn balance --address $BOB_ADDRESS
    # Expected output:
    # ts-nitro:util Balance of account 0xBBB676f9cFF8D242e9eaC39D063848807d3D1D94 is 2000000000000000000 +0ms

    # Charlie's (go-nitro peer) balance
    yarn balance --address $CHARLIE_ADDRESS
    # Expected output:
    # ts-nitro:util Balance of account 0x67D5b55604d1aF90074FcB69b8C51838FFF84f8d is 1000000000000000050 +0ms
    ```

* Close the browser client along with the example-web-app dev server, the go-nitro client and the watcher server (relay node)

### mobymask-v3 (browser <-> watcher)

* Check that hardhat chain is running and nitro contract are deployed 

* Start the MobyMask v3 watcher:
    ```bash
    # In mobymask-v3-watcher-ts
    yarn server
    
    # Expected output:
    # laconic:relay Relay node started with id 12D3KooWJmiEGTzqBpLSmjNkux1aaHZfara47ggQGsvAC9atfJC8 (rotten-gold-ardelle) +0ms
    # laconic:relay Listening on: +0ms
    # laconic:relay /ip4/127.0.0.1/tcp/9090/ws/p2p/12D3KooWJmiEGTzqBpLSmjNkux1aaHZfara47ggQGsvAC9atfJC8 +1ms
    # .
    # .
    # vulcanize:server Peer ID: 12D3KooWGEaoVcaFMwZve8ReXQgiucoPrjdwHPVbBgc35acHpL9u +0ms
    # .
    # .
    # ts-nitro:engine Constructed Engine +0ms
    # vulcanize:server Starting server... +0ms
    ```

* Run the lxdao-mobymask app in dev mode:
    ```bash
    # In mobymask-ui
    yarn start
    
    # Should open the app in a browser tab at http://localhost:3000/
    ```

* Open the console in browser inspect and enable debug logs:
    ```bash
    localStorage.debug = 'ts-nitro:*'
    # Refresh the tab for taking effect
    ```

* In the app's debug panel, check that the peer gets connected to relay node and watcher peer

    * Wait for at least 5 seconds after restart to connect properly with watcher peer

* Open the `NITRO` tab in debug panel

    * Click on Connect Wallet button to connect to MetaMask

    * Import private key that is already funded in hardhat
    ```bash
        47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a
    ```
    * Reset accounts in MetaMask if chain is restarted

* Click on `DIRECT FUND` button against known client (which is the watcher peer) to create a ledger channel

    * A MetaMask notification appears, click on the `Confirm` button 
    
    * Creating ledger channel takes some time

* Click on `VIRTUAL FUND` button to create a virtual payment channel 

    * Payment channel details would be shown below
    
* Click on `PAY` button to make a payment on the created payment channel

    * Check that balance has updated in payment channel details

* Click on `VIRTUAL DEFUND` to close the virtual payment channel

    * Payment channel details dissapear as it completes
    
* Click on `DIRECT DEFUND` to close the ledger channel

    * A MetaMask notification appears, click on the `Confirm` button
    
    * Requires some time to close ledger channel

* Check balances of accounts on chain
    ```bash
    # In browser-ts-nitro/packages/nitro-util

    # Get CLIENT_ADDRESS from NITRO tab in the debug panel
    export DAVID_ADDRESS=<CLIENT_ADDRESS>
    export ERIN_ADDRESS=0xB2B22ec3889d11f2ddb1A1Db11e80D20EF367c01

    # Alice's (browser peer) balance
    yarn balance --address $DAVID_ADDRESS
    # Expected output:
    # ts-nitro:util Balance of account 0x6eaAD2a3a587c25c46D920b2fF2eE883cd75b54e is 999999999999999950 +0ms

    # Bob's (watcher) balance
    yarn balance --address $ERIN_ADDRESS
    # Expected output:
    # ts-nitro:util Balance of account 0xB2B22ec3889d11f2ddb1A1Db11e80D20EF367c01 is 1000000000000000050 +0ms
    ```
    

## Clean Up

* After stopping the watcher, clear storage by deleting the DB directory:
    ```bash
    # In mobymask-v3-watcher-ts
    rm -r ./out
    ```

* In browser apps call `clearClientStorage` method to delete all indexedDBs:
    ```bash
    await clearClientStorage()
    ```
