Raiden Network 1.0.0 Documentation

This is the documentation for the 1.0.0 version of the Raiden Network. You can find the source code in our Github Repository.

Note

We are currently reworking our documentation for Raiden. While this is still an ongoing process you can already view the updated parts in this new but incomplete version of the documentation.

What is the Raiden Network?

The Raiden Network is an off-chain scaling solution, enabling near-instant, low-fee and scalable payments. It’s complementary to the Ethereum blockchain and works with any ERC20 compatible token. The Raiden project is work in progress. Its goal is to research state channel technology, define protocols and develop reference implementations.

How to get started

Whether you’ve just heard of Raiden for the first time or you’re here looking for something specific here’s a short list of relevant resources and links.

New to Raiden?

If you’re new to Raiden and just want to install and try it out, you can either:

Developing on Raiden?

If you’re looking for documentation relevant for building on top of Raiden:

Contributing to Raiden?

If you’re looking for a more in depth understanding of Raiden and are interested in contributing:

Need help?

If you run in to any kind of problems or you discover bugs:

  • Ask for help or project related questions in the Raiden gitter.
  • Create a Github issue if you discover a bug or have a feature request.

Disclaimer

Please note, that even though we do our best to ensure the quality and accuracy of the information provided, this publication may contain views and opinions, errors and omissions for which the content creator(s) and any represented organization cannot be held liable. The wording and concepts regarding financial terminology (e.g. “payments”, “checks”, “currency”, “transfer” [of value]) are exclusively used in an exemplary way to describe technological principles and do not necessarily conform to the real world or legal equivalents of these terms and concepts.

Contents

System Requirements and Installation Guide

Introduction

Raiden is a payment channel implementation which provides scalable, low latency, and cheap token payments for Ethereum.

Installation

To install Raiden you can either:

  • Use the Raiden Wizard
  • Download a self contained application bundle from the GitHub release page
  • Use pip or, on macOS, homebrew
  • Run a raiden docker image

Below we will give details on how to use the self contained application bundles on different platforms, as well as the other installation methods.

Installation via Raiden Wizard

See the Raiden Wizard documentation.

Installation from GitHub

Linux

Download the latest raiden-<version>-linux-x86_64.tar.gz, and extract it:

tar -xvzf raiden-<version>-linux-x86_64.tar.gz

The Raiden binary should work on most 64bit GNU/Linux distributions without any specific system dependencies, other than an Ethereum client installed in your system (see below). The Raiden binary takes the same command line arguments as the raiden script.

macOS

Download the latest raiden-<version>-macOS-x86_64.zip, and extract it:

unzip raiden-<version>-macOS-x86_64.zip

The resulting binary will work on any version of macOS from 10.12 onwards without any other dependencies.

Or you can use Homebrew to install the most up to date binary:

brew tap raiden-network/raiden
brew install raiden

An Ethereum client is required in both cases. The Raiden binary takes the same command line arguments as the raiden script.

Raiden is also available as a PyPi package and can be installed with pip install raiden.

Raspberry Pi

Download the latest raiden-<version>-linux-armv7l.tar.gz or raiden-<version>-linux-aarch64.tar.gz for the respective Raspberry Pi Model and extract it:

tar -xvzf  raiden-<version>-linux-*.tar.gz

The resulting binary will work on any Raspberry Pi from Model 2B onwards without any other dependencies.

An Ethereum client is required in both cases. The Raiden binary takes the same command line arguments as the raiden script.

Installation using pip

To get the latest available stable version via pip:

pip install raiden

If you’d like to give the pre-releases a spin, use pip’s –pre flag:

pip install --pre raiden

Installation via Docker

There are two options to run a raiden docker image:

Create the Image yourself and use our Dockerfile as template or use the already built image from Dockerhub:

docker run -it raidennetwork/raiden:latest

The required keystore can easily be mounted in the docker container:

docker run -it --mount src=/PATH/TO/LOCAL/KEYSTORE,target=/keystore,type=bind raidennetwork/raiden:latest --keystore-path /keystore

Other flags such as the JSON-RPC endpoint to an Ethereum node can easily be chained to the command.

Dependencies

You will need a local or remote Ethereum node to connect Raiden to.

  • Check this link to install the go-ethereum client.
  • Follow these instructions to install the parity client.
  • Or sign up at a service like Infura <https://infura.io> to set up a remote node.

Now you are ready to get started.

For developers

If you plan to develop on the Raiden source code, or the binary distributions do not work for your system, you can follow these steps to install a development version.

Linux

Additional dependencies for development installations
Installation from source

Clone the repository:

git clone https://github.com/raiden-network/raiden.git

Navigate to the directory:

cd raiden

It’s strongly advised to create a virtualenv for Raiden (requires python3.7) and install all python dependencies there.

After you have done that you can proceed to install the dependencies:

make install-dev

You will also need to connect your Ethereum client to the Ropsten testnet. See below for guidelines on how to connect with both Parity and Geth.

macOS

Please refer to the detailed step-by-step guide for setting up a macOS development environment.

nix

Please refer to the nix setup guide for setting up a development environment using the nix package manager.

Requirements for Safe Usage

In order to use Raiden correctly and safely there are some things that need to be taken care of by the user:

  • Layer 1 works reliably: That means that you have a local Ethereum node, either geth or parity, that is always synced and working reliably. If there are any problems or bugs on the client then Raiden can not work reliably.
  • Dedicated account for Raiden: We need to have a specific Ethereum account dedicated to Raiden. Creating any manual transaction with the account that Raiden uses, while the Raiden client is running, can result in undefined behaviour
  • Raiden account has sufficient ETH: Raiden will try to warn you if there is not enough ETH in your Raiden account in order to maintain your current open channels and go through their entire cycle. But it is your job as the user to refill your account with ETH and always have it filled.
  • Persistency of local DB: Your local state database is located at ~/.raiden. This data should not be deleted by the user or tampered with in any way. Frequent backups are also recommended. Deleting this directory could mean losing funds.
  • Raiden always online: Make sure that your node is always working, your network connection is stable and that the Raiden node is always online. If it crashes for whatever reason you are responsible to restart it and keep it always online. We recommend running it inside some form of monitor that will restart if for some reason the Raiden node crashes.
  • Ethereum client always online: Make sure that your Ethereum client is always running and is synced. We recommend running it inside some form of monitor that will restart if for some reason it crashes.
  • Ethereum client is not changed: Swapping the Ethereum client while transactions are not mined is considered unsafe. We recommend avoiding switching Ethereum clients once the Raiden node is running.
  • Raiden REST API is never exposed to the public: For Raiden’s operation, the client needs to be able to sign transactions at any point in time. Therefore you should never expose the Raiden Rest API to the public. Be very careful when changing the –rpc and –rpccorsdomain values.
  • “Wormhole Attack” is possible: When your Raiden node plays the role of a mediator, a so-called “wormhole attack” is possible. Under this attack, even though the whole payment succeeds, your incoming and outgoing capacities will be locked until the expiration, and the attackers gain mediation fees. However, such an attacker can also avoid your node altogether, and avoid locking their capacities.
  • Be patient: Do not mash buttons in the webUI and do not shut down the client while on-chain transactions are on the fly and have not yet been confirmed.

Firing it up

To fire up Raiden you need at least
  1. a synced Ethereum Node - using geth, parity or infura
  2. an Ethereum keystore file - whereas the address holds ETH, RDN, and the ERC20 token you want to transfer
  3. If you want to use Raiden services that charge a fee, a deposit of RDN tokens to pay the services with.

More about the Raiden services (pathfinding and monitoring service) will be explained below. On the testnets there are also free services available, and on any network it is possible (though not recommended) to use Raiden without Raiden services.

We will provide you with the necessary cli arguments step by step. Full example is at the end of the page.

1. and 2. The synced Ethereum Node & Keystore

  • Using geth

Run the Ethereum client and let it sync:

geth --syncmode fast --rpc --rpcapi eth,net,web3

Note

When you want to use a testnet add one of the --testnet, --rinkeby or --goerli flags or set the network id with --networkid directly.

Unless you already have an account you can also create one in the console by invoking personal.newAccount().

If problems arise for above method, please see the Ropsten README for further instructions.

Then launch Raiden with the default testnet keystore path:

raiden --keystore-path  ~/.ethereum/testnet/keystore --pathfinding-service-address $PFS_ADDRESS
  • Using parity

Run the client and let it sync:

parity --no-warp --jsonrpc-apis=web3,eth,net,parity

Note

When you want to use a testnet add the --chain ropsten or --chain kovan flags or set the network id with --network-id directly.

Attention

Parity sometimes loses its historical DB (potentially after updates). Due to this some events might be lost which will result in Raiden not being able to fetch all events. Therefore it is recommended to make sure to have Parity fully synced with the --no-warp option.

After syncing the chain, an existing Ethereum account can be used or a new one can be generated using parity-ethkey. After account creation, launch Raiden with the path of your keystore supplied:

raiden --keystore-path ~/.local/share/io.parity.ethereum/keys/test --pathfinding-service-address $PFS_ADDRESS
  • Using Infura

Sign up with Infura to get an API token. After that you can start using Raiden directly:

raiden --keystore-path  ~/.ethereum/testnet/keystore --eth-rpc-endpoint "https://<network>.infura.io/v3/<yourToken>"

Where <network> can be mainnet, ropsten, etc.

Select the desired Ethereum account when prompted, and type in the account’s password.

3. Depositing tokens to pay the services

To pay the services, you have to lock some of your Raiden tokens in the UserDeposit contract. Normally the Raiden Wizard or some other auxilliary scripts would do the contract interaction for you. In this section, we will briefly explain how it can be done manually so you are able to use Raiden without them.

All services that are registered in the service registry of a given network will use one shared instance of UserDeposit. You can obtain the address of the contract from

https://github.com/raiden-network/raiden-contracts/blob/master/raiden_contracts/data/deployment_services_<network>.json

where network is one of mainnet, ropsten, rinkeby or goerli.

As an example, suppose we want to run a Raiden node with address 0x3040435D7F1012e861f0B0989422a47D1825F120 on the mainnet and deposit 10 Raiden tokens (10**19 REI) for it to use. Here we use MetaMask to access our wallet and the contract interface of Etherscan to do the transactions. Of course, you can also use another service or your own Ethereum node.

We log into MetaMask with our account that holds the Raiden tokens (which should be a different account than the one we use with Raiden, as the latter is supposed to be used with Raiden only.) To find the UserDeposit contract, we take a look at deployment_services_mainnet.json:

{
    "contracts_version": null, "chain_id": 1,
    (...)
    "UserDeposit": {
        "address": "0x53Cc1decDD7d452c8844a5f383e23AD479A1f614",
        (...)

We can then look up the contract address on Etherscan, and use Etherscan’s “read/write contract” panels to interact with it. The Raiden token (RDN) can be searched by name on Etherscan, or we can look up its address in the UserDeposit contract’s token property. On the testnets, the token symbol is SVT (service token) rather than RDN and it may not be possible to find the token by name, but it can always be found in UserDeposit.token.

As usual with ERC-20 tokens, we need to call two contract functions:

approve(0x53Cc1decDD7d452c8844a5f383e23AD479A1f614, 10000000000000000000)

on the RDN (or SVT) token contract, to allow the UserDeposit contract to move the 10 RDN, and

deposit(0x3040435D7F1012e861f0B0989422a47D1825F120, 10000000000000000000)

on the UserDeposit contract.

Optional CLI arguments

There are further CLI arguments with which you can control, among other things

  1. The choice of a pathfinding service
  2. The choice of a monitoring service
  3. Logging

1. Pathfinding service

A pathfinding service is a third party service helping your node with efficient transfer routing. It is usually paid in RDN tokens.

Raiden can be configured to not use a pathfinding service and rely on its internal routing instead. This is discouraged since the node has less information about the network that it can use to find routes and compute fees. So transfers will be more likely to fail to route, and paid fees will often be unnecessarily high when internal routing is used. If you want to use internal routing anyway, you can do so with --routing-mode local.

Note

Although otherwise discouraged, --routing-mode local has to be used at the moment to try out Raiden on the mainnet. The Raiden Service Bundle, with pathfinding service and registry, will not be deployed on the mainnet until the Alderaan release.

If you want to use a particular pathfinding service, e.g. one of the testnet pathfinding services given below, you can do so with --pathfinding-service-address <url>. Otherwise Raiden will automatically pick one of the pathfinding services from the registry.

The default setting for the pathfinding options is to use a pathfinding service and choose it automatically (--routing-mode pfs --pathfinding-service-address auto).

There are pathfinding services running on every testnet at the moment, some that charge fees and some that are for free.

Testnet pfs with fees pfs without fees
Görli https://pfs-goerli-with-fee.services-dev.raiden.network https://pfs-goerli.services-dev.raiden.network
Ropsten https://pfs-ropsten-with-fee.services-dev.raiden.network https://pfs-ropsten.services-dev.raiden.network
Kovan https://pfs-kovan-with-fee.services-dev.raiden.network https://pfs-kovan.services-dev.raiden.network
Rinkeby https://pfs-rinkeby-with-fee.services-dev.raiden.network https://pfs-rinkeby.services-dev.raiden.network

For the mainnet we don’t want to prefer and suggest specific pathfinding services.

2. Monitoring service

A monitoring service watches a client’s open channels while it is offline, and represents the client in case of settlement. Like the pathfinding service, it is paid in RDN tokens. If you want to use a monitoring service, use the option --enable-monitoring and Raiden will automatically pick one from its service registry.

3. Logging configuration

By default raiden keeps a “debug” log file so that people who have not configured logging but are facing problems can still provide us with some logs to debug their problems.

For expert users of raiden who want to configure proper logging we recommend disabling the debug log file and configuring normal logging appropriately.

To disable the log file the --disable-debug-logfile argument should be passed.

To specify the logging level add: --log-config ":debug" if you want all debug statements to be logged. The logging level can actually be configured down to the module level through this argument.

To provide the filename for the logs use --log-file XXX where XXX is the full path and filename to the log you want to create or append to. Note that Raiden uses a python WatchedFileHandler for this log. That means that if you or your system moves the logfile (for example due to log rotation) then Raiden will detect that and close and reopen the log file handler with the same name.

Finally by default the output of the logs are in plain readable text format. In order to make them machine readable and parsable json add the --log-json argument.

Summing up these are the arguments you need to append if you want to disable the debug log and want to configure normal logging for up to debug statement in json inside a file called raiden.log

--disable-debug-logfile --log-config ":debug" --log-file raiden.log --log-json

Further reading

Now that Raiden is up and running, head over to the API walkthrough for further instructions on how to interact with Raiden. There’s also a Web UI tutorial available for people who prefer a graphical interface, and a Mainnet tutorial for your first mainnet transfers via API.

Raiden Alderaan Mainnet Tutorial

Introduction

In this tutorial we show how to use Raiden to do off chain payments using the Raiden Network on the Ethereum mainnet. It is based on the upcoming Alderaan release. Since the Alderaan release is a bug bounty release, certain limits have been made to the amount of tokens that can be deposited in channels. This is done in order to minimize the funds that are potentially lost in case something goes wrong.

Raiden has a Restful API with URL endpoints corresponding to actions that users can perform with their channels. The endpoints accept and return JSON encoded objects. The API URL paths always start with: /api/, followed by the current api version. The current version is version 1, so all queries start with /api/v1/.

We assume that you have Raiden correctly installed and running in the desired configuration, see the Installation Guide.

Whitelisted tokens

For the Alderaan Mainnet release, only two tokens can be used with the Raiden Network: W-ETH and DAI.

W-ETH stands for wrapped Ether, meaning that Ether is packaged to conform to the ERC20 token guidelines which Raiden relies on. To learn more about W-ETH you can read the announcement blog post.

To create W-ETH from your Ether you can either use interfaces like 0x OTC or Radar Relay. You can also use the contract directly.

DAI is a popular stablecoin, see here for further information and for how to purchase it.

Joining a token network

The first thing we need to do is to join a token network. In this case we want to join the (W-ETH) network.

Note: 1 W-ETH == 10**18 wei. For the sake of readability and simplicity all token values in this tutorial are denominated in wei and not W-ETH.

In order to do so, we need the address of the token and the initial amount of tokens that we want to join the network with:

http

PUT /api/v1/connections/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{
    "funds": "20000"
}

curl

curl -i -X PUT http://localhost:5001/api/v1/connections/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 -H 'Content-Type: application/json' --data-raw '{"funds": "20000"}'

wget

wget -S -O- --method=PUT http://localhost:5001/api/v1/connections/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 --header='Content-Type: application/json' --body-data='{"funds": "20000"}'

httpie

echo '{
  "funds": "20000"
}' | http PUT http://localhost:5001/api/v1/connections/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2 Content-Type:application/json

python-requests

requests.put('http://localhost:5001/api/v1/connections/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2', headers={
    'Content-Type': 'application/json',
}, json={
    'funds': '20000',
})

By default, Raiden connects automatically to 3 channels to other nodes and splits up 60% of the funds between them. The remaining 40% of tokens will be used to join channels that are automatically opened by other participants. So in our example, we will open three channels in the network and fund each of them with 4000 wrapped wei.

We’re now ready to start sending W-ETH tokens using the Raiden Network.

In case we know of a specific address in the network that we will do frequent payments to, we can open a channel directly to this address by doing the following:

http

PUT /api/v1/channels HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{
    "partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9",
    "token_address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
    "total_deposit": 2000,
    "settle_timeout": 500
}

curl

curl -i -X PUT http://localhost:5001/api/v1/channels -H 'Content-Type: application/json' --data-raw '{"partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9", "settle_timeout": 500, "token_address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "total_deposit": 2000}'

wget

wget -S -O- --method=PUT http://localhost:5001/api/v1/channels --header='Content-Type: application/json' --body-data='{"partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9", "settle_timeout": 500, "token_address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2", "total_deposit": 2000}'

httpie

echo '{
  "partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9",
  "settle_timeout": 500,
  "token_address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
  "total_deposit": 2000
}' | http PUT http://localhost:5001/api/v1/channels Content-Type:application/json

python-requests

requests.put('http://localhost:5001/api/v1/channels', headers={
    'Content-Type': 'application/json',
}, json={
    'partner_address': '0x61C808D82A3Ac53231750daDc13c777b59310bD9',
    'settle_timeout': 500,
    'token_address': '0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2',
    'total_deposit': 2000,
})

At this point the specific value of the total_deposit field isn’t too important, since it’s always possible to deposit more tokens to a channel if need be.

Successfully opening a channel returns the following information:

HTTP/1.1 201 CREATED
Content-Type: application/json

{
    "channel_identifier": 13,
    "token_network_address": "0x3C158a20b47d9613DDb9409099Be186fC272421a",
    "partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9",
    "token_address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
    "balance": "2000",
    "total_deposit": "2000",
    "state": "opened",
    "settle_timeout": "500",
    "reveal_timeout": "50"
}

Payments

Now that we have joined a token network, we can start making payments. For this, we need the address of the W-ETH token and the address of the recipient of the payment:

http

POST /api/v1/payments/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x61C808D82A3Ac53231750daDc13c777b59310bD9 HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{
    "amount": "42"
}

curl

curl -i -X POST http://localhost:5001/api/v1/payments/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x61C808D82A3Ac53231750daDc13c777b59310bD9 -H 'Content-Type: application/json' --data-raw '{"amount": "42"}'

wget

wget -S -O- http://localhost:5001/api/v1/payments/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x61C808D82A3Ac53231750daDc13c777b59310bD9 --header='Content-Type: application/json' --post-data='{"amount": "42"}'

httpie

echo '{
  "amount": "42"
}' | http POST http://localhost:5001/api/v1/payments/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x61C808D82A3Ac53231750daDc13c777b59310bD9 Content-Type:application/json

python-requests

requests.post('http://localhost:5001/api/v1/payments/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x61C808D82A3Ac53231750daDc13c777b59310bD9', headers={
    'Content-Type': 'application/json',
}, json={
    'amount': '42',
})

This is an example of a direct transfer. Since we have an channel with the address we are sending to, 0x61C808D82A3Ac53231750daDc13c777b59310bD9, the payment goes straight to it. If we specify an address that we do not have a direct channel with, Raiden will try to do a mediated transfer, i. e. to find a path from us to the target address in the network of channels.

It’s as simple as that to do payments using the Raiden Network. The first payment is done after just two API calls - one to join the token network and one to do the payment. The third call to open a direct channel is optional.

Let’s say we know someone with the address 0x00014853D700AE1F39BA9dbAbdeC1c8683CF1b2A, who is also part of the W-ETH token network. Even though we do not have a channel with this person it is as easy as above to send a payment. All we need is the address:

http

POST /api/v1/payments/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x00014853D700AE1F39BA9dbAbdeC1c8683CF1b2A HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{
    "amount": "73"
}

curl

curl -i -X POST http://localhost:5001/api/v1/payments/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x00014853D700AE1F39BA9dbAbdeC1c8683CF1b2A -H 'Content-Type: application/json' --data-raw '{"amount": "73"}'

wget

wget -S -O- http://localhost:5001/api/v1/payments/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x00014853D700AE1F39BA9dbAbdeC1c8683CF1b2A --header='Content-Type: application/json' --post-data='{"amount": "73"}'

httpie

echo '{
  "amount": "73"
}' | http POST http://localhost:5001/api/v1/payments/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x00014853D700AE1F39BA9dbAbdeC1c8683CF1b2A Content-Type:application/json

