testnet-laconicd-stack/testnet-nitro-node.md

30 KiB

testnet-nitro-node

Prerequisites

  • Local:

    • Clone the cerc-io/testnet-ops repository:

      git clone git@git.vdb.to:cerc-io/testnet-ops.git
      
    • Ansible: see installation

  • On deployment machine:

Setup

  • Move to nitro-nodes-setup :

    cd testnet-ops/nitro-nodes-setup
    
  • Fetch the required Nitro node config:

    wget -O nitro-vars.yml https://git.vdb.to/cerc-io/testnet-laconicd-stack/raw/branch/main/ops/stage2/nitro-node-config.yml
    
  • Fetch required asset addresses:

    wget -O assets.json https://git.vdb.to/cerc-io/testnet-laconicd-stack/raw/branch/main/ops/stage2/assets.json
    
  • Ask testnet operator to send L1 tokens and ETH to your chain address

  • Check balance of your tokens once they are transferred:

    # Note: Account address should be without "0x"
    export ACCOUNT_ADDRESS="<account-address>"
    
    export GETH_CHAIN_ID="1212"
    export GETH_CHAIN_URL="https://fixturenet-eth.laconic.com"
    
    export ASSET_ADDRESS_1=$(jq -r --arg chainId "$GETH_CHAIN_ID" '.[$chainId][0].contracts.TestToken.address' assets.json)
    export ASSET_ADDRESS_2=$(jq -r --arg chainId "$GETH_CHAIN_ID" '.[$chainId][0].contracts.TestToken2.address' assets.json)
    
    # Check balance of eth account
    curl -X POST $GETH_CHAIN_URL \
    -H "Content-Type: application/json" \
    -d '{
      "jsonrpc":"2.0",
      "method":"eth_getBalance",
      "params":["'"$ACCOUNT_ADDRESS"'", "latest"],
      "id":1
    }'
    
    # Check balance of first asset address
    curl -X POST $GETH_CHAIN_URL \
     -H "Content-Type: application/json" \
     -d '{
       "jsonrpc":"2.0",
       "method":"eth_call",
       "params":[{
         "to": "'"$ASSET_ADDRESS_1"'",
         "data": "0x70a08231000000000000000000000000'"$ACCOUNT_ADDRESS"'"
       }, "latest"],
       "id":1
     }'
    
    # Check balance of second asset address
    curl -X POST $GETH_CHAIN_URL \
     -H "Content-Type: application/json" \
     -d '{
       "jsonrpc":"2.0",
       "method":"eth_call",
       "params":[{
         "to": "'"$ASSET_ADDRESS_2"'",
         "data": "0x70a08231000000000000000000000000'"$ACCOUNT_ADDRESS"'"
       }, "latest"],
       "id":1
     }'
    
  • Edit nitro-vars.yml and add the following variables:

    # Private key for your Nitro account (same as the one used in stage0 onboarding)
    # Export the key from Laconic wallet (https://wallet.laconic.com)
    nitro_sc_pk: ""
    
    # Private key for a funded account on L1
    # This account should have L1 tokens for funding your Nitro channels
    nitro_chain_pk: ""
    
    # Multiaddr with publically accessible IP address / DNS for your L1 nitro node
    # Use port 3007
    # Example: "/ip4/192.168.x.y/tcp/3007"
    # Example: "/dns4/example.com/tcp/3007"
    nitro_l1_ext_multiaddr: ""
    
    # Multiaddr with publically accessible IP address / DNS for your L2 nitro node
    # Use port 3009
    # Example: "/ip4/192.168.x.y/tcp/3009"
    # Example: "/dns4/example.com/tcp/3009"
    nitro_l2_ext_multiaddr: ""
    
  • Edit the setup-vars.yml to update the target directory:

    # Set absolute path to desired deployments directory (under your user)
    # Example: /home/dev/nitro-node-deployments
    ...
    nitro_directory: <path-to-deployments-dir>
    ...
    
    # Will create deployments at <path-to-deployments-dir>/l1-nitro-deployment and <path-to-deployments-dir>/l2-nitro-deployment
    

Run Nitro Nodes

NOTE: When following this setup, Nitro nodes from two parties won't be able to communicate with each other if they are on the same network

