Smart Contracts for Raiden Services

Overview

The Raiden services (Raiden Monitoring Service and Raiden Pathfinding Service) require a set of smart contracts to function. There are two general smart contracts:

  • UserDeposit
  • ServiceRegistry

and one additional contract for each of the services

  • MonitoringService, used as integral part of how the MS functions
  • OneToN, a minimal one-to-N payment solution used to pay fees to the PFS

which depend on the former two contracts.

Service Contracts Overview

There might also be an additional contract to facilitate the onboarding of new Raiden users, which has been called “Hub Contract” in some discussions. There are no detailed plans for that contract, yet.

ServiceRegistry

The ServiceRegistry provides a registry in which services have to register before becoming a full part of the Raiden services system. Services have to deposit RDN tokens in this contract for a successful registration. This avoids attacks using a large number of services and increases the incentive for service provider to not harm the Raiden ecosystem.

UserDeposit

The Raiden services will ask for payment in RDN. The Monitoring Service and the Pathfinding Service require deposits to be made in advance of service usage. These deposits are handled by the User Deposit Contract. Usage of the deposit for payments is not safe from double spending, but measures can be taken to reduce the likelihood to acceptable levels. This is a good trade off as long as the money lost on double spending is less than the savings in gas cost.

Requirements

  • Users can deposit and withdraw tokens.
  • Tokens can be deposited to the benefit of other users. This could facilitate onboarding of new Raiden users and allow a MS to defer the monitoring to another MS.
  • Tokens can’t be withdrawn immediately, but only after a certain delay. This allows services to claim their deserved payments before the withdraw takes place.
  • Services can read the effective balance of a user (current balance - planned withdrawals)
  • Service contracts are trusted and can claim tokens for the service providers.
  • Services can listen to events which notify them of decreasing user balances. A service can then claim payments before double spending becomes too likely.

Use cases

Monitoring Service rewards

The MS is promised a reward for each settlement in which it took part on behalf of the non-closing participant. Before accepting a monitor request, the MS checks if enough tokens are deposited in the UDC. The MS that has submit the latest BP upon settlement will receive the promised tokens on it’s UDC balance.

1-n payments

The PFS will be paid with signed IOUs, roughly a simplified uRaiden adapted to 1-n payments. The IOU contains the amount of tokens that can be claimed from the signer’s UDC balance. See OneToN for details.

OneToN

Overview

The OneToN contract handles payments for the PFS. It has been chosen with the following properties in mind:

  • easy to implement
  • low initial gas cost even when fees are paid to many PFSs
  • a certain risk of double spends is accepted

The concept is based on the idea to use a user’s single deposit in the UDC as a security deposit for off-chain payments to all PFSs. The client sends an IOU consisting of (sender, receiver, amount, expiration, signature) to the PFS with every path finding request. The PFS verifies the IOU and checks that amount >= prev_amount + pfs_fee. At any time, the PFS can claim the payment by submitting the IOU on-chain. Afterwards, no further IOU with the same (sender, receiver, expiration) can be claimed.

Related:

Requirements

  • low latency (<1s)
  • reliability, high probability of success (P > 0.99)
  • low cost overhead (<5% of transferred amount)
  • low fraud rate (< 3%, i.e. some fraud is tolerable)
  • can be implemented quickly

Communication between client and PFS

When requesting a route, the IOU is added as new JSON object to the existing parameters when requesting paths. The IOU object has the following properties:

Field Name Field Type Description
sender address Sender of the payment (Ethereum address of client)
receiver address Receiver of the payment (Ethereum address of PFS)
amount uint256 Total amount of tokens transferred to the receiver within this session (sender, receiver, expiration_block)
expiration_block uint256 Last block in which the IOU can be claimed
signature bytes Signature of the payment arguments [1]

The PFS then thoroughly checks the IOU:

  • Is the PFS the receiver?
  • Did the amount increase enough to make the request profitable for the PFS (amount >= prev_amount + pfs_fee)
  • Is expiration_block far enough in the future to potentially accumulate a reasonable amount of fees and claim the payment
  • Is the IOU for (sender, receiver, expiration) still unclaimed
  • Did the client create too many small IOU instead of increasing the value of an existing one? This would make claiming the IOU unprofitable for the PFS
  • Is the signature valid
  • Is the deposit much larger than amount

If one of the conditions is not met, a corresponding error message is returned and the client can try to submit a request with a proper IOU or try a different PFS. Otherwise, the PFS returns the requested routes as described in the current spec and saves the latest IOU for this (sender, expiration_block).