python-requests

requests.post('http://localhost:5001/api/v1/payments/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x00014853D700AE1F39BA9dbAbdeC1c8683CF1b2A', headers={
    'Content-Type': 'application/json',
}, json={
    'amount': '73',
})

Just like this we can send payments to anyone who is part of the token network for the W-ETH token.

Depositing tokens

If we spend more tokens than we receive and hence deplete our channels, it it possible to “top up” channels. For this we need the token address and the partner address:

http

PATCH /api/v1/channels/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x61C808D82A3Ac53231750daDc13c777b59310bD9 HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{
     "total_deposit": "4000"
}

curl

curl -i -X PATCH http://localhost:5001/api/v1/channels/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x61C808D82A3Ac53231750daDc13c777b59310bD9 -H 'Content-Type: application/json' --data-raw '{"total_deposit": "4000"}'

wget

wget -S -O- --method=PATCH http://localhost:5001/api/v1/channels/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x61C808D82A3Ac53231750daDc13c777b59310bD9 --header='Content-Type: application/json' --body-data='{"total_deposit": "4000"}'

httpie

echo '{
  "total_deposit": "4000"
}' | http PATCH http://localhost:5001/api/v1/channels/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x61C808D82A3Ac53231750daDc13c777b59310bD9 Content-Type:application/json

python-requests

requests.patch('http://localhost:5001/api/v1/channels/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x61C808D82A3Ac53231750daDc13c777b59310bD9', headers={
    'Content-Type': 'application/json',
}, json={
    'total_deposit': '4000',
})

Notice that we need to specify the total deposit, not the amount we wish to top up: We initially deposited 2000 wei and want to add 2000 more, so we give a total_deposit of 4000. This way the top-up request is idempotent - if it is sent repeatedly (by accident or as part of an attack) it will have no further effect.

Channel status

We can at any point in time see things like how many tokens we have spent in a specific channel and how many tokens we have received. We do this by querying the status of a specific channel by it’s channel_identifier:

http

GET /api/v1/channels/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x61C808D82A3Ac53231750daDc13c777b59310bD9 HTTP/1.1
Host: localhost:5001
Content-Type: application/json

curl

curl -i http://localhost:5001/api/v1/channels/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x61C808D82A3Ac53231750daDc13c777b59310bD9 -H 'Content-Type: application/json'

wget

wget -S -O- http://localhost:5001/api/v1/channels/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x61C808D82A3Ac53231750daDc13c777b59310bD9 --header='Content-Type: application/json'

httpie

http http://localhost:5001/api/v1/channels/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x61C808D82A3Ac53231750daDc13c777b59310bD9 Content-Type:application/json

python-requests

requests.get('http://localhost:5001/api/v1/channels/0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2/0x61C808D82A3Ac53231750daDc13c777b59310bD9', headers={
    'Content-Type': 'application/json',
})

This returns the following JSON response:

.. sourcecode:: http

   HTTP/1.1 200 OK
   Content-Type: application/json

   {
       "token_network_address": "0xE5637F0103794C7e05469A9964E4563089a5E6f2",
       "channel_identifier": "0xa24f51685de3effe829f7c2e94b9db8e9e1b17b137da59fa727a793ae2cae776",
       "partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9",
       "token_address": "0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2",
       "balance": "3958",
       "state": "open",
       "settle_timeout": "500",
       "reveal_timeout": "50"
   }

We can see that the current balance of the channel is 3958 which matches with the two deposits and one payment we’ve made 2000 + 2000 - 42.

If we send more payments and receive some payments we can see how the balance of the channel updates accordingly.

Wrap-up

It is easy to get started doing payments using the Raiden Network. As a matter of fact one can even receive tokens through the Raiden Network without having any ether or any tokens. To achieve this the receiver needs to have a full Raiden node running as well as rely on the senders of the payments to be willing to pay the transaction fees for the on-chain transactions.

This tutorial does not mention how to close and settle a specific channel or how to leave a token network. Please consult the API documentation.

Getting started with the Raiden API

Introduction

Raiden has a Restful API with URL endpoints corresponding to actions that users can perform with their channels. The endpoints accept and return JSON encoded objects. The API URL path always contains the API version in order to differentiate queries to different API versions. All queries start with: /api/<version>/ where <version> is an integer representing the current API version.

This section walks through the steps necessary to participate in a Raiden Token Network. Some different scenarios such as joining an already existing token network, registering a new token network, together with opening, closing and settling channels, are provided.

Before getting started with below guides, please see Overview and Guide, to make sure that a proper connection to Raiden is established.

Furthermore, to see all available endpoints, please see the REST API documentation.

Scenarios

Below is a series of different scenarios showing different ways a user can interact with the Raiden API.

A good way to check that Raiden was started correctly before proceeding is to check that the Raiden address is the same address as the Ethereum address chosen, when starting the Raiden node:

http

GET /api/v1/address HTTP/1.1
Host: localhost:5001

curl

curl -i http://localhost:5001/api/v1/address

wget

wget -S -O- http://localhost:5001/api/v1/address

httpie

http http://localhost:5001/api/v1/address

python-requests

requests.get('http://localhost:5001/api/v1/address')

If this returns the same address, we know that the Raiden node is up and running correctly.

Bootstrapping a token network

In this scenario it is assumed that a user holds some ERC20 token, with address 0x9aBa529db3FF2D8409A1da4C9eB148879b046700, which has not yet been registered with Raiden.

The user wants to register the token, which creates a Token Network for that token. For each registered token there is a corresponding token network. Token networks are responsible for opening new payment channels between two parties.

Checking if a token is already registered

One way of checking if a token is already registered is to get the list of all registered tokens. Then, in the returned list, check if the address of the token wanted for interaction exists:

http

GET /api/v1/tokens HTTP/1.1
Host: localhost:5001

curl

curl -i http://localhost:5001/api/v1/tokens

wget

wget -S -O- http://localhost:5001/api/v1/tokens

httpie

http http://localhost:5001/api/v1/tokens

python-requests

requests.get('http://localhost:5001/api/v1/tokens')

If the address of the token exists in the list, see the Joining an already existing token network scenario. If it does not exist in the list, it is desired to register the token.

Registering a token

Note

For the Raiden Red Eyes release, it will not be possible to register more than one token, due to security reasons in order to minimise possible loss of funds in the case of bugs. The one token that will be registered is W-ETH.

In order to register a token, only its address is needed. When a new token is registered a Token Network contract is deployed. This is quite expensive in terms of gas usage (costs about 3.5 million gas). Luckily, this only has to be done once per token.

To register a token simply use the endpoint listed below:

http

PUT /api/v1/tokens/0x9aBa529db3FF2D8409A1da4C9eB148879b046700 HTTP/1.1
Host: localhost:5001
Content-Type: application/json

curl

curl -i -X PUT http://localhost:5001/api/v1/tokens/0x9aBa529db3FF2D8409A1da4C9eB148879b046700 -H 'Content-Type: application/json'

wget

wget -S -O- --method=PUT http://localhost:5001/api/v1/tokens/0x9aBa529db3FF2D8409A1da4C9eB148879b046700 --header='Content-Type: application/json'

httpie

http PUT http://localhost:5001/api/v1/tokens/0x9aBa529db3FF2D8409A1da4C9eB148879b046700 Content-Type:application/json

python-requests

requests.put('http://localhost:5001/api/v1/tokens/0x9aBa529db3FF2D8409A1da4C9eB148879b046700', headers={
    'Content-Type': 'application/json',
})

If successful this call returns the address of the freshly created Token Network like this:

HTTP/1.1 201 CREATED
Content-Type: application/json

{
    "token_network_address": "0xC4F8393fb7971E8B299bC1b302F85BfFB3a1275a"
}

The token is now registered. However, since the token was just registered, there are no other Raiden nodes connected to the token network. This means that there are no nodes to connect to. Due to this the token network for this specific token needs to be bootstrapped. If the address of some other Raiden node that holds some of the tokens is known or it’s simply desired to pay some tokens to another Raiden node in a one-way-channel, it can be done by opening a channel with this node. The way to open a channel with another Raiden node is the same whether the partner already holds some tokens or not.

Opening a channel

To open a channel with another Raiden node four things are needed: the address of the token, the address of the partner node, the amount of tokens desired for deposit, and the settlement timeout period. With these things ready a channel can be opened:

http

PUT /api/v1/channels HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{
    "partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9",
    "token_address": "0x9aBa529db3FF2D8409A1da4C9eB148879b046700",
    "total_deposit": "1337",
    "settle_timeout": "500"
}

curl

curl -i -X PUT http://localhost:5001/api/v1/channels -H 'Content-Type: application/json' --data-raw '{"partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9", "settle_timeout": "500", "token_address": "0x9aBa529db3FF2D8409A1da4C9eB148879b046700", "total_deposit": "1337"}'

wget

wget -S -O- --method=PUT http://localhost:5001/api/v1/channels --header='Content-Type: application/json' --body-data='{"partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9", "settle_timeout": "500", "token_address": "0x9aBa529db3FF2D8409A1da4C9eB148879b046700", "total_deposit": "1337"}'

httpie

echo '{
  "partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9",
  "settle_timeout": "500",
  "token_address": "0x9aBa529db3FF2D8409A1da4C9eB148879b046700",
  "total_deposit": "1337"
}' | http PUT http://localhost:5001/api/v1/channels Content-Type:application/json

python-requests

requests.put('http://localhost:5001/api/v1/channels', headers={
    'Content-Type': 'application/json',
}, json={
    'partner_address': '0x61C808D82A3Ac53231750daDc13c777b59310bD9',
    'settle_timeout': '500',
    'token_address': '0x9aBa529db3FF2D8409A1da4C9eB148879b046700',
    'total_deposit': '1337',
})

Note

For the Raiden Red Eyes release the maximum deposit per node in a channel is limited to 0.075 worth of W-ETH. This means that the maximum amount of tokens in a channel is limited to 0.15 worth of W-ETH. This is done to mitigate risk since the Red Eyes release is an alpha testing version on the mainnet.

At this point the specific value of the total_deposit field isn’t too important, since it’s always possible to deposit more tokens to a channel if need be.

Successfully opening a channel returns the following information:

HTTP/1.1 201 CREATED
Content-Type: application/json

{
    "channel_identifier": "0xfb43f382bbdbf209f854e14b74d183970e26ad5c1fd1b74a20f8f6bb653c1617",
    "token_network_address": "0x3C158a20b47d9613DDb9409099Be186fC272421a",
    "partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9",
    "token_address": "0x9aBa529db3FF2D8409A1da4C9eB148879b046700",
    "balance": "1337",
    "total_deposit": "1337",
    "state": "opened",
    "settle_timeout": "500",
    "reveal_timeout": "50"
}

Here it’s interesting to notice that a channel_identifier has been generated. This means that the channel has been created inside the Token Network.

Depositing to a channel

A payment channel is now open between the user’s node and a counterparty. However, since only one of the nodes has deposited to the channel, only that node can make payments at this point in time. Now would be a good time to notify the counterparty that a channel has been opened with it, so that it can also deposit to the channel. All the counterparty needs in order to do this is to use the endpoint consisting of a combination of the token_address and the participant_address:

http

PATCH /api/v1/channels/0x9aBa529db3FF2D8409A1da4C9eB148879b046700/0x61C808D82A3Ac53231750daDc13c777b59310bD9 HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{
     "total_deposit": "7331"
}

curl

curl -i -X PATCH http://localhost:5001/api/v1/channels/0x9aBa529db3FF2D8409A1da4C9eB148879b046700/0x61C808D82A3Ac53231750daDc13c777b59310bD9 -H 'Content-Type: application/json' --data-raw '{"total_deposit": "7331"}'

wget

wget -S -O- --method=PATCH http://localhost:5001/api/v1/channels/0x9aBa529db3FF2D8409A1da4C9eB148879b046700/0x61C808D82A3Ac53231750daDc13c777b59310bD9 --header='Content-Type: application/json' --body-data='{"total_deposit": "7331"}'

httpie

echo '{
  "total_deposit": "7331"
}' | http PATCH http://localhost:5001/api/v1/channels/0x9aBa529db3FF2D8409A1da4C9eB148879b046700/0x61C808D82A3Ac53231750daDc13c777b59310bD9 Content-Type:application/json

python-requests

requests.patch('http://localhost:5001/api/v1/channels/0x9aBa529db3FF2D8409A1da4C9eB148879b046700/0x61C808D82A3Ac53231750daDc13c777b59310bD9', headers={
    'Content-Type': 'application/json',
}, json={
    'total_deposit': '7331',
})

Note

For the Raiden Red Eyes release the maximum deposit per node in a channel is limited to 0.075 worth of W-ETH. This means that the maximum amount of tokens in a channel is limited to 0.15 worth of W-ETH. This is done to mitigate risk since the Red Eyes release is an alpha testing version on the mainnet.

To see if and when the counterparty deposited tokens, the channel can be queried for the corresponding events. The from_block parameter in the request represents the block number to query from. (in general the default value should be fine):

http

GET /api/v1/events/channels/0x9aBa529db3FF2D8409A1da4C9eB148879b046700/0x61C808D82A3Ac53231750daDc13c777b59310bD9?from_block=1337 HTTP/1.1
Host: localhost:5001

curl

curl -i 'http://localhost:5001/api/v1/events/channels/0x9aBa529db3FF2D8409A1da4C9eB148879b046700/0x61C808D82A3Ac53231750daDc13c777b59310bD9?from_block=1337'

wget

wget -S -O- 'http://localhost:5001/api/v1/events/channels/0x9aBa529db3FF2D8409A1da4C9eB148879b046700/0x61C808D82A3Ac53231750daDc13c777b59310bD9?from_block=1337'

httpie

http 'http://localhost:5001/api/v1/events/channels/0x9aBa529db3FF2D8409A1da4C9eB148879b046700/0x61C808D82A3Ac53231750daDc13c777b59310bD9?from_block=1337'

python-requests

requests.get('http://localhost:5001/api/v1/events/channels/0x9aBa529db3FF2D8409A1da4C9eB148879b046700/0x61C808D82A3Ac53231750daDc13c777b59310bD9?from_block=1337')

This returns a list of events that has happened in the specific payment channel. The relevant event in this case is:

{
    "amount": "682",
    "block_number": "3663408",
    "event": "EventPaymentSentSuccess",
    "identifier": "1531927405484",
    "target": "0x25511699C252eeA2678266857C98F459Df97B77c"
},

From the above event it can be deducted that the counterparty deposited to the channel. It is possible for both parties to query the state of the specific payment channel by calling:

http

GET /api/v1/channels/0x9aBa529db3FF2D8409A1da4C9eB148879b046700/0x61C808D82A3Ac53231750daDc13c777b59310bD9 HTTP/1.1
Host: localhost:5001

curl

curl -i http://localhost:5001/api/v1/channels/0x9aBa529db3FF2D8409A1da4C9eB148879b046700/0x61C808D82A3Ac53231750daDc13c777b59310bD9

wget

wget -S -O- http://localhost:5001/api/v1/channels/0x9aBa529db3FF2D8409A1da4C9eB148879b046700/0x61C808D82A3Ac53231750daDc13c777b59310bD9

httpie

http http://localhost:5001/api/v1/channels/0x9aBa529db3FF2D8409A1da4C9eB148879b046700/0x61C808D82A3Ac53231750daDc13c777b59310bD9

python-requests

requests.get('http://localhost:5001/api/v1/channels/0x9aBa529db3FF2D8409A1da4C9eB148879b046700/0x61C808D82A3Ac53231750daDc13c777b59310bD9')

This gives a result similar to those in Opening a Channel that represents the current state of the payment channel.

A new token resulting in a new token network has now been registered. A channel between two Raiden nodes has been opened, and both nodes have deposited to the channel. From here on the two nodes can start sending payments to each other.

The above is not how a user would normally join an already existing token network. It is only included here to show how it works under the hood.

In the next scenario it is explained how to join already bootstrapped token networks.

Joining an already existing token network

In above scenario it was shown how to bootstrap a token network for an unregistered token. In this section the most common way of joining a token network is explained. In most cases users don’t want to create a new token network, but they want to join an already existing token network for an ERC20 token that they already hold.

The main focus of this section is the usage of the connect and the leave endpoints. The connect endpoint allows users to automatically connect to a token network and open channels with other nodes. Furthermore the leave endpoint allows users to leave a token network by automatically closing and settling all of their open channels.

It’s assumed that a user holds at least 2000 Raiden Testnet ERC20 token (RTT). The user knows that a token network already exists for this token.

Connect

Connecting to an already existing token network is quite simple. All that is needed, is as mentioned above, the address of the token network to join and the amount of the corresponding token that the user is willing to deposit in channels:

http

PUT /api/v1/connections/0x0f114A1E9Db192502E7856309cc899952b3db1ED HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{
    "funds": "2000"
}

curl

curl -i -X PUT http://localhost:5001/api/v1/connections/0x0f114A1E9Db192502E7856309cc899952b3db1ED -H 'Content-Type: application/json' --data-raw '{"funds": "2000"}'

wget

wget -S -O- --method=PUT http://localhost:5001/api/v1/connections/0x0f114A1E9Db192502E7856309cc899952b3db1ED --header='Content-Type: application/json' --body-data='{"funds": "2000"}'

httpie

echo '{
  "funds": "2000"
}' | http PUT http://localhost:5001/api/v1/connections/0x0f114A1E9Db192502E7856309cc899952b3db1ED Content-Type:application/json

python-requests

requests.put('http://localhost:5001/api/v1/connections/0x0f114A1E9Db192502E7856309cc899952b3db1ED', headers={
    'Content-Type': 'application/json',
}, json={
    'funds': '2000',
})

Note

For the Raiden Red Eyes release the maximum deposit per node in a channel is limited to 0.075 worth of W-ETH. This means that the maximum amount of tokens in a channel is limited to 0.15 worth of W-ETH. This is done to mitigate risk since the Red Eyes release is an alpha testing version on the mainnet.

This automatically opens channels with three random peers in the token network, with 20% of the funds deposited to each channel. Furthermore it leaves 40% of the funds initially unassigned. This allows new nodes joining the network to open payment channels with this node in the same way that it just opened channels with random nodes in the network.

The user node is now connected to the token network for the RTT token. It should also have a path to all other nodes that have joined this token network. This means that it can pay tokens to all nodes participating in this network. See the Token Payments section for instructions on how to pay tokens to other nodes.

Leave

If at some point it is desired to leave the token network, the leave endpoint is available. This endpoint takes care of closing and settling all open channels for a specific token network:

http

DELETE /api/v1/connections/0x0f114A1E9Db192502E7856309cc899952b3db1ED HTTP/1.1
Host: localhost:5001
Content-Type: application/json

curl

curl -i -X DELETE http://localhost:5001/api/v1/connections/0x0f114A1E9Db192502E7856309cc899952b3db1ED -H 'Content-Type: application/json'

wget

wget -S -O- --method=DELETE http://localhost:5001/api/v1/connections/0x0f114A1E9Db192502E7856309cc899952b3db1ED --header='Content-Type: application/json'

httpie

http DELETE http://localhost:5001/api/v1/connections/0x0f114A1E9Db192502E7856309cc899952b3db1ED Content-Type:application/json

python-requests

requests.delete('http://localhost:5001/api/v1/connections/0x0f114A1E9Db192502E7856309cc899952b3db1ED', headers={
    'Content-Type': 'application/json',
})

This call takes some time to finalize, due to the nature of the way that settlement of payment channels work. For instance there is a settlement_timeout period after calling close that needs to expire before settle can be called.

Token payments

For the token payment example it is assumed a node is connected to the RTT token network as mentioned above. In this case the node is connected to five peers, since the standard connect() parameters were used.

Payments

Paying tokens to another node is quite easy. The address of the token desired for the payment is 0x0f114A1E9Db192502E7856309cc899952b3db1ED. All that then remains is the address of the target node. Assume the address of the target node is 0x61C808D82A3Ac53231750daDc13c777b59310bD9:

http

POST /api/v1/payments/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x61C808D82A3Ac53231750daDc13c777b59310bD9 HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{
    "amount": "42"
}

curl

curl -i -X POST http://localhost:5001/api/v1/payments/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x61C808D82A3Ac53231750daDc13c777b59310bD9 -H 'Content-Type: application/json' --data-raw '{"amount": "42"}'

wget

wget -S -O- http://localhost:5001/api/v1/payments/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x61C808D82A3Ac53231750daDc13c777b59310bD9 --header='Content-Type: application/json' --post-data='{"amount": "42"}'

httpie

echo '{
  "amount": "42"
}' | http POST http://localhost:5001/api/v1/payments/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x61C808D82A3Ac53231750daDc13c777b59310bD9 Content-Type:application/json

python-requests

requests.post('http://localhost:5001/api/v1/payments/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x61C808D82A3Ac53231750daDc13c777b59310bD9', headers={
    'Content-Type': 'application/json',
}, json={
    'amount': '42',
})

An "identifier": <some_integer> can also be added to the payload, but it’s optional. The purpose of the identifier is solely for the benefit of the Dapps built on top of Raiden in order to provide a way to tag payments.

If there is a path in the network with enough capacity and the address sending the payment holds enough tokens to pay the amount in the payload, the payment goes through. The receiving node should then be able to see incoming payments by querying all its open channels. This is done by doing the following for all addresses of open channels:

