Dart SDK/CLI Updates

Hi everyone,

I’ve updated the Dart SDK and Dart CLI with support for Sporks and HTLC.
I’m requesting community testing to ensure the implementations are accurate and ready for production.

For HTLC-related content, check out:

Below are instructions to get you started, along with scenarios to test some of the new functions in Dart CLI.
Feel free to try the other HTLC functions that aren’t mentioned in this post.
Please let me know if you encounter any issues.

Setting up the environment

Details
  1. Follow @CryptoFish’s Windows or Linux tutorials for setting up devnet

    • Omit the remaining instructions when you reach “Zenon CLI for .NET” and follow the steps below to test functionality in Dart
  2. You may instead use my devnet node if you don’t want to set one up

    • Append --url ws://node.zenon.fun:36998 to all commands
    • Send me a DM if you need tokens
    • Explorer details
  3. Install Dart

  4. git clone -b spork_htlc https://github.com/Sol-Sanctum/znn_cli_dart.git && cd znn_cli_dart

  5. Depending on your OS:

    • Windows: make windows
    • Linux: make linux
  6. cd build

  7. Depending on your OS:

    • Windows: znn-cli.exe
    • Linux: ./znn-cli

Setting up wallets

Details

The primary address of Alice is z1qqjnwjjpnue8xmmpanz6csze6tcmtzzdtfsww7

The primary address of Bob is z1qpsjv3wzzuuzdudg7tf6uhvr6sk4ag8me42ua4

Create Alice wallet with password secret

znn-cli wallet.createFromMnemonic "route become dream access impulse price inform obtain engage ski believe awful
 absent pig thing vibrant possible exotic flee pepper marble rural fire fancy" secret Alice

Create Bob wallet with password secret

znn-cli wallet.createFromMnemonic "alone emotion announce page spend eager middle lucky frame craft junk artefact upper finger drive corn version slot blade picnic festival wealth critic silver" secret Bob

Fuse Plasma to both addresses

znn-cli plasma.fuse z1qqjnwjjpnue8xmmpanz6csze6tcmtzzdtfsww7 5000 -k Alice
znn-cli plasma.fuse z1qpsjv3wzzuuzdudg7tf6uhvr6sk4ag8me42ua4 5000 -k Alice

Optional - Send Bob some tokens

znn-cli send z1qpsjv3wzzuuzdudg7tf6uhvr6sk4ag8me42ua4 100 ZNN -k Alice
znn-cli send z1qpsjv3wzzuuzdudg7tf6uhvr6sk4ag8me42ua4 100 QSR -k Alice

HTLC Scenarios (Copied from here)

Alice wants to buy something from Bob

Alice wants to buy something from Bob. She will give Bob 1 hour the time to deliver her the goods in exchange for 100 ZNN.

Alice checks her balance to make sure she has enough funds.

znn-cli balance -k Alice

Alice locks 100 ZNN for Bob for 1 hour, generating a random preimage.
Keep the preimage for a future step.

znn-cli htlc.create z1qpsjv3wzzuuzdudg7tf6uhvr6sk4ag8me42ua4 ZNN 100 3600 -k Alice

Example output:

Creating htlc with amount 100.00000000 tZNN using preimage IDPF68R3VjI2vR1HlhbUpvwoW
Can be unlocked by z1qpsjv3wzzuuzdudg7tf6uhvr6sk4ag8me42ua4 with hashlock 4c4b3f1e4ba60c3b35a644a5535375ce6114d4f1369a9b8171ca66f603cd5b79 hashtype 0

Alice makes sure the HTLC is created and the funds have been deducted from her account before notifying Bob.

znn-cli htlc.timeLocked z1qqjnwjjpnue8xmmpanz6csze6tcmtzzdtfsww7
znn-cli balance -k Alice

Alice notifies Bob for him to inspect the HTLC.

znn-cli htlc.hashLocked -k Bob

Bob inspects the HTLC and agrees to the conditions and writes down the HTLC hash id.

Bob has 1 hour the time to do his part of the deal. Once finished, Alice will reveal the pre-image to Bob so that he can unlock the 100 ZNN.

znn-cli htlc.unlock [hash id] [preimage] -k Bob

Bob has unlocked the 100 ZNN which the contract has send to his wallet. Bob needs to receive the unreceived transactions.

znn-cli receiveAll -k Bob

