testnet-laconicd-stack/testnet-onboarding-demo.md

35 KiB

testnet-onboarding-demo

Setup

Laconic Wallet

  1. Follow the Install steps from the laconic-wallet README to setup Android Studio

  2. Clone the repository

    git clone git@git.vdb.to:cerc-io/laconic-wallet.git
    
  3. Enter the project directory

    cd laconic-wallet
    
  4. Setup .env

    • Copy and update .env

      cp .env.example .env
      
    • In the .env file add your WalletConnect project id. You can generate your own ProjectId at https://cloud.walletconnect.com (use gmail address)

      WALLET_CONNECT_PROJECT_ID=39bc93c...
      
  5. Install dependencies

    yarn
    
  6. Exit project repo

    cd ../
    

Testnet Onboarding App

  1. Clone the repository

    git clone git@git.vdb.to:cerc-io/testnet-onboarding-app.git
    
  2. Enter the project directory

    cd testnet-onboarding-app
    
  3. Setup .env

    • Copy and update .env

      cp .env.example .env
      
    • In the .env file, add the WalletConnect project ID used in your laconic-wallet setup.

      WALLET_CONNECT_PROJECT_ID=39bc93c...
      
  4. Install dependencies

    yarn
    
  5. Exit project repo

    cd ../
    

Stack Orchestrator

Fixturenet laconicd Stack and laconic-faucet

  1. Clone the stack repos:

    laconic-so fetch-stack git.vdb.to/cerc-io/fixturenet-laconicd-stack --git-ssh --pull
    laconic-so fetch-stack git.vdb.to/cerc-io/testnet-laconicd-stack --git-ssh --pull
    
  2. Clone required repositories:

    # laconicd
    laconic-so --stack ~/cerc/fixturenet-laconicd-stack/stack-orchestrator/stacks/fixturenet-laconicd setup-repositories --git-ssh --pull
    laconic-so --stack ~/cerc/testnet-laconicd-stack/stack-orchestrator/stacks/laconic-faucet setup-repositories --git-ssh --pull
    
  3. Build the container images:

    # laconicd
    laconic-so --stack ~/cerc/fixturenet-laconicd-stack/stack-orchestrator/stacks/fixturenet-laconicd build-containers --force-rebuild
    laconic-so --stack ~/cerc/testnet-laconicd-stack/stack-orchestrator/stacks/laconic-faucet build-containers --force-rebuild
    
  4. Create a deployment for stage 0:

    • Create spec files for the deployment:

      laconic-so --stack ~/cerc/fixturenet-laconicd-stack/stack-orchestrator/stacks/fixturenet-laconicd deploy init --output stage0-spec.yml
      
    • Edit network in the spec file to map container ports to host ports as required:

      # stage0-spec.yml
      ...
      network:
        ports:
          laconicd:
            - '6060'
            - '26657:26657'
            - '26656:26656'
            - '9473:9473'
            - '9090:9090'
            - '1317:1317'
      
    • Create a deployment from the spec file:

      laconic-so --stack ~/cerc/fixturenet-laconicd-stack/stack-orchestrator/stacks/fixturenet-laconicd deploy create --spec-file  stage0-spec.yml --deployment-dir stage0-deployment
      
    • In stage0-deployment/config.env file, set the following env variable:

      # Set to true to enable adding participants functionality of the onboarding module
      ONBOARDING_ENABLED=true
      
  5. Create a deployment for stage 1:

    • Create spec file for the deployment:

      laconic-so --stack ~/cerc/fixturenet-laconicd-stack/stack-orchestrator/stacks/fixturenet-laconicd deploy init --output stage1-spec.yml
      
    • Edit network in the spec file to map container ports to host ports as required:

      # stage1-spec.yml
      ...
      network:
        ports:
          laconicd:
            - '6060'
            - '26657:26657'
            - '26656:26656'
            - '9473:9473'
            - '9090:9090'
            - '1317:1317'
      
    • Create a deployment from the spec file:

      laconic-so --stack ~/cerc/fixturenet-laconicd-stack/stack-orchestrator/stacks/fixturenet-laconicd deploy create --spec-file  stage1-spec.yml --deployment-dir stage1-deployment
      
  6. Create a deployment for laconic-faucet:

    • Create spec file for the deployment:

      laconic-so --stack ~/cerc/testnet-laconicd-stack/stack-orchestrator/stacks/laconic-faucet deploy init --output laconic-faucet-spec.yml
      
    • Edit network in the spec file to map container port to host port as required:

      # laconic-faucet-spec.yml
      ...
      network:
        ports:
          laconic-faucet:
            - '4000:3000'
      
    • Create a deployment from the spec file:

      laconic-so --stack ~/cerc/testnet-laconicd-stack/stack-orchestrator/stacks/laconic-faucet deploy create --spec-file laconic-faucet-spec.yml --deployment-dir laconic-faucet-deployment
      
      # Place in the same namespace as stage0
      cp stage0-deployment/deployment.yml laconic-faucet-deployment/deployment.yml
      