http

GET /api/v1/events/channels/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x61C808D82A3Ac53231750daDc13c777b59310bD9?from_block=1337 HTTP/1.1
Host: localhost:5001
Content-Type: application/json

curl

curl -i 'http://localhost:5001/api/v1/events/channels/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x61C808D82A3Ac53231750daDc13c777b59310bD9?from_block=1337' -H 'Content-Type: application/json'

wget

wget -S -O- 'http://localhost:5001/api/v1/events/channels/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x61C808D82A3Ac53231750daDc13c777b59310bD9?from_block=1337' --header='Content-Type: application/json'

httpie

http 'http://localhost:5001/api/v1/events/channels/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x61C808D82A3Ac53231750daDc13c777b59310bD9?from_block=1337' Content-Type:application/json

python-requests

requests.get('http://localhost:5001/api/v1/events/channels/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x61C808D82A3Ac53231750daDc13c777b59310bD9?from_block=1337', headers={
    'Content-Type': 'application/json',
})

Which returns a list of events. All that then needs to be done is to filter for incoming payments.

Please note that one of the most powerful features of Raiden is that users can send payments to anyone connected to the network as long as there is a path to them with enough capacity, and not just to the nodes that a user is directly connected to. This is called mediated transfers.

Close

If at any point in time it is desired to close a specific channel it can be done with the close endpoint:

http

PATCH /api/v1/channels/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x61C808D82A3Ac53231750daDc13c777b59310bD9 HTTP/1.1
Host: localhost:5001
Content-Type: application/json

 {
     "state":"closed"
 }

curl

curl -i -X PATCH http://localhost:5001/api/v1/channels/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x61C808D82A3Ac53231750daDc13c777b59310bD9 -H 'Content-Type: application/json' --data-raw '{"state": "closed"}'

wget

wget -S -O- --method=PATCH http://localhost:5001/api/v1/channels/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x61C808D82A3Ac53231750daDc13c777b59310bD9 --header='Content-Type: application/json' --body-data='{"state": "closed"}'

httpie

echo '{
  "state": "closed"
}' | http PATCH http://localhost:5001/api/v1/channels/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x61C808D82A3Ac53231750daDc13c777b59310bD9 Content-Type:application/json

python-requests

requests.patch('http://localhost:5001/api/v1/channels/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x61C808D82A3Ac53231750daDc13c777b59310bD9', headers={
    'Content-Type': 'application/json',
}, json={
    'state': 'closed',
})

When successful this gives a response with a channel object where the state is set to "closed":

HTTP/1.1 200 OK
Content-Type: application/json

 {
     "channel_identifier": "0xfb43f382bbdbf209f854e14b74d183970e26ad5c1fd1b74a20f8f6bb653c1617",
     "token_network_address": "0x3C158a20b47d9613DDb9409099Be186fC272421a",
     "token_address": "0x0f114A1E9Db192502E7856309cc899952b3db1ED",
     "balance": "350",
     "state": "closed",
     "settle_timeout": "500",
     "reveal_timeout": "50"
 }

Notice how the state is now set to "closed" compared to the previous channel objects where it was "opened".

Settle

Once close has been called, the settle timeout period starts. The channel is automatically settled as soon as it is over.

The balance of the channel is now 0 and the state "settled". This means that the net balances that the two parties participating in the channel owe each other have now been transferred on the blockchain. It also means that the life cycle of the payment channel has ended.

Interacting with the Raiden Echo Node

Note

For the Raiden Red Eyes release on mainnet the Echo Node will not be available. Currently the Echo Node is available on the Ropsten testnet according to the text below.

For easy testing of Raiden, there is a specialized Raiden node running, the “Raiden Echo Node”. The Echo Node responds to received payments by sending a payment back to the initiator. The echo payment follows certain rules:

  • consecutive payments with the same identifier and same amount from the same address are ignored (as in: the Echo Node just keeps your money)
  • the echo_identifier of all echo payments is identifier + echo_amount
  • payments with an amount divisible by 3 will be answered with an echo payment of echo_amount = amount - 1
  • payments with an amount = 7 are special lottery payments. They will go to a lottery pool. After the Echo Node has received seven lottery payments, it will choose a winner that receives an echo payment with echo_amount = 49 and the pool is reset. To query the current number of tickets in the pool, a participant can send another payment with amount = 7 – if the participant already takes part in the current draw, the Echo Node will respond with a payment with echo_amount = number_of_tickets, otherwise it will enter the pool.
  • for a payment with any other amount it returns echo_amount = amount

The address of the Echo Node is 0x02f4b6BC65561A792836212Ebc54434Db0Ab759a and it is connected to the Raiden Testnet Token (RTT) with the address 0x0f114a1e9db192502e7856309cc899952b3db1ed. The RTT token contract is verified and can be seen in etherscan. To interact with the Echo Node, first join the RTT network.

You can obtain RTT tokens by calling the mint() function of the token. In javascript you can load the RTT token contract and call mint as such:

var rtt_token_abi = [{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"}],"name":"approve","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[],"name":"mint","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"totalSupply","outputs":[{"name":"supply","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_from","type":"address"},{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"decimals","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"version","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"name":"balance","type":"uint256"}],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"symbol","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"amount","type":"uint256"}],"name":"mint","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"amount","type":"uint256"},{"name":"target","type":"address"}],"name":"mintFor","outputs":[],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"_spender","type":"address"},{"name":"_value","type":"uint256"},{"name":"_extraData","type":"bytes"}],"name":"approveAndCall","outputs":[{"name":"success","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"_owner","type":"address"},{"name":"_spender","type":"address"}],"name":"allowance","outputs":[{"name":"remaining","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"_tokenName","type":"string"},{"name":"_tokenSymbol","type":"string"}],"payable":false,"type":"constructor"},{"payable":false,"type":"fallback"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_owner","type":"address"},{"indexed":true,"name":"_spender","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Approval","type":"event"}];
var rtt_token_address = "0x0f114A1E9Db192502E7856309cc899952b3db1ED";
var rtt_token = web3.eth.contract(rtt_token_abi).at(rtt_token_address);
rtt_token.mint({from: eth.accounts[0]}); // adjust to your raiden account and unlock first!

Then you can send a payment to it via the payments endpoint:

http

POST /api/v1/payments/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x02f4b6BC65561A792836212Ebc54434Db0Ab759a HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{
    "amount": "1",
    "identifer": "42"
}

curl

curl -i -X POST http://localhost:5001/api/v1/payments/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x02f4b6BC65561A792836212Ebc54434Db0Ab759a -H 'Content-Type: application/json' --data-raw '{"amount": "1", "identifer": "42"}'

wget

wget -S -O- http://localhost:5001/api/v1/payments/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x02f4b6BC65561A792836212Ebc54434Db0Ab759a --header='Content-Type: application/json' --post-data='{"amount": "1", "identifer": "42"}'

httpie

echo '{
  "amount": "1",
  "identifer": "42"
}' | http POST http://localhost:5001/api/v1/payments/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x02f4b6BC65561A792836212Ebc54434Db0Ab759a Content-Type:application/json

python-requests

requests.post('http://localhost:5001/api/v1/payments/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x02f4b6BC65561A792836212Ebc54434Db0Ab759a', headers={
    'Content-Type': 'application/json',
}, json={
    'amount': '1',
    'identifer': '42',
})

Afterwards you can check your events and you should find an EventPaymentReceivedSuccess event with:

{
    "event": "EventPaymentReceivedSuccess",
    "amount": "1",
    "identifier": "43",
    "initiator": "0x02f4b6BC65561A792836212Ebc54434Db0Ab759a",
    "log_time": "2018-10-30T07:04:22.293"
}

According to the rules from above, you should try the same with different amounts, 3, 6, 7, … – have fun!

Web Application Tutorial

Note

We are currently reworking our documentation for Raiden and just finished updating this tutorial for the web application. You can view the updated web application tutorial in this new but incomplete version of the documentation.

In order to quickly give an overview and idea of what Raiden is capable of, a web application has been created. This application utilizes the Raiden REST API endpoints to allow the user to interact with token networks, make token payments, see the current status of open channels along with closing and settling channels to name some of the functionalities. For a more specific guide of the API itself see the API Walkthrough.

The main focus of the web application is to display functionality. If you want to contribute, don’t hesitate to create a pull request.

Running the web application

In order to run the Raiden web application (WebUI) you just need to install Raiden. See install instructions for this.

After the installation, we can fire up Raiden. Make sure, you add the CORS domain to the start parameters of your ethereum client:

geth <...other parameters...> --rpccorsdomain http://127.0.0.1:5001

Raiden can be started without the web application by providing the --no-web-ui flag.

Now all that is left to do is to navigate to 127.0.0.1:5001 and interaction with Raiden through a web application can begin.

The landing page

The first thing that will meet the user is the landing page. The landing page is meant to give a short introduction to Raiden and link to some relevant documentation.

Below is a screenshot of the landing page.

Raiden web app landing page

One last thing that might be interesting to note is that the address of the running Raiden node is always displayed in the top bar.

Tokens

The Tokens view provides information about the registered token networks. Furthermore it also allows for automatically joining an existing token network along with registering a new token network.

The first thing to notice in this view is the list of tokens for which a token network exists. All tokens that have been registered in Raiden will show up in this list. If the user knows the name or the address of a token, it’s very easy to search for it using the Filter input. If the token the user searches for does not show up, it most likely means that it is not yet registered. Registering can however be done by pressing the Circular Plus button and provide the token address. For each token in the list of tokens some information is provided. This information includes the Symbol of the token, the Address of the token, the Name of the token and the user’s Balance of a specific token. It’s easy to sort the tokens, so that only tokens that a user actually holds, show up in the beginning of the list. This is done simply by selecting an entry on the Sort by dropdown menu. You can change the sorting order by pressing the arrow on the right side of the Sort by dropdown menu.

Note

The Circular Plus button for token registration will not be available for the Red Eyes release.

You can access the Network Events by selecting the View network events option of the overflow menu.

Initially, before joining any token network, the only button available will be the Join Network. After pressing the button, a pop up will then appear where the user can choose how many tokens to automatically join the token network with. See connect for more details on how this works.

After joining the network the Pay button becomes available. This will allow the user to choose an address to send tokens to that the user is not directly connected to. This is done by mediating transfers through nodes that are connected with each other.

Should it at some point in time be desired to entirely leave a token network. The Leave  Network button point allows you to do so. This will automatically close and settle all open channels within a specified token network. For more information on how this works, please see leave.

The overflow menu provides the View token events option. This will simply redirect you to a new page where you can see all channels created and deleted for the specific token.

In further releases it will also be possible to perform token swaps with the Swap Tokens button. This function is not part of the Red Eyes release.

Raiden web app tokens page

Above is a screenshot of the Tokens view with some registered tokens.

Channels

The Channels page is where a lot of the interesting stuff is going on. If a node has no open channels, not a lot of interesting information is displayed here. Under the Network Events tab it is however possible to see whenever a new token is registered. With no open channels the most interesting thing that can be done from this view is to manually open a new channel. This is done by pressing the Circular Plus button and filling in the information in the pop up formula.

Once a channel is opened it will show up in the list of open channels. For each channel some relevant data is shown. The Channel, Partner fields represent the address of the payment channel itself, the address of the partner and the address of the token that the channel is opened with. Furthermore the Balance shows the amount of tokens that the Raiden node has available for the specific channel. You can view more information about the token just by hovering over the token Symbol above the Balance. The State represents the current state of the channel i.e. if it is opened, closed or settled. Lastly there are buttons that represent the interactions that can be made with a channel. Pay sends a payment to the counterparty of the channel. Deposit allows the user to deposit more funds in the channel. Close closes the channel and updates the State of the channel to closed. Once the channel is closed no more payments can be carried out and the settle_timeout is initialised. Furthermore once the settle_timeout has expired the channel will settle and payout the correct amount of the deposit to each channel participant. It is possible to sort the list of channels by the Sort By dropdown menu and change the sorting order by the arrow on the right of the field, or to search for a specific partner or token address etc. using the Filter field.

Raiden web app channels page

Above is a screenshot of the Channels view with some open channels.

Raiden’s API Documentation

Introduction

Raiden has a Restful API with URL endpoints corresponding to user-facing interaction allowed by a Raiden node. The endpoints accept and return JSON encoded objects. The api url path always contains the api version in order to differentiate queries to different API versions. All queries start with: /api/<version>/

JSON Object Encoding

The objects that are sent to and received from the API are JSON-encoded. Following are the common objects used in the API.

Channel Object

{
   "channel_identifier": "21",
   "token_network_address": "0x2a65Aca4D5fC5B5C859090a6c34d164135398226",
   "partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9",
   "token_address": "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8",
   "balance": "25000000",
   "total_deposit": "35000000",
   "state": "opened",
   "settle_timeout": "500",
   "reveal_timeout": "50"
}

A channel object consists of a

  • channel_identifier should be an integer containing the identifier of the channel.
  • partner_address should be a string containing the EIP55-encoded address of the partner with whom we have opened a channel.
  • token_address should be a string containing the EIP55-encoded address of the token we are trading in the channel.
  • token_network_address should be a string containing the EIP55-encoded address of the token network the channel is part of.
  • balance should be an integer of the amount of the token_address token we have available for payments.
  • total_deposit should be an integer of the amount of the token_address token we have deposited into the contract for this channel.
  • state should be the current state of the channel represented by a string. Possible value are: - 'opened': The channel is open and tokens are tradeable - 'closed': The channel has been closed by a participant - 'settled': The channel has been closed by a participant and also settled.
  • 'settle_timeout': The number of blocks that are required to be mined from the time that close() is called until the channel can be settled with a call to settle().
  • 'reveal_timeout': The maximum number of blocks allowed between the setting of a hashlock and the revealing of the related secret.

Event Object

Channel events are encoded as json objects with the event arguments as attributes of the dictionary, with one difference. The event_type and the block_number are also added for all events to easily distinguish between events.

Errors

For any non-successful http status code, e.g. 409 Conflict or 400 Bad Request there will be an accompanying errors field in the response json which you can check for more information on what went wrong with your request. However, when Raiden fails to process the incoming request and raises an exception, the returned http status code will be 500 Internal Server Error. The caveat of this is that the response body will be just a string message which says “Internal server error”. This is because we rely on our underlying stack to handle this while we take care of shutting down the API server preventing further incoming requests caused the exception in the first place from tampering with a state that was corrupted. In any way, we consider 500 Internal Server Error errors as bugs in the Raiden client. If you encounter such errors, please report the bug here.

Endpoints

Following are the available API endpoints with which you can interact with Raiden.

Querying Information About Your Raiden Node

GET /api/(version)/address

Query your address. When raiden starts, you choose an ethereum address which will also be your raiden address.

Example Request:

http

GET /api/v1/address HTTP/1.1
Host: localhost:5001

curl

curl -i http://localhost:5001/api/v1/address

wget

wget -S -O- http://localhost:5001/api/v1/address

httpie

http http://localhost:5001/api/v1/address

python-requests

requests.get('http://localhost:5001/api/v1/address')

Example Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "our_address": "0x2a65Aca4D5fC5B5C859090a6c34d164135398226"
}
GET /api/(version)/version

Query the version of the Raiden instance

Example Request:

http

GET /api/v1/version HTTP/1.1
Host: localhost:5001

curl

curl -i http://localhost:5001/api/v1/version

wget

wget -S -O- http://localhost:5001/api/v1/version

httpie

http http://localhost:5001/api/v1/version

python-requests

requests.get('http://localhost:5001/api/v1/version')

Example Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "version": "0.100.5a1.dev157+geb2af878d"
}

Deploying

Note

For the Raiden Red Eyes release, it will not be possible to register more than one token, due to security reasons in order to minimise possible loss of funds in the case of bugs. The one token that will be registered is W-ETH.

PUT /api/(version)/tokens/(token_address)

Registers a token. If a token is not registered yet (i.e.: A token network for that token does not exist in the registry), we need to register it by deploying a token network contract for that token.

Example Request:

http

PUT /api/v1/tokens/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8 HTTP/1.1
Host: localhost:5001

curl

curl -i -X PUT http://localhost:5001/api/v1/tokens/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8

wget

wget -S -O- --method=PUT http://localhost:5001/api/v1/tokens/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8

httpie

http PUT http://localhost:5001/api/v1/tokens/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8

python-requests

requests.put('http://localhost:5001/api/v1/tokens/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8')

Example Response:

HTTP/1.1 201 CREATED
Content-Type: application/json

{
    "token_network_address": "0xC4F8393fb7971E8B299bC1b302F85BfFB3a1275a"
}
Status Codes:
  • 201 Created – A token network for the token has been successfully created.
  • 402 Payment Required – Insufficient ETH to pay for the gas of the register on-chain transaction
  • 403 Forbidden – Maximum of allowed token networks reached. No new token networks can be registered.
  • 404 Not Found – The given token address is invalid.
  • 409 Conflict
    • The token was already registered before, or
    • The registering transaction failed.
  • 501 Not Implemented – Registering a token only works on testnet temporarily. On mainnet this error is returned.
  • 503 Service Unavailable – The API is currently unavailable, e. g. because the Raiden node is still in the initial sync or shutting down.
Response JSON Object:
 
  • token_network_address (address) – The deployed token networks address.

Querying Information About Channels and Tokens

GET /api/(version)/channels

Get a list of all unsettled channels.

Example Request:

http

GET /api/v1/channels HTTP/1.1
Host: localhost:5001

curl

curl -i http://localhost:5001/api/v1/channels

wget

wget -S -O- http://localhost:5001/api/v1/channels

httpie

http http://localhost:5001/api/v1/channels

python-requests

requests.get('http://localhost:5001/api/v1/channels')

Example Response:

HTTP/1.1 200 OK
Content-Type: application/json

[
    {
        "token_network_address": "0xE5637F0103794C7e05469A9964E4563089a5E6f2",
        "channel_identifier": "20",
        "partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9",
        "token_address": "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8",
        "balance": "25000000",
        "total_deposit": "35000000",
        "total_withdraw": "5000000",
        "state": "opened",
        "settle_timeout": "500",
        "reveal_timeout": "50"
    }
]
Status Codes:
GET /api/(version)/channels/(token_address)

Get a list of all unsettled channels for the given token address.

Example Request:

http

GET /api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8 HTTP/1.1
Host: localhost:5001

curl

curl -i http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8

wget

wget -S -O- http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8

httpie

http http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8

python-requests

requests.get('http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8')

Example Response:

HTTP/1.1 200 OK
Content-Type: application/json

[
    {
        "token_network_address": "0xE5637F0103794C7e05469A9964E4563089a5E6f2",
        "channel_identifier": "20",
        "partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9",
        "token_address": "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8",
        "balance": "25000000",
        "total_deposit": "35000000",
        "total_withdraw": "5000000",
        "state": "opened",
        "settle_timeout": "500",
        "reveal_timeout": "50"
    }
]
Status Codes:
GET /api/(version)/channels/(token_address)/(partner_address)

Query information about one of your channels. The channel is specified by the address of the token and the partner’s address.

Example Request:

http

GET /api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9 HTTP/1.1
Host: localhost:5001

curl

curl -i http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9

wget

wget -S -O- http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9

httpie

http http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9

python-requests

requests.get('http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9')

Example Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "token_network_address": "0xE5637F0103794C7e05469A9964E4563089a5E6f2",
    "channel_identifier": "20",
    "partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9",
    "token_address": "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8",
    "balance": "25000000",
    "total_deposit": "35000000",
    "total_withdraw": "5000000",
    "state": "opened",
    "settle_timeout": "500",
    "reveal_timeout": "50"
}
Status Codes:
  • 200 OK – Successful query
  • 404 Not Found
    • The given token and / or partner addresses are not valid eip55-encoded Ethereum addresses, or
    • The channel does not exist
  • 500 Internal Server Error – Internal Raiden node error
  • 503 Service Unavailable – The API is currently unavailable, e. g. because the Raiden node is still in the initial sync or shutting down.
GET /api/(version)/tokens

Returns a list of addresses of all registered tokens.

Example Request:

http

GET /api/v1/tokens HTTP/1.1
Host: localhost:5001

curl

curl -i http://localhost:5001/api/v1/tokens

wget

wget -S -O- http://localhost:5001/api/v1/tokens

httpie

http http://localhost:5001/api/v1/tokens

python-requests

requests.get('http://localhost:5001/api/v1/tokens')

Example Response:

HTTP/1.1 200 OK
Content-Type: application/json

[
    "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8",
    "0x61bB630D3B2e8eda0FC1d50F9f958eC02e3969F6"
]
Status Codes:
GET /api/(version)/tokens/(token_address)

Returns the address of the corresponding token network for the given token, if the token is registered.

Example Request:

http

GET /api/v1/tokens/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8 HTTP/1.1
Host: localhost:5001

curl

curl -i http://localhost:5001/api/v1/tokens/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8

wget

wget -S -O- http://localhost:5001/api/v1/tokens/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8

httpie

http http://localhost:5001/api/v1/tokens/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8

python-requests

requests.get('http://localhost:5001/api/v1/tokens/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8')

Example Response:

HTTP/1.1 200 OK
Content-Type: application/json