Bob checks his balance to make sure everything is fine.

znn-cli balance -k Bob

Atomic Swapping

Two users want to swap tokens in a trust-less manner.
Alice will send 10 ZNN to Bob; Bob will send 100 QSR to Alice.
For this scenario, Alice will need two terminals and Bob will need one.

  • Note: we’re assuming both parties already have these assets and fused QSR for plasma.
  1. Alice locks 10 ZNN for Bob for 1 hour, generating a random preimage.
    znn-cli htlc.create z1qpsjv3wzzuuzdudg7tf6uhvr6sk4ag8me42ua4 ZNN 10 3600 -k Alice
  • Save the randomly-generated preimage
  • Assuming hashLockType: 0
  1. Alice will send Bob the hashLock.

    • Doesn’t matter how, Alice sends the hashLock by email, SMS, instant message, etc.
  2. Bob receives the hashLock from Alice and locks his 100 QSR using the same hashLock.
    znn-cli htlc.create z1qqjnwjjpnue8xmmpanz6csze6tcmtzzdtfsww7 QSR 100 3600 [hashLock] -k Bob

  3. Bob confirms that the HTLC was created.
    znn-cli htlc.timeLocked z1qpsjv3wzzuuzdudg7tf6uhvr6sk4ag8me42ua4
    or
    znn-cli htlc.hashLocked z1qqjnwjjpnue8xmmpanz6csze6tcmtzzdtfsww7

  4. Bob notes the hltcId and sends it to Alice.

    • Note: he merely needs to inform Alice that it’s been created. She can check the details herself (Step 7).
  5. Shortly after Step 5, Bob starts monitoring the all HTLCs associated with his address.
    znn-cli htlc.monitorAll -k Bob

  6. Alice confirms that Bob has configured the HTLC with the correct hashLock.
    znn-cli htlc.timeLocked z1qpsjv3wzzuuzdudg7tf6uhvr6sk4ag8me42ua4
    or
    znn-cli htlc.hashLocked z1qqjnwjjpnue8xmmpanz6csze6tcmtzzdtfsww7

  7. For the sake of this demo, Alice decides to monitor all HTLCs associated with her address, as well.
    In Terminal 1:
    znn-cli htlc.monitorAll -k Alice

  8. Alice is ready to unlock Bob’s funds
    In Terminal 2:
    znn-cli htlc.unlock [Bob's htlcId] [preimage] -k Alice

Alice’s Terminal 2: htlc is unlocked, funds ready to be received.
Alice’s Terminal 1: after a few momentums, Bob will discover the preimage, unlock Alice’s HTLC automatically, and Alice will see a confirmation of that result

Bob’s Terminal: Bob will discover the preimage and unlock Alice’s HTLC automatically

Both parties need to run znn-cli receiveAll -k [keystore] to receive their funds.

Alice did not need to trust that Bob had the funds; they were locked in escrow with a hashLock that she could unlock.
Bob did not need to trust that Alice had the funds; they were locked in escrow before he submitted his transaction.

Sporks

High level process
  1. A new feature is implemented in go-zenon, tested in devnet, and is ready to be deployed to mainnet.
  2. The owner of the spork address creates a new spork, signaling to network participants that a soft-fork is potentially going to occur.
  3. The devs add the spork’s hash id to go-zenon and release the updated code to users
  4. After most network participants have adopted the new code, the owner of the spork address activates the spork, disabling any nodes that did not install the new code.
Scenario

A new feature is being deployed! We need to create and activate a spork in order for the feature to go live.

Note: we will need to make a few changes in order to achieve this since we do not control the spork address.

For this scenario, you will setup your own devnet.

  1. Follow @CryptoFish’s Windows or Linux tutorials but also do the following:

    • Before make znnd
      Edit this file in your local repository:
      Comment the block.Address checks at lines 34 and 97
      //if block.Address != *types.SporkAddress {
      //	return constants.ErrPermissionDenied
      //}
      
    • Omit the remaining instructions when you reach “Zenon CLI for .NET”
  2. Install Dart

  3. git clone -b spork_htlc https://github.com/Sol-Sanctum/znn_cli_dart.git && cd znn_cli_dart

  4. Depending on your OS:

    • Windows: make windows
    • Linux: make linux
  5. cd build

  6. Depending on your OS:

    • Windows: znn-cli.exe
    • Linux: znn-cli
  7. Display a list of sporks on the network

    • znn-cli spork.list
  8. Create a new “Example-spork” spork

    • znn-cli spork.create "Example-spork" "Acta Non Verba" -k Alice
  9. Save the new spork’s Hash for the next step

    • znn-cli spork.list
  10. Now the network participants need to update znnd/libznn with that spork

    • Edit this file in your local repository
      Update the var with two changes:
      • Add a new spork:
        ExampleSpork = NewImplementedSpork("Hash from Step 7")

      • Include it in the ImplementedSporksMap:
        ExampleSpork.SporkId: true,

  11. Now make znnd again and run the new binary on all participating network infrastructure (pillars and nodes)

  • For this example, we just need to run it on the pillar.
  1. After the pillar starts producing momentums, return to znn_cli_dart and run:
    • znn-cli spork.activate <Hash from Step 7> -k Alice
  2. Display a list of sporks on the network
    • znn-cli spork.list
    • Example-spork should be Activated
8 Likes

When I try to build with make linux or make windows on the first scenario I get the following spaghetti

What happens if you run:
dart run .\cli_handler.dart

It worked. Some little issues in your tutorial.

  • at the wallet creation it’s not “” and not the ““ you used. Like this actually:

./znn-cli wallet.createFromMnemonic “route become dream access impulse price inform obtain engage ski believe awful absent pig thing vibrant possible exotic flee pepper marble rural fire fancy” secret Alice

  • When Alice notifies Bob, address should be included.

  • For Linux your commands should start with ./ ? At least it has to for me.

  • In your second scenario Bob had no QSR. I reversed ZNN and QSR from Alice and Bob

  • htlc.monitorAll has to be stopped with CTRL+C

Everything else seems to work so just little tweaks in your tutos to be done but the code seems solid ser.

I only tested the htlc scenario though.

1 Like

I appreciate the feedback :slight_smile:

  1. The quotes for the wallet creation step were wrong? I manually edited them now.

  2. “When Alice notifies Bob, address should be included.”
    I assume Alice and Bob inform each other of their address before commencing. But once an HTLC is created, the other party can check for all HTLCs tied to their address, as well.

  3. htlc.monitorAll will continue running until all monitored HTLCs are resolved (unlocked or reclaimed). Otherwise, you’re right.

I updated some steps to reflect the Linux CLI notation and funding Bob with QSR.

Were you able to resolve the make issue?

Yep perfect :slight_smile:

Get the following error (testing this release) from @aliencoder

./znn-cli wallet.createFromMnemonic “route become dream access impulse price inform obtain engage ski believe awful absent pig thing vibrant possible exotic flee pepper marble rural fire fancy” secret Alice
Incorrect number of arguments. Expected:
wallet.createFromMnemonic "mnemonic" passphrase [keyStoreName]

Could be the quotes. I think the forum formatting changes those characters.

on make linux I get a long list of errors, starting with

x3639@ubuntu:~/sol/znn_cli_dart$ make linux
mkdir -p build
dart compile exe cli_handler.dart -o build/znn-cli
Info: Compiling with sound null safety
Error: Couldn't resolve the package 'bip39' in 'package:bip39/bip39.dart'.
Error: Couldn't resolve the package 'dcli' in 'package:dcli/dcli.dart'.
Error: Couldn't resolve the package 'path' in 'package:path/path.dart'.
Error: Couldn't resolve the package 'random_string_generator' in 'package:random_string_generator/random_string_generator.dart'.
Error: Couldn't resolve the package 'collection' in 'package:collection/collection.dart'.
Error: Couldn't resolve the package 'znn_sdk_dart' in 'package:znn_sdk_dart/znn_sdk_dart.dart'.
Error: Couldn't resolve the package 'znn_sdk_dart' in 'package:znn_sdk_dart/src/abi/abi.dart'.
Error: Couldn't resolve the package 'logging' in 'package:logging/logging.dart'.
cli_handler.dart:5:8: Error: Not found: 'package:bip39/bip39.dart'

Full error log: znn-error - Pastebin.com

I updated the makefile.
dart pub get needs to be executed first.

1 Like

that worked

Just to follow up on this command, for some reason when you paste into a bash terminal, the parentheses are changed somehow. You need to delete them and type them manually from your keyboard for the command to work correctly.

./znn-cli wallet.createFromMnemonic "route become dream access impulse price inform obtain engage ski believe awful absent pig thing vibrant possible exotic flee pepper marble rural fire fancy" secret Alice

I see what is wrong w/ this command. You need to insert the command in a code box. then it will NOT change the " ".

1 Like

Thanks for the tip! I updated the original post and the quotes should be correct now.

1 Like

@vilkris has submitted some code changes for znn_cli_dart, primarily updating the way preimages are generated.
I’ve tested all htlc functions again and everything is working well.

Still requesting community feedback :slight_smile:

I think the change I made to use hex encoding for the preimage now makes the Dart CLI and the C# CLI incompatible with each other. @CryptoFish would you mind taking a look if you have any thoughts on that?

1 Like

A quick check that I did indicates that both CLIs are mostly compatible, though the user experience is not entirely the same.

Main issue

  • Dart CLI now generates a 64-char preimage, exceeding C# CLI’s htlc.KeyMaxSize of 32 to unlock an htlc. If this check is removed or updated, both CLIs should be able to unlock HTLCs created with the other application.

Other differences

  • Dart CLI’s createHash does not allow users to enter their own preimage.
  • Dart CLI’s htlc.create auto-generates a random preimage, while C# CLI allows users to enter their own. The resulting hashlocks are still calculated the same way.
  • Dart CLI’s monitor function auto-reclaims expired HTLCs.
  • Dart CLI does not require a chainId parameter to be passed with the command
  • Dart CLI creates HTLCs based on the node’s time instead of relying on the user’s local time.

I probably missed some stuff. This will require some more interoperability testing.

1 Like

The KeyMaxSize can be specified when creating the htlc. The default KeyMaxSize is 32.

znn-cli htlc.create --help

  hashLockedAddress (pos. 1)              Required.
  tokenStandard (pos. 2) [ZNN/QSR/ZTS]    Required.
  amount (pos. 3)                         Required.
  expirationTime (pos. 4)                 Required. Total seconds from now.
  hashLock (pos. 5)                       Required. The hash lock as a hexidecimal string.
  hashType (pos. 6)                       (Default: 0) 0 = SHA3-256, 1 = SHA-256
  keyMaxSize (pos. 7)                     (Default: 32) Maximum size of the pre-image.

When unlocking the htlc, the KeyMaxSize is checked in the CLI, but enventually also in the htlc contract.

I think the change I made to use hex encoding for the preimage now makes the Dart CLI and the C# CLI incompatible with each other.

The hashlock argument of the htlc.create command accepts a hex encoded string. Is it the size of the preimage or the format causing the incompatibality?

Or is it because the Dark CLI’s htlc.create auto.generates a random preimage with a 64-char preimage?

I haven’t had the time to look into the Dart htlc implementation yet, but it would be nice to have an consensus on the preferred implementation.

Isn’t the KeyMaxSize in the embedded contract referring to byte array length, not string length? This is where the incompatibility stems from with the Dart CLI. The C# CLI checks the preimage string length, not the preimage length as a byte array. Also, the C# CLI doesn’t handle the preimage input as a hex string when unlocking the HTLC.

In my opinion the user should not be allowed to specify their own preimage because of safety reasons. In the C# CLI you can use a preimage of any length but you’d have to manually set the KeyMaxSize when creating the HTLC if the preimage length is over 32 bytes. This wouldn’t be an issue if the client generates the preimage.

Maybe the user could specify an optional KeySize argument instead of KeyMaxSize which would create a preimage of that size and set the KeyMaxSize accordingly when creating the HTLC.

In the Dart CLI there’s a hardcoded variable int hashLockLength = 32; which is used to set KeyMaxSize when creating the HTLC. This is misleading as we’re setting the max length of the preimage, not the hashlock length.

Correct, the KeyMaxSize is referring to the byte array length of the array.

The htlc.unlock does this indeed. This will need to be changed.

In the case of the Atomic Swap scenario Bob needs to create an htlc with a hashlock that already exists. How would Bob be able to supply the hashlock if the htlc.create command generates the preimage?

According to @georgezgeorgez the KeyMaxSize was introduced to prevent Secret Size Attacks. It puts a guarantee on max size of the unlock tx. For other networks there is tx size limit. We have to pay plasma per byte.
So the bounded size ensures that Bob knows he’ll be able to redeem his, if Alice redeems hers.