Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release v0.1.0 integration #47

Merged
merged 2 commits into from
Nov 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 16 additions & 18 deletions .github/workflows/syrius_builder.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,16 @@ name: Build and release syrius
on:
push:
branches-ignore:
- master
pull_request:
branches:
- dev
# Allows you to run this workflow manually from the Actions tab
- master
tags:
- '*'
workflow_dispatch:

env:
FLUTTER_VERSION: "3.10.x"

jobs:
build-macos:
environment: wallet-connect
env:
WALLET_CONNECT_PROJECT_ID: ${{ secrets.WC_PROJECT_ID }}
runs-on: macos-12
Expand All @@ -28,8 +28,8 @@ jobs:
- name: Setup Flutter
uses: subosito/[email protected]
with:
flutter-version: ${{env.FLUTTER_VERSION}}
channel: "stable"
flutter-version: "3.10.2"
- name: Check flutter version
run: flutter --version
- name: Build syrius desktop
Expand Down Expand Up @@ -57,7 +57,6 @@ jobs:
name: macos-artifacts
path: syrius-alphanet-macos-universal.dmg
build-windows:
environment: wallet-connect
env:
WALLET_CONNECT_PROJECT_ID: ${{ secrets.WC_PROJECT_ID }}
runs-on: windows-latest
Expand All @@ -67,8 +66,8 @@ jobs:
- name: Setup Flutter
uses: subosito/[email protected]
with:
flutter-version: ${{env.FLUTTER_VERSION}}
channel: "stable"
flutter-version: "3.10.2"
- name: Check flutter version
run: flutter --version
- name: Build syrius desktop
Expand All @@ -84,7 +83,6 @@ jobs:
name: windows-artifacts
path: syrius-alphanet-windows-amd64.zip
build-linux:
environment: wallet-connect
env:
WALLET_CONNECT_PROJECT_ID: ${{ secrets.WC_PROJECT_ID }}
runs-on: ubuntu-20.04
Expand All @@ -98,8 +96,8 @@ jobs:
- name: Setup Flutter
uses: subosito/[email protected]
with:
flutter-version: ${{env.FLUTTER_VERSION}}
channel: "stable"
flutter-version: "3.10.2"
- name: Set permissions
run: |
sudo chmod -R 777 linux/
Expand All @@ -123,19 +121,18 @@ jobs:
make-release:
needs: [build-macos, build-windows, build-linux]
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'
if: startsWith(github.ref, 'refs/tags/v')
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Set variables
run: |
SYRIUS="v$(cat pubspec.yaml | grep version | sed 's/version://' | xargs)"
echo "Syrius Version: $SYRIUS"
echo "SYRIUS_VERSION=$SYRIUS" >> $GITHUB_ENV
echo "SYRIUS_VERSION=${{ github.ref }}" >> $GITHUB_ENV
echo "Syrius Version: $SYRIUS_VERSION"
GOZENON=$(curl -s https://raw.githubusercontent.com/zenon-network/go-zenon/master/metadata/version.go | grep Version | awk -F '"' '{print $2}')
echo "Go-Zenon Version: $GOZENON"
BODY=$(cat <<EOF
Syrius $SYRIUS features the pre-release version of the [go-zenon](https://github.com/zenon-network/go-zenon) $GOZENON full node.
Syrius $SYRIUS_VERSION features the pre-release version of the [go-zenon](https://github.com/zenon-network/go-zenon) $GOZENON full node.

Syrius for Windows requires Microsoft Visual C++ to be installed.
[Download Microsoft Visual C++](https://aka.ms/vs/16/release/vc_redist.x64.exe)
Expand Down Expand Up @@ -180,9 +177,10 @@ jobs:
uses: svenstaro/[email protected]
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: releases/*
release_name: ${{ env.SYRIUS_VERSION }}
tag: ${{ env.SYRIUS_VERSION }}-alphanet
prerelease: ${{ contains(env.SYRIUS_VERSION, '-') }}
tag: ${{ env.SYRIUS_VERSION }}
file_glob: true
file: releases/*
overwrite: true
body: ${{ env.BODY }}
7 changes: 0 additions & 7 deletions .github/workflows/syrius_lib_updater.yml
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
name: Library updater for syrius

on:
push:
branches-ignore:
- master
pull_request:
branches:
- dev
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

jobs:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# s y r i u s

[![Build and release syrius](https://github.com/zenon-network/syrius/actions/workflows/syrius_builder.yml/badge.svg?branch=cicd)](https://github.com/zenon-network/syrius/actions/workflows/syrius_builder.yml) [![Library updater for syrius](https://github.com/zenon-network/syrius/actions/workflows/syrius_lib_updater.yml/badge.svg?branch=cicd)](https://github.com/zenon-network/syrius/actions/workflows/syrius_lib_updater.yml)
[![Build and release syrius](https://github.com/zenon-network/syrius/actions/workflows/syrius_builder.yml/badge.svg?branch=develop)](https://github.com/zenon-network/syrius/actions/workflows/syrius_builder.yml) [![Library updater for syrius](https://github.com/zenon-network/syrius/actions/workflows/syrius_lib_updater.yml/badge.svg?branch=develop)](https://github.com/zenon-network/syrius/actions/workflows/syrius_lib_updater.yml)

Cross-platform non-custodial wallet designed for Alphanet - Network of Momentum Phase 0.

Expand Down
4 changes: 4 additions & 0 deletions assets/svg/ic_completed_symbol.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions assets/svg/ic_unsuccessful_symbol.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
110 changes: 110 additions & 0 deletions docs/p2p_swaps.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# P2P Swaps in Syrius

The P2P Swap feature in Syrius offers users an easy and censorship resistant way of exchanging value, peer-to-peer, without intermediaries on Network of Momentum. With no fees, users can trade any ZTS token with any counterparty.

P2P Swaps use HTLCs to facilitate the swaps.

## Conducting a P2P Swap in Syrius
P2P Swaps have two parties, the starting party and the joining party. The two parties will first have to find each other (in a chatroom for example) and agree upon the amounts they want to swap. After this, they can use Syrius to conduct a trustless swap with no fees directly with each other.

### Example

Alice is the starting party for the swap and she wants to swap 100 ZNN for 1,000 QSR. Bob is the joining party and has agreed to be Alice's counterparty for the swap. Bob has provided Alice with his NoM address.

1. Alice starts a P2P swap in Syrius and deposits 100 ZNN for Bob. She then sends her deposit's ID to Bob via a messaging service (e.g. Telegram).
2. Bob uses the deposit ID to get the swap's details in Syrius and he can see that Alice has deposited 100 ZNN for him.
3. Bob joins the swap by depositing 1,000 QSR for Alice.
4. Alice sees that Bob has deposited the QSR and proceeds to complete the swap. Once Alice completes the swap, she receives 1,000 QSR.
5. Bob's Syrius sees that Alice has completed the swap and Syrius automatically proceeds to unlock the 100 ZNN For Bob.
6. The swap has now been successfuly completed.

The deposits are timelocked, so if either party backs out of the swap before it is completed, both parties can reclaim their deposits.

## Technical overview

The P2P swaps use the embedded HTLC contract to facilitate the swaps with HTLCs. A swap requires two HTLCs - the initial HTLC and the counter HTLC.

The following constants are used for HTLC based P2P swaps in Syrius:

```
kInitialHtlcDuration = Duration(hours: 8)
kCounterHtlcDuration = Duration(hours: 1)
kMaxAllowedInitialHtlcDuration = Duration(hours: 24)
kMinSafeTimeToFindPreimage = Duration(hours: 6)
kMinSafeTimeToCompleteSwap = Duration(minutes: 10)
```

### Starting the swap

When the starting party starts a swap in Syrius, depositing 100 ZNN, an HTLC is created with the following inputs:

```
hashLocked: ${joiningPartyAddress}
expirationTime: ${frontierMomentumTime} + ${kInitialHtlcDuration}
tokenStandard: zts1znnxxxxxxxxxxxxx9z4ulx
amount: 100000000000
hashType: 0
keyMaxSize: 255
hashLock: [A 32-byte hash of a preimage generated by Syrius]
```
The initial HTLC's expiration time is always set to 8 hours into the future. The preimage is stored into an encrypted database locally. Syrius hashes the preimage with the SHA3-256 hash function, so the `hashType` parameter is set to `0`.

### Joining the swap
The joining party has 1 hour to join the swap. The `kMinSafeTimeToFindPreimage` ensures that the joining party will have at least 6 hours to find the swap's preimage. Since the `kCounterHtlcDuration` makes sure that the counter HTLC's duration is 1 hour, the user cannot join the swap if the initial HTLC's time until expiration is less than the combined duration of `kMinSafeTimeToFindPreimage` and `kCounterHtlcDuration`.

Syrius will not allow the user to join a swap if the initial HTLC's duration exceeds the `kMaxAllowedInitialHtlcDuration` constant.

When the joining party joins the swap, depositing 1,000 QSR, an HTLC is created with the following inputs:
```
hashLocked: ${startingPartyAddress}
expirationTime: ${frontierMomentumTime} + ${kCounterHtlcDuration}
tokenStandard: zts1qsrxxxxxxxxxxxxxmrhjll
amount: 1000000000000
hashType: 0
keyMaxSize: 255
hashLock: ${initialHtlcHashlock}
```

In case the joining party does not join the swap, the starting party will have to wait until the initial HTLC expires. After the HTLC has expired, the funds can be reclaimed.

### Completing the swap
After both parties have deposited their funds, the swap can be completed.

#### The starting party

When the starting party completes the swap, the embedded HTLC contract's `Unlock` method is called with the following inputs:
```
id: ${counterHtlcId}
preimage: ${preimageFromLocalStorage}
```

The starting party has 50 minutes to complete the swap. Although the counter HTLCs duration is 1 hour, the unlock transaction sending has to be started at least 10 minutes (`kMinSafeTimeToCompleteSwap`) before the counter HTLC expires. This is to ensure that the transaction has enough time to get published and processed by the network so that the counter HTLC does not expire in between the time the user sends the transaction and the HTLC contract processes the transaction. This could lead to a situation where the preimage is published on-chain, but the starting party doesn't have access to the hashlocked funds anymore.

If the starting party does not complete the swap, both parties will have to wait for their HTLCs to expire to reclaim their funds.

#### The joining party
Once the starting party has unlocked the counter HTLC, the joining party's Syrius will actively monitor the chain to find the preimage the starting party published on chain when calling the HTLC contract's `Unlock` method.

The joining party should keep Syrius running until either the swap is completed, or the counter HTLC expires. This is to ensure that Syrius can find the preimage and unlock the funds deposited to the joining party. If Syrius is closed during this time, the joining party has at least 6 hours (`kMinSafeTimeToFindPreimage`) to reopen Syrius, so that the preimage can be found.

Once the preimage has been found, the embedded HTLC contract's `Unlock` method is automatically called by Syrius with the following inputs:

```
id: ${initialHtlcId}
preimage: ${preimageFoundOnChain}
```

### What if the joining party fails to find the preimage?
If the joining party fails to find the preimage and unlock the initial HTLC before it expires, access to the funds will be lost and the starting party will be able to reclaim the funds.

To reduce the risk of this happening, Syrius enables the computer's wakelock, so that the computer doesn't go into sleep mode while Syrius is monitoring the chain for the preimage after the joining party has joined the swap. Since the counter HTLC's duration is 1 hour, that is the maximum time that the joining party has to stay vigiliant during the swap. If Syrius is not running during this time and the starting party completes the swap, the joining party will have at least 6 hours to reopen Syrius.

[HTLC Watchtowers](https://github.com/hypercore-one/htlc-watchtower) can also be deployed by community members to further reduce the chance of users losing funds.


## The future of P2P swaps
HTLCs are the only way right now to facilitate trustless trading on Network of Momentum, but they are not necessarily the most convenient way to facilitate same chain P2P swaps. Superior ways to facilitate trading will hopefully be available in the future.

The Syrius implementation for P2P swaps has been designed in such a way, that the underlying primitives that the swaps are based upon can be changed, but the experience for the user can remain more or less the same.

While only ZTS to ZTS swaps are currently supported, HTLCs can be used to facilitate cross-chain swaps as well and supporting cross-chain swaps could be a future goal.
6 changes: 3 additions & 3 deletions lib/blocs/accelerator/project_list_bloc.dart
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ class ProjectListBloc with RefreshBlocMixin {

/*
This method filters the projects according to the following rule:
if a user doesn't have a Pillar, then we only show him the active
projects
if a user doesn't have a Pillar, only show the active
projects or all owned projects
*/
Future<List<Project>> _filterProjectsAccordingToPillarInfo(
Set<Project> projectList) async {
Expand All @@ -142,7 +142,7 @@ class ProjectListBloc with RefreshBlocMixin {
.where(
(project) =>
project.status == AcceleratorProjectStatus.active ||
project.owner.toString() == kSelectedAddress,
kDefaultAddressList.contains(project.owner.toString()),
)
.toList();
if (activeProjects.isNotEmpty) {
Expand Down
23 changes: 15 additions & 8 deletions lib/blocs/auto_receive_tx_worker.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dart:collection';

import 'package:json_rpc_2/json_rpc_2.dart';
import 'package:logging/logging.dart';
import 'package:zenon_syrius_wallet_flutter/blocs/auto_unlock_htlc_worker.dart';
import 'package:zenon_syrius_wallet_flutter/blocs/blocs.dart';
import 'package:zenon_syrius_wallet_flutter/main.dart';
import 'package:zenon_syrius_wallet_flutter/model/model.dart';
Expand All @@ -14,7 +15,6 @@ import 'package:znn_sdk_dart/znn_sdk_dart.dart';
class AutoReceiveTxWorker extends BaseBloc<WalletNotification> {
static AutoReceiveTxWorker? _instance;
Queue<Hash> pool = Queue<Hash>();
HashSet<Hash> processedHashes = HashSet<Hash>();
bool running = false;

static AutoReceiveTxWorker getInstance() {
Expand All @@ -23,10 +23,11 @@ class AutoReceiveTxWorker extends BaseBloc<WalletNotification> {
}

Future<void> autoReceive() async {
if (pool.isNotEmpty && !running) {
// Make sure that AutoUnlockHtlcWorker is not running since it should be
// given priority to send transactions.
if (pool.isNotEmpty && !running && !sl<AutoUnlockHtlcWorker>().running) {
running = true;
Hash currentHash = pool.first;
pool.removeFirst();
try {
String toAddress =
(await zenon!.ledger.getAccountBlockByHash(currentHash))!
Expand All @@ -45,17 +46,22 @@ class AutoReceiveTxWorker extends BaseBloc<WalletNotification> {
blockSigningKey: keyPair,
waitForRequiredPlasma: true,
);
pool.removeFirst();
_sendSuccessNotification(response, toAddress);
} on RpcException catch (e, stackTrace) {
_sendErrorNotification(e.toString());
Logger('AutoReceiveTxWorker')
.log(Level.WARNING, 'autoReceive', e, stackTrace);
if (e.message.compareTo('account-block from-block already received') !=
if (e.message.compareTo('account-block from-block already received') ==
0) {
pool.addFirst(currentHash);
pool.removeFirst();
} else {
_sendErrorNotification(e.toString());
}
} catch (e, stackTrace) {
Logger('AutoReceiveTxWorker')
.log(Level.WARNING, 'autoReceive', e, stackTrace);
_sendErrorNotification(e.toString());
}
running = false;
}
Expand Down Expand Up @@ -85,15 +91,16 @@ class AutoReceiveTxWorker extends BaseBloc<WalletNotification> {
}

Future<void> addHash(Hash hash) async {
if (!processedHashes.contains(hash)) {
if (!pool.contains(hash)) {
zenon!.stats.syncInfo().then((syncInfo) {
if (!processedHashes.contains(hash) &&
// Verify that the pool does not already contain the hash after the
// asynchronous request has completed and that the node is in sync.
if (!pool.contains(hash) &&
(syncInfo.state == SyncState.syncDone ||
(syncInfo.targetHeight > 0 &&
syncInfo.currentHeight > 0 &&
(syncInfo.targetHeight - syncInfo.currentHeight) < 3))) {
pool.add(hash);
processedHashes.add(hash);
}
});
}
Expand Down
Loading