"0x61bB630D3B2e8eda0FC1d50F9f958eC02e3969F6"
Status Codes:
  • 200 OK – Successful query
  • 404 Not Found – No token network found for the provided token address
  • 503 Service Unavailable – The API is currently unavailable, e. g. because the Raiden node is still in the initial sync or shutting down.
GET /api/(version)/tokens/(token_address)/partners

Returns a list of all partners with whom you have non-settled channels for a certain token.

Example Request:

http

GET /api/v1/tokens/0x61bB630D3B2e8eda0FC1d50F9f958eC02e3969F6/partners HTTP/1.1
Host: localhost:5001

curl

curl -i http://localhost:5001/api/v1/tokens/0x61bB630D3B2e8eda0FC1d50F9f958eC02e3969F6/partners

wget

wget -S -O- http://localhost:5001/api/v1/tokens/0x61bB630D3B2e8eda0FC1d50F9f958eC02e3969F6/partners

httpie

http http://localhost:5001/api/v1/tokens/0x61bB630D3B2e8eda0FC1d50F9f958eC02e3969F6/partners

python-requests

requests.get('http://localhost:5001/api/v1/tokens/0x61bB630D3B2e8eda0FC1d50F9f958eC02e3969F6/partners')

Example Response:

HTTP/1.1 200 OK
Content-Type: application/json

[
   {
       "partner_address": "0x2a65aca4d5fc5b5c859090a6c34d164135398226",
       "channel": "/api/<version>/channels/0x61C808D82A3Ac53231750daDc13c777b59310bD9/0x2a65aca4d5fc5b5c859090a6c34d164135398226"
   }
]
Status Codes:
  • 200 OK – Successful query
  • 302 Found – If the user accesses the channel link endpoint
  • 404 Not Found
    • The token does not exist
    • The token address is not a valid eip55-encoded Ethereum address
  • 500 Internal Server Error – Internal Raiden node error
  • 503 Service Unavailable – The API is currently unavailable, e. g. because the Raiden node is still in the initial sync or shutting down.
Response JSON Array of Objects:
 
  • partner_address (address) – The partner we have a channel with
  • channel (link) – A link to the channel resource
GET /api/(version)/pending_transfers

Returns a list of all transfers that have not been completed yet.

Example Request:

http

GET /api/v1/pending_transfers HTTP/1.1
Host: localhost:5001

curl

curl -i http://localhost:5001/api/v1/pending_transfers

wget

wget -S -O- http://localhost:5001/api/v1/pending_transfers

httpie

http http://localhost:5001/api/v1/pending_transfers

python-requests

requests.get('http://localhost:5001/api/v1/pending_transfers')

See below for an example response.

GET /api/(version)/pending_transfers/(token_address)

Like above, but limited to pending transfers of the specified token.

Example Request:

http

GET /api/v1/pending_transfers/0xd0A1E359811322d97991E03f863a0C30C2cF029C HTTP/1.1
Host: localhost:5001

curl

curl -i http://localhost:5001/api/v1/pending_transfers/0xd0A1E359811322d97991E03f863a0C30C2cF029C

wget

wget -S -O- http://localhost:5001/api/v1/pending_transfers/0xd0A1E359811322d97991E03f863a0C30C2cF029C

httpie

http http://localhost:5001/api/v1/pending_transfers/0xd0A1E359811322d97991E03f863a0C30C2cF029C

python-requests

requests.get('http://localhost:5001/api/v1/pending_transfers/0xd0A1E359811322d97991E03f863a0C30C2cF029C')

See below for an example response.

GET /api/(version)/pending_transfers/(token_address)/(partner_address)

Like above, but limited to the specified channel.

Example Request:

http

GET /api/v1/pending_transfers/0xd0A1E359811322d97991E03f863a0C30C2cF029C/0x2c4b0Bdac486d492E3cD701F4cA87e480AE4C685 HTTP/1.1
Host: localhost:5001

curl

curl -i http://localhost:5001/api/v1/pending_transfers/0xd0A1E359811322d97991E03f863a0C30C2cF029C/0x2c4b0Bdac486d492E3cD701F4cA87e480AE4C685

wget

wget -S -O- http://localhost:5001/api/v1/pending_transfers/0xd0A1E359811322d97991E03f863a0C30C2cF029C/0x2c4b0Bdac486d492E3cD701F4cA87e480AE4C685

httpie

http http://localhost:5001/api/v1/pending_transfers/0xd0A1E359811322d97991E03f863a0C30C2cF029C/0x2c4b0Bdac486d492E3cD701F4cA87e480AE4C685

python-requests

requests.get('http://localhost:5001/api/v1/pending_transfers/0xd0A1E359811322d97991E03f863a0C30C2cF029C/0x2c4b0Bdac486d492E3cD701F4cA87e480AE4C685')

Example Response:

HTTP/1.1 200 OK
Content-Type: application/json

[
   {
      "channel_identifier": "255",
      "initiator": "0x5E1a3601538f94c9e6D2B40F7589030ac5885FE7",
      "locked_amount": "119",
      "payment_identifier": "1",
      "role": "initiator",
      "target": "0x00AF5cBfc8dC76cd599aF623E60F763228906F3E",
      "token_address": "0xd0A1E359811322d97991E03f863a0C30C2cF029C",
      "token_network_address": "0x111157460c0F41EfD9107239B7864c062aA8B978",
      "transferred_amount": "331"
   }
]
Status Codes:
Response JSON Array of Objects:
 
  • role (string) – One of “initiator”, “mediator” and “target”

Channel Management

PUT /api/(version)/channels

Opens (i. e. creates) a channel.

Example Request:

http

PUT /api/v1/channels HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{
    "partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9",
    "token_address": "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8",
    "total_deposit": "35000000",
    "settle_timeout": "500",
    "reveal_timeout": "50"
}

curl

curl -i -X PUT http://localhost:5001/api/v1/channels -H 'Content-Type: application/json' --data-raw '{"partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9", "reveal_timeout": "50", "settle_timeout": "500", "token_address": "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8", "total_deposit": "35000000"}'

wget

wget -S -O- --method=PUT http://localhost:5001/api/v1/channels --header='Content-Type: application/json' --body-data='{"partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9", "reveal_timeout": "50", "settle_timeout": "500", "token_address": "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8", "total_deposit": "35000000"}'

httpie

echo '{
  "partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9",
  "reveal_timeout": "50",
  "settle_timeout": "500",
  "token_address": "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8",
  "total_deposit": "35000000"
}' | http PUT http://localhost:5001/api/v1/channels Content-Type:application/json

python-requests

requests.put('http://localhost:5001/api/v1/channels', headers={
    'Content-Type': 'application/json',
}, json={
    'partner_address': '0x61C808D82A3Ac53231750daDc13c777b59310bD9',
    'reveal_timeout': '50',
    'settle_timeout': '500',
    'token_address': '0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8',
    'total_deposit': '35000000',
})
Request JSON Object:
 
  • partner_address (address) – The partner we want to open a channel with.
  • token_address (address) – The token we want to be used in the channel.
  • total_deposit (int) – Total amount of tokens to be deposited to the channel
  • settle_timeout (int) – The amount of blocks that the settle timeout should have.
  • reveal_timeout (int) – The amount of blocks that the reveal timeout should have.

The request’s payload is a channel object; since it is a new channel, its channel_address and status fields will be ignored and can be omitted.

The request to the endpoint will later return the fully created channel object.

Note

For the Raiden Red Eyes release the maximum deposit per node in a channel is limited to 0.075 worth of W-ETH. This means that the maximum amount of tokens in a channel is limited to 0.15 worth of W-ETH. This is done to mitigate risk since the Red Eyes release is an alpha testing version on the mainnet.

Example Response:

HTTP/1.1 201 CREATED
Content-Type: application/json

{
    "token_network_address": "0xE5637F0103794C7e05469A9964E4563089a5E6f2",
    "channel_identifier": "20",
    "partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9",
    "token_address": "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8",
    "balance": "25000000",
    "total_deposit": "35000000",
    "total_withdraw": "0",
    "state": "opened",
    "settle_timeout": "500",
    "reveal_timeout": "50"
}
Status Codes:
PATCH /api/(version)/channels/(token_address)/(partner_address)

This request is used to close a channel or to increase the deposit in it.

Example Request (close channel):

http

PATCH /api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9 HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{
    "state": "closed"
}

curl

curl -i -X PATCH http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9 -H 'Content-Type: application/json' --data-raw '{"state": "closed"}'

wget

wget -S -O- --method=PATCH http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9 --header='Content-Type: application/json' --body-data='{"state": "closed"}'

httpie

echo '{
  "state": "closed"
}' | http PATCH http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9 Content-Type:application/json

python-requests

requests.patch('http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9', headers={
    'Content-Type': 'application/json',
}, json={
    'state': 'closed',
})

Example Request (increase deposit):

http

PATCH /api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9 HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{
    "total_deposit": "100"
}

curl

curl -i -X PATCH http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9 -H 'Content-Type: application/json' --data-raw '{"total_deposit": "100"}'

wget

wget -S -O- --method=PATCH http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9 --header='Content-Type: application/json' --body-data='{"total_deposit": "100"}'

httpie

echo '{
  "total_deposit": "100"
}' | http PATCH http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9 Content-Type:application/json

python-requests

requests.patch('http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9', headers={
    'Content-Type': 'application/json',
}, json={
    'total_deposit': '100',
})

Example Request (withdraw tokens):

http

PATCH /api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9 HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{
    "total_withdraw": "100"
}

curl

curl -i -X PATCH http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9 -H 'Content-Type: application/json' --data-raw '{"total_withdraw": "100"}'

wget

wget -S -O- --method=PATCH http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9 --header='Content-Type: application/json' --body-data='{"total_withdraw": "100"}'

httpie

echo '{
  "total_withdraw": "100"
}' | http PATCH http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9 Content-Type:application/json

python-requests

requests.patch('http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9', headers={
    'Content-Type': 'application/json',
}, json={
    'total_withdraw': '100',
})

Example Request (update channel reveal timeout):

http

PATCH /api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9 HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{
    "reveal_timeout": "50"
}

curl

curl -i -X PATCH http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9 -H 'Content-Type: application/json' --data-raw '{"reveal_timeout": "50"}'

wget

wget -S -O- --method=PATCH http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9 --header='Content-Type: application/json' --body-data='{"reveal_timeout": "50"}'

httpie

echo '{
  "reveal_timeout": "50"
}' | http PATCH http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9 Content-Type:application/json

python-requests

requests.patch('http://localhost:5001/api/v1/channels/0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8/0x61C808D82A3Ac53231750daDc13c777b59310bD9', headers={
    'Content-Type': 'application/json',
}, json={
    'reveal_timeout': '50',
})
Request JSON Object:
 
  • state (string) – Desired new state; the only valid choice is "closed"
  • total_deposit (int) – The increased total deposit
  • total_withdraw (int) – The increased total withdraw
  • reveal_timeout (int) – The new reveal timeout value

Note

For the Raiden Red Eyes release the maximum deposit per node in a channel is limited to 0.075 worth of W-ETH. This means that the maximum amount of tokens in a channel is limited to 0.15 worth of W-ETH. This is done to mitigate risk since the Red Eyes release is an alpha testing version on the mainnet.

Example Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "token_network_address": "0xE5637F0103794C7e05469A9964E4563089a5E6f2",
    "channel_identifier": "20",
    "partner_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9",
    "token_address": "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8",
    "balance": "25000000",
    "total_deposit": "35000000",
    "total_withdraw": "5000000",
    "state": "closed",
    "settle_timeout": "500",
    "reveal_timeout": "50"
}
Status Codes:
  • 200 OK – Success
  • 400 Bad Request
    • The provided JSON is in some way malformed, or
    • there is nothing to do since none of state, total_deposit or total_withdraw have been given, or
    • the value of state is not a valid channel state.
  • 402 Payment Required – Insufficient balance to do a deposit, or insufficient ETH to pay for the gas of the on-chain transaction
  • 404 Not Found – The given token and / or partner addresses are not valid eip55-encoded Ethereum addresses
  • 408 Request Timeout – Deposit event was not read in time by the Ethereum node
  • 409 Conflict
    • Provided channel does not exist or
    • state, total_deposit and total_withdraw have been attempted to update in the same request or
    • attempt to deposit token amount lower than on-chain balance of the channel
    • attempt to deposit more tokens than the testing limit
  • 500 Internal Server Error – Internal Raiden node error
  • 503 Service Unavailable – The API is currently unavailable, e. g. because the Raiden node is still in the initial sync or shutting down.

Connection Management

GET /api/(version)/connections

Query details of all joined token networks.

The request will return a JSON object where each key is a token address for which you have open channels.

Example Request:

http

GET /api/v1/connections HTTP/1.1
Host: localhost:5001

curl

curl -i http://localhost:5001/api/v1/connections

wget

wget -S -O- http://localhost:5001/api/v1/connections

httpie

http http://localhost:5001/api/v1/connections

python-requests

requests.get('http://localhost:5001/api/v1/connections')

Example Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "0x2a65Aca4D5fC5B5C859090a6c34d164135398226": {
        "funds": "100",
        "sum_deposits": "67",
        "channels": "3"
    },
    "0x0f114A1E9Db192502E7856309cc899952b3db1ED": {
        "funds": "49",
        "sum_deposits": "31",
        "channels": "1"
    }
}
Status Codes:
Response JSON Array of Objects:
 
  • funds (int) – Funds from last connect request
  • sum_deposits (int) – Sum of deposits of all currently open channels
  • channels (int) – Number of channels currently open for that token
PUT /api/(version)/connections/(token_address)

Automatically join a token network. The request will only return once all blockchain calls for opening and/or depositing to a channel have completed.

The request’s payload has initial_channel_target and joinable_funds_target as optional arguments. If not provided they default to initial_channel_target = 3 and joinable_funds_target = 0.4.

If the initial_channel_target is bigger than the current number of participants of the token network then the funds will still be split according to the initial_channel_target but the number of channels made will be equal to the number of participants in the network. So eventually you will end up with less channels, but each channel will have the expected number of funds allocated to it. The remaining channels will be opened once more peers become available.

Example Request:

http

PUT /api/v1/connections/0x2a65Aca4D5fC5B5C859090a6c34d164135398226 HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{
    "funds": "1337"
}

curl

curl -i -X PUT http://localhost:5001/api/v1/connections/0x2a65Aca4D5fC5B5C859090a6c34d164135398226 -H 'Content-Type: application/json' --data-raw '{"funds": "1337"}'

wget

wget -S -O- --method=PUT http://localhost:5001/api/v1/connections/0x2a65Aca4D5fC5B5C859090a6c34d164135398226 --header='Content-Type: application/json' --body-data='{"funds": "1337"}'

httpie

echo '{
  "funds": "1337"
}' | http PUT http://localhost:5001/api/v1/connections/0x2a65Aca4D5fC5B5C859090a6c34d164135398226 Content-Type:application/json

python-requests

requests.put('http://localhost:5001/api/v1/connections/0x2a65Aca4D5fC5B5C859090a6c34d164135398226', headers={
    'Content-Type': 'application/json',
}, json={
    'funds': '1337',
})
Status Codes:
  • 204 No Content – For a successful connection creation.
  • 402 Payment Required – If any of the channel deposits fail due to insufficient ETH balance to pay for the gas of the on-chain transactions.
  • 404 Not Found – The given token address is not a valid eip55-encoded Ethereum address
  • 408 Request Timeout – If a timeout happened during any of the transactions.
  • 409 Conflict – If any of the provided input to the call is invalid.
  • 500 Internal Server Error – Internal Raiden node error.
  • 503 Service Unavailable – The API is currently unavailable, e. g. because the Raiden node is still in the initial sync or shutting down.
Request JSON Object:
 
  • funds (int) – Amount of funding you want to put into the network.
  • initial_channel_target (int) – Number of channels to open proactively.
  • joinable_funds_target (float) – Fraction of funds that will be used to join channels opened by other participants.

Note

Currently, the API calls are blocking. This means that in the case of long running calls like join, if other calls to join are made concurrently, they will block too and wait for the first call to finish. If an API call is currently being processed by Raiden, all pending calls will be queued and processed with their passed API call argument.

DELETE /api/(version)/connections/(token_address)

Leave a token network. The request will only return once all blockchain calls for closing/settling a channel have completed.

Example Request:

http

DELETE /api/v1/connections/0x2a65Aca4D5fC5B5C859090a6c34d164135398226 HTTP/1.1
Host: localhost:5001
Content-Type: application/json

curl

curl -i -X DELETE http://localhost:5001/api/v1/connections/0x2a65Aca4D5fC5B5C859090a6c34d164135398226 -H 'Content-Type: application/json'

wget

wget -S -O- --method=DELETE http://localhost:5001/api/v1/connections/0x2a65Aca4D5fC5B5C859090a6c34d164135398226 --header='Content-Type: application/json'

httpie

http DELETE http://localhost:5001/api/v1/connections/0x2a65Aca4D5fC5B5C859090a6c34d164135398226 Content-Type:application/json

python-requests

requests.delete('http://localhost:5001/api/v1/connections/0x2a65Aca4D5fC5B5C859090a6c34d164135398226', headers={
    'Content-Type': 'application/json',
})

Example Response:

HTTP/1.1 200 OK
Content-Type: application/json

[
    "0x41BCBC2fD72a731bcc136Cf6F7442e9C19e9f313",
    "0x5A5f458F6c1a034930E45dC9a64B99d7def06D7E",
    "0x8942c06FaA74cEBFf7d55B79F9989AdfC85C6b85"
]

The response is a list with the addresses of all closed channels.

Status Codes:
  • 200 OK – For successfully leaving a token network
  • 404 Not Found – The given token address is not a valid eip55-encoded Ethereum address
  • 500 Internal Server Error – Internal Raiden node error
  • 503 Service Unavailable – The API is currently unavailable, e. g. because the Raiden node is still in the initial sync or shutting down.

Note

Currently, the API calls are blocking. This means that in the case of long running calls like leave, if an API call is currently being processed by Raiden, all pending calls will be queued and processed with their passed API call argument.

Payments

POST /api/(version)/payments/(token_address)/(target_address)

Initiate a payment.

The request will only return once the payment either succeeded or failed. A payment can fail due to the expiration of a lock, the target being offline, channels on the path to the target not having enough settle_timeout and reveal_timeout in order to allow the payment to be propagated safely, not enough funds etc.

Example Request:

http

POST /api/v1/payments/0x2a65Aca4D5fC5B5C859090a6c34d164135398226/0x61C808D82A3Ac53231750daDc13c777b59310bD9 HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{
    "amount": "200",
    "identifier": "42"
}

curl

curl -i -X POST http://localhost:5001/api/v1/payments/0x2a65Aca4D5fC5B5C859090a6c34d164135398226/0x61C808D82A3Ac53231750daDc13c777b59310bD9 -H 'Content-Type: application/json' --data-raw '{"amount": "200", "identifier": "42"}'

wget

wget -S -O- http://localhost:5001/api/v1/payments/0x2a65Aca4D5fC5B5C859090a6c34d164135398226/0x61C808D82A3Ac53231750daDc13c777b59310bD9 --header='Content-Type: application/json' --post-data='{"amount": "200", "identifier": "42"}'

httpie

echo '{
  "amount": "200",
  "identifier": "42"
}' | http POST http://localhost:5001/api/v1/payments/0x2a65Aca4D5fC5B5C859090a6c34d164135398226/0x61C808D82A3Ac53231750daDc13c777b59310bD9 Content-Type:application/json

python-requests

requests.post('http://localhost:5001/api/v1/payments/0x2a65Aca4D5fC5B5C859090a6c34d164135398226/0x61C808D82A3Ac53231750daDc13c777b59310bD9', headers={
    'Content-Type': 'application/json',
}, json={
    'amount': '200',
    'identifier': '42',
})
Request JSON Object:
 
  • amount (int) – Amount to be sent to the target
  • identifier (int) – Identifier of the payment (optional)
  • lock_timeout (int) – lock timeout, in blocks, to be used with the payment. Default is 2 * channel’s reveal_timeout, Value must be greater than channel’s reveal_timeout (optional)

Example Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
    "initiator_address": "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8",
    "target_address": "0x61C808D82A3Ac53231750daDc13c777b59310bD9",
    "token_address": "0x2a65Aca4D5fC5B5C859090a6c34d164135398226",
    "amount": "200",
    "identifier": "42",
    "secret": "0x4c7b2eae8bbed5bde529fda2dcb092fddee3cc89c89c8d4c747ec4e570b05f66",
    "secret_hash": "0x1f67db95d7bf4c8269f69d55831e627005a23bfc199744b7ab9abcb1c12353bd"
}
Status Codes:
  • 200 OK – Successful payment
  • 400 Bad Request – If the provided json is in some way malformed
  • 402 Payment Required – If the payment can’t start due to insufficient balance
  • 404 Not Found – The given token and / or target addresses are not valid eip55-encoded Ethereum addresses
  • 408 Request Timeout – If a timeout happened during the payment
  • 409 Conflict – If the address or the amount is invalid or if there is no path to the target, or if the identifier is already in use for a different payment.
  • 500 Internal Server Error – Internal Raiden node error
  • 503 Service Unavailable – The API is currently unavailable, e. g. because the Raiden node is still in the initial sync or shutting down.

Note

This endpoint will return as soon the initiator has unlocked the payment(i.e Unlock message is sent). However, this does not necessarily mean that querying the balance from the target node, immediately after the initiator returns, will return the new balance amount due to the fact that the target might not have received or processed the unlock.

