Smart Contract
==========================================
Smart Contracts, Unittests and Infrastructure for RaidenPaymentChannel
.. toctree::
self
Installation
------------
The Smart Contracts can be installed separately from the other
components.
Prerequisites
~~~~~~~~~~~~~
- Python 3.6
- `pip `__
Setup
~~~~~
.. code:: sh
pip install -r requirements.txt
Usage
~~~~~
- from ``root/contracts``:
.. code:: sh
# 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**
""""""""""""""
1) Start the geth-node from the commandline:
.. code-block:: sh
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**
"""""""""""""""""
1. Get some testnet-Ether at the `kovan-faucet `__
#. Modify the `project.json `__ to change the default account
#. Start the `Parity `__ node from the commandline:
.. code-block:: sh
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**
""""""""""""
1. Get some testnet-Ether at the `ropsten-faucet `__
#. Modify the `project.json `__ to change the default account
#. Start the geth node from the commandline:
.. code-block:: sh
geth --testnet \
--rpc --rpcport 8545 \
--unlock 0xbB5AEb01acF5b75bc36eC01f5137Dd2728FbE983 \
--password ~/password.txt
**rinkeby**
""""""""""""
1. 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.
.. code-block:: sh
# 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
.. _contract-development:
API
---
Generated docs
~~~~~~~~~~~~~~
.. _Auto-Generated-API: https://github.com/raiden-network/microraiden/blob/master/docs/contract/RaidenMicroTransferChannels.md
There is a 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:])``
.. figure:: diagrams/ChannelOpen_223.png
ERC20 compatible
^^^^^^^^^^^^^^^^
.. code:: py
# approve token transfers to the contract from the Sender's behalf
Token.approve(contract, deposit)
Contract.createChannel(receiver_address, deposit)
Gas cost (testing): 120090
.. figure:: diagrams/ChannelOpen_20.png
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
.. code:: py
_data = sender_address[2:] + receiver_address[2:] + hex(open_block_number)[2:].zfill(8)
_data = bytes.fromhex(_data)
.. figure:: diagrams/ChannelTopUp_223.png
ERC20 compatible
^^^^^^^^^^^^^^^^
.. code:: py
#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
.. figure:: diagrams/ChannelTopUp_20.png
.. _contract-validate-balance-proof:
Generating and validating a balance proof
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
(to be updated post EIP712)
.. code:: python
# 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)
.. _contract-validate-close:
Generating and validating a closing agreement
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. code:: python
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:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
.. code:: python
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
~~~~~~~~~~~~~~~~~
.. code:: py
# 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)
.. figure:: diagrams/ChannelCycle.png