Nitro nodes can be set up on a target machine using Ansible:

  • In testnet-ops/nitro-nodes-setup, create a new hosts.ini file:

    cp ../hosts.example.ini hosts.ini
    
  • Edit the hosts.ini file to run the playbook on a remote machine:

    [<deployment_host>]
    <host_name> ansible_host=<target_ip> ansible_user=<ssh_user> ansible_ssh_common_args='-o ForwardAgent=yes'
    
    • Replace <deployment_host> with nitro_host
    • Replace <host_name> with the alias of your choice
    • Replace <target_ip> with the IP address or hostname of the target machine
    • Replace <ssh_user> with the username of the user that you set up on target machine (e.g. dev, ubuntu)
  • Verify that you are able to connect to the host using the following command

    ansible all -m ping -i hosts.ini
    
    # If using password based authentication, enter the ssh password on prompt; otherwise, leave it blank
    
    # Expected output:
    
    # <host_name> | SUCCESS => {
    #  "ansible_facts": {
    #      "discovered_interpreter_python": "/usr/bin/python3.10"
    #  },
    #  "changed": false,
    #  "ping": "pong"
    # }
    
  • Execute the run-nitro-nodes.yml Ansible playbook to setup and run a Nitro node (L1+L2):

    LANG=en_US.utf8 ansible-playbook -i hosts.ini run-nitro-nodes.yml --extra-vars='{ "target_host": "nitro_host"}' --user $USER
    

Check Deployment Status

  • Run the following commands on deployment machine:

    cd <path-to-deployments-dir>
    
    # Check the logs, ensure that the nodes are running
    laconic-so deployment --dir l1-nitro-deployment logs nitro-node -f
    laconic-so deployment --dir l2-nitro-deployment logs nitro-node -f
    
    # Let L1 node sync up with the chain
    # Expected logs after sync:
    # nitro-node-1  | 2:04PM INF Initializing Http RPC transport...
    # nitro-node-1  | 2:04PM INF Completed RPC server initialization url=127.0.0.1:4005/api/v1
    
  • Get your Nitro node's info:

    laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client get-node-info -p 4005 -h nitro-node"
    
    # Expected output:
    # {
    #   "SCAddress": "0xd0eA8b27591b1D070cCcD4D30b8D408fe794FDfc",
    #   "MessageServicePeerId": "16Uiu2HAmSHRjoxveaPmJipzmdq69U8zme8BMnFjSBPferj1E5XAd"
    # }
    
    # SCAddress -> nitro address, MessageServicePeerId -> libp2p peer id
    

Create Channels