To use Raiden for an atomic swap (see Token Swaps), the endpoint could be called to initiate a payment while providing values for secret and secret_hash.

Example Request:

http

POST /api/v1/payments/0x2a65Aca4D5fC5B5C859090a6c34d164135398226/0x61C808D82A3Ac53231750daDc13c777b59310bD9 HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{
    "amount": "200",
    "identifier": "42",
    "secret": "0x4c7b2eae8bbed5bde529fda2dcb092fddee3cc89c89c8d4c747ec4e570b05f66",
    "secret_hash": "0x1f67db95d7bf4c8269f69d55831e627005a23bfc199744b7ab9abcb1c12353bd"
}

curl

curl -i -X POST http://localhost:5001/api/v1/payments/0x2a65Aca4D5fC5B5C859090a6c34d164135398226/0x61C808D82A3Ac53231750daDc13c777b59310bD9 -H 'Content-Type: application/json' --data-raw '{"amount": "200", "identifier": "42", "secret": "0x4c7b2eae8bbed5bde529fda2dcb092fddee3cc89c89c8d4c747ec4e570b05f66", "secret_hash": "0x1f67db95d7bf4c8269f69d55831e627005a23bfc199744b7ab9abcb1c12353bd"}'

wget

wget -S -O- http://localhost:5001/api/v1/payments/0x2a65Aca4D5fC5B5C859090a6c34d164135398226/0x61C808D82A3Ac53231750daDc13c777b59310bD9 --header='Content-Type: application/json' --post-data='{"amount": "200", "identifier": "42", "secret": "0x4c7b2eae8bbed5bde529fda2dcb092fddee3cc89c89c8d4c747ec4e570b05f66", "secret_hash": "0x1f67db95d7bf4c8269f69d55831e627005a23bfc199744b7ab9abcb1c12353bd"}'

httpie

echo '{
  "amount": "200",
  "identifier": "42",
  "secret": "0x4c7b2eae8bbed5bde529fda2dcb092fddee3cc89c89c8d4c747ec4e570b05f66",
  "secret_hash": "0x1f67db95d7bf4c8269f69d55831e627005a23bfc199744b7ab9abcb1c12353bd"
}' | http POST http://localhost:5001/api/v1/payments/0x2a65Aca4D5fC5B5C859090a6c34d164135398226/0x61C808D82A3Ac53231750daDc13c777b59310bD9 Content-Type:application/json

python-requests

requests.post('http://localhost:5001/api/v1/payments/0x2a65Aca4D5fC5B5C859090a6c34d164135398226/0x61C808D82A3Ac53231750daDc13c777b59310bD9', headers={
    'Content-Type': 'application/json',
}, json={
    'amount': '200',
    'identifier': '42',
    'secret': '0x4c7b2eae8bbed5bde529fda2dcb092fddee3cc89c89c8d4c747ec4e570b05f66',
    'secret_hash': '0x1f67db95d7bf4c8269f69d55831e627005a23bfc199744b7ab9abcb1c12353bd',
})
Request JSON Object:
 
  • amount (int) – Amount to be sent to the target
  • identifier (int) – Identifier of the payment (optional)
  • secret (string) – The secret to be used for the payment
  • secret_hash (string) – The secret hash (should be equal to SHA256 of the secret)

Querying Events

Events are kept by the node. A normal user should only care about the events exposed for payments. Those events show if a payment failed or if it was successful.

For raiden_events you can provide a limit and an offset number which would define the limit of results to return and the offset from which to return results respectively.

raiden_events contain a timestamp field, log_time, indicating when they were written to the write-ahead log. The format of log_time is ISO8601 with milliseconds.

GET /api/(version)/payments/(token_address)/(target_address)
Query the payment history. This includes successful (EventPaymentSentSuccess) and failed (EventPaymentSentFailed) sent payments as well as received payments (EventPaymentReceivedSuccess). token_address and target_address are optional and will filter the list of events accordingly.

Example Request:

http

GET /api/v1/payments/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x82641569b2062B545431cF6D7F0A418582865ba7 HTTP/1.1
Host: localhost:5001

curl

curl -i http://localhost:5001/api/v1/payments/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x82641569b2062B545431cF6D7F0A418582865ba7

wget

wget -S -O- http://localhost:5001/api/v1/payments/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x82641569b2062B545431cF6D7F0A418582865ba7

httpie

http http://localhost:5001/api/v1/payments/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x82641569b2062B545431cF6D7F0A418582865ba7

python-requests

requests.get('http://localhost:5001/api/v1/payments/0x0f114A1E9Db192502E7856309cc899952b3db1ED/0x82641569b2062B545431cF6D7F0A418582865ba7')

Example Response:

HTTP/1.1 200 OK
Content-Type: application/json

[
    {
        "event": "EventPaymentReceivedSuccess",
        "amount": "5",
        "initiator": "0x82641569b2062B545431cF6D7F0A418582865ba7",
        "identifier": "1",
        "log_time": "2018-10-30T07:03:52.193",
        "token_address" : "0x5a2d2b9b015b46b8eaff7bffdc5db0051db7439b"
    },
    {
        "event": "EventPaymentSentSuccess",
        "amount": "35",
        "target": "0x82641569b2062B545431cF6D7F0A418582865ba7",
        "identifier": "2",
        "log_time": "2018-10-30T07:04:22.293",
        "token_address" : "0x5a2d2b9b015b46b8eaff7bffdc5db0051db7439b"
    },
    {
        "event": "EventPaymentSentSuccess",
        "amount": "20",
        "target": "0x82641569b2062B545431cF6D7F0A418582865ba7",
        "identifier": "3",
        "log_time": "2018-10-30T07:10:13.122",
        "token_address" : "0x5a2d2b9b015b46b8eaff7bffdc5db0051db7439b"
    }
]
Status Codes:
  • 200 OK – For successful query
  • 404 Not Found – The given token and / or partner addresses are not valid eip55-encoded Ethereum addresses
  • 409 Conflict – If the given block number or token_address arguments are invalid
  • 500 Internal Server Error – Internal Raiden node error
  • 503 Service Unavailable – The API is currently unavailable, e. g. because the Raiden node is still in the initial sync or shutting down.

Querying node state

GET /api/(version)/status

Query the node status. Possible answers are:

  • "ready": The node is listening on its API endpoints
  • "syncing": The node is still in the initial sync. Number of blocks to sync will also be given.
  • "unavailable": The node is unavailable for some other reason

Example Request:

http

GET /api/v1/status HTTP/1.1
Host: localhost:5001

curl

curl -i http://localhost:5001/api/v1/status

wget

wget -S -O- http://localhost:5001/api/v1/status

httpie

http http://localhost:5001/api/v1/status

python-requests

requests.get('http://localhost:5001/api/v1/status')

Example Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
   "status": "syncing",
   "blocks_to_sync": "130452"
}
Status Codes:

API endpoints for testing

POST /api/(version)/_testing/tokens/(token_address)/mint

Mint tokens. This requires the token at token_address to implement a minting method with one of the common interfaces:

  • mint(address,uint256)
  • mintFor(uint256,address)
  • increaseSupply(uint256,address)

Depending on the token, it may also be necessary to have minter privilege.

Example Request:

http

POST /api/v1/_testing/tokens/0x782CfA3c74332B52c6f6F1758913815128828209/mint HTTP/1.1
Host: localhost:5001
Content-Type: application/json

{
   "to": "0x2c4b0Bdac486d492E3cD701F4cA87e480AE4C685",
   "value": "1000"
}

curl

curl -i -X POST http://localhost:5001/api/v1/_testing/tokens/0x782CfA3c74332B52c6f6F1758913815128828209/mint -H 'Content-Type: application/json' --data-raw '{"to": "0x2c4b0Bdac486d492E3cD701F4cA87e480AE4C685", "value": "1000"}'

wget

wget -S -O- http://localhost:5001/api/v1/_testing/tokens/0x782CfA3c74332B52c6f6F1758913815128828209/mint --header='Content-Type: application/json' --post-data='{"to": "0x2c4b0Bdac486d492E3cD701F4cA87e480AE4C685", "value": "1000"}'

httpie

echo '{
  "to": "0x2c4b0Bdac486d492E3cD701F4cA87e480AE4C685",
  "value": "1000"
}' | http POST http://localhost:5001/api/v1/_testing/tokens/0x782CfA3c74332B52c6f6F1758913815128828209/mint Content-Type:application/json

python-requests

requests.post('http://localhost:5001/api/v1/_testing/tokens/0x782CfA3c74332B52c6f6F1758913815128828209/mint', headers={
    'Content-Type': 'application/json',
}, json={
    'to': '0x2c4b0Bdac486d492E3cD701F4cA87e480AE4C685',
    'value': '1000',
})
Request JSON Object:
 
  • to (address) – The address to assign the minted tokens to.
  • value (int) – The amount of tokens to be minted.

Example Response:

HTTP/1.1 200 OK
Content-Type: application/json

{
   "transaction_hash": "0x90896386c5b218d772c05586bde5c37c9dc90db5de660bba5bd897705c976edb"
}
Status Codes:
  • 200 OK – The transaction was successful.
  • 400 Bad Request – Something went wrong.
  • 503 Service Unavailable – The API is currently unavailable, e. g. because the Raiden node is still in the initial sync or shutting down.
Response JSON Object:
 
  • transaction_hash (string) – The hash of the minting transaction.

Raiden Services

Introduction

The Raiden network includes auxiliary services, that enhance the overall user experience. These services include

  • finding short or cheap routes through the network and
  • allowing users to go offline safely by monitoring open payment channels.

Pathfinding Services

Pathfinding services have a global view on a token network can provide suitable payment paths for Raiden nodes.

The service will keep its view on the token network updated by listening to blockchain events and a public matrix room where current capacities and fees (Capacity Updates) are being published. Nodes can publish their channel capacities and fees in order to advertise their channels and mediate payments.

Using a Pathfinding Service

Using a Pathfinding service increases the likelihood of successful payments, especially when multiple mediators are used. Therefore, using a Pathfinding service is enabled by default.

Note

Direct token transfers (using no mediators) never need information from a PFS, so in that case no request for a PFS is done.

To disable the usage of Pathfinding services use the --routing-mode command line flag. This option is set to pfs by default, but can also be set to local or private if you don’t want to use a Pathfinding service. See below for further information about privacy implications.

Choosing a Pathfinding Service

By default the Raiden client will chose a suitable Pathfinding service for you. As all PFSs are registered in the service registry, it will iterate over all of them and choose one that has a fee which is lower then a given threshold.

This threshold can be changed with the --pathfinding-max-fee command line flag and is set to 0.05 RDN by default.

If you want to use a certain PFS, then you can set it by using the --pathfinding-service-address command line flag.

Sent information

The PFS relies on information from the individual Raiden nodes to keep its network representation up-to-date. Therefore the Raiden clients will send information about channel capacities and fees to the PFS by default.

This can be disabled by using the private routing mode, where no such updates are broadcasted. However, this also means that the PFS has no information about the channels of that node and will never mediate payments over these channels.

Monitoring Services

Monitoring services can watch open payment channels when the user is not online. In case one channel partner closes a channel while the counterparty is offline (or doesn’t react for 80% of the settlement timeout after close has been called), the Monitoring service sends the latest balance proof to the channel smart contract and thus ensures correct settlement of the channel.

Monitoring for channels is disabled by default. To enable it, the --enable-monitoring command line flag is used. This will enable monitoring for all open channels.

Note

It is currently not possible to enable monitoring for selected channels, but this will be possible in future version. This feature is tracked in this issue.

Sent information

In order to update the channel state the monitoring services need information about the channel state. For that reason, when monitoring is enabled, the client will send the latest received balance proof with additional information necessary for the payment of the monitoring services (see the spec for more information) to the monitoring services.

Monitoring rewards

The Monitoring Service expects a reward when it updates a channel on the user’s behalf. This reward is only paid out when the user did not update the channel state itself (this is handled by the Raiden client automatically). The reward is not configurable and has a value of 5 RDN.

Raiden on Private Network Tutorial

Introduction

This tutorial shows how to run Raiden on a private network, using the master branch (this is useful when you are working on a pull-request). This tutorial assumes Ubuntu 18.04.2 LTS and bash.

Creating a Virtual Environment

In a shell, run

$ sudo apt-get install libncurses5-dev
$ mkdir priv_chain

If mkdir fails, choose a different name, or move the existing priv_chain directory to somewhere else.

$ cd priv_chain
$ virtualenv -p python3.7 env
$ source env/bin/activate

You should now be in the virtual environment, where all Python package installations are separately managed.

Now the command prompt should look like:

(env) $

Install Raiden and dependencies

(env) $ pwd
<snip>/priv_chain
(env) $ git clone https://github.com/raiden-network/raiden
(env) $ cd raiden
(env) $ pip install pip-tools
(env) $ make install-dev

Launch a private network

Installing Geth

Follow the guide and install Geth. A command geth should be available in your shell. This guide assumes version 1.9.7, but other versions might work.

Preparing a genesis config

Prepare a file genesis.json with the following content (@offerm kindly allowed to use his file here).

(env) $ cd ..
(env) $ pwd
<snip>/priv_chain
(env) $ cat genesis.json
{
"config": {
"chainId": 4321,
"homesteadBlock": 0,
"eip150Block": 0,
"eip155Block": 0,
"eip158Block": 0,
"ByzantiumBlock": 0
},
"alloc": {},
"difficulty" : "0x1",
"gasLimit"   : "0x9880000"
}

Starting a chain

With the genesis.json you can initialize a blockchain.

(env) $ pwd
<snip>/priv_chain
(env) $ geth --datadir blkchain1 init genesis.json
(env) $ geth --rpc --datadir blkchain1 --networkid 4321 --rpcapi "eth,net,web3" console
<snip>
> personal.newAccount()
"0xd4de892c06cf4a0557c7d515f79fd20b8356d6cf"

Copy the shown address somewhere. And start mining on your own private blockchain.

> miner.start()

In this console geth should keep running.

Figure out the contract version

Open a new console, and load the Python environment.

$ pwd
<snip>/priv_chain
$ source env/bin/activate
(env) $

Figure out the value CONTRACTS_VERSION

(env) $ cd raiden
(env) $ grep 'CONTRACTS_VERSION = ' -r ../env/lib/python3.7/site-packages/raiden_contracts

../env/lib/python3.7/site-packages/raiden_contracts/constants.py:CONTRACTS_VERSION = “0.25.0”

Copy the shown version somewhere.

Define constants

The contract version will be used quite often, so let bash remember it (“0.25.1” is broken, so change the raiden version when you see “0.25.1”).

(env) $ export VERSION="0.25.0"

You will need your private key for the account you created.

(env) $ cd ..
(env) $ pwd
<snip>/priv_chain
(env) $ export PRIV_KEY=./blkchain1/keystore/UTC-<use TAB-completion to fill in>

If the TAB-completion shows more than two files, something has gone wrong. In that case, back up all files and start over.

The biggest 256-bit unsigned int is a useful default as deposit limits and the max number of TokenNetwork contracts.

(env) $ export MAX_UINT256=115792089237316195423570985008687907853269984665640564039457584007913129639935

The RPC connection point is used often.

(env) $ export PROVIDER="http://127.0.0.1:8545"

Deploy contracts

Now we can start deploying the Raiden smart contracts on the private chain.

(env) $ pwd
<snip>/priv_chain
(env) $ python -m raiden_contracts.deploy raiden --rpc-provider $PROVIDER --private-key $PRIV_KEY --gas-price 10 --gas-limit 6000000 --contracts-version $VERSION --max-token-networks $MAX_UINT256
{
    "SecretRegistry": "0x6436d3B7205F18044a320403b1Cd0FfFd7e5D998",
    "TokenNetworkRegistry": "0xC5e4a9189ac801077317CD6BCFA643677897D15B"
}

We will use these addresses later, so let’s remember them.

(env) $ export TokenNetworkRegistry="0xC5e4a9189ac801077317CD6BCFA643677897D15B"
(env) $ export SecretRegistry="0x6436d3B7205F18044a320403b1Cd0FfFd7e5D998"

Before we deploy the other contracts, we need a token contract for service payments.

(env) $ python -m raiden_contracts.deploy token --rpc-provider $PROVIDER --private-key $PRIV_KEY --gas-price 10 --gas-limit 6000000 --token-supply 10000000000 --token-name ServiceToken --token-decimals 18 --token-symbol SVT --contracts-version $VERSION
{
   "CustomToken": "0xC5e9F7407359d1492d515C303A3aeDB434D3f0e1"
}

We use the address of this token to deploy service contracts.

(env) $ export SERVICE_TOKEN="0xC5e9F7407359d1492d515C303A3aeDB434D3f0e1"
(env) $ python -m raiden_contracts.deploy services --rpc-provider $PROVIDER --private-key $PRIV_KEY --gas-price 10 --gas-limit 6000000 --token-address $SERVICE_TOKEN --user-deposit-whole-limit $MAX_UINT256 --service-deposit-bump-numerator 5 --service-deposit-bump-denominator 4 --service-deposit-decay-constant 100000000 --initial-service-deposit-price 100000000000 --service-deposit-min-price 1000 --service-registration-duration 234000000 --contracts-version $VERSION --token-network-registry-address $TokenNetworkRegistry

From the output, we remember the address of the UserDeposit contract.

(env) $ export UserDeposit="0x50E5f50b98a78615163E89A65fD60D551933CaE2"

We deploy another Token contract that’s going to be transferred on Raiden network.

(env) $ python -m raiden_contracts.deploy token --rpc-provider $PROVIDER --private-key $PRIV_KEY --gas-price 10 --gas-limit 6000000 --token-supply 10000000000 --token-name Token --token-decimals 18 --token-symbol TKN --contracts-version $VERSION
{
    "CustomToken": "0x818cBB172D1a1b769acaA94e80e4c71ba40bdc79"
}

We register this token to the TokenNetworkRegistry.

(env) $ export TOKEN="0x818cBB172D1a1b769acaA94e80e4c71ba40bdc79"
(env) $ python -m raiden_contracts.deploy register --rpc-provider $PROVIDER --private-key $PRIV_KEY --gas-price 10 --gas-limit 6000000 --token-address $TOKEN --token-network-registry-address $TokenNetworkRegistry --contracts-version $VERSION --channel-participant-deposit-limit 10000000 --token-network-deposit-limit 1000000000

Start Raiden Client

In geth console, figure out the deployer’s address.

> web3.toChecksumAddress(eth.accounts[0])
"0x35ebA3Dc57D2A66D378638B19A7CEb194dc29eb6"

Find the relevant contract addresses.

(env) $ export DeployerAddress="0x35ebA3Dc57D2A66D378638B19A7CEb194dc29eb6"

Store the password associated with the private key.

(env) $ echo "password" > passwd_file

And you can start the Raiden client:

(env) $ raiden --datadir exchange-a  --keystore-path   ./blkchain1/keystore/ --network-id 4321  --accept-disclaimer --address $DeployerAddress --rpc --api-address 0.0.0.0:5001 --web-ui  --environment-type development  --console --no-sync-check --accept-disclaimer --user-deposit-contract-address $UserDeposit --routing-mode local --password-file passwd_file

Raiden Glossary

available balance
The available balance \(B_a\) of a channel participant is \(B_a = B_n - B_l\).
balance
The balance \(B_n\) of a channel participant \(P\) is his total deposit \(P_d\) along with the amount of tokens he received \(P_r\) minus the amount \(P_s\) of token he has sent. So \(B_n = P_d + P_r - P_s\)
balance proof
Balance proof is any kind of message used in order to cryptographically prove on the blockchain what the latest transferred amount and locked amount received from a counter party is.
channel capacity
A channel’s capacity is the sum of the total deposits minus the sum of the total withdraws of both its participants. It is also the sum of the channel participants balance.
counterparty
The counterparty of a channel is the other participant of the channel that is not ourselves.
hashlock
A hashlock is the hashed secret that accompanies a locked message: sha3(secret).
initiator
In a payment the initiator is the raiden node which starts the payment
lock expiration
The lock expiration is the highest block_number until which the transfer can be settled.
locked amount
The locked amount is the total amount of tokens one participant of a payment channel has locked in pending transfers towards his counterparty
locked balance
The locked balance \(B_l\) of a channel participant is the sum of the locked amount for all pending transfers \(T_p\). So \(B_l = \sum_{k=0}^{N-1} T_p\) where \(N\) is the number of pending transfers.
MediatedTransfer
A mediated transfer is a hashlocked transfer between an initiator and a target propagated through nodes in the network.
merkletree root
locksroot
The root of the merkle tree which holds the hashes of all the locks in the channel.
payee
In a channel relationship between two raiden nodes the payee is the participant who receives a transfer
payer
In a channel relationship between two raiden nodes the payer is the participant who sends a transfer.
payment
In Raiden a payment denotes the process of sending tokens from one account to another. A payment has an initiator and a target and can be composed of multiple transfers.
payment channel
The on-chain payment channel between two raiden nodes.
preimage
secret
The preimage, what we call the secret in Raiden, is 32 bytes of random cryptographically secure data whose keccak hash ends up being the hashlock.
RefundTransfer
A refund transfer is a special type of MediatedTransfer that is used when a node can no longer propagate a transfer and a routing backtrack needs to be done.
reveal timeout
The number of blocks in a channel allowed for learning about a secret being revealed through the blockchain and acting on it.
RevealSecret
The reveal secret message is sent to a node that is known to have an interest to learn the secret.
secret message
The secret message is a message containing the secret and used for synchronization between mediated transfer participants.
SecretRequest
The secret request message is sent by the target of a mediated transfer to its initiator in order to request the secret to unlock the transfer.
settlement timeout
settlement window
The number of blocks after the closing of a channel within which the counterparty is able to call updateNonClosingBalanceProof with the latest balance proof they received.
target
In a payment the target is the raiden node for which the payment sent by the initiator is intended
transfer
In Raiden a transfer denotes a single hop transfer of tokens, either direct or hash time locked inside a payment channel.
transferred amount
The transferred amount is the total amount of tokens one participant of a payment channel has sent to his counterparty.

