Smart Contracts for Raiden Services¶
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.
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.
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.
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.
- 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.
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.
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.
- 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 |
The PFS then thoroughly checks the IOU:
- Is the PFS the receiver?
- Did the amount increase enough to make the request profitable for the
amount >= prev_amount + pfs_fee)
expiration_blockfar 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
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).
The signature is calculated by
ecdsa_recoverable(privkey, sha3_keccak("\x19Ethereum Signed Message:\n104" || sender || receiver || amount || expiration_block ))
You can use
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
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.
Having the field
expiration_block as part of the IOU serves multiple
- Combined with the
receiverfields it identifies a single payment session. Under this identifier, multiple payments are aggregated by continuously increasing the
amountand 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_blockmapping which is used to prevent double claims after expiry. This frees blockchain storage and thereby reduces gas costs.
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
amountto 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
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:
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)
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.
- 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
claimReward(uint256 channel_identifier, address token_network_address, address closing_participant, address non_closing_participant)¶
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
- 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