Create a ledger channel with the bridge on L1 which is mirrored on L2

  • Run the following commands on deployment machine

  • Set required variables:

    cd <path-to-deployments-dir>
    
    export BRIDGE_NITRO_ADDRESS=$(yq eval '.bridge_nitro_address' nitro-node-config.yml)
    
    export GETH_CHAIN_ID="1212"
    
    # Get asset addresses from assets.json file
    export ASSET_ADDRESS_1=$(jq -r --arg chainId "$GETH_CHAIN_ID" '.[$chainId][0].contracts.TestToken.address' assets.json)
    export ASSET_ADDRESS_2=$(jq -r --arg chainId "$GETH_CHAIN_ID" '.[$chainId][0].contracts.TestToken2.address' assets.json)
    
  • Check that you have no existing channels on L1 or L2:

    laconic-so deployment --dir l1-nitro-deployment exec nitro-rpc-client "nitro-rpc-client get-all-ledger-channels -p 4005 -h nitro-node"
    laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client get-all-ledger-channels -p 4005 -h nitro-node"
    
    # Expected output:
    # []
    
  • Ensure that your account has enough balance of tokens from assets.json

  • Create a ledger channel between your L1 Nitro node and Bridge with custom asset:

    laconic-so deployment --dir l1-nitro-deployment exec nitro-rpc-client "nitro-rpc-client direct-fund $BRIDGE_NITRO_ADDRESS --asset "$ASSET_ADDRESS_1:1000,1000" --asset "$ASSET_ADDRESS_2:1000,1000" -p 4005 -h nitro-node"
    
    # Follow your L1 Nitro node logs for progress
    
    # Expected Output:
    # Objective started DirectFunding-0x161d289a50222caa781db215bb82a3ede4f557217742245525b8e8cbff04ec21
    # Channel Open 0x161d289a50222caa781db215bb82a3ede4f557217742245525b8e8cbff04ec21
    
    # Set the resulting ledger channel id in a variable
    export LEDGER_CHANNEL_ID=
    
    • Check the Troubleshooting section if command to create a ledger channel fails or gets stuck
  • Once direct-fund objective is complete, the bridge will create a mirrored channel on L2

  • Check L2 Nitro node's logs to see that a bridged-fund objective completed:

    laconic-so deployment --dir l2-nitro-deployment logs nitro-node -f --tail 30
    
    # Expected Output:
    # nitro-node-1  | 5:01AM INF INFO Objective cranked address=0xaaa6628ec44a8a742987ef3a114ddfe2d4f7adce objective-id=bridgedfunding-0x6a9f5ccf1fa802525d794f4a899897f947615f6acc7141e61e056a8bfca29179 waiting-for=WaitingForNothing
    # nitro-node-1  | 5:01AM INF INFO Objective is complete & returned to API address=0xaaa6628ec44a8a742987ef3a114ddfe2d4f7adce objective-id=bridgedfunding-0x6a9f5ccf1fa802525d794f4a899897f947615f6acc7141e61e056a8bfca29179
    
  • Check status of L1 ledger channel with the bridge using channel id:

    laconic-so deployment --dir l1-nitro-deployment exec nitro-rpc-client "nitro-rpc-client get-ledger-channel $LEDGER_CHANNEL_ID -p 4005 -h nitro-node"
    
    # Example output:
    # {
    #   ID: '0xbb28acc2e1543f4b41eb1ab9eb2e354b18554aefe4e7f0fa5f20046869d8553f',
    #   Status: 'Open',
    #   Balances: [
    #     {
    #       AssetAddress: '0xa6b4b8b84576047a53255649b4994743d9c83a71',
    #       Me: '0xdaaa6ef3bc03f9c7dabc9a02847387d2c19107f5',
    #       Them: '0xf0e6a85c6d23aca9ff1b83477d426ed26f218185',
    #       MyBalance: 1000n,
    #       TheirBalance: 1000n
    #     },
    #     {
    #       AssetAddress: '0x0000000000000000000000000000000000000000',
    #       Me: '0xdaaa6ef3bc03f9c7dabc9a02847387d2c19107f5',
    #       Them: '0xf0e6a85c6d23aca9ff1b83477d426ed26f218185',
    #       MyBalance: 1000n,
    #       TheirBalance: 1000n
    #     }
    #   ],
    #   ChannelMode: 'Open'
    # }
    
  • Check status of the mirrored channel on L2:

    laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client get-all-ledger-channels -p 4005 -h nitro-node"
    
    # Example output:
    # [
    #   {
    #     "ID": "0xb34210b763d4fdd534190ba11886ad1daa1e411c87be6fd20cff74cd25077c46",
    #     "Status": "Open",
    #     "Balances": [
    #       {
    #         "AssetAddress": "0xa4351114dae1abeb2d552d441c9733c72682a45d",
    #         "Me": "0x075400039e303b3fb46c0cff0404c5fa61947c05",
    #         "Them": "0xf0e6a85c6d23aca9ff1b83477d426ed26f218185",
    #         "MyBalance": 1000,
    #         "TheirBalance": 1000
    #       },
    #       {
    #         "AssetAddress": "0x314e43f9825b10961859c2a62c2de6a765c1c1f1",
    #         "Me": "0x075400039e303b3fb46c0cff0404c5fa61947c05",
    #         "Them": "0xf0e6a85c6d23aca9ff1b83477d426ed26f218185",
    #         "MyBalance": 1000,
    #         "TheirBalance": 1000
    #       }
    #     ],
    #     "ChannelMode": "Open"
    #   }
    # ]
    

Payments On L2 Channel