L1 eth and L2 optimism stacks

  1. Clone the stack repo:

    laconic-so fetch-stack git.vdb.to/cerc-io/fixturenet-eth-stacks --pull
    laconic-so fetch-stack git.vdb.to/cerc-io/fixturenet-optimism-stack --pull
    
  2. Clone required repositories:

    # L1 (fixturenet-eth)
    laconic-so --stack ~/cerc/fixturenet-eth-stacks/stack-orchestrator/stacks/fixturenet-eth setup-repositories --pull
    
    # L2 (optimism)
    laconic-so --stack ~/cerc/fixturenet-optimism-stack/stack/fixturenet-optimism setup-repositories --pull
    
    # If this throws an error as a result of being already checked out to a branch/tag in a repo, remove all repositories from that stack and re-run the command
    # The repositories are located in $HOME/cerc by default
    
  3. Build the container images:

    # Remove any older foundry image with `latest` tag
    docker rmi ghcr.io/foundry-rs/foundry:latest
    
    # L1 (fixturenet-eth)
    laconic-so --stack ~/cerc/fixturenet-eth-stacks/stack-orchestrator/stacks/fixturenet-eth build-containers --force-rebuild
    
    # L2 (optimism)
    laconic-so --stack ~/cerc/fixturenet-optimism-stack/stack/fixturenet-optimism build-containers --force-rebuild
    
    # If errors are thrown during build, old images used by this stack would have to be deleted
    
    • NOTE: this will take >10 mins depending on the specs of your machine, and requires 16GB of memory or greater.

    • Remove any dangling Docker images (to clear up space):

      docker image prune
      
  4. Create spec files for deployments, which will map the stack's ports and volumes to the host:

    laconic-so --stack ~/cerc/fixturenet-eth-stacks/stack-orchestrator/stacks/fixturenet-eth deploy init --output fixturenet-eth-spec.yml
    
    laconic-so --stack ~/cerc/fixturenet-optimism-stack/stack/fixturenet-optimism deploy init --output fixturenet-optimism-spec.yml
    
  5. Configure ports:

    • fixturenet-eth-spec.yml

      ...
      network:
        ports:
          fixturenet-eth-bootnode-geth:
            - '9898:9898'
            - '30303'
          fixturenet-eth-geth-1:
            - '8545:8545'
            - '8546:8546'
            - '40000'
            - '6060'
          fixturenet-eth-lighthouse-1:
            - '8001'
      ...
      
    • fixturenet-optimism-spec.yml

      ...
      network:
        ports:
          op-geth:
            - '9545:8545'
            - '9546:8546'
          ...
      
  6. Create deployments: Once you've made any needed changes to the spec files, create deployments from them:

    laconic-so --stack ~/cerc/fixturenet-eth-stacks/stack-orchestrator/stacks/fixturenet-eth deploy create --spec-file fixturenet-eth-spec.yml --deployment-dir fixturenet-eth-deployment
    
    laconic-so --stack ~/cerc/fixturenet-optimism-stack/stack/fixturenet-optimism deploy create --spec-file fixturenet-optimism-spec.yml --deployment-dir fixturenet-optimism-deployment
    
    # Place them both in the same namespace (cluster)
    cp fixturenet-eth-deployment/deployment.yml fixturenet-optimism-deployment/deployment.yml
    
  7. Env configuration: In fixturenet-eth-deployment/config.env file add the following env variables:

    # Allow unprotected txs for Optimism contracts deployment
    CERC_ALLOW_UNPROTECTED_TXS=true
    

Go Nitro

  1. Clone go-nitro repository

    git clone git@github.com:cerc-io/go-nitro.git
    cd go-nitro
    
    # Install Node.js dependencies and build the repo
    yarn && yarn build
    
    # Install go dependencies
    go mod tidy
    
  2. Build go-nitro and bridge binaries

    go build
    go build -o nitro-bridge cmd/start-bridge/main.go
    
  3. Generate TLS certificate (prerequisite: mkcert)

    cd tls
    make create-cert
    
    # Go back to go-nitro
    cd ../
    
  4. Install nitro-rpc-client package globally:

    # In go-nitro
    npm install -g ./packages/nitro-rpc-client
    
    # Confirm global installation by running
    nitro-rpc-client --version
    

