Welcome to microraiden’s documentation!¶
Contents¶
Proxy tutorial¶
Introduction¶
In this tutorial we will create a simple paywalled server that will
echo a requested path paramter, payable with a custom token. You can find example code for this tutorial
in microraiden/examples/echo_server.py
.
Requirements¶
Please refer to README.md to install all required dependencies. You will also need a Chrome browser with the MetaMask plugin.
Setting up the proxy¶
Initialization¶
- For initialization you will have to supply the following parameters:
- The private key of the account receiving the payments (to extract it from a keystore file you can use MyEtherWallet’s “View Wallet Info” functionality).
- A file in which the proxy stores off-chain balance proofs. Set this to a path writable by the user that starts the server.
from microraiden.make_helpers import make_paywalled_proxy
app = make_paywalled_proxy(private_key, state_file_name)
make_paywalled_proxy()
is a helper that handles the setup of the channel manager
and returns a PaywalledProxy
instance.
Microraiden also includes other helpers that parse common commandline options. We are not using them in this example - for a quick overview how to use them,
refer to i.e. __main__()
The channel manager will start syncing with the blockchain immediately.
Resource types¶
Now we will create a custom resource class that simply echoes a path-parameter of the user’s request for a fixed price.
The workflow is the same as with the Flask-restful: Subclass microraiden.proxy.resources.Expensive
and
implement the HTTP methods you want to expose.
from microraiden.proxy.resources import Expensive
class StaticPriceResource(Expensive):
def get(self, url: str, param: str):
log.info('Resource requested: {} with param "{}"'.format(request.url, param))
return param
We add one static resource to our PaywalledProxy
instance.
The url argument will comply with standard flask routing rules.
app.add_paywalled_resource(
cls=StaticPriceResource,
url="/echofix/<string:param>",
price=5
)
The resource will then be available for example at the URI /echofix/foo
. Only after a
payment of 5 tokens, the proxy will send the foo
parameter back to the user and will
set the Content-Type header appropriately. Without payment, the
server responds with 402 Payment Required
.
A probably more useful paywalled resource is a URL. This is useful to fetch content from a remote CDN:
from microraiden.proxy.content import PaywalledProxyUrl
app.add_paywalled_resource(
cls=PaywalledProxyUrl,
url="cdn\/.*",
resource_class_kwargs={"domain": 'http://cdn.myhost.com:8000/resource42'}
)
Note, that the kwargs for the constructor of the resource-class (here our PaywalledProxyUrl
)
have to be passed as a dict with the resource_class_kwargs
argument.
In this case, the domain
kwarg is the remote URL specifying where to fetch the content from.
Setting a price for the resource dynamically¶
We can also construct the Resource in a way that the price will be dynamically calculated, e.g. based on the requests parameters.
class DynamicPriceResource(Expensive):
def get(self, url: str, param: str):
log.info('Resource requested: {} with param "{}"'.format(request.url, param))
return param
def price(self):
return len(request.view_args['param'])
app.add_paywalled_resource(
cls=DynamicPriceResource,
url="/echodyn/<string:param>",
)
Here, the price to be paid is the length of the requested string.
A request of the /echodyn/foo
resource, would therefore require a payment of 3 tokens.
Starting/stopping the proxy¶
You start proxy by calling run()
method. This call is non-blocking
– the proxy is started as a WSGI greenlet. Use join()
to sync with
the task. This will block until proxy has stopped. To terminate the
server, call stop() from another greenlet.
app.run(debug=True)
app.join()
Accessing the content¶
Browser¶
To access the content with your browser, navigate to the URL of the resource you’d like to get. You’ll be faced with a paywall – a site requesting you to pay for the resource. To do so, you first have to open a new channel. If you have the MetaMask extension installed, you can set the amount to be deposited to the channel. After confirming the deposit, you can navigate and payments will be done automatically.
Side notes¶
Proxy state file¶
Off-chain transactions are stored in a sqlite database. You should do regular backups of this file – it contains balance signatures of the client, and if you lose them, you will have no way of proving that the client is settling the channel using less funds than he has actually paid to the proxy.
REST API¶
Introduction¶
µRaiden exposes a Restful API to provide insight into a channel state, balances, and it allows proxy operator to close and settle the channels.
Proxy endpoints¶
Getting the status of the proxy¶
/api/1/stats
Return proxy status: balances, open channels, contract ABI etc.
- deposit_sum - sum of all open channel deposits
- open_channels - count of all open channels
- pending_channels - count of all closed, but not yet settled channels
- balance_sum - sum of all spent, but not yet settled funds
- unique_senders - count of all unique addresses that have channels open
- liquid_balance - amount of tokens that are settled and available to the receiver
- token_address - token contract address
- contract_address - channel manager contract address
- receiver_address - server’s ethereum address
- manager_abi - ABI of the channel manager contract
- token_abi - ABI of the token contract
Example Request¶
GET /api/1/stats
Example Response¶
200 OK
and
{
"deposit_sum": "268",
"open_channels": "33",
"pending_channels": "15",
"balance_sum": "12",
"unique_senders": "6",
"liquid_balance": "334",
"token_address" : "0x8227a53130c90d32e0294cdde576411379138ba8",
"contract_address": "0x69f8b894d89fb7c4f6f082f4eb84b2b2c3311605",
"receiver_address": "0xe67104491127e419064335ea5bf714622a209660",
"manager_abi": "{ ... }",
"token_abi": "{ ... }",
}
Channel endpoints¶
Getting all open channels¶
/api/1/channels/
Return a list of all open channels.
Example Request¶
GET /api/1/channels
Example Response¶
200 OK
and
[
{
"sender_address" : "0x5601ea8445a5d96eeebf89a67c4199fbb7a43fbb",
"open_block" : "3241462",
"balance" : "0",
"deposit" : "10",
},
{
"sender_address" : "0x5176305093fff279697d3fc9b6bc09574303edb4",
"open_block" : "32654234",
"balance" : "0",
"deposit" : "25",
},
]
Getting all open channels for a given sender¶
/api/1/channels/<sender_address>
Return a list of all open channels for the sender specified in the second argument of the URL.
Example Request¶
GET /api/1/channels/0x5601ea8445a5d96eeebf89a67c4199fbb7a43fbb
Example Response¶
200 OK
and
[
{
"sender_address" : "0x5601ea8445a5d96eeebf89a67c4199fbb7a43fbb",
"open_block" : "3241462",
"balance" : "0",
"deposit" : "10",
"state" : "open",
},
]
Getting a single channel info¶
/api/1/channels/<sender_address>/<open_block>
Return an info about the channel, identified by sender and open block id.
Example Request¶
GET /api/1/channels/0x5601ea8445a5d96eeebf89a67c4199fbb7a43fbb/3241462
Example Response¶
200 OK
and
{
"sender_address" : "0x5601ea8445a5d96eeebf89a67c4199fbb7a43fbb",
"open_block" : "3241462",
"balance" : "0",
"deposit" : "10",
"state" : "open",
}
Cooperatively closing a channel¶
/api/1/channels/<sender_address>/<open_block>
Return a receiver’s signature that can be used to settle the channel immediately (by calling contract’s cooperativeClose() function).
Example Request¶
DELETE /api/1/channels/0x5601ea8445a5d96eeebf89a67c4199fbb7a43fbb/3241642
with payload balance - last balance of the channel
{
"balance": 13000,
}
Example Response¶
200 OK
and
{
"close_signature" : "0xb30809f9a32e4f5012a3e7a7275e4f0f96eaff49f7a34747507abc3147a0975c31cf9f9aa318d1f9675d6e39f062a565213bcef4baa820f0332616f0c38324fe01",
}
Possible Responses¶
HTTP Code | Condition |
---|---|
200 OK | For a successful coop-close |
500 Server Error | Internal Raiden node error |
400 Bad request | Invalid address, signature, or channel doesn’t exist. |
Components overview¶
HTTP Headers¶
Response Headers¶
200 OK¶
Headers | Type | Description |
---|---|---|
RDN-Gateway-Path | bytes | Path root of the channel management app |
RDN-Receiver-Address | address | Address of the Merchant |
RDN-Contract-Address | address | Address of RaidenMicroTransferChannels contract |
RDN-Token-Address | address | Address of the Token contract |
RDN-Price | uint | Resource price |
RDN-Sender-Address | address | Address of the Client |
RDN-Sender-Balance | uint | Balance of the Channel |
402 Payment Required¶
Headers | Type | Description |
---|---|---|
RDN-Gateway-Path | bytes | Path root of the channel management app |
RDN-Receiver-Address | address | Address of the Merchant |
RDN-Contract-Address | address | Address of RaidenMicroTransferChannels contract |
RDN-Token-Address | address | Address of the Token contract |
RDN-Price | uint | Resource price |
RDN-Sender-Address | address | Address of the Client |
RDN-Sender-Balance | uint | Balance of the Channel |
RDN-Balance-Signature | bytes | Optional. Last saved balance proof from the sender. |
+ one of the following: | ||
RDN-Insufficient-Conf irmations | uint | Failure - not enough confirmations after the channel creation. Client should wait and retry. |
RDN-Nonexisting-Channel | string | Failure - channel does not exist or was closed. |
RDN-Invalid-Balance- Proof | uint | Failure - Balance must not be greater than deposit or The balance must not decrease. |
RDN-Invalid-Amount | uint | Failure - wrong payment value |
409¶
- ValueError
502¶
- Ethereum node is not responding
- Channel manager ETH balance is below limit
Request Headers¶
Headers | Type | Description |
---|---|---|
RDN-Contract-Address | address | Address of MicroTransferChannels contract |
RDN-Receiver-Address | address | Address of the Merchant |
RDN-Sender-Address | address | Address of the Client |
RDN-Payment | uint | Amount of the payment |
RDN-Sender-Balance | uint | Balance of the Channel |
RDN-Balance-Signature | bytes | Signature from the Sender, signing the balance (post payment) |
RDN-Open-Block | uint | Opening block number of the channel required for unique identification |
Off-Chain Micropayment Sequence¶
(not-so-standard sequence diagram) For a better overview, also check out how the smart contract does a balance-proof validation.