Raiden Developer Onboarding Guide

Introduction

This is a general onboarding guide whose main purpose is to help people who want to develop Raiden. It provides an explanation of the protocol followed by an explanation of the architecture.

For information on coding style, commit rules and other development rules please refer to the Contributing Guide.

The Raiden Protocol

In this section we will have the general explanation of how the Raiden protocol works, starting from the smart contracts and ending with the offchain messages that are exchanged between Raiden nodes. For a quick overview, please watch the video “Raiden Network Protocol Explained”. For a more formal definition of the protocol please refer to the specification.

Smart contracts

Raiden has 4 smart contracts that are needed to support the protocol. They can all be found at the smart contracts repository. The repository also contains scripts to deploy and verify the contracts on different networks. For more information on the contracts and the channel lifecycle check the smart contract specification.

Messages Exchanged during a Raiden Transfer

The Happy Case
_images/transfer_happy_case.gif

Happy case of a Raiden Transfer

Let’s first look at the messages exchanged in the happy path of a Raiden Transfer. Each Transfer has an Initiator, a Target and zero or more Mediators. The Initiator creates a Locked Transfer message and propagates it to the Target through multiple Mediators. A LockedTransfer message reserves the amount for the pending payment in each channel between Initiator/Mediator and Mediator/Target.

Once the LockedTransfer reaches the Target then they request the secret from the Initiator by sending a Secret Request message. When the Initiator receives the SecretRequest message, the Initiator can safely assume that a mediated locked transfer with the required amount has arrived to the Target, since Target as a payment receiver has all the incentives to be honest.

When the Initiator gets the secret request message, they check to make sure that it’s a valid one and that it corresponds to a locked transfer that they sent out. If all checks out they send a Reveal Secret message back to the Target. The RevealSecret message contains a secret that allows each Mediator or the Target along the path to claim the locked amount in the pending transfer.

The Target will process the secret message, register it into their state and then proceed to reveal the secret backwards by sending their own RevealSecret message to their counterparty.

The counterparty which can either be a Mediator or the Initiator will receive this RevealSecret message and process it. This message tells them that the payee (either the target or another mediator if we got multiple hops) knows the secret and wants to claim the lock off-chain. So then they may unlock the lock and send an up-to date balance proof to the payee. This is done by sending what we (unfortunately) call the Secret message back to the partner who sent the Reveal Secret.

This concludes the transfer for that hop. If the receiver of RevealSecret was the Initiator then the transfer is finished end-to-end. If it was just a Mediator then they will have to propagate the transfer backwards by sending a RevealSecret message backwards to their partner repeating the procedure outlined above.

An Unhappy Case
_images/transfer_unhappy_case.gif

Unhappy case of a Raiden Transfer

Looking at a similar network topology as shown in the happy case above, let’s see how the protocol behaves when something goes wrong and our partner does not follow the protocol.

As seen in the figure above once the payee sends the Reveal Secret message the payer does not respond with the expected balance proof message. If that happens the payee has two choices:

  1. If the amount involved in the token is really small then the payee can just do nothing and forfeit it.
  2. If the amount is worth an on-chain transaction then the payee can go on-chain by registering the secret on the SecretRegistry contract and prove he knew the secret before the block of the lock expiration. From that point on the protocol can continue as before but now the secret is visible onchain so everyone along the path now knows it.
Offchain messages at Lock Expiration

If for some reason the protocol does not proceed and the Target never requests for the secret then the pending transfer lock will at some point expire. At the point of expiration in a payer-payee channel the payer will have to notify the payee that the lock has expired by sending a LockExpired message.

The payee receives the LockExpired message, removes the lock from its pending locks for the partner and updates the state with the new balance proof.

Routing

_images/routing_a_transfer.gif

Routing a Transfer

At the moment routing in Raiden works in a very simple manner. Each node has a global view of the network knowing the initial capacity of each channel by watching for the deposit events happening on chain. As a result each node keeps a graph of the network but that graph may be outdated due to the capacity changing because of offchain transfers.

Each node tries to forward the transfer through the shortest path with enough capacity to the target. If at some poin the transfer can’t go through due to the actual capacity not being sufficient or due to the node being offline then a special kind of LockedTransfer called a Refund Transfer will be sent back to the payer, effectively refunding him the transferred amount and allowing him to try another route. This is repeated until either a route is found or we have no other ways to reach the target at which case the Transfer fails.

If the transfer reaches the target and the protocol is followed properly as we saw in the happy transfer case above then all the pending transfers in the path will be unlocked and the node balances will be updated.

Pending Transfers

_images/pending_transfers_for_mediator.gif

Pending transfers from the perspective of a mediator

When a node mediates transfers all of the locks are kept on the state of the mediator node inside a merkle tree. For each new transfer the lock is appended to the merkle tree.

If the protocol is followed as shown in the happy transfer case above then the corresponding lock is unlocked and removed from the merkle tree.

Unlocking Pending Transfers

At this section we are going to look in more detail how the unlocking of pending transfers mentioned in the previous section works.

_images/settle_pending_locks.gif

Unlocking pending transfers onchain after settlement

Continuing from the example seen in the pending transfers section above let’s explore what happens when B’s partner closes the channel while there are transfers pending.

In the figure above the following things happen:

  1. For the payment A->B->C , C follows the protocol and send the secret back to B.
  2. At the same time A closes the channel and so the normal offchain protocol can not be followed. Instead we enter the channel settlement lifecycle lifecycle we saw in the previous section with A closing the channel with what he received from his partner B.
  3. Now B has to register the secret received by C onchain as he can no longer do it offchain. He has to prove that he knew the secret at a block height before the pending transfer’s expiration. He does that by calling registerSecret on the SecretRegistry contract.
  4. Now it’s B’s turn to update the contract with what he has received from A. He will provide a hash of the merkle root, the transferred amount and the locked amount to the contract via the updateNonclosingbalanceproof call.
  5. After both are done and the settlement period has passed then anyone can settle the channel and send the tokens amounts owed to A and B respectively back to its owners.
  6. After settlement whoever has pending transfers that need to be unlocked on chain has to unlock them onchain. In this example B will provide the merkle tree to the contract via the unlock function. That will result in the contract checking each one of the locks and send the locked tokens for which the secret was registered on time to the intended receiver (B) and those for which it wasn’t back to the payer (A).

Raiden Architecture

In this section we are going to see an explanation of how the code of the Raiden client is structured and how it implements the protocol detailed in the previous section and.

Architecture Overview

_images/architecture_overview.png

Raiden Architecture Overview

At the core of the Raiden architecture lies a state machine. The state machine gets fed state changes from various sources.

  • Action* state changes are caused by user commands directly from the user through the REST API.
  • ContractReceive* state changes are caused by blockchain events fetched via polling.
  • Receive* state changes are caused by receiving an offchain message.

All these state changes are processed along with the current state and produce a new state along with something that we call the “Raiden Internal Events” which is essentially I/O since the state machine can’t do I/O on its own.

Processing those raiden internal events performs all kinds of I/O.

  • Send* events send offchain messages.
  • ContractSend* events send onchain transactions.
  • Event* events cause node events (for example, logging a debug message).

The State Machine

The entire state machine code is located under the transfer directory. For a good overview of all the classes used in the state machine check the architecture file.

The StateManager class is where the application state is stored. Also at the dispatch() function is where the state changes are applied to the current state through the state transition function and produce the next state and a list of Raiden Internal events.

The result of the application of a state change is represented by the TransitionResult class. It is essentially a tuple containing the new state and a list of Raiden internal events produced by the state transition.

_images/state_tasks.png

State tasks hierarchy

The state in Raiden is kept in a hierarchical manner in what we call “Tasks”. At the top is the node state represented by the ChainState class. Whenever a node starts up the first state change we get is the ActionInitChain state change and through its application we get the aforementioned Chain State. All state changes first pass through this level via the node state transition function.

When we start we also create a new TokenNetworkRegistry state corresponding to the default Token Network Registry contract. In the future there could be multiple token network registries but at the moment we only register the default.

Whenever we get a blockchain event denoting that a new Token Network was created then an ActionNewTokenNetwork state change is created. Processing that state change a TokenNetworkState is added to the TokenNetworkRegistryState. All state changes that need to go down to the TokenNetwork are eventually subdispatched from the node state to the Token Network’s state transition function.

ChannelOpened is a blockchain event denoting that a new channel was opened. Whenever we receive ChannelOpened and we are a participant, a ContractReceiveChannelNew state change is generated and sent into the state machine. The state change contains the channel’s NettingChannelState. When the state change is processed, the NettingChannelState is added into the corresponding TokenNetworkState. From this point on all state changes that concern a specific channel are subdispatched from the TokenNetwork processing to the channel’s state transition function.

All the state related to mediated transfers is kept under the transfer/mediated_transfer directory.

If our node initiates a transfer then it takes on the role of the Initiator and an ActionInitInitiator state change is generated. Then it’s subdispatched to the initiator manager’s state transition where a new InitiatorPaymentState task will be created. From now on all state changes that affect this transfer will be subdispatched to this Initiator task.

If our node mediated a transfer then it takes on the role of the mediator and an ActionInitMediator state change is generated. Then it’s subdispatched to the mediator’s state transition function where a new MediatorTransferState task will be created. From now on all state changes that affect this transfer will be subdispatched to this Mediator Task.

Finally if our node receives a transfer whose intended recipient is the node itself then it takes on the role of the target and an ActionInitTarget state change is generated. Then it’s subdispatched to the target’s state transition function where a new TargetTransferState task will be created. From now on all state changes that affect this transfer will be subdispatched to this Target Task.

Raiden Internal Events

As mentioned before all state transitions may generate a list of Raiden Events.

Since the state machine itself can have no side effects or I/O these events act as a trigger for all side effects. After a state change has been processed we get the event list. For each of these events we invoke the RaidenEventHandler which will process the events and trigger the appropriate side effects.

For example send a locked transfer or settle a channel if the settlement period has ended.

The Write Ahead Log

_images/write_state_change_to_wal.png

Logging a state change to the WAL before dispatching to the state machine

Before a state change is dispatched to the state machine for processing we write it into a Database called the Write Ahead Log. This allows Raiden to be persistent in case of crashes or other forms of irregular shutdown.

All that is needed in order to recreate the latest state is the initial state and the sum of state changes that lead up to it. So during a restart we read all the state changes in the WAL and replay them to recreate the latest state.

_images/restore_wal.png

Restoring the state from the WAL

If Raiden has been running for many days then a lot of state changes will have gathered. Replaying all of these state changes at restart would take a lot of time so as an optimization at regular internals we are taking a snapshot of the current state. Subsequently at restart we restore the snapshotted state, retrieve the state changes since the snapshots and replay only those state changes to get to the final state.

The Transport Layer

The Raiden Transport layer is responsible for the receiving and sending of the off-chain messages. The current architecture allows for a pluggable transport layer through the use of a common transport interface. We have one implementation of this interface. The MatrixTransport.

Irrespective of the transport layer once a message is received it will eventually be forwarded to the MessageHandler which will generate the proper state changes and dispatch them to the state machine described in the previous section.

The Matrix Transport

The reasoning behind the choice of Matrix as a transport layer for Raiden is nicely explained in this blogpost.

In this section we are going to only look over the main points in the code which are the entries to the transport layer. For more information please check out the matrix transport spec.

In Matrix each user has a userid in the form of @<userId>:<homeserver_uri>. userId is the lowercased ethereum address of the node, possibly followed by a 4-bytes hex-encoded random suffix, separated from the address by a dot. The homeserver_uri is the URI of the matrix homeserver at which the user registers.

Each pair of nodes have a private room for communication. Once a message is added to any of these rooms, they are processed in batch by MatrixTransport._handle_sync_messages, after decoding and validation these messages are forwarded to RaidenService.on_messages and processed by the node.

As for sending messages to a partner in a channel the send_async() function is the entry point. It essentially populates the sending queue for the partner. The actual messages will be sent from the queue during the main loop of the transport through the _check_and_send() function.

Messages acknowledgment and processing

All the messages seen in the offchain messages section need to be (1) seen and (2) succesfully processed by the partner node. To facilitate synchronization of that fact the transport layer makes sure that all messages except for Delivered itself cause a Delivered to be sent.

The Delivered message is sent right when the transport receives a message and before processing. It just tells the sender that the message was received and will be processed.

The Processed message is sent for the following cases (essentially messages containing a BP):

  • Succesfully handling a valid unlock (aka Secret) message at both target and mediator.
  • Handling a valid refund transfer message
  • Handling a valid lock expired message
  • Handling a valid locked transfer message

On the sender’s side for the messages in the unordered queue:

  • Secret Request
  • Secret Reveal
  • Processed

Receiving a Delivered is enough to remove them from the queue triggering the transport to stop retrying sending them.

On the sender’s side for the specific queues they’ll wait for the Processed message, signaling not only that the message was delivered, but also that the processing of the respective state change occurred successfully, or else keep retrying. If a Processed is received the the specific queue is cleared.

So, for a specific queue message, e.g. a LockedTransfer in a specific channel:

  • -> A sends a LockedTransfer and starts a retry loop for it with message_id=123
  • <- B receives it and sends Delivered(123).
  • <- B accepts it (i.e. succesfully processes it). Then sends Processed(123) and starts a retry loop for it.
  • -> A receives Delivered(123). Stops retry loop for any message_id=123 from B in its unordered queue, which is none, so it effectivelly skips it.
  • -> A receives Processed(123), stops retry loop for any message_id=123 from B in its specific queue (in this case, LockedTransfer), sends Delivered(123) in reply to Processed(123).
  • <- B receives Delivered(123), stops retry loop for any message_id=123 from A in its unordered queue (in this case, Processed).

Blockchain Communication

We communicate with the blockchain through the JSONRPCClient class. That class is a wrapper of web3.py for all blockchain JSON RPC calls and also checks that the underlying ethereum client is compatible with Raiden. Checks things such as that all required interfaces are enabled and that the version is high enough (Byzantium enabled).

We communicate with each smart contract through the notion of a smart contract proxy. Each proxy is a essentially a class exposing the functionality of a specific contract using the JSONRPCClient.

We have proxies for all the contracts:

Processing onchain events

All the events that happen onchain are polled after a new block is received and all found events are forwarded to the blockchain event handler.

From there each different event is processed and appropriate state changes are generated and dispatched to the state machine to be processed by it as we saw before.

Sending onchain transactions

As mentioned before a byproduct of state transitions in the state machine are Raiden Internal events. A certain subset of those events, the ContractSendEvent is what allows us to send on chain transactions.

As seen in the Raiden Internal Events section if a ContractSendXXX event is sent to the RaidenEventHandler then it will be processed and eventually the appropriate proxy will generate an onchain transaction.

The Rest API

All Raiden user facing actions are exposed via a REST API. For a full documentation of the endpoints check the REST API documentation.

As far as the code is concerned all of the functionality to interact with Raiden is inside what we call the Python API. The RaidenAPI class has all the functions which deal with channel operations, transfers e.t.c.

These functions are exposed to the user through the REST API endpoints of the RestAPI class.

The WebUI

Raiden has a graphical user interface. It’s an angular application running by default along with the raiden node and exposing an interface that can be accessed via the user’s Browser

TODO: Small overview of code architecture for the WebUI.

Frequently Asked Questions

What is MS/PFS?
These are smart contracts to be deployed in the future. See Monitoring Service and Pathfinding Service in the smart contract specification.
How are messages encoded?
The messages specification should describe the message formats. On the implementation side, the messages file contains the details. See encode() method of Message class, and packed() method of each subclass of Message. Ultimately the byte sequence of the packed messages is defined in the encoding/messages file.
Why does updateNonClosingBalanceProof() require one more signatures than closeChannel()?
The two functions authenticate the beneficiary of the balance proof in different ways. closeChannel() uses msg.sender while updateNonClosingBalanceProof() checks the non_closing_signature argument. This allows a delegate (like Monitoring Services) to call updateNonClosingBalanceProof(), which has to be called during a limited challenge period.
Why do closeChannel() and updateNonClosingBalanceProof() authenticate both parties of the channel?
The authors of the balance proofs control their tokens, so their signatures must be checked. The receiver’s signatures must be checked because they should be able to refuse balance proofs. For example, when the transferred amount decreases in a newer balance proof, the receiver can choose not to add the second signature on the balance proof.
Why are balance hashes used in closeChannel() and updateNonClosingBalanceProof() instead of plain balance proofs?
For privacy reasons. If updateNonClosingBalanceProof() required plain balance proofs, actual token amounts would be visible in all balance proofs sent to Monitoring Services. The Monitoring Services and eavesdroppers would learn a lot about transfer patterns of each user.

Contract Proxies Guide

Introduction

A Raiden node accesses smart contracts through wrappers called proxies. The proxies are implemented in raiden/network/proxies directory. The proxies are supposed to be used with some special care, and they are implemented in a specific way.

The complication exists because there is always the possibility of a race between our node, the blockchain(s) and other parties. The Raiden node usually recognizes events on the blockchain only after some confirmation period. By the time the Raiden node recognizes an onchain event, the Raiden node has seen several blocks have been mined on top. However, when Raiden posts a transaction to the blockchain, the transaction is sent to miners who operate on the newest available block.

The proxies try to prevent the users from spending gas costs for transactions that fail anyway, and also to give a reasonable diagnosis why a transaction doesn’t (or didn’t go through).

A Proxy’s Workflow

Read-only case

If the call is read-only, the proxy never throws a transaction to the blockchain. The proxy asks the Ethereum client to execute the call in the specified blockhash.

State-modifying case

If the call modifies the state, the proxy does the following things in the successful case:

  1. the proxy checks conditions on the specified block, and sees whether the call would fail (the post-condition checks)
  2. the proxy then asks the Ethereum client to estimate gas, which might fail.
  3. the proxy then asks the Ethereum client to submit the transaction to the blockchain.
  4. the proxy sees the transaction receipt and sees if it’s successful.

When the precondition checks fail, the proxy raises BrokenPreconditionError, blaming the caller for making a call without proper checks.

When the gas estimation fails, the proxy performs additional checks on the latest available block in order to determine the cause of the failure.

When the transaction was included in a block but the execution has failed, the proxy performs additional checks on that block in order to determine the cause of the failure. The checks use the chain state at the end of the failing block.

Depending on the cause of the failure, the proxy raises different kinds of exceptions. If you use the proxies, you’ll need to make sense of these exceptions (see below).

A Guide for Using Proxies

Before calling a proxy, make sure that the call is going to succeed in a confirmed block. Pick a confirmed block and query the blockchain so that the chain state allows a successful execution at that moment. And then, pass the blockhash of the confirmed block to the proxy when you call it.

The proxy checks the preconditions on the confirmed block. If any of the preconditions fail because of the chain state, it raises BrokenPreconditionError. This means there is a mistake in the Raiden codebase, and a check must be added before calling the proxy.

However, the proxy raises BrokenPreconditionError only when the error is about the chain state. There are values that are invalid regardless of the chain state. These cause RaidenValidationError instead of BrokenPreconditionError. The RaidenValidationError is not considered as a bug in the codebase.

When the proxy doesn’t raise an exception, the call was successful. A transaction was included in a block and the transaction has been executed successfully. Moreover the proxy has waited for the block to be confirmed so that the state change is visible to the Raiden node.

When the proxy raises RaidenUnrecoverableError, it means that there is a bug in the client codebase or in the smart contracts.

When the proxy raises RaidenRecoverableError, it might mean:

  • somebody else posted another transaction that altered the chain state in a conflicting way.
  • a third party smart contract behaved weirdly.

The proxy tries hard to determine whether the problem is in the Raiden codebase (client or smart contract), but ultimately, if the proxy is not sure, it raises RaidenRecoverableError.

A Guide for Implementing Proxies

When you implement proxies, the best documentation to follow is the source of TokenNetwork proxy.

Sometimes precondition checks are impossible because the specified block is too old (pruned in the Ethereum client). In this case, the precondition check can be skipped.

Checks before the gas estimation should raise one of the following exceptions:

  • BrokenPreconditionError when the specified block has an unsuitable chain state for the call.
  • RaidenValidationError when the given argument is invalid regardless of the chain state.
  • Instead of RaidenValidationError, you can also raise a special exception that you derive from RaidenError, but make sure you catch it. The typical use case is to provide a nice HTTP status number.

When you implement a new method of a proxy, consider refusing the string "latest" as the block identifier. Usually passing "latest" as a block identifier to a proxy method poses a possibility of BrokenPreconditionError. The method can raise a ValueError when "latest" is passed as the block identifier. Or, you might want to introduce a new type so that mypy complains against using "latest" as the block identifier.