Run

  • Start L1, L2 stacks: (run steps in directory where the stack deployments had been created)

    • Start fixturenet-eth-deployment deployment:

      laconic-so deployment --dir fixturenet-eth-deployment start
      
      • Check status of L1

        • Run command in intervals of 3 seconds to check new blocks are created

          laconic-so deployment --dir fixturenet-eth-deployment exec foundry "cast block-number"
          
        • Check geth logs to ensure that new blocks are getting created

          laconic-so deployment --dir fixturenet-eth-deployment logs -f fixturenet-eth-geth-1
          
    • Start fixturenet-optimism-deployment deployment:

      laconic-so deployment --dir fixturenet-optimism-deployment start
      

      NOTE: The fixturenet-optimism-contracts service will configure and deploy the Optimism contracts to L1, exiting when complete. This may take several minutes; you can follow the progress by following the container's logs

      • Check L2 logs

        laconic-so deployment --dir fixturenet-optimism-deployment logs -f op-geth
        
        # Ensure new blocks are getting created
        
  • Send ETH from L1 to L2 (run steps in directory where the stack deployments had been created)

    • Get information about funded accounts on L1

      curl 127.0.0.1:9898/accounts.csv
      
    • Send some ETH from the desired account to the L1StandardBridgeProxy contract on L1 to bridge it to L2:

      • Set the following variables:

        L1_RPC=http://fixturenet-eth-geth-1:8545
        L2_RPC=http://op-geth:8545
        
        DEPLOYMENT_CONTEXT=1212
        ACCOUNT=0xe6CE22afe802CAf5fF7d3845cec8c736ecc8d61F
        
      • Read the bridge contract address from the L1 deployment records in the op-node container:

        BRIDGE=$(laconic-so deployment --dir fixturenet-optimism-deployment exec op-node "cat /l1-deployment/$DEPLOYMENT_CONTEXT-deploy.json" | jq -r .L1StandardBridgeProxy)
        
        # Get the funded account's pk
        ACCOUNT_PK=$(laconic-so deployment --dir fixturenet-optimism-deployment exec op-node "jq -r '.AdminKey' /l2-accounts/accounts.json")
        
      • Use cast to send ETH to the bridge contract:

        laconic-so deployment --dir fixturenet-eth-deployment exec foundry "cast send --from $ACCOUNT --value 1ether $BRIDGE --rpc-url $L1_RPC --private-key $ACCOUNT_PK"
        

        NOTE: This is for sending funds to the contracts deployer account which is also the Bridge node account

      • Allow a couple minutes for the bridge to complete

    • Check balance on L2

      laconic-so deployment --dir fixturenet-eth-deployment exec foundry "cast balance $ACCOUNT --rpc-url $L2_RPC"
      
      # 100000000000000000
      
  • Deploy go-nitro contracts on L1 and L2 (run steps in go-nitro repo)

    • Go to packages/nitro-protocol

      # In go-nitro
      cd packages/nitro-protocol
      
    • Export variables for geth and optimism urls and the deployer private key (Private key used by bridge nodes as well)

      export GETH_URL="http://127.0.0.1:8545"
      export GETH_CHAIN_ID=1212
      export OPTIMISM_URL="http://127.0.0.1:9545"
      
      export GETH_DEPLOYER_PK=888814df89c4358d7ddb3fa4b0213e7331239a80e1f013eaa7b2deca2a41a218
      
      # Use same account on both Geth and Optimism
      export OPTIMISM_DEPLOYER_PK=$GETH_DEPLOYER_PK
      
    • Export variables for token name, token symbol and initial supply

      export TOKEN_NAME="LaconicNetworkToken"
      export TOKEN_SYMBOL="LNT"
      
      # Note: Token supply denotes actual number of tokens and not the supply in Wei
      export INITIAL_TOKEN_SUPPLY="10000000"
      
    • Disable deterministic deployment to make sure bridge node and address associated to it is the owner of contracts

      export DISABLE_DETERMINISTIC_DEPLOYMENT=true
      
    • Deploy contracts on L1 and L2

      # Deploy contracts on geth
      yarn contracts:deploy-geth
      
      # Deploy contracts on Optimism
      yarn contracts:deploy-optimism
      
    • Deploy custom token on L1

      # Deploy token on geth
      yarn contracts:deploy-token-geth
      
      • Note address of the deployed token on L1 and update ~/go-nitro/cmd/test-configs/bridge-assets-map.toml config file

        [[assets]]
        l1AssetAddress = "<Token address on L1>"
        ...
        
    • Deploy custom token on L2

      # Deploy token on Optimism
      yarn contracts:deploy-token-optimism
      
      • Note address of the deployed token on L2 and update ~/go-nitro/cmd/test-configs/bridge-assets-map.toml config file

        [[assets]]
        l1AssetAddress = "<Token address on L1>"
        l2AssetAddress = "<Token address on L2>"
        
  • Send custom tokens to Alice and Charlie on L1

    • Export variables for L1 token address

      export L1_ASSET_ADDRESS="<Token Address on L1>"
      export A_CHAIN_ADDRESS="0xe22AD83A0dE117bA0d03d5E94Eb4E0d80a69C62a"
      export C_CHAIN_ADDRESS="0xf1ac8Dd1f6D6F5c0dA99097c57ebF50CD99Ce293"
      
    • Send tokens to Alice and Charlie

      # Send tokens to Alice
      yarn hardhat transfer --contract $L1_ASSET_ADDRESS --to $A_CHAIN_ADDRESS --amount 1000 --network geth
      
      #Send tokens to Charlie
      yarn hardhat transfer --contract $L1_ASSET_ADDRESS --to $C_CHAIN_ADDRESS --amount 1000 --network geth
      
  • Go to go-nitro repo root

    cd ../../
    
  • Update cmd/test-configs/bridge.toml config file

    chainpk            = "888814df89c4358d7ddb3fa4b0213e7331239a80e1f013eaa7b2deca2a41a218"
    statechannelpk     = "0279651921cd800ac560c21ceea27aab0107b67daf436cdd25ce84cad30159b4"
    l1chainurl         = "ws://127.0.0.1:8546"
    l2chainurl         = "ws://127.0.0.1:9546"
    nodel1msgport      = 3005
    nodel2msgport      = 3006
    rpcport            = 4006
    assetmapfilepath   = "bridge-assets-map.toml"
    
  • Start testnet-onboarding-app (run command in testnet-onboarding-app repo)

    # In testnet-onboarding-app
    yarn start
    

    NOTE: Ignore source map warnings in the terminal

  • Start laconic-wallet android app (run steps in laconic-wallet repo)

    • Set up the Android device

    • Setup port forwarding for your device using the following command:

      # Get device id
      adb devices
      
      # Setup port forwarding
      adb -s <device-id> reverse tcp:26657 tcp:26657
      
    • Start the application:

      # In laconic-wallet
      yarn start
      
    • Press a to run the application on android and wait till the wallet app opens up on your phone

  • In laconic-wallet app, click on Create wallet and add laconicd chain using Add network button:

    Network type - `COSMOS`
    chain ID - `laconic_9000-1`
    Network name - `laconicd`
    New RPC URL - `http://127.0.0.1:26657`
    Coin Type - `118`
    Native Denom - `photon`
    Address Prefix - `laconic`
    Gas Price - `200000`
    