µRaiden Server¶
Non-detailed components overview. For function arguments and types, please check source code and docstrings.
Channel manager¶

Proxy¶

Python Client¶

Web Client¶
For an overview of the web client, please refer to the JavaScript client library documentation.
Smart Contract¶
For an overview of the RaidenMicroTransferChannels smart contract, please refer to the Smart Contract API documentation.
JavaScript client library¶
Smart Contract¶
Smart Contracts, Unittests and Infrastructure for RaidenPaymentChannel
Installation¶
The Smart Contracts can be installed separately from the other components.
Setup¶
pip install -r requirements.txt
Usage¶
- from
root/contracts
:
# compilation
populus compile
# tests
pytest
pytest -p no:warnings -s
pytest tests/test_uraiden.py -p no:warnings -s
# Recommended for speed:
# you have to comment lines in tests/conftest.py to use this
pip install pytest-xdist==1.17.1
pytest -p no:warnings -s -n NUM_OF_CPUs
Deployment¶
Chain setup for testing¶
Note - you can change RPC/IPC chain connection, timeout parameters etc. in project.json
privtest¶
- Start the geth-node from the commandline:
geth --ipcpath="~/Library/Ethereum/privtest/geth.ipc" \ --datadir="~/Library/Ethereum/privtest" \ --dev \ ---rpc --rpccorsdomain '\*' --rpcport 8545 \ --rpcapi eth,net,web3,personal \ --unlock 0xf590ee24CbFB67d1ca212e21294f967130909A5a \ --password ~/password.txt # geth console # you have to mine yourself: miner.start() geth attach ipc:/Users/loredana/Library/Ethereum/privtest/geth.ipc
kovan¶
- Get some testnet-Ether at the kovan-faucet
- Modify the project.json to change the default account
- Start the Parity node from the commandline:
parity --geth \ --chain kovan \ --force-ui --reseal-min-period 0 \ --jsonrpc-cors http://localhost \ --jsonrpc-apis web3,eth,net,parity,traces,rpc,personal \ --unlock 0x5601Ea8445A5d96EEeBF89A67C4199FbB7a43Fbb \ --password ~/password.txt \ --author 0x5601Ea8445A5d96EEeBF89A67C4199FbB7a43Fbb
ropsten¶
- Get some testnet-Ether at the ropsten-faucet
- Modify the project.json to change the default account
- Start the geth node from the commandline:
geth --testnet \
--rpc --rpcport 8545 \
--unlock 0xbB5AEb01acF5b75bc36eC01f5137Dd2728FbE983 \
--password ~/password.txt
rinkeby¶
- Get some testnet-Ether at the rinkeby-faucet
- Modify the /contracts/project.json to change the default account
Fast deployment¶
There are some scripts to provide you with convenient ways to setup a quick deployment.
# Fast deploy on kovan | ropsten | rinkeby | tester | privtest # Following two calls are equivalent python -m deploy.deploy_testnet # --owner is web.eth.accounts[0] python -m deploy.deploy_testnet \ --chain kovan \ --owner 0x5601Ea8445A5d96EEeBF89A67C4199FbB7a43Fbb \ --challenge-period 500 \ --token-name CustomToken --token-symbol TKN \ --supply 10000000 --token-decimals 18 # Provide a custom deployed token python -m deploy.deploy_testnet --token-address TOKEN_ADDRESS
API¶
Generated docs¶
There is an Auto-Generated-API, that is compiled with soldocs.
Prerequisites
pip install soldocs
populus compile
soldocs --input build/contracts.json --output docs/contract/RaidenMicroTransferChannels.md --contracts RaidenMicroTransferChannels
Opening a transfer channel¶
ERC223 compatible (recommended)¶
Sender sends tokens to the Contract, with a payload for calling
createChannelPrivate
.
Token.transfer(_to, _value, _data)
Gas cost (testing): 88976
_to
=Contract.address
_value
= deposit value (number of tokens)_data
contains the Sender and Receiver addresses encoded in 20 bytes- in python
_data = bytes.fromhex(sender_address[2:] + receiver_address[2:])