Mind the number of RPC calls you are making. Instead of fetching a block number and then the block hash, there is usually a way to get the whole block in a single RPC call. When you post multiple RPC calls, you introduce more race conditions and performance bottlenecks.

Changelog

0.200.0-rc2 2019-11-25

  • [Feature]: Update WebUI to version 0.10.1 https://github.com/raiden-network/webui/releases/tag/v0.10.1
  • [Feature] #5053: Make mediation fees non-negative by default. This fixes some counter-intuitive behaviour.
  • [Feature] #5217: Fully support infura as an underlying ethereum rpc node.
  • [Feature] #5278: Always use private rooms in the matrix transport.
  • [Feature] #5050: Raiden’s argument –debug-logfile-name has been renamed to –debug-logfile-path to better reflect the argument’s function.
  • [Bug] #4835: Fix etherscan sync by passing user-agent in the HTTP request. The request was failing because etherscan is protected by Cloudflare.
  • [Bug] #5055: Fix withdraw messages deserialization when the messages are queued in queueids_to_queues.
  • [Bug] #5064: Display a user-friendly error message when the PFS info request fails.
  • [Bug] #5050: Raiden now works on OSX Catalina. Debug logfile is no longer written in the current directory.

0.200.0-rc1 2019-08-12

  • [Feature]: Added a new api endpoint /api/v1/version to query the raiden version via the Rest API.
  • [Feature]: Update WebUI to version 0.10.0 https://github.com/raiden-network/webui/releases/tag/v0.10.0
  • [Feature] #4102: Display progress during syncing the blockchain.
  • [Feature] #4653: Allow setting per token network flat mediation fee from CLI.
  • [Feature] #4653: Allow setting per token network flat fees from CLI
  • [Feature] #4697: lock_timeout can be provided when making a payment.
  • [Feature] #4654: Define imbalance fees relative to channel balance.
  • [Feature] #4731: Setting fee defaults for Alderaan
  • [Feature] #4751: Add Fees to internal Routing
  • [Feature] #4815: Exclude direct transfers from fees
  • [Feature] #4844: Formalize fee calculation
  • [Feature] #4858: Add check for bound in med fee calculation
  • [Feature] #4860: Update per-channel proportional fee calculation
  • [Feature] #4917: Added documentation on using Raiden for atomic swaps.
  • [Feature] #4976: Geth users no longer need to activate the special txpool RPC api when starting their geth node.
  • [Feature]: The lowest supported geth version is now 1.8.21.
  • [Feature] #4905: Added API parameter to the PATCH channel endpoint to update channel’s reveal timeout.
  • [Bug] #4446: Fix assertion error in ‘calculate_imbalance_fees’
  • [Bug] #4561: Limit and offset should now work properly in the payment API event queries.
  • [Bug] #4560: Formatting of timestamp fields on the API should follow ISO8601.
  • [Bug] #4685: Invalidate a withdraw transaction on restart if the channel is closed.
  • [Bug] #4762: Properly check the withdraw expiration on the TokenNetworkProxy. This gives a better error message to the users and prevents a corner case error.
  • [Bug] #4835: Catch undefined med fee inside the sate machine

0.100.5-a0 2019-08-12

  • [Feature]: Update WebUI to version 0.9.2 https://github.com/raiden-network/webui/releases/tag/v0.9.2
  • [Bug] #4502: Fix a Raiden crash related to routing feedback
  • [Bug] #4348: Fix wrong calculation of balance field of channel information when tokens are locked in payments
  • [Bug] #4498: Raiden now waits for synchronization with the blockchain events before finishing its startup and opening the API.

0.100.5-dev0 2019-07-30

  • [Feature]: Update WebUI to version 0.9.1 https://github.com/raiden-network/webui/releases/tag/v0.9.1
  • [Feature] #4457: Raiden now checks the version of the ethereum node at startup and if it is not supported quits with an appropriate message.
  • [Bug] #4301: Providing an endpoint argument without a port no longer leads to a crash.
  • [Bug] #4377: The client now sends proper capacity updates to the PFS.
  • [Bug] #4373: Fix a deserialization error for imbalance penalty
  • [Bug] #4378: Fix json decoding error that could lead to a crash.
  • [Bug] #4383: Fix locked transfer not being sent due to global queue handling.
  • [Bug] #4446: Fix problems with the calculation of mediation fees

0.100.4 2019-06-08

  • [Feature] #1498: Implement on-chain channel withdraw
  • [Feature] #3303: Use direct channels for payments when possible, without asking PFS
  • [Feature] #3754: Publish mediation fee infos to PFS
  • [Feature] #3863: Implement permissive source routing
  • [Feature] #3894: Drop support for UDP transport
  • [Feature] #4062: Use PFS requested fee instead of client max fee
  • [Feature] #4088: Check PFS info about registry address, prevent use of a PFS that doesn’t support the current network.
  • [Feature] #4095: Prevent Raiden from sending IOU to PFS when fee is 0
  • [Bug] #3778: Fix handling of pruned blocks in proxies.
  • [Bug] #4036: Initiator should check the state of the partner nodes

0.100.3 2019-05-22

  • [Feature] #3461: Static PFS payment for provided routes through the user deposits contract. Only usable if Raiden is run in development environment
  • [Feature] #3462: Static Monitoring service reward through user deposits contract. Only usable if Raiden is run in development environment
  • [Feature] #3464: Raiden will warn users about insufficient user deposit funds (If monitoring service or path-finding service are enabled and used).
  • [Feature] #3697: Make sure a token implements the ERC20 interface when registering a new token network. In this case, totalSupply function existence is implemented
  • [Feature] #4043: Update raiden-contracts to 0.19.0 with Görli Testnet support
  • [Bug] #3566: Handle cases where Raiden tries to query blocks which are old and pruned by the blockchain client (Geth & Parity)
  • [Bug] #3567: Resolve an issue in route filtering where the partner’s network state is taken into account when choosing a route
  • [Bug] #3687: Fix startup initialization issue which caused Raiden to crash on private chains
  • [Bug] #3832: Fix Raiden startup when a previous run aborted during migrations
  • [Bug] #3856: Handle pruned blocks during settle/unlock when requesting on-chain state, use latest if block is pruned
  • [Bug] #3874: Fix invalidation of a batch-unlock transaction in case a similar transaction was already sent/mined by channel partner
  • [Bug] #4024: Fix clearing a channel state iff all unlocks are done by channel participants

0.100.3-rc3 2019-04-15

  • [Feature]: Add support for Görli testnet in Raiden.

0.100.3-rc1 2019-03-29

  • [Feature] #3425: Update raiden-contracts package to version 0.9.0
  • [Feature] #3318: allow secret and/or hash with payment request
  • [Feature] #2436: Add an API endpoint to list pending transfers
  • [Feature] #3467: Raiden now chooses a PFS from a provided registry. Also added a new argument --routing-mode to configure the routing mode to either be PFS or BASIC.
  • [Bug] #3475: Properly check async_result in rest api payments
  • [Bug] #3567: Properly check handling offline partners
  • [Bug] #3558: Raiden will no longer crash if starting with a fresh DB due to the ethereum node queries timing out.

0.100.2 2019-02-21

  • [Bug] #3529: Do not crash raiden if a SecretRequest message with invalid channel identifier is received.
  • [Bug] #3528: Do not crash raiden if a LockExpired message with invalid channel identifier is received.

0.100.2-rc4 2019-02-04

  • [Feature] #2793: Faster restarts, transactions are sent in parallel on restarts.
  • [Feature]: Set python 3.7 as a minimum python version requirement to run Raiden.
  • [Feature] #3317: Return the secretHash and the Secret as part of payment response
  • [Bug] #2974: Alarm task is not longer blocking until transactions are mined.
  • [Bug] #3369: Fix high CPU usage when the raiden node is idle.
  • [Bug] #3380: Connection manager no longer attempts deposit if per partner funds are zero.

0.100.2-rc3 2019-01-25

0.100.2-rc2 2019-01-11

0.100.2-rc1 2019-01-04

  • [Feature] #3217: If channel is already updated onchain don’t call updateNonClosingBalanceProof.
  • [Bug] #3190: Prevents removal of initiator task when one of the transfers is expired.
  • [Bug] #3201: Workaround for gas price strategy crashing Raiden with an Infura ethereum node.
  • [Bug] #3121: If the same payment identifier is reused avoid a specific race condition that can crash Raiden.
  • [Bug] #3211: If using parity and getting the already imported error, attempt to handle it and not crash the client.
  • [Bug] #3216: If coming online after partner closed channel don’t try to send updateNonClosingBalanceProof twice and crash Raiden.

0.100.1 2018-12-21

  • [Bug] #3146: If a refund transfer is received and there are no other routes, keep the payment task so that the channel does not hang when mediator sends a LockExpired.
  • [Bug] #3170: If the same refund transfer is received multiple times, the mediator state machine will reject subsequent ones rather than clearing up the mediator task.
  • [Bug] #3175: If Github checking of latest version returns unexpected response do not let Raiden crash.
  • [Bug] #3179: Properly process a SendRefundTransfer event if it’s the last one before settlement and not crash the client.
  • [Bug] #3183: If as initiator our nodes receives a RefundTransfer then do not delete the payment task at the lock expiration block but wait for a LockExpired message. Solves one hanging transfer case.
  • [Bug] #3193: Channel balance shown to the user now takes locked amount into account.
  • [Bug] #3196: If our partner updates onchain with earlier balance proof find the event in the DB and properly perform the unlock onchain.
  • [Bug] #3171: Do not crash raiden if the Matrix server is offline when joining a discovery room.

0.19.0 2018-12-14

  • [Feature] #3157: Change REST api version prefix from 1 to v1.
  • [Bug] #3135: In development mode if more than 100 * (10^18) tokens are deposited then raiden no longer crashes.
  • [Bug] #3152: If the onchain unlock has already been mined when we try to send the transaction don’t crash Raiden.
  • [Bug] #3153: If a non-contract address is given for token_address in the channel open REST API call, the client no longer crashes.

0.18.1 2018-12-07

  • [Bug] #3093: Getting raiden payment history will no longer crash raiden for failed sent payment events.
  • [Bug] #3094: Raiden will now properly return payment failure and no longer hang if a payment times out due to a lock expiration.
  • [Bug] #3103: Fixes a bug in matrix which prevented retries of messages.
  • [Bug] #2779: Fixes a long standing bug that could cause payments to hang indefinitely.

0.18.0 2018-11-30

  • [Bug] #3046: Sync with the matrix server using the last known sync token. This solves the issue of missing messages during restart as previously only the last 10 were fetched.
  • [Bug] #3054: Client will now reject any signatures with v not in (0, 1, 27, 28)
  • [Bug] #3091: Client will no longer accept secret of 0x0 or secrethash keccak(0x0).

0.17.0 2018-11-16

  • [Bug] #2931: Fixes serialization of state changes for refund transfers, allowing it to be used for unlocks.
  • [Bug] #3001: Don’t delete payment task when receiving invalid secret request.
  • [Bug] #2932: Node will no longer crash if it mediated a transfer and the channel cycle for mediation has completed.
  • [Bug] #3022: Reject REST API channel opening with an error if there is not enough token balance for the initial deposit.
  • [Bug] #3013: Encode all integers before saving to the sqlite database
  • [Bug] #3035: Registering a token twice should now return a proper error.

0.16.0 2018-11-09

  • [Feature] #2962: Check that the ethereum node has all required json rpc interfaces enabled when Raiden starts. If not fail with a proper error.
  • [Feature] #2946: Do not show full block information in the INFO logging message.
  • [Bug] #2923: Fix a race with multiple calls circumventing the gas reserve check.
  • [Bug] #2918: Fixed a synchronization problem, where a node would send invalid balance proofs.
  • [Bug] #2938: Don’t cleanup mediator if the transfer could not be forwarded. Could lead to stuck channels.
  • [Bug] #2934: Don’t send unecessary register secret transactions.
  • [Bug] #2951: Fallback to eth_getTransactionCount if there is no api to get the next available nonce.
  • [Bug] #2921: Properly estimate gas cost of transactions so that we have a more reasonable minimal amount of ETH required to run Raiden.
  • [Bug] #2973: Introduce special handling of infura endpoints so that the old getTransactionCount is used.
  • [Bug] #2963: Fixes an overflow issue with the hint of the join network dialog.

0.15.1 2018-11-03

  • [Bug] #2933: Raiden can now recover from crashes/restarts when there are pending onchain transactions.

0.15.0 2018-10-27

  • [Feature] #2858: Changed contract address argument names to be consistent with the names of the contracts in the contracts repository.
  • [Feature] #2857: Respect the --environment-type for private chain setup.
  • [Feature] #2909: Add explicit flag –unrecoverable-error-should-crash to control UnrecoverableError crashing behaviour.
  • [Bug] #2894: Raiden will no longer miss confirmation blocks at restart and will emit the block state change only for confirmed blocks.
  • [Bug] #2905: Mediator task must wait for the expired message, not just for the lock to expire, otherwise the channel will be unsychronized.

0.14.0 2018-10-20

  • [Feature] #2752: Renamed --network-type cli option to --environment-type.
  • [Bug] #2664: Raiden node will now wait for 5 block confirmations before processing a given transaction.
  • [Bug] #2794: UnlockPartialProofState does no longer raise AttributeError when accessing lockhash.
  • [Bug] #2813: Fixed swapped message and payment id, which caused problems on node restart.
  • [Bug] #2827: Fixed a typo in the handle_secretrequest function.
  • [Bug] #2449: Only polling events from confirmed blocks to prevent conflicts with reorgs.
  • [Bug] #2836: Contract version check now works for any deployed contract version.
  • [Bug] #2835: Incorrectly accepting a RemoveLockExpired is no longer possible
  • [Bug] #2845: Properly update local state balance proof during a lock expiration.

0.13.1 2018-10-15

  • [Bug] #2776: Properly include per chain contract json data in the created binaries
  • [Bug] #2784: Raiden node is no longer left with a partial update if it crashes during polling.

0.13.0 2018-10-12

  • [Feature] #2708: Add –showconfig CLI flag which dumps all configuration values that will control Raiden behavior.
  • [Feature] #2713: Added the protocol version in the Ping message.
  • [Feature] #2764: Support pre-deployed contracts on Kovan and Rinkeby testnets
  • [Bug] #2720: A lock expired message must be considered invalid if the block in which the lock expired has not been confirmed.
  • [Bug] #2730: Refuse to send a transfer and ignore it during receiving, if its secret is already registered on-chain.
  • [Bug] #2662: Fix wrong deserialization of snapshots in special cases.
  • [Bug] #2746: Refuse to process a payment with an identifier already in use for another payment, and return a 409 Conflict in that case.

0.12.0 2018-10-05

  • [Feature] #2568: Validate the state changes for the Delivered and Processed sender.
  • [Feature] #2699: Add /channels/<token_address> REST-API endpoint to query all node’s channels for a specific token.
  • [Bug] #2630: If a smaller deposit than total_deposit is given to the deposit RPC call then return 409 Conflict and not 200 OK.
  • [Bug] #2655: Raiden node will now properly crash if communication with the ethereum node is lost.
  • [Bug] #2676: Return an error if an invalid joinable_funds_target value is provided to the connect endpoint.
  • [Bug] #2567: Increase default channel reveal timeout to 50 blocks.

0.11.0 2018-09-28

  • [Feature] #2600: Improve logging for on-chain transactions
  • [Bug] #2535: Registering a secret on-chain for a locked transfer is now checked if it was received before the lock has expired.
  • [Bug] #2577: Small logging improvements
  • [Bug] #2602: On-chain secret reveal forces off-chain reveal
  • [Bug] #2603: Prevent crash in case of invalid Matrix server response
  • [Bug] #2609: Allow numeric network ids in the config file
  • [Bug] #2566: Warn the user about older existing database versions
  • [Bug] #2631: Prevent excessive state replay on restart

0.10.0 2018-09-21

  • [Feature] #2470: Add a main/test network switch enabling or disabling specific functionality depending on the network type.
  • [Feature] #2517: Increase the time a notification stays visible on the webui.
  • [Bug] #2414: If partner uses our old balance proof on-chain, the raiden client will now recover it from the WAL and properly use it on-chain.
  • [Bug] #2449: Fix a race condition when handling channel close events.
  • [Bug] #2501: Adds a matrix.private_rooms config to communicate only through private rooms in Matrix
  • [Bug] #2507: Fix a security issue where an attacker could eavesdrop Matrix communications between two nodes in private rooms
  • [Bug] #2512: Add descending order by block_number as default for blockchain events on webui.
  • [Bug] #2515: Adds validation for settle timeout against reveal timeout when opening a channel from the webui.

0.9.0 2018-09-14

  • [Feature] #2460: Pinned depedencies versions, builds are now reproducible and build artifacts won’t break because of downstream dependencies.
  • [Feature] #1473: Add gas price strategies that adapt the gas price to the network conditions.
  • [Feature] #2252: Adds payment history page to the webui.
  • [Feature] #2307: Matrix discovery rooms now are decentralized, aliased and shared by all servers in the federation
  • [Feature] #2287: Internal events now have timestamps.
  • [Bug] #2431: Do not crash on recoverable errors during settlement
  • [Bug] #2427: Fix a bug crashing the client when an unlock event for our address is seen on the chain
  • [Bug] #2419: Fix Matrix transport crash due to inability to decode events
  • [Bug] #2439: Return properly filtered results from the API payments event endpoint
  • [Bug] #2370: Fixes a few issues with the token amount input.
  • [Bug] #2437: Fix a bug where neighbors couldn’t communicate through matrix after restart
  • [Bug] #2453: Connection manager will no longer be stuck if there are no available channel partners
  • [Bug] #2367: Token network selection dropdown will not filter out not connected networks.
  • [Bug] #2461: For received payments events filter based on the initiator.

0.8.0 2018-09-07

  • [Feature] #2340: Add --accept-disclaimer argument to bypass the experimental software disclaimer.
  • [Feature] #2363: Add copy functionality for addresses shown on the webui.
  • [Feature] #862: Switch WAL serialization format to JSON in order to facilitate for WAL upgradability.
  • [Feature] #1894: We now start having nightly releases found here: https://raiden-nightlies.ams3.digitaloceanspaces.com/index.html
  • [Bug] #2336: Fixes webui wallet page not loading data due to error.
  • [Bug] #2283: Fix API server Internal server error at token deposits.
  • [Bug] #2291: Adds EIP55 address validation to webui address inputs.
  • [Bug] #2362: Renamed wallet to tokens in the webui.
  • [Bug] #2356: Create a new database per token network registry.
  • [Bug] #2373: Include events for received payments in the payment events API endpoint.

0.7.0 2018-08-31

  • [Feature] #2225: Using a constant expiration for lock, making sure that on-chain unlocks are atomic.
  • [Feature] #2285: Request user acknowledgement for the experimental software disclaimer.
  • [Feature] #2251: Add webui support for switching token input between decimal and integer values.
  • [Feature] #2296: Gracefully handle malformed messages
  • [Bug] #2170: Removed block number from internal events and rearranged REST API debug endpoints
  • [Bug] #2264: Notification fonts are now aligned with the rest of the WebUI.
  • [Bug] #2278: Fixes leave network button request.
  • [Bug] #2277: Fixes sorting by balance for tokens and channels.
  • [Bug] #2284: Fixes balance notifications showing for wrong channels.
  • [Bug] #2282: Fixes internal webui error that would not propagate channel updates.
  • [Bug] #2275: Adds scientific notation for really small fractions when displaying balances.
  • [Bug] #2293: Initiator had the payment and message identifiers swapped.

0.6.0 2018-08-24

  • [Feature] #2253: Make addresses in REST logging user readable
  • [Feature] #2134: Database is now versioned and the DB directory path now uses that version
  • [Feature] #2192: Show notification on the WebUI when transfer is received or when channel is opened
  • [Feature] #2034: Update WebUI’s design
  • [Bug] #2197: WebUI now handles token decimals
  • [Bug] #2233: Fix MatrixTransport exception for invalid user displayname
  • [Bug] #2176: Expose total_deposit in the Rest API and fix depositing in the WebUI
  • [Bug] #2198: Fix building of the WebUI in the linux bundle.

0.5.1 2018-08-17

  • [Feature] #439: Limit the number of pending transfers per channel.
  • [Feature] #1898: Improve the event formatting in the REST API
  • [Bug] #2111: Correctly update network graph for non-participating channels
  • [Bug] #2164: Update echo node to work with the new endpoint for channel history

0.5.0 2018-08-10

  • [Feature] #1950: Breaking change: Better transaction handling on restart. This change breaks binary compatibility with the previous WAL.
  • [Feature] #1998: Add a strategy to make sure that the account Raiden runs on always has enough balance to settle all channels. No new channels can be openend when no sufficient balance for the whole channel lifecycle is available.
  • [Feature] #2084: Rename the /transfers/ endpoint to /payments/.
  • [Feature] #1949: Add an endpoint to query the payment history.
  • [Feature] #682: Store a Snapshot of WAL state as recovery optimization.
  • [Feature] #2090: Rename transfers to payments in the webui.
  • [Bug] #2027: Raiden should now be able to connect to Infura.
  • [Bug] #2125: Show proper error message for invalid tokens on /connections.
  • [Bug] #2149: Don’t crash if reusing same payment identifier for a payment