Perform payments using a virtual payment channel created with another Nitro node over the mirrored L2 channel with bridge as an intermediary

  • Prerequisite: Ledger channel is required to create a payment channel

  • Note: Currently payment channel is created from first asset present in ledger channel

  • Run the following commands on deployment machine

  • Switch to the nitro-node directory:

    cd <path-to-deployments-dir>
    
  • Check status of the mirrored channel on L2:

    laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client get-all-ledger-channels -p 4005 -h nitro-node"
    
    # Example output:
    # [
    #   {
    #     "ID": "0xb34210b763d4fdd534190ba11886ad1daa1e411c87be6fd20cff74cd25077c46",
    #     "Status": "Open",
    #     "Balances": [
    #       {
    #         "AssetAddress": "0xa4351114dae1abeb2d552d441c9733c72682a45d",
    #         "Me": "0x075400039e303b3fb46c0cff0404c5fa61947c05",
    #         "Them": "0xf0e6a85c6d23aca9ff1b83477d426ed26f218185",
    #         "MyBalance": 1000,
    #         "TheirBalance": 1000
    #       },
    #       {
    #         "AssetAddress": "0x314e43f9825b10961859c2a62c2de6a765c1c1f1",
    #         "Me": "0x075400039e303b3fb46c0cff0404c5fa61947c05",
    #         "Them": "0xf0e6a85c6d23aca9ff1b83477d426ed26f218185",
    #         "MyBalance": 1000,
    #         "TheirBalance": 1000
    #       }
    #     ],
    #     "ChannelMode": "Open"
    #   }
    # ]
    
  • Set required variables:

    export BRIDGE_NITRO_ADDRESS=$(yq eval '.bridge_nitro_address' nitro-node-config.yml)
    
    # Mirrored channel on L2
    export L2_CHANNEL_ID=<l2-channel-id>
    
    # Amount to create the payment channel with
    export PAYMENT_CHANNEL_AMOUNT=500
    
  • Set counterparty address

    export COUNTER_PARTY_ADDRESS=<counterparty-nitro-address>
    
    • Get the nitro address of the counterparty's node with whom you want create payment channel

    • To get the nitro address of the your node:

      laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client get-node-info -p 4005 -h nitro-node"
      # `SCAddress` -> nitro address
      
  • Check for existing payment channels for the L2 channel:

    laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client get-payment-channels-by-ledger $L2_CHANNEL_ID -p 4005 -h nitro-node"
    
  • Create a virtual payment channel:

    laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client virtual-fund $COUNTER_PARTY_ADDRESS $BRIDGE_NITRO_ADDRESS --amount $PAYMENT_CHANNEL_AMOUNT -p 4005 -h nitro-node"
    
    # Follow your L2 Nitro node logs for progress
    
    # Expected Output:
    # Objective started VirtualFund-0x43db45a101658387263b36d613322cc952d8ce5b70de51e3a495513c256bef4d
    # Channel Open 0x43db45a101658387263b36d613322cc952d8ce5b70de51e3a495513c256bef4d
    
    # Set the resulting payment channel id in a variable
    PAYMENT_CHANNEL_ID=<payment-channel-id>
    

    Multiple virtual payment channels can be created at once

  • Check the payment channel's status:

    laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client get-payment-channel $PAYMENT_CHANNEL_ID -p 4005 -h nitro-node"
    
    # Expected output:
    # {
    #   ID: '0xb29aeb32c9495a793ebf7bd116232075d1e7bfe89fc82281c7d498e3ffd3e3bf',
    #   Status: 'Open',
    #   Balance: {
    #     AssetAddress: '0x0000000000000000000000000000000000000000',
    #     Payee: '<your-nitro-address>',
    #     Payer: '<counterparty-nitro-address>',
    #     PaidSoFar: 0n,
    #     RemainingFunds: <payment-channel-amount>n
    #   }
    # }
    
  • Send payments using the virtual payment channel:

    export PAY_AMOUNT=200
    laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client pay $PAYMENT_CHANNEL_ID $PAY_AMOUNT -p 4005 -h nitro-node"
    
    # Expected output
    # {
    #   Amount: <pay-amount>,
    #   Channel: '<payment-channel-id>'
    # }
    
    # This can be done multiple times until the payment channel balance is exhausted
    
  • Check payment channel's status again to view updated channel state

  • Close the payment channel to settle on the L2 mirrored channel:

    laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client virtual-defund $PAYMENT_CHANNEL_ID -p 4005 -h nitro-node"
    
    # Expected output:
    # Objective started VirtualDefund-0x43db45a101658387263b36d613322cc952d8ce5b70de51e3a495513c256bef4d
    # Channel complete 0x43db45a101658387263b36d613322cc952d8ce5b70de51e3a495513c256bef4d
    
  • Check L2 mirrored channel's status after the virtual payment channel is closed:

    • This can be checked by both nodes
    laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client get-all-ledger-channels -p 4005 -h nitro-node"
    
    # Example output:
    # [
    #   {
    #     "ID": "0xb34210b763d4fdd534190ba11886ad1daa1e411c87be6fd20cff74cd25077c46",
    #     "Status": "Open",
    #     "Balances": [
    #       {
    #         "AssetAddress": "0xa4351114dae1abeb2d552d441c9733c72682a45d",
    #         "Me": "0x075400039e303b3fb46c0cff0404c5fa61947c05",
    #         "Them": "0xf0e6a85c6d23aca9ff1b83477d426ed26f218185",
    #         "MyBalance": <updated balance>,
    #         "TheirBalance": <updated balance>
    #       },
    #       {
    #         "AssetAddress": "0x314e43f9825b10961859c2a62c2de6a765c1c1f1",
    #         "Me": "0x075400039e303b3fb46c0cff0404c5fa61947c05",
    #         "Them": "0xf0e6a85c6d23aca9ff1b83477d426ed26f218185",
    #         "MyBalance": <updated balance>,
    #         "TheirBalance": <updated balance>
    #       }
    #     ],
    #     "ChannelMode": "Open"
    #   }
    # ]
    

    Your balance on the L2 channel should be reduced by total payments done on the virtual payment channel