ERC20 compatible¶
# approve token transfers to the contract from the Sender's behalf
Token.approve(contract, deposit)
Contract.createChannel(receiver_address, deposit)
Gas cost (testing): 120090

Topping up a channel¶
Adding tokens to an already opened channel.
ERC223 compatible (recommended)¶
Sender sends tokens to the Contract, with a payload for calling
topUp
.
Token.transfer(_to, _value, _data)
Gas cost (testing): 54885
_to
=Contract.address
_value
= deposit value (number of tokens)_data
contains the Sender and Receiver addresses encoded in 20 bytes + the open_block_number in 4 bytes- in python
_data = sender_address[2:] + receiver_address[2:] + hex(open_block_number)[2:].zfill(8)
_data = bytes.fromhex(_data)

ERC20 compatible¶
#approve token transfers to the contract from the Sender's behalf
Token.approve(contract, added_deposit)
# open_block_number = block number at which the channel was opened
Contract.topUp(receiver_address, open_block_number, added_deposit)
Gas cost (testing): 85414

Generating and validating a balance proof¶
(to be updated post EIP712)
# Sender has to provide a balance proof to the Receiver when making a micropayment
# The contract implements some helper functions for that
# Balance message
bytes32 balance_message_hash = keccak256(
keccak256(
'string message_id',
'address receiver',
'uint32 block_created',
'uint192 balance',
'address contract'
),
keccak256(
'Sender balance proof signature',
_receiver_address,
_open_block_number,
_balance,
address(this)
)
);
# balance_message_hash is signed by the Sender with MetaMask
balance_msg_sig
# Data is sent to the Receiver (receiver, open_block_number, balance, balance_msg_sig)
Generating and validating a closing agreement¶
from eth_utils import encode_hex
# Sender has to provide a balance proof to the Contract and
# a closing agreement proof from Receiver (closing_sig)
# closing_sig is created in the same way as balance_msg_sig, but it is signed by the Receiver
# Closing signature message
bytes32 balance_message_hash = keccak256(
keccak256(
'string message_id',
'address sender',
'uint32 block_created',
'uint192 balance',
'address contract'
),
keccak256(
'Receiver closing signature',
_sender_address,
_open_block_number,
_balance,
address(this)
)
);
# balance_message_hash is signed by the Sender with MetaMask
balance_msg_sig
# balance_msg_sig is signed by the Receiver inside the microraiden code
closing_sig
# Send to the Contract (example of collaborative closing, transaction sent by Sender)
Contract.transact({ "from": Sender }).cooperativeClose(
_receiver_address,
_open_block_number,
_balance,
_balance_msg_sig,
_closing_sig
)
Balance proof / closing agreement signature verification:¶
sender_address = Contract.call().extractBalanceProofSignature(receiver_address, open_block_number, balance, balance_msg_sig)
receiver_address = Contract.call().extractClosingSignature(sender_address, open_block_number, balance, closing_sig)
Closing a channel¶
# 1. Receiver calls Contract with the sender's signed balance message = instant close & settle
# 2. Client calls Contract with receiver's closing signature = instant close & settle
# Gas cost (testing): 71182
Contract.cooperativeClose(receiver_address, open_block_number, balance, balance_msg_sig, closing_sig)
# 3. Client calls Contract without receiver's closing signature = challenge period starts, channel is not settled yet
# Gas cost (testing): 53876
Contract.uncooperativeClose(receiver_address, open_block_number, balance)
# 3.a. During the challenge period, 1. can happen.
# 3.b. Client calls Contract after settlement period ends
# Gas cost (testing): 40896
Contract.settle(receiver_address, open_block_number)