0.4.2 2018-08-02

  • [Feature] #1844: Log debug output to a file to make debugging of problems easier.
  • [Feature] #2011: Add a --disable-debug-logfile argument to disable the always on debug file if required by the user.
  • [Bug] #1994: Starting Raiden with a corrupt database will now throw a proper error instead of crashing with an exception.
  • [Bug] #1996: Providing contracts addresses via the CLI that either have no code or contain unexpected code will now result in an error and not crash Raiden.
  • [Bug] #1817: Change the webui error message when the token registration fails.
  • [Bug] #1821: Show a better error message when channel creation fails.
  • [Bug] #2039: Return error for negative deposits via REST API
  • [Bug] #2004: Show a webui error when JSON-RPC requests fail.

0.4.1 2018-07-27

  • [Feature] #1825: Added periodical update notification and security releases checks.
  • [Bug] #1975: Fix balance hash generation for zero transfers and empty locksroot
  • [Bug] #1899: Print proper error without throwing exception if no accounts are found in the keystore
  • [Bug] #1911: The syncing message is now printed properly and does not repeat across the screen
  • [Bug] #1902: Check for ethnode connection at start and print proper error if Raiden can not connect
  • [Bug] #1869: Various matrix improvements. Prevent DOS attacks, and race conditions that caused client crashes. Require peers to be present to send message to them. Improves user discovery across Matrix federation.
  • [Bug] #1916: Return E409 on two concurrent conflicting channel deposits
  • [Bug] #1960: Return E409 when trying to open a channel for a token that is not registered
  • [Bug] #1969: Return E409 if negative initial_funds are given to the connect endpoint
  • [Bug] #1883: Properly update menu state when channel state changes on webui
  • [Bug] #1976: Remove the ability to removedb. User should not be able to easily delete local state.
  • [Bug] #1897: Limit number of concurrent matrix connections so that raiden client does not crash.
  • [Bug] #1879: Leaving a token network should now work. Also removed the only_receiving parameter from the leave endpoint

0.4.0 2018-07-19

  • [Feature] #1328: Use separate database directory per network id. This is a breaking change. You will need to copy your data from the previous directory to the new network id subdirectory.
  • [Feature] #1195: Improve AccountManager error handling if keyfile is invalid.
  • [Feature] #1518: Update installation docs with Homebrew tap and update Homebrew formula on release.
  • [Feature]: Restartability in case of a proper shutdown of the Raiden node.
  • [Feature]: Smart contracts refactoring for readability, gas costs and new features.
  • [Feature]: New Matrix transport protocol.
  • [Feature]: Considerable codebase refactoring.
  • [Bug] #1237: Inform the user if geth binary is missing during raiden smoketest.

0.3.0 2018-02-22

  • [Feature] #921: Add /api/1/connection API endpoint returning information about all connected token networks.
  • [Feature] #1022: Include an errors field in all unsuccessful API responses.
  • [Feature] #1010: Add amount and target to EventTransferSentSuccess event.
  • [Feature] #670: Block raiden startup until ethereum node is fully synchronized.
  • [Feature] #1037: Add show_default to CLI options.
  • [Feature] #507: Making python’s channels crash resilient (recoverable). Note, this is a breaking change, the serialization format of channel objects changed to a WAL compatible representation.
  • [Feature] #1038: Introduce an upper limit for the settle_timeout attribute of the netting channel.
  • [Feature] #1097: Added --gas-price command line option.
  • [Feature] #1093: Reconnect raiden to ethereum node after disconnect.
  • [Feature] #1015: Added macOS compatibility and binary releases.
  • [Feature] #87: Update raiden to use Python 3 and the latest version of pyethereum.
  • [Feature] #1230: Unless specifically provided gas price and gas limit are now dynamically calculated from the eth_gasPrice() and latest blocks limit respectively.
  • [Bug] #1011: Remove settled attribute from the NettingChannel smart contract.
  • [Bug] #870: User selectable NAT traversal.
  • [Bug] #450: Removed block_number from contracts events, using block_number from block on which it was mined.
  • [Bug] #1049: Make raiden byzantium compatible by no longer relying on estimateGas.
  • [Bug] #1044: Rename /connection API endpoint to /connections for consistency.
  • [Bug] #1138: REST and Python API close did not work if a transfer was made.
  • [Bug] #1261: REST API now returns json error for invalid endpoints.
  • [Bug] #1224: Fix internal server error on REST endpoint /events/tokens/ for non-existing tokens.
  • [Bug] #1217: Correctly decode network events in the REST API.
  • [Bug] #1273: Don’t crash when using the --nat=ext:IP command line option.

0.1.0 2017-09-12

Raiden Config File

Raiden supports reading configuration parameters from a configuration file.

Location

The default location is <datadir>/config.toml (where datadir defaults to ~/.raiden).

It is possible to override the datadir in the config file but please be aware that at that point the config file will already have been loaded from the default location and therefore won’t be re-read from the ‘new’ datadir.

Precedence

The precedence order in which configuration option values are applied is as follows (high to low):

  1. Option given on the command line
  2. Option read from the config file
  3. Option default value (as seen in the output of raiden --help)

Format

The config file uses the TOML format.

Option names may be quoted unless they contain punctuation in which case they must be. Values except numbers must always be quoted. Both single or double quotes are acceptable.

Lines starting with a # are comments.

Parameter Naming

All parameters that can be given as command line options are also settable in the config file. The name corresponds to the long option name without the leading double dash (--). For example the CLI option --password-file would be called password-file inside the config file.

The only option deviating from this scheme is the logging configuration which is explained below.

Logging Configuration

Raiden allows configuration of the logging system using a concise syntax on the command line. Inside the configuration file this is split out into a somewhat more expanded syntax.

The logging configuration is placed inside a section called [log-config] which each following lines key representing the logger name and the value the log level.

Example:

# CLI:
--log-config ':debug,raiden.network:info'

# Config file equivalent:
[log-config]
"" = "debug"
"raiden.network" = "info"

Trademark Attributions

  • MacOS® is a trademark of Apple Inc., registered in the U.S. and other countries.
  • Linux® is the registered trademark of Linus Torvalds in the U.S. and other countries.

Raiden ADRs

The Raiden project utilizes the Architectural Decision Records (ADR) system to capture the important architectural decisions made during development along with their context and consequences.

The following is an overview of the Raiden ADRs

Contents

Better testing framework for the entire Raiden suite (client, MS and PFS)

  • Status: proposed
  • Deciders: @czepluch, @stefante
  • Date: 2019-11-03 (last updated)
Context and Problem Statement

@rakanalh @karlb @LefterisJP and @czepluch had a meeting to discuss testing moving forward. More precisely how we can test the client together with the MS and PFS. Most of the discussion was focused on whether it makes sense to continue to support the scenario player and update it to support the third party services. Currently the SP is good for testing happy cases, but it is not easy to debug when errors occur and it doesn’t allow for introspection in the same way as pytest does. On the other hand, the current way that the integration tests work by spinning up a new blockchain per test is very inefficient. It’s also quite intimidating for people new to the project or less experienced to grasp how the integration tests work. Based on these short comings of the current two solutions, we discussed what could be done to create a setup that solves both problems.

Decision Drivers
  • Lack debug options for scenario player
  • Slow to spin up a fresh blockchain for every integration test
  • Duplicated tests between integration tests and SP
  • Make it easier for people new to the project or less experienced people to write tests
  • Have a way of testing all Raiden components
Considered Options
  • Option1: New repo that integrate the client with the MS/PFS with rewritten fixtures that only spins up one blockchain per test suit session. Link to meeting discussing this
  • Option2: Stick with things as they are and focus on adding functionality to the scenario player
Decision Outcome

TBD

Pros and Cons of the Options
[option 1]
  • Good, because writing what we currently call integration tests will be easier
  • Good, because there will be one blockchin spun up per testing session instead of per test
  • Good, because we will use pytest and make debugging easier than it currently is with the SP
  • Good, because we will enforce a “language” that interacts with the API server instead of python functions
  • Good, because we don’t need to maintain the SP anymore
  • Bad, because it will be quite some effort to rewrite all the fixtures to use one blockchain per session
[option 2]
  • Good, because we don’t have to create a new repo and rewrite the fixtures
  • Bad, because we have to maintain the SP and write scenarios
  • Bad, because the SP offer limited flexibility
  • Bad, because debugging scenarios that fail can be very difficult
  • Bad, because it’s difficult to get started writing integration tests at the moment

Raiden Team - Git Workflow

  • Status: proposed
  • Deciders: @lefterisjp, @hackaugusto, @konradkonrad, @rakanalh
  • Date: 2019-04-15
Context and Problem Statement

The current workflow team members in the Raiden team currently use is as simple as pick issues, create a respective branch for that issue and present a PR once the bug/feature is fixed/implemented.

This newly created branch will be merged into master regardless of what category the implementation falls into. There are currently 3 categories that a single PR can have: 1. Bug fix 2. Feature 3. Enhancement / Refactorings

Right now, all of these branches which can have any combination of those 3 categories will be merged into the master branch once it undergoes code review. However, we have come to realize that merging everything into master will cause our code to have a mixture of: 1. The bug fixes that we should release to the public. 2. Features that move Raiden forward into integrating with the PFS / MS services (which are under heavy development) 3. Code refactorings that address certain technical debts the team is constantly finding issues in, and/or is annoying and hard to work with.

The set of problems that the team finds in this approach is: 1. It is getting harder to make faster release cycles provided that some new code paths might be executed which are intended to support a new feature that Red-Eyes users should not / are not supposed to use. 2. Large issues are broken into smaller, self-contained PRs which move Raiden forward towards resolving the issue collectively but not individually. The justification for this is to have smaller PRs to review which is a huge advantange. However, this could potentially leave us with a state where the master branch is broken.

Decision Drivers
  • Increase the velocity of progress
  • Pave the way for faster mainnet release cycles
  • Have certain recent checkpoints in the project’s codebase where new features / functionalities are known to be stable.
Considered Options
Original proposal

After discussing this with @hackaugusto, @LefterisJP and @konradkonrad, we realized that we need to come up with a better way to separate our workflow for bug fixing from the ones for introducing new features and refactoring of the code base.

So, we seem to agree on using parts of the git-workflow where: 1. A develop branch is introduced. 2. The master branch will be our “production-ready” branch. 3. When a bug is reported, the assignee of the issue will branch of the latest master, provide a fix which will be merged into both master and develop. 4. The develop branch will contain all the work we do for new features and code refactorings. 5. Once any code changes are merged to master, develop should be merged on top of the latest master to ensure that our fixes are also residing in the develop branch in case any team member is working on the same code base.

The Pros of this new workflow: 1. Resolving bugs, merging them to master and instantly creating a release which contains the new bug fix(es) 2. Removing the worry about a broken master branch because the develop branch is going to contain all the potential breaking changes whose issues will be resolved separately. 3. Enable separate test configurations where the master would run tests on CI with production settings while develop runs with development configurations.

The Cons of this approach: 1. Rebasing develop should some how be automated as soon as any changes are merged into master, or otherwise if both branches diverge alot from each other, this could be a pain to resolve all the conflicts and get the develop branch back in shape. 2. It’s a new workflow so team members have to get used to this and map what they’re working on to the destination branch on which their implementation will land.

“Successful branching model”

It was suggested to follow The Successful git branching model which is quite similar to the original proposal.

Decision Outcome

It was decided to follow the “Successful git branching model” option which is conveyed by the following:

https://user-images.githubusercontent.com/44281/56030116-5cdd8680-5d1c-11e9-8de8-d3fb61ad7d8e.png

Where:

  • master is maintained to be production-ready branch.
  • develop is the target branch for new features.
  • New feature branches are merged into develop.
  • Bug fixes are merged into both develop and master.
  • Nightly builds are created on latest develop.
  • If a certain nightly is to be released, a release branch is created to include changes required for creating that release such as bumpversion. Bug fixes specific to a certain release would be merged into that release branch.
  • Once a mainnet release is out, develop is merged into master and the process is restarted.
  • Provided we follow the sematic versioning scheme, every bug fix should be rolled out with a new minor version.

[Python Package Dependency Management]

  • Status: proposed
  • Deciders: TBD
  • Date: 2019-06-18
Context and Problem Statement

We as a team have been struggling with dependency management for a while now. Our current approach (‘manual’ requirements + pip constraints files) is cumbersome and error prone especially in case of dependency package version upgrades. Generally better tool support was seen as a solution to the issue.

Decision Drivers
  • The Process of upgrading a Python package dependency is an error prone, cumbersome and manual process
  • There were multiple occasions of failed dependency upgrades leading to failed CI builds and downstream incompatibilities
Considered Options
Decision Outcome

pip-tools was chosen after a discussion between @hackaugusto, @konradkonrad, @palango and @ulope as it currently seems to be the least disruptive and most well-used tool available. Medium term poetry might become the preferred solution but didn’t appear mature enough currently.

Pros and Cons of the Options
pip-tools

Currently the most mature tool.

  • Pros
    • Small scope, only manages dependencies
    • (Relatively) easy to understand operation model
    • Stable with a long history of being maintained
    • Better dependency solver than pip (which doesn’t have one)
  • Cons
    • No built-in support for dependencies between various requirement types (e.g. prod, dev). Requiring a custom wrapper tool.
    • CLI isn’t very intuitive
poetry

Looks to be a good candidate to switch to in the medium future.

  • Pros
    • Very polished cli
    • Handles the complete package life-cycle including optional venv management
    • Proper dependency solver
  • Cons
    • Still very new with some bugs and some usage types not supported (yet)
    • Very much a departure from the established ‘way of doing things’
    • Dependency resolution can currently be very slow
pipenv

Similar in concept to poetry, yet seems to be not a stable tool to build upon.

  • Pros
    • ?
  • Cons
    • Also a very new tools
    • Many reports of arbitrary breakage with minor upgrades
    • Dependency resolution appears not to be stable

Withdraw & Expiry

Status: implemented Deciders: @konradkonrad @palango @hackaugusto @rakanalh Date: 2019-07-03

Context and Problem Statement

Withdraw functionality was introduced into Raiden to enable users to withdraw funds from their open channels into their accounts. The implemented flow works as follows:

  1. Alice initiates the withdraw by dispatching ActionInitWithdraw with a monitonic total withdraw value.
  2. Alice sends a signed WithdrawRequest message to its partner to agree on the new total withdraw.
  3. Bob receives the withdraw request, validates it and replies with a signed WithdrawConfirmation message to Alice.
  4. Alice receives the withdraw confirmation, validates it and uses signatures from step (2) and step(3) to send an on-chain transaction to withdraw the funds.

Here, a problem arises when Bob is unavailable or is not cooperative. In this case, Alice would have sent a withdraw request, locked part or all of its deposited amount for withdraw and no confirmation was received from Bob. This will lead to Alice not being able to use the locked funds for withdraw until Bob replies. In the case of Bob not being cooperative on this withdraw request, Alice’s locked withdraw funds are unavailable indefinitely until the channel is closed.

Considered Options

  • Option 1: Alice could close the channel with Bob. In this case, Alice gets back the funds it originally locked for withdraw. One downside of this approach is forcing the user to close the channel just to be able to unlock the withdraw funds. However, the counter-argument for this downside is a question of whether the user would want to have an open channel with a non-cooperating partner node.
  • Option 2: Implement withdraw expiry messages where Alice calculates a block at which the withdraw request expires. Bob will have to be aware of this expiry option and be able to react to a WithdrawExpired message which will clear the expired withdraw state for the partner. This approach resolves the issue of having the locked funds indefinitely or until the channel is closed with a non-cooperating partner node because once the withdraw request expires, Alice will remove the expired total withdraw state and locked withdraw will be unlocked.

Decision

Option 2 of WithdrawExpiry has the disadvantage of adding a collection of new messages to the protocol, which could be seen as further complication of the protocol. However, it has the advantage that amounts locked for withdraw can be unlocked and used for transfers instead in case of an expired withdraw attempt.

Though Option 1 can be argued that its much simpler, the benefit of unlocking funds previously locked for withdraw was seen as more viable solution even with the added complexity.

Examples of Option 2

Simple:
  • Alice’s balance = 100 tokens
  • Alice requests a withdraw of 50 tokens. In this case, usable balance of Alice is 50 (assuming it did not send/receive transfers to/from Bob). total_withdraw=50.
  • Bob does not confirm with withdraw.
  • Alice sends Bob a WithdrawExpired message. Alice only had 1 pending withdraw state of 50. Before sending WithdrawExpired, Alice clears the expired withdraw state and total_withdraw is set to 0 because that is the only withdraw state that was requested.
Complex:
  • Alice’s balance = 100 tokens

  • Alice requests a withdraw of 10 tokens. In this case, usable balance of Alice is 50 (assuming it did not send/receive transfers to/from Bob). total_withdraw=10.

  • Alice requests a withdraw of another 10 tokens. total_withdraw=20.

  • Alice requests a withdraw of another 20 tokens. total_withdraw=40.

  • Alice withdraw states look as follows:

    [
      {
        "total_withdraw": 10,
      },
      {
        "total_withdraw": 20,
      }
      {
        "total_withdraw": 30,
      }
    ]
    
  • Bob does not confirm any withdraw.

  • Alice sends Bob a WithdrawExpired message for the first withdraw request which had a total_withdraw=10. Before sending WithdrawExpired, Alice clears the expired withdraw state total_withdraw=10. However, that doesn’t affect Alice’s total_withdraw because the latest one is 30 and stays 30.

  • Alice sends Bob a WithdrawExpired again for the second withdraw request which had a total_withdraw=20. Same as before applies.

  • Alice sends Bob a WithdrawExpired again for the third and last withdraw request which had a total_withdraw=30. Similar to the simple case, this was the only withdraw state that is pending, therefore expiring this withdraw state means that the total_withdraw of Alice goes back to zero.

Why Nonce was included in a non-balance proof message

Previously, only balance-proof messages had a nonce. The nonce value provides certain guarantees one of which is the fact that we are able to process messages in the exact order in which they were sent. Though WithdrawRequest, WithdrawConfirmation and WithdrawExpired messages are not balance-proof messages, a nonce value was required to make sure that these messages are also processed in the order in which they were sent. To accomodate for this change, the nonce field has to be decoupled from being based on the latest balance proof to a value that is maintained for the two sides of the channel state so that the next value is requested by either balance-proof based messages or withdraw messages.

Transport: Using multilayer transport with WebRTC

Status: Under investigation

Deciders: Raiden Core Team

Date: 2020-03-17

Context and Problem Statement

Matrix is likely to become the bottleneck for payment speed as well as throughput with a reasonable number of users and payments per second. Out of a Tech Deep Dive Session the raiden team considered different alternatives to the problem. The current implemented transport based on Matrix meets all of the necessary requirements Raiden has from a transport. Also the solution is working but with downsides regarding throughput and payment speed (message delivery speed).

Considered Options

  • Option 1: Multi layer transport. A multi layer transport has a robust base transport layer which meets all requirements. Raiden must work on this transport layer although with performance issues possible. Different Requirements can be outsourced to different other protocols which scale with the number of users in order to A) improve performance and B) take of load from base layer. If anything goes wrong in the outsourced layers, the base serves as a fallback. The Downside lies in increased complexity of implementing and maintaining multiple protocols.
  • Option 2: Go-libp2p-daemon. Libp2p is a very promising alternative p2p communication framework. It is configurable on multiple layers of transmission protocols. In the current stage it is still in a very experimental state. It probably does not fullfill all requirements for being a full transport layer for Raiden.
  • Option 3: Custom websocket solution. Another alternative is an inhouse built solution. Since the current Matrix transport is designed for its purpose being a chat protocol for humans there has been work done to abstract it to Raiden’s needs. A customized solution can be “tailored” to adapt perfectly to raiden’s use case and would probably be more lightweight than the current Matrix. A self-built transport of course requires additional maintainance capacity.

Decision

Option 1 was decided to be a short term solution to improve performance and scalability. Matrix already facilitates easy connection establishment of WebRTC through special events which can be send via rooms. It seems to be a reasonable amount of effort to implement in comparison to the gains in performance and speed. Examples have shown that subsecond payments are possible with WebRTC. Matrix as the base layer provides a complete functionality and serves as a fallback. Whereas payments are communicated via p2p WebRTC channels between the participants.

After a longer period (6+ months) the performance and throughput will be reevaluated. This also gives other protocols the chance to mature.

Examples of Option 1

  • Alice’s opens a matrix room with Bob
  • Bob receives the invite and joins
  • Alice as well as Bob use a signalling server to receive WebRTC
  • Both use the room and the special events to exchange canditates
  • Once they negotiated, they gonna open WebRTC data channels outside of Matrix.
  • If the connection breaks, the private room between Alice and Bob still exists as a fallback and will be used immediately.

Why WebRTC as the above layer solution

WebRTC is usually already built-in into any browser and very easy to use. As a matter of fact, the light client already implemented a proof of concept. Additionaly, as mentioned above, Matrix already provides a supported channel negotiation for their VoIP. In some examples, WebRTC proved to realize subsecond mediated payments. Ideally with this solution, Matrix only serves for discovery and presence and can therefore accept a much higher number of users until it becomes the bottleneck.

Current Status

  • The implementation for the light client is almost merged.
  • The implementation for the python client is still under investigation. It needs to be solved how and which framework to use for handling WebRTC data channels.