Swaps on L2

Perform swaps using a swap channel created with another Nitro node over the mirrored L2 channel with bridge as an intermediary

  • Prerequisite: Ledger channel is required to create a swap channel

  • Run the following commands on deployment machine

  • Switch to the nitro-node directory:

    cd <path-to-deployments-dir>
    
  • Check status of the mirrored channel on L2:

    laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client get-all-ledger-channels -p 4005 -h nitro-node"
    
    # Example output:
    # [
    #   {
    #     "ID": "0xb34210b763d4fdd534190ba11886ad1daa1e411c87be6fd20cff74cd25077c46",
    #     "Status": "Open",
    #     "Balances": [
    #       {
    #         "AssetAddress": "0xa4351114dae1abeb2d552d441c9733c72682a45d",
    #         "Me": "0x075400039e303b3fb46c0cff0404c5fa61947c05",
    #         "Them": "0xf0e6a85c6d23aca9ff1b83477d426ed26f218185",
    #         "MyBalance": 1000,
    #         "TheirBalance": 1000
    #       },
    #       {
    #         "AssetAddress": "0x314e43f9825b10961859c2a62c2de6a765c1c1f1",
    #         "Me": "0x075400039e303b3fb46c0cff0404c5fa61947c05",
    #         "Them": "0xf0e6a85c6d23aca9ff1b83477d426ed26f218185",
    #         "MyBalance": 1000,
    #         "TheirBalance": 1000
    #       }
    #     ],
    #     "ChannelMode": "Open"
    #   }
    # ]
    
  • Set required variables:

    export BRIDGE_NITRO_ADDRESS=$(yq eval '.bridge_nitro_address' nitro-node-config.yml)
    
    export GETH_CHAIN_ID="1212"
    
    # Get asset addresses from assets.json file
    export ASSET_ADDRESS_1=$(jq -r --arg chainId "$GETH_CHAIN_ID" '.[$chainId][0].contracts.TestToken.address' assets.json)
    export ASSET_ADDRESS_2=$(jq -r --arg chainId "$GETH_CHAIN_ID" '.[$chainId][0].contracts.TestToken2.address' assets.json)
    
  • Set counterparty address

    export COUNTER_PARTY_ADDRESS=<counterparty-nitro-address>
    
    • Get the nitro address of the counterparty's node with whom you want create swap channel

    • To get the nitro address of the your node:

      laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client get-node-info -p 4005 -h nitro-node"
      # `SCAddress` -> nitro address
      
  • Create swap channel:

    laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client swap-fund  $COUNTER_PARTY_ADDRESS $BRIDGE_NITRO_ADDRESS --asset "$ASSET_ADDRESS_1:100,100" --asset "$ASSET_ADDRESS_2:100,100" -p 4005 -h nitro-node"
    
    # Expected output
    # Objective started SwapFund-0x1dbd58d314f123f4b0f4147eee7fd92fa523ba7082d8a75b846f6d1189e2f0e9
    # Channel open 0x1dbd58d314f123f4b0f4147eee7fd92fa523ba7082d8a75b846f6d1189e2f0e9
    
  • Export swap channel ID:

    export SWAP_CHANNEL_ID=
    
  • Check swap channel:

    laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client get-swap-channel $SWAP_CHANNEL_ID -p 4005 -h nitro-node"
    
    # Expected output:
    # {
    #   ID: '0x1dbd58d314f123f4b0f4147eee7fd92fa523ba7082d8a75b846f6d1189e2f0e9',
    #   Status: 'Open',
    #   Balances: [
    #     {
    #       AssetAddress: '0xa4351114dae1abeb2d552d441c9733c72682a45d',
    #       Me: '0x075400039e303b3fb46c0cff0404c5fa61947c05',
    #       Them: '0xd0ea8b27591b1d070cccd4d30b8d408fe794fdfc',
    #       MyBalance: 100n,
    #       TheirBalance: 100n
    #     },
    #     {
    #       AssetAddress: '0x314e43f9825b10961859c2a62c2de6a765c1c1f1',
    #       Me: '0x075400039e303b3fb46c0cff0404c5fa61947c05',
    #       Them: '0xd0ea8b27591b1d070cccd4d30b8d408fe794fdfc',
    #       MyBalance: 100n,
    #       TheirBalance: 100n
    #     }
    #   ]
    # }
    