[1]

The signature is calculated by

ecdsa_recoverable(privkey,
                  sha3_keccak("\x19Ethereum Signed Message:\n104"
                              || sender || receiver || amount || expiration_block ))

You can use raiden_contracts.utils.sign_one_to_n_iou to generate such a signature.

Claiming the IOU

A OneToN contract (OTNC) which is trusted by the UDC accepts IOUs (see table above for parameters) and uses the UDC to transfer amount from sender to receiver. The OTNC stores a mapping hash(receiver, sender, expiration_block) => expiration_block to make sure that each IOU can only be claimed once. To make claims more gas efficient, multiple claims can be done in a single transaction and expired claims can be removed from the storage.

Expiration

Having the field expiration_block as part of the IOU serves multiple purposes:

  • Combined with the sender and receiver fields it identifies a single payment session. Under this identifier, multiple payments are aggregated by continuously increasing the amount and only a single on-chain transaction is needed to claim the total payment sum. After claiming, the identifier is stored on-chain and used to prevent the receiver from claiming the same payments, again.
  • When old IOUs have expired (current_block > expiration_block), the sender can be sure that he won’t have to pay this IOU. So after waiting for expiry, the sender knows that IOUs which have been lost for some reason (e.g. disk failure) won’t be redeemed and does not have to prepare for unpredictable claims of very old IOUs.
  • Entries can be deleted from the hash(receiver, sender, expiration_block) => expiration_block mapping which is used to prevent double claims after expiry. This frees blockchain storage and thereby reduces gas costs.

Double Spending

Since the same deposit is used for payments to multiple parties, it is possible that the deposit is drained before each party has been paid. This is an accepted trade-off, because the amounts are small and low gas costs are more important, as long as the actual double spending does not reach a high level. To somewhat reduce the risks of double spends, the following precautions are taken:

  • Users can’t immediately withdraw tokens from the UDC. They first have to announce their intention and then wait until a withdraw delay has elapsed.
  • The PFS demands a higher deposit than it’s currently owed amount to give it some safety margin when other parties claim tokens
  • Only PFSs registered in the ServiceRegistry are allowed to claim IOUs. This is important because claims allow circumventing the UDC’s withdraw delay.

A user and a PFS can theoretically collude to quickly withdraw the complete deposit (via a claim) before other services are paid. This should be unlikely due to the following aspects:

  • The savings achieved by cheating the other services are low compared to the coordination cost for the collusion
  • The PFS is itself a party receiving payments of services and does not want to promote cheating against services
  • If this becomes widespread, cheating users can theoretically be blacklisted by PFSs. This will require them to close their existing channels and reopen new channels at a cost which will most likely be higher than the profit gained by cheating

MonitoringService

The Raiden Monitoring Service submits an up-to-date balance proof on behalf of users who are offline when a channel is closed to prevent them from losing tokens. This could be done without a dedicated contract by calling TokenNetwork.updateNonClosingBalanceProof <update-channel> but then the MS would not be able to claim a reward for its work. To handle the rewards, the MonitoringService contract provides two functions. One for wrapping updateNonClosingBalanceProof and creating the reward and another one for claiming the reward after the settlement:

contract MonitoringService is Utils
function monitor(address closing_participant, address non_closing_participant, bytes32 balance_hash, uint256 nonce, bytes32 additional_hash, bytes memory closing_signature, bytes memory non_closing_signature, uint256 reward_amount, address token_network_address, bytes memory reward_proof_signature)
 canMonitor(msg . sender)
public
Notice:

Called by a registered MS, when providing a new balance proof to a monitored channel. Can be called multiple times by different registered MSs as long as the BP provided is newer than the current newest registered BP.

Parameters:
  • nonce – Strictly monotonic value used to order BPs omitting PB specific params, since these will not be provided in the future
  • reward_amount – Amount of tokens to be rewarded
  • token_network_address – Address of the Token Network in which the channel being monitored exists.
  • reward_proof_signature – The signature of the signed reward proof
function claimReward(uint256 channel_identifier, address token_network_address, address closing_participant, address non_closing_participant)
public
returns (bool)
Notice:

Called after a monitored channel is settled in order for MS to claim the reward Can be called once per settled channel by everyone on behalf of MS

Parameters:
  • token_network_address – Address of the Token Network in which the channel
  • closing_participant – Address of the participant of the channel that called close
  • non_closing_participant – The other participant of the channel