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:
- Use the Raiden Wizard for quickly installing and running a Raiden node.
- Read about different options for installing and firing up a Raiden client.
- Check out the WebUI tutorial to quickly get started doing payments.
Developing on Raiden?¶
If you’re looking for documentation relevant for building on top of Raiden:
- Read the thorough guide to get started with the Raiden API.
- Checkout the complete API documentation.
- Read the document How is Raiden Tested.
Contributing to Raiden?¶
If you’re looking for a more in depth understanding of Raiden and are interested in contributing:
- Take a look at the onboarding guide.
- Check out the code in our Github repository.
- Read the Raiden specification.
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¶
- You need to make sure that your system has
solc
, the ethereum solidity compiler installed. Refer to its documentation for the installation steps. - You will also need to obtain the system dependencies for pyethapp.
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
- a synced Ethereum Node - using geth, parity or infura
- an Ethereum keystore file - whereas the address holds ETH, RDN, and the ERC20 token you want to transfer
- 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
- The choice of a pathfinding service
- The choice of a monitoring service
- 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.
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 sameamount
from the same address are ignored (as in: the Echo Node just keeps your money) - the
echo_identifier
of all echo payments isidentifier + echo_amount
- payments with an
amount
divisible by3
will be answered with an echo payment ofecho_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 withecho_amount = 49
and the pool is reset. To query the current number of tickets in the pool, a participant can send another payment withamount = 7
– if the participant already takes part in the current draw, the Echo Node will respond with a payment withecho_amount = number_of_tickets
, otherwise it will enter the pool. - for a payment with any other
amount
it returnsecho_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.

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.

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.

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 aninteger
containing the identifier of the channel.partner_address
should be astring
containing the EIP55-encoded address of the partner with whom we have opened a channel.token_address
should be astring
containing the EIP55-encoded address of the token we are trading in the channel.token_network_address
should be astring
containing the EIP55-encoded address of the token network the channel is part of.balance
should be an integer of the amount of thetoken_address
token we have available for payments.total_deposit
should be an integer of the amount of thetoken_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 thatclose()
is called until the channel can be settled with a call tosettle()
.'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: - 200 OK – Successful query
- 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)/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: - 200 OK – Successful query
- 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.
-
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: - 200 OK – Successful query
- 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/
(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: - 200 OK – Successful query
- 404 Not Found – The queried channel or token was not found
- 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: - 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
andstatus
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: - 201 Created – Channel created successfully
- 400 Bad Request – Provided JSON is in some way malformed
- 402 Payment Required – Insufficient ETH to pay for the gas of the channel open on-chain transaction
- 408 Request Timeout – Deposit event was not read in time by the Ethereum node
- 409 Conflict – Invalid input, e. g. too low a settle timeout
- 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.
-
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
ortotal_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
andtotal_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.
- state (string) – Desired new state; the only valid choice is
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: - 200 OK – For a successful query
- 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: - 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
andjoinable_funds_target
as optional arguments. If not provided they default toinitial_channel_target = 3
andjoinable_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 theinitial_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 tojoin
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
andreveal_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
andsecret_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
andtarget_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: - 200 OK – Successful query
- 500 Internal Server Error – Internal Raiden error
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¶
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¶
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:
- If the amount involved in the token is really small then the payee can just do nothing and forfeit it.
- 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¶
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¶
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.
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:
- For the payment A->B->C ,
C
follows the protocol and send the secret back toB
. - 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 withA
closing the channel with what he received from his partnerB
. - Now
B
has to register the secret received byC
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 theSecretRegistry
contract. - Now it’s
B
’s turn to update the contract with what he has received fromA
. He will provide a hash of the merkle root, the transferred amount and the locked amount to the contract via the updateNonclosingbalanceproof call. - After both are done and the settlement period has passed then anyone can settle the channel and send the tokens amounts owed to
A
andB
respectively back to its owners. - 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¶
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.
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¶
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.
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
), sendsDelivered(123)
in reply toProcessed(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:
- TokenNetworkRegistry
- TokenNetwork
- SecretRegistry
- PaymentChannel - This is just a wrapper of the token network functions for a specific channel.
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 ofMessage
class, andpacked()
method of each subclass ofMessage
. 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()
usesmsg.sender
whileupdateNonClosingBalanceProof()
checks thenon_closing_signature
argument. This allows a delegate (like Monitoring Services) to callupdateNonClosingBalanceProof()
, 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:
- the proxy checks conditions on the specified block, and sees whether the call would fail (the post-condition checks)
- the proxy then asks the Ethereum client to estimate gas, which might fail.
- the proxy then asks the Ethereum client to submit the transaction to the blockchain.
- 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 fromRaidenError
, 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¶
Next release
- [Feature]: Update WebUI to version 0.11.0 https://github.com/raiden-network/webui/releases/tag/v0.11.0
- [Feature] #5589: The Rest API now includes the token address in all returned payment related events.
- [Feature] #4588: Remove the echo_node subcommand of the command line interface.
- [Feature] #5281: Add a /status endpoint; start the API earlier and return 503 SERVICE UNAVAILABLE during the initial sync.
- [Feature] #5338: The number of blocks queried for events is now dynamically adjusted. This is necessary to prevent timeouts because the Ethereum client is overloaded.
- [Feature]: Update WebUI to version 0.11.1 https://github.com/raiden-network/webui/releases/tag/v0.11.1
- [Bug] #5395: Convert and return big integers as strings in the API response body.
- [Bug] #5591: Rest API payment events can now be properly filtered by token address.
- [Bug] #5583: The connection manager no longer opens channels with offline nodes when trying to connect to a token network.
- [Bug] #5779: Handle the API exception when no further token networks can be registered by returning 403 FORBIDDEN.
- :release:`0.200.0-rc3`
- [Bug] #6066: Workaround slow speed of geth on mainnet for eth_getLogs.
- [Bug] #6067: Workaround gevent’s bug on wait for single elements.
- [Bug] #6072: Always return valid JSON on the config endpoint, even when the REST API is starting.
- :release:`0.200.0-rc6`
- [Bug] #6077: Fix missing requirement to build macOS binaries
- :release:`0.200.0-rc7`
- [Bug] #6075: Fixed serialization problem for pending transactions.
- [Bug] #6071: Fixed transport race condition which prevented a node to restart after a failure.
- [Bug] #6083: Weakened byte code check to prevent errors with client pruning.
- [Bug] #6082: Small bug fix, use of undefined variable.
- :release:`0.200.0-rc8`
- :release:`0.200.0-rc9`
- :release:`1.0.0`
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
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
- [Feature] #2988: If estimateGas returns failure don’t send a transaction.
- [Feature] #3236: Add backwards-compatible PFS integration in the routing layer
- [Feature]: Update WebUI to version 0.8.0 https://github.com/raiden-network/webui/releases/tag/v0.8.0
- [Bug] #3196: Proper fix for the bug that caused not finding locksroot in the DB during unlock
0.100.2-rc2 2019-01-11
- [Feature]: Update WebUI to version 0.7.1 https://github.com/raiden-network/webui/releases/tag/v0.7.1
- [Bug] #3257: Requesting the channel list with a token address and not a partner address via the API should no longer cause a 500 server error.
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
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
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
andtarget
toEventTransferSentSuccess
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
- [Feature]: This is the Raiden Developer Preview release. Introduces a raiden test network on ropsten, the API and all the basic functionality required to use Raiden in Dapps. For more information read the blog post or the documentation of v0.1.0.
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):
- Option given on the command line
- Option read from the config file
- 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:

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
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:
- Alice initiates the withdraw by dispatching ActionInitWithdraw with a monitonic total withdraw value.
- Alice sends a signed WithdrawRequest message to its partner to agree on the new total withdraw.
- Bob receives the withdraw request, validates it and replies with a signed WithdrawConfirmation message to Alice.
- 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.