Demo

  • Start the stack for stage 0 laconicd (run command in directory where stage0-deployment had been created)

    laconic-so deployment --dir stage0-deployment start
    
    # Check the logs, ensure that new blocks are getting created
    laconic-so deployment --dir stage0-deployment logs laconicd -f
    
  • Run laconic-faucet:

    • Get private key of funded faucet account from laconicd

      laconic-so deployment --dir stage0-deployment exec laconicd "laconicd keys export alice --keyring-backend test --unarmored-hex --unsafe"
      
    • In laconic-faucet-deployment/config.env file, set the following env variables:

      # Private key of a funded faucet account
      CERC_FAUCET_KEY=<faucet-account-pk>
      
    • Start the stack for laconic-faucet

      laconic-so deployment --dir laconic-faucet-deployment start
      
  • In the wallet, add 2 accounts (Alice and Charlie) for both the networks (ethereum and laconicd) by selecting the network and clicking on Add account

  • Go to go-nitro repo root and start the nitro bridge using CLI:

    # Export contract addresses stored in output files
    source ./packages/nitro-protocol/hardhat-deployments/geth/.contracts.env
    source ./packages/nitro-protocol/hardhat-deployments/optimism/.contracts.env
    
    # Start bridge CLI
    ./nitro-bridge -config cmd/test-configs/bridge.toml
    
  • Get Ethereum private keys for accounts Alice and Charlie from laconic-wallet (to be used as statechannel PKs)

  • Start nitro nodes for Alice and Charlie on L1 and L2:

    • Prepare config files in go-nitro repo cmd/test-configs

      • Note: Enter PKs without the leading 0x

      • cmd/test-configs/l1alice.toml

        usedurablestore = true
        msgport = 3007
        rpcport = 4007
        pk = "<Private key of Alice>"
        chainpk = "570b909da9669b2f35a0b1ac70b8358516d55ae1b5b3710e95e9a94395090597"
        chainurl = "ws://127.0.0.1:8546"
        bootpeers = "/ip4/127.0.0.1/tcp/3005/p2p/16Uiu2HAmJDxLM8rSybX78FH51iZq9PdrwCoCyyHRBCndNzcAYMes"
        
      • cmd/test-configs/l2alice.toml

        usedurablestore = true
        msgport = 3008
        rpcport = 4008
        pk = "<Private key of Alice>"
        chainpk = "570b909da9669b2f35a0b1ac70b8358516d55ae1b5b3710e95e9a94395090597"
        chainurl = "ws://127.0.0.1:9546"
        bootpeers = "/ip4/127.0.0.1/tcp/3006/p2p/16Uiu2HAmJDxLM8rSybX78FH51iZq9PdrwCoCyyHRBCndNzcAYMes"
        durablestorefolder = "./data/l2-nitro-store"
        l2 = true
        
      • cmd/test-configs/l1charlie.toml

        usedurablestore = true
        msgport = 3009
        rpcport = 4009
        pk = "<Private key of Charlie>"
        chainpk = "111b7500bdce494d6f4bcfe8c2a0dde2ef92f751d9070fac6475dbd6d8021b3f"
        chainurl = "ws://127.0.0.1:8546"
        bootpeers = "/ip4/127.0.0.1/tcp/3005/p2p/16Uiu2HAmJDxLM8rSybX78FH51iZq9PdrwCoCyyHRBCndNzcAYMes"
        
      • cmd/test-configs/l2charlie.toml

        usedurablestore = true
        msgport = 3010
        rpcport = 4010
        pk = "<Private key of Charlie>"
        chainpk = "111b7500bdce494d6f4bcfe8c2a0dde2ef92f751d9070fac6475dbd6d8021b3f"
        chainurl = "ws://127.0.0.1:9546"
        bootpeers = "/ip4/127.0.0.1/tcp/3006/p2p/16Uiu2HAmJDxLM8rSybX78FH51iZq9PdrwCoCyyHRBCndNzcAYMes"
        durablestorefolder = "./data/l2-nitro-store"
        l2 = true
        
    • In a new terminal, go to go-nitro repo root and initialize node A on L1

      # Export L1 contract addresses
      source ./packages/nitro-protocol/hardhat-deployments/geth/.contracts.env
      
      ./go-nitro -config cmd/test-configs/l1alice.toml -naaddress $NA_ADDRESS -vpaaddress $VPA_ADDRESS -caaddress $CA_ADDRESS
      
    • In another terminal, initialize node A' on L2

      # Export contract addresses stored in output files
      source ./packages/nitro-protocol/hardhat-deployments/geth/.contracts.env
      source ./packages/nitro-protocol/hardhat-deployments/optimism/.contracts.env
      
      ./go-nitro -config cmd/test-configs/l2alice.toml  -bridgeaddress $BRIDGE_ADDRESS -vpaaddress $VPA_ADDRESS -caaddress $CA_ADDRESS
      
    • In another terminal, initialize node C on L1:

      # Export L1 contract addresses
      source ./packages/nitro-protocol/hardhat-deployments/geth/.contracts.env
      
      ./go-nitro -config cmd/test-configs/l1charlie.toml -naaddress $NA_ADDRESS -vpaaddress $VPA_ADDRESS -caaddress $CA_ADDRESS
      
    • In another terminal, initialize node C' on L2

      # Export contract addresses stored in output files
      source ./packages/nitro-protocol/hardhat-deployments/geth/.contracts.env
      source ./packages/nitro-protocol/hardhat-deployments/optimism/.contracts.env
      
      ./go-nitro -config cmd/test-configs/l2charlie.toml  -bridgeaddress $BRIDGE_ADDRESS -vpaaddress $VPA_ADDRESS -caaddress $CA_ADDRESS
      
  • Create ledger channels on L1 and mirrored channel on L2s

    • Open new terminal

    • Set the NODE_EXTRA_CA_CERTS environment variable to the path of mkcert's root CA certificate. This allows Node.js to trust locally-trusted development certificates created by mkcert

      export NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem"
      
    • Check that no channels exist on L2

      nitro-rpc-client get-all-l2-channels -p 4006
      
    • Set address of bridge and address of custom token on L1 in the current terminal

      export BRIDGE_ADDRESS=0xBBB676f9cFF8D242e9eaC39D063848807d3D1D94
      export L1_ASSET_ADDRESS="<Token Address on L1>"
      

      NOTE: Replace <Token Address on L1> with LNT token address deployed previously on L1 in Run section

    • Create ledger channel between A and Bridge with custom token

      nitro-rpc-client direct-fund $BRIDGE_ADDRESS --assetAddress $L1_ASSET_ADDRESS -p 4007
      
      • Once direct-fund objective is complete, bridge will create mirrored channel on L2
      • Check node A' logs to see bridged-fund objective completed
    • Check status of L1 ledger channel between A and Bridge

      nitro-rpc-client get-ledger-channel <ledger channel ID> -p 4007
      
      # Expected output:
      # {
      #   ID: '0x161d289a50222caa781db215bb82a3ede4f557217742245525b8e8cbff04ec21',
      #   Status: 'Open',
      #   Balance: {
      #     AssetAddress: '<Token address on L1>',
      #     Me: '0xaaa6628ec44a8a742987ef3a114ddfe2d4f7adce',
      #     Them: '0xbbb676f9cff8d242e9eac39d063848807d3d1d94',
      #     MyBalance: 1000000n,
      #     TheirBalance: 1000000n
      #   },
      #   ChannelMode: 'Open'
      # }
      
    • Create ledger channel between C and Bridge with custom token

      nitro-rpc-client direct-fund $BRIDGE_ADDRESS --assetAddress $L1_ASSET_ADDRESS -p 4009
      
      • Once direct fund objective is complete, bridge will create mirrored channel on L2
      • Check node C' logs to see bridged-fund objective completed
    • Check status of L1 ledger channel between C and Bridge

      nitro-rpc-client get-ledger-channel <ledger channel ID> -p 4009
      
      # Expected output:
      # {
      #   ID: '0x69a3f09b6f4f94f033cf084e6e4a9453438c45b43606e9a95f5434f4c6527543',
      #   Status: 'Open',
      #   Balance: {
      #     AssetAddress: '<Token address on L1>',
      #     Me: '0xa8d2d06ace9c7ffc24ee785c2695678aecdfd7a0',
      #     Them: '0xbbb676f9cff8d242e9eac39d063848807d3d1d94',
      #     MyBalance: 1000000n,
      #     TheirBalance: 1000000n
      #   },
      #   ChannelMode: 'Open'
      # }
      
    • Check status of all L2 mirrored ledger channels

      nitro-rpc-client get-all-l2-channels -p 4006
      
      # Expected output:
      # {"ID":"0x15dbe6b996e4e46fdd6ea3e2074cbca58014dbb07368e3e7ba286df5c7b9da0d","Status":"Open","Balance":{"AssetAddress":"<Token_address_on_L2>","Me":"0xbbb676f9cff8d242e9eac39d063848807d3d1d94","Them":"0xa8d2d06ace9c7ffc24ee785c2695678aecdfd7a0","MyBalance":1000000,"TheirBalance":1000000},"ChannelMode":"Open"}
      # {"ID":"0x6a9f5ccf1fa802525d794f4a899897f947615f6acc7141e61e056a8bfca29179","Status":"Open","Balance":{"AssetAddress":"<Token_address_on_L2>","Me":"0xbbb676f9cff8d242e9eac39d063848807d3d1d94","Them":"0xaaa6628ec44a8a742987ef3a114ddfe2d4f7adce","MyBalance":1000000,"TheirBalance":1000000},"ChannelMode":"Open"}
      

      In above expected output the following are observed

      • In ledger channel with ID 0x15dbe6b996e4e46fdd6ea3e2074cbca58014dbb07368e3e7ba286df5c7b9da0d
        • Alice is a participant since Them address is 0xa8d2d06ace9c7ffc24ee785c2695678aecdfd7a0
        • Alice amount is 1000000 since TheirBalance corresponds to her amount
      • In ledger channel with ID 0x6a9f5ccf1fa802525d794f4a899897f947615f6acc7141e61e056a8bfca29179
        • Charlie is participant since Them address is 0xaaa6628ec44a8a742987ef3a114ddfe2d4f7adce
        • Charlie amount is 1000000 since TheirBalance corresponds to his amount
  • Onboard participants

    • Open the testnet-onboarding-app at http://localhost:3000

    • Connect to the testnet-onboarding app by clicking on the WalletConnect icon on the top right corner in the wallet and scanning QR code of the app

    • Choose Alice's nitro and laconicd account to onboard

      • Use nitro accounts for which ledger channels have been created on L2
    • Sign using the nitro key

      • Approve sign request on Wallet
    • Fund the laconic account by clicking on the REQUEST TOKENS FROM FAUCET button

    • Send transaction request to the Wallet

      • Approve and send transaction to laconicd chain
    • Repeat onboarding for other (Charlies's) account by clicking on the web app header "Testnet Onboarding"

    • List the participants on stage 1 (run in the directory where laconicd deployment was created):

      laconic-so deployment --dir stage0-deployment exec laconicd "laconicd query onboarding list"
      
      # Expected output
      # - cosmos_address: <Alice Laconic address>
      #   ethereum_address: <Alice Ethereum address>
      # - cosmos_address: <Charlie Laconic address>
      #   ethereum_address: <Charlie Ethereum address>
      
    • Halt the stage 0 laconicd deployment:

      # Run where deployments are created
      laconic-so deployment --dir stage0-deployment stop
      
    • Use the scripts in fixturenet-laconicd stack to generate genesis file for stage 1 with token allocations:

      cd ~/cerc/fixturenet-laconicd-stack/stack-orchestrator/stacks/fixturenet-laconicd
      
      ./scripts/generate-stage1-genesis.sh <stage0-deployment-absolute-path>
      
      # Expected output:
      # Genesis file for stage1 written to output/genesis.json
      
      # Remove the temporary data directory
      sudo rm -rf stage1-genesis
      
      # Go back to the directory where deployments are created
      cd -
      
    • Copy over the generated genesis file (.json) containing the onboarding module state with funded participants to data directory in stage1 deployment (stage1-deployment/data/genesis-config):

      # Run where deployments are created
      cp ~/cerc/fixturenet-laconicd-stack/stack-orchestrator/stacks/fixturenet-laconicd/output/genesis.json stage1-deployment/data/genesis-config/genesis.json
      
    • Start the deployment for stage 1

      laconic-so deployment --dir stage1-deployment start
      
    • The bank module transfers are disabled on stage 1 laconicd

    • Query the list of registered participants in stage 1 laconicd:

      laconic-so deployment --dir stage1-deployment exec laconicd "laconicd query onboarding list"
      
      # Expected output: same as the result from stage0-deployment
      
    • Query the balances of registered participants:

      export A_LACONIC_ADDRESS=<Alice Laconic address>
      export C_LACONIC_ADDRESS=<Charlie Laconic address>
      
      laconic-so deployment --dir stage1-deployment exec laconicd "laconicd query bank balances $A_LACONIC_ADDRESS"
      
      laconic-so deployment --dir stage1-deployment exec laconicd "laconicd query bank balances $C_LACONIC_ADDRESS"
      
      # Expected output: Account balances equal to Alice's and Charlie's holdings on the bridge
      
    • The bridge holdings are therefore reflected on stage 1 laconicd chain as genesis allocations

    • TODO: The registered participants with balances on stage 1 laconicd chain can join as validators

Payments Demo in L2

  • Ensure the NODE_EXTRA_CA_CERTS environment variable in the current terminal is set to the path of mkcert's root CA certificate.

    echo $NODE_EXTRA_CA_CERTS
    # ~/.local/share/mkcert/rootCA.pem
    
    # If not present, set the environment variable
    export NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem"
    
  • Create virtual channel on L2 from A' to C' via Bridge' as intermediary

    export BRIDGE_ADDRESS=0xBBB676f9cFF8D242e9eaC39D063848807d3D1D94
    export A_ADDRESS=<Alice Nitro address>
    export C_ADDRESS=<Charlie Nitro address>
    
    # Starts virtual fund objective on L2 to create virtual channel from A' to C'
    nitro-rpc-client virtual-fund $C_ADDRESS $BRIDGE_ADDRESS -p 4008
    
  • Check payment channel between A' and C'

    nitro-rpc-client get-payment-channel <payment channel ID> -p 4008
    
      # Expected output:
      # {
      #   ID: '0xb29aeb32c9495a793ebf7bd116232075d1e7bfe89fc82281c7d498e3ffd3e3bf',
      #   Status: 'Open',
      #   Balance: {
      #     AssetAddress: '<Token address on L2>',
      #     Payee: '0xa8d2d06ace9c7ffc24ee785c2695678aecdfd7a0',
      #     Payer: '0xaaa6628ec44a8a742987ef3a114ddfe2d4f7adce',
      #     PaidSoFar: 0n,
      #     RemainingFunds: 1000n
      #   }
      # }
    
  • After virtual fund objective is complete, make payments

    nitro-rpc-client pay <payment channel ID> <amount> -p 4008
    
      # Expected output:
      # {
      #   Amount: 200,
      #   Channel: '0xb29aeb32c9495a793ebf7bd116232075d1e7bfe89fc82281c7d498e3ffd3e3bf'
      # }
    
  • Check payment channel status again to view updated channel state

  • Close payment channel after payments

    nitro-rpc-client virtual-defund <payment channel ID> -p 4008
    
  • Check L2 mirrored channels status after virtual-defund is complete:

    • Note balance change in A' node:

      nitro-rpc-client get-all-ledger-channels -p 4008
      
      # Expected output:
      # {"ID":"0x6a9f5ccf1fa802525d794f4a899897f947615f6acc7141e61e056a8bfca29179","Status":"Open","Balance":{"AssetAddress":"<Token_address_on_L2>","Me":"0xaaa6628ec44a8a742987ef3a114ddfe2d4f7adce","Them":"0xbbb676f9cff8d242e9eac39d063848807d3d1d94","MyBalance":999800,"TheirBalance":1000200},"ChannelMode":"Open"}
      
    • Note balance change in C' node:

      nitro-rpc-client get-all-ledger-channels -p 4010
      
      # Expected output:
      # {"ID":"0x15dbe6b996e4e46fdd6ea3e2074cbca58014dbb07368e3e7ba286df5c7b9da0d","Status":"Open","Balance":{"AssetAddress":"<Token_address_on_L2>","Me":"0xa8d2d06ace9c7ffc24ee785c2695678aecdfd7a0","Them":"0xbbb676f9cff8d242e9eac39d063848807d3d1d94","MyBalance":1000200,"TheirBalance":999800},"ChannelMode":"Open"}
      

Demo cleanup

  • Stop the bridge, A, A', C and C' terminals

    • Change directory to go-nitro repo root

    • Clear the durable store

      rm -rf ./data/
      
  • Reset stage 0 and stage 1 laconicd deployments:

    • Stop deployment and remove volumes:

      # Run where deployments are created
      laconic-so deployment --dir stage0-deployment stop --delete-volumes
      laconic-so deployment --dir stage1-deployment stop --delete-volumes
      
    • Remove data from stage 0 and stage 1 deployments:

      # Run where deployments are created
      sudo rm -rf 'stage0-deployment/data/laconicd-data/*'
      sudo rm -rf 'stage0-deployment/data/genesis-config/*'
      
      sudo rm -rf 'stage1-deployment/data/laconicd-data/*'
      sudo rm -rf 'stage1-deployment/data/genesis-config/*'
      
  • Reset faucet deployment:

    • Stop deployment and remove volumes:

      laconic-so deployment --dir laconic-faucet-deployment stop --delete-volumes
      
    • Remove data from the deployment

      # Run where deployments are created
      sudo rm -rf 'laconic-faucet-deployment/data/faucet-data/*'
      

Re-run

  • After running demo cleanup, follow the steps from Demo to re-run the demo

Cleanup

  • Stop Nitro nodes:

    • Stop (Ctrl+C) the bridge, A, A', C and C' nitro nodes

    • Clear out nitro nodes data and configurations:

      • Change directory to go-nitro repo root

      • Cleanup:

        # In go-nitro
        git clean -xdf
        
  • Reset wallet and stop the app:

    • In laconic-wallet, click on the Reset Wallet button to disconnect all apps and clear the accounts

    • Stop (Ctrl+C) both laconic-wallet and testnet-onboarding-app

  • Clean up stage 0 and stage 1 laconicd deployments:

    • Stop deployment and remove volumes:

      # Run where deployments are created
      laconic-so deployment --dir stage0-deployment stop --delete-volumes
      laconic-so deployment --dir stage1-deployment stop --delete-volumes
      
    • Clear deployments:

      # Run where deployments are created
      sudo rm -rf stage0-deployment
      sudo rm -rf stage1-deployment
      
  • Clean up L1 and L2 deployments:

    • Stop deployment and remove volumes:

      # Run where deployments are created
      laconic-so deployment --dir fixturenet-optimism-deployment stop --delete-volumes
      laconic-so deployment --dir fixturenet-eth-deployment stop --delete-volumes
      
    • Clear deployments:

      # Run where deployments are created
      sudo rm -rf fixturenet-optimism-deployment
      sudo rm -rf fixturenet-eth-deployment
      
  • Clean up faucet deployment:

    • Stop deployment and remove volumes:

      laconic-so deployment --dir laconic-faucet-deployment stop --delete-volumes
      
    • Clear deployment

      # Run where deployments are created
      sudo rm -rf laconic-faucet-deployment
      

Future enhancements

  • Use latest optimism releases (e.g. v1.7.7) in fixturenet-optimism
  • Implement external stack for go-nitro
    • Add stack for bridge
    • Add stack for nitro node
  • LATER: Implement flow for registered participants with balance to join as validators in stage 1 laconicd chain