Performing swaps

  • Ensure that environment variables for asset addresses are set (should be done by both parties):

    export GETH_CHAIN_ID="1212"
    
    # Get asset addresses from assets.json file
    export ASSET_ADDRESS_1=$(jq -r --arg chainId "$GETH_CHAIN_ID" '.[$chainId][0].contracts.TestToken.address' assets.json)
    export ASSET_ADDRESS_2=$(jq -r --arg chainId "$GETH_CHAIN_ID" '.[$chainId][0].contracts.TestToken2.address' assets.json)
    
  • Get all active swap channels for a specific mirrored ledger channel (should be done by both parties)

    • To get mirrored ledger channels:

      laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client get-all-ledger-channels -p 4005 -h nitro-node"
      
      # Example output:
      # [
      #   {
      #     "ID": "0xb34210b763d4fdd534190ba11886ad1daa1e411c87be6fd20cff74cd25077c46",
      #     "Status": "Open",
      #     "Balances": [
      #       {
      #         "AssetAddress": "0xa4351114dae1abeb2d552d441c9733c72682a45d",
      #         "Me": "0x075400039e303b3fb46c0cff0404c5fa61947c05",
      #         "Them": "0xf0e6a85c6d23aca9ff1b83477d426ed26f218185",
      #         "MyBalance": 1000n,
      #         "TheirBalance": 1000n
      #       },
      #       {
      #         "AssetAddress": "0x314e43f9825b10961859c2a62c2de6a765c1c1f1",
      #         "Me": "0x075400039e303b3fb46c0cff0404c5fa61947c05",
      #         "Them": "0xf0e6a85c6d23aca9ff1b83477d426ed26f218185",
      #         "MyBalance": 1000n,
      #         "TheirBalance": 1000n
      #       }
      #     ],
      #     "ChannelMode": "Open"
      #   }
      # ]
      
    • Export ledger channel ID:

        export LEDGER_CHANNEL_ID=
      
    • To get swap channels for a ledger channel:

      laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client get-swap-channels-by-ledger $LEDGER_CHANNEL_ID -p 4005 -h nitro-node"
      # Example Output:
      # [
      #   {
      #     ID: '0x1dbd58d314f123f4b0f4147eee7fd92fa523ba7082d8a75b846f6d1189e2f0e9',
      #     Status: 'Open',
      #     Balances: [
      #       {
      #         AssetAddress: '0xa4351114dae1abeb2d552d441c9733c72682a45d',
      #         Me: '0x075400039e303b3fb46c0cff0404c5fa61947c05',
      #         Them: '0xd0ea8b27591b1d070cccd4d30b8d408fe794fdfc',
      #         MyBalance: 100,
      #         TheirBalance: 100n
      #       },
      #       {
      #         AssetAddress: '0x314e43f9825b10961859c2a62c2de6a765c1c1f1',
      #         Me: '0x075400039e303b3fb46c0cff0404c5fa61947c05',
      #         Them: '0xd0ea8b27591b1d070cccd4d30b8d408fe794fdfc',
      #         MyBalance: 100,
      #         TheirBalance: 100
      #       }
      #     ]
      #   }
      # ]
      
    • Export swap channel ID:

      export SWAP_CHANNEL_ID=
      
  • One of the participants can initiate the swap and other one will either accept it or reject it

  • For initiating the swap:

    laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client swap-initiate $SWAP_CHANNEL_ID --AssetIn "$ASSET_ADDRESS_1:20" --AssetOut "$ASSET_ADDRESS_2:10" -p 4005 -h nitro-node"
    
    # Expected output:
    # {
    #   SwapAssetsData: {
    #     TokenIn: '0xa4351114dae1abeb2d552d441c9733c72682a45d',
    #     TokenOut: '0x314e43f9825b10961859c2a62c2de6a765c1c1f1',
    #     AmountIn: 20,
    #     AmountOut: 10
    #   },
    #   Channel: '0x1dbd58d314f123f4b0f4147eee7fd92fa523ba7082d8a75b846f6d1189e2f0e9'
    # }
    

    OR

  • For receiving the swap

    • Get the pending swap:

      laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client get-pending-swap $SWAP_CHANNEL_ID -p 4005 -h nitro-node"
      
      # Expected output:
      # {
      #   Id: '0x7d582020753335cfd2f2af14127c9b51c7ed7a5d547a674d9cb04fe62de6ddf3',
      #   ChannelId: '0x1dbd58d314f123f4b0f4147eee7fd92fa523ba7082d8a75b846f6d1189e2f0e9',
      #   Exchange: {
      #     TokenIn: '0xa4351114dae1abeb2d552d441c9733c72682a45d',
      #     TokenOut: '0x314e43f9825b10961859c2a62c2de6a765c1c1f1',
      #     AmountIn: 20,
      #     AmountOut: 10
      #   },
      #   Sigs: {
      #     '0': '0x0a018de18a091f7bfb400d9bc64fe958d298882e569c1668c5b1c853b5493221576b2d72074ef6e1899b79e60eaa9934afac5c1e07b7000746bac5b3b1da93311b'
      #   },
      #   Nonce: 2840594896360394000
      # }
      
    • Export swap ID:

      export SWAP_ID=
      
    • Either accept or reject the swap

      • To accept:

        laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client swap-accept $SWAP_ID -p 4005 -h nitro-node"
        
        # Expected output:
        # Confirming Swap with accepted
        # Objective complete Swap-0x7d582020753335cfd2f2af14127c9b51c7ed7a5d547a674d9cb04fe62de6ddf3
        

        OR

      • To reject:

        laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client swap-reject $SWAP_ID -p 4005 -h nitro-node"
        
        # Expected output:
        # Confirming Swap with accepted
        # Objective complete Swap-0x7d582020753335cfd2f2af14127c9b51c7ed7a5d547a674d9cb04fe62de6ddf3
        
  • Check swap channel:

    laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client get-swap-channel $SWAP_CHANNEL_ID -p 4005 -h nitro-node"
    
    # Example output:
    # {
    #   ID: '0x1dbd58d314f123f4b0f4147eee7fd92fa523ba7082d8a75b846f6d1189e2f0e9',
    #   Status: 'Open',
    #   Balances: [
    #     {
    #       AssetAddress: '0xa4351114dae1abeb2d552d441c9733c72682a45d',
    #       Me: '0xd0ea8b27591b1d070cccd4d30b8d408fe794fdfc',
    #       Them: '0x075400039e303b3fb46c0cff0404c5fa61947c05',
    #       MyBalance: 120n,
    #       TheirBalance: 80n
    #     },
    #     {
    #       AssetAddress: '0x314e43f9825b10961859c2a62c2de6a765c1c1f1',
    #       Me: '0xd0ea8b27591b1d070cccd4d30b8d408fe794fdfc',
    #       Them: '0x075400039e303b3fb46c0cff0404c5fa61947c05',
    #       MyBalance: 90n,
    #       TheirBalance: 110n
    #     }
    #   ]
    # }
    
  • Close swap channel:

    laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client swap-defund $SWAP_CHANNEL_ID -p 4005 -h nitro-node"
    
    # Expected output:
    # Objective started SwapDefund-0x1dbd58d314f123f4b0f4147eee7fd92fa523ba7082d8a75b846f6d1189e2f0e9
    # Objective complete SwapDefund-0x1dbd58d314f123f4b0f4147eee7fd92fa523ba7082d8a75b846f6d1189e2f0e9
    
  • Check L2 mirrored channel status:

    laconic-so deployment --dir l2-nitro-deployment exec nitro-rpc-client "nitro-rpc-client get-all-ledger-channels -p 4005 -h nitro-node"
    
    # Example output:
    # [
    #   {
    #     "ID": "0xb34210b763d4fdd534190ba11886ad1daa1e411c87be6fd20cff74cd25077c46",
    #     "Status": "Open",
    #     "Balances": [
    #       {
    #         "AssetAddress": "0xa4351114dae1abeb2d552d441c9733c72682a45d",
    #         "Me": "0x075400039e303b3fb46c0cff0404c5fa61947c05",
    #         "Them": "0xf0e6a85c6d23aca9ff1b83477d426ed26f218185",
    #         "MyBalance": <updated balance>,
    #         "TheirBalance": <updated balance>
    #       },
    #       {
    #         "AssetAddress": "0x314e43f9825b10961859c2a62c2de6a765c1c1f1",
    #         "Me": "0x075400039e303b3fb46c0cff0404c5fa61947c05",
    #         "Them": "0xf0e6a85c6d23aca9ff1b83477d426ed26f218185",
    #         "MyBalance": <updated balance>,
    #         "TheirBalance": <updated balance>
    #       }
    #     ],
    #     "ChannelMode": "Open"
    #   }
    # ]
    

Update nitro nodes

  • Switch to deployments dir:

    cd $DEPLOYMENTS_DIR/nitro-node
    
  • Rebuild containers:

    laconic-so --stack ~/cerc/nitro-stack/stack-orchestrator/stacks/nitro-node build-containers --force-rebuild
    
  • Restart the nodes

    laconic-so deployment --dir l1-nitro-deployment stop
    laconic-so deployment --dir l1-nitro-deployment start
    
    laconic-so deployment --dir l2-nitro-deployment stop
    laconic-so deployment --dir l2-nitro-deployment start
    

Clean up

  • Switch to deployments dir:

    cd <path-to-deployments-dir>
    
  • Stop all Nitro services running in the background:

    laconic-so deployment --dir l1-nitro-deployment stop
    laconic-so deployment --dir l2-nitro-deployment stop
    
  • To stop all services and also delete data:

    laconic-so deployment --dir l1-nitro-deployment stop --delete-volumes
    laconic-so deployment --dir l2-nitro-deployment stop --delete-volumes
    
    # Remove deployment directories (deployments will have to be recreated for a re-run)
    sudo rm -r l1-nitro-deployment
    sudo rm -r l2-nitro-deployment
    

Troubleshooting

  • Check the logs of nitro node to see if the objective is completed

    # To check logs of L1 nitro-node
    laconic-so deployment --dir l1-nitro-deployment logs nitro-node -f --tail 30
    
    # To check logs of L2 nitro-node
    laconic-so deployment --dir l2-nitro-deployment logs nitro-node -f --tail 30
    
    • If the objective is completed, you can safely stop (Ctrl+C) the running CLI command and continue with the further instructions
  • Stop (Ctrl+C) the direct-fund command if it is stuck

  • Restart the L1 Nitro node:

    • Stop the deployment:

      cd <path-to-deployments-dir>
      
      laconic-so deployment --dir l1-nitro-deployment stop
      
    • Reset the node's durable store:

      sudo rm -rf l1-nitro-deployment/data/nitro_node_data
      
      mkdir l1-nitro-deployment/data/nitro_node_data
      
    • Restart the deployment:

      laconic-so deployment --dir l1-nitro-deployment start
      
  • Retry the ledger channel creation command