Background and Motivation

With the advent of the blockchain and its benefits such as security guarantees, visibility, decentralization, there is a need for systems that provide scalability for increased number of transactions and bypass the high fees for on-chain transactions, such that adoption is feasible in commercial applications. The requirements can be satisfied by using payment channels, which create an exclusive two-party peer-to-peer protocol that locks funds, allowing the participants to perform any number of transactions while conserving the volume of initially locked funds. Firstly, the system is scalable because there are only two on-chain transactions: channel creation and channel closing. The participants exchange signed proofs containing the transaction value and the communication is limited by the network bandwidth of their link. The exchange can be uni-directional, analogous to a customer-vendor monetary exchange or bi-directional, analogous to a scenario where each party provides a service in exchange of fees and the differences are self-balanced. As a general rule, scalability in a blockchain system can be achieved by some form of centralization (see next paragraph), but where the security guarantees are entirely made by the cryptographic primitives used in the protocol. On termination of the payment channel, each party will be paid or paid back the correct amount. Secondly, payment channels significantly lower the transaction fees. In an on-chain scenario, if we assume a fixed transaction fee of f and a large number of n transactions made uni-directionally, then the transaction fees would be n * f. Using payment channels, there would be one initial channel opening transaction and a final closing transaction, amounting to fees of 2 * f. This clearly constitutes an advantage for using payment channels. In the case of micropayments, the fees paid can be significantly larger than the transferred amount, which is inacceptable.

In implementing such a system, the strawman’s solution requiring centralization can be immediately ruled out in favor of a decentralized approach with smart contracts. The smart contract stores an immutable state of the payment channel participants, such that access to the funds is prohibited for third-party entities - the only authorized addresses are those of the two channel peers. No party can lock the funds indefinitely because of a time-lock-like mechanism that destroys the channel after a predefined amount of time. The principle can be extended to include multiple participants, creating an overlay network of payment channels over which transactions can be routed to peers who are more than one hop away. This can be achieved by hash time-locks, which are used in cross-chain atomic swaps and represent a conditional payment mechanism based on hash pre-image resistance, but these go beyond the scope of the implemented decentralized application.

This project achieved an implementation of a uni-directional micropayment channel smart contract and a web interface that can be seen as a payment portal used in an online service, allowing customers to make a deposit from which they can execute virtually an unlimited number of payment transactions to the vendor. This system has wide applicability for merchants who support cryptocurrency payments and moreover promotes the idea of using cryptocurrencies for increased profit (psychological factors mentioned in pchannels)). It is important to note that existing systems have a limited average transaction throughput: VISA 4000 tx/sec (with a capacity of 65000 tx/sec), BTC 7 tx/sec, ETH 15 tx/sec.

Architectural Choice and Implementation

Figure 1: Opening a channel

Figure 2: Closing a channel

The project is built using Truffle framework: the front-end of the application is written in HTML, Javascript and JQuery and the smart contract in Solidity. The smart contract deployment is done on the Ganache local blockchain (UI). The user interface was inspired by an exiting micropayment channel based on ERC223 tokens called \(\mu\)Raiden. In the design process, I pondered the options of using standard tokens (e.g., ERC20), but because of the unnecessary layer of indirection that would be added, I chose to work directly with payment-to-contract in ether. In the following description of the protocol, the roles of the parties are expressed interchangeably as follows: buyer/sender/customer and seller/receiver/vendor respectively.

The design of the protocol respects the sequence diagrams in Figures 1 and 2 and it is based on the interaction of the client-side with the smart contract. This is possible with the help of the Web3 library used to connect to the Metamask wallet. Figure 1 shows the steps taken for channel creation, which are reflected in the implementation as follows: the user (buyer role) retrieves his identity and balance from Metamask by selecting and account. The vendor address is fixed, as the assumption is that the payment service kicks-in as a redirection from a vendor’s website, substituting the checkout stage. The buyer selects an amount to deposit and a timeout and opens the channel. This is done on-chain by paying the amount to the contract and registering the buyer address and the vendor address.

In the design, I started off from a single smart contract that represents the payment channel; this would self-destruct on close, sending the final amount to the vendor and the rest back to the buyer. Then I moved on to extend the smart contract to support multiple channels between buyer and seller. This is achieved by assigning IDs to a new data structure called Chanel. All channels are stored in a mapping the opened and closed channels tracked using two sets best represented as mappings in Solidity. The extended version prompts the buyer to specify the channel ID on which he wants the payment to go through and the vendor to specify the ID of the channel to be closed.

Figure 2 shows the closing interaction. Each time the buyer wants to pay the user some amount from a channel, he creates a proof (tuple contract address-amount), signs it and sends the total paid amount so far via network to the vendor. For simplicity, I have simulated the network as a shared key-value store memory environment: buyer updates it with the last signed proof and vendor retrieves last sign proof. In practice this can be achieved via web or TCP sockets. The next step is to simulate a multi-signature transaction: this can be more simply achieved by splitting in two transactions. The vendor initiates the channel closing and sends the last buyer signed proof to the smart contract, which gets verified and registered in a mapping. Then, the vendor sends the proof with his own signature to the contract. Through this, the contract is sure that both parties have agreed on closing the channel. If the vendor (receiver) does not respect the service agreement or simply wants to lock funds, the sender can use his challenge timeout period to request closing the channel for getting back his funds. Honest behaviour of both participants is guaranteed to restitute the correct amounts.

Threat model

We will address each key element of the STRIDE model for an exhaustive threat model analysis.

Spoofing Given that the interaction with the smart contract is done from the web browser, the identity of either participant can be spoofed by various web-based attacks (MITM, DOM control via browser extensions, etc.), as the smart contract calls are assumed to be made over RPC, which uses binary format, so it may be harder to make an online MITM attack, especially if encryption is used as well. The application assumes that key management is externally taken care of, thus an attacker can easily exploit this vector. Even though the identity can be spoofed and the collateral will be sent to the contract, a channel redirection attack scenario can be achieved only if the off-chain communication channel is compromised as well.

Tampering The only possible attack vector is again a web-based attack in this case, in which a piece of malicious JS code can, for example, change the initial deposit amount to a much higher one. The channel has higher collateral waiting which has been subtracted from the buyer’s account, therefore he will not be able to transact it for other purposes until the channel times out or the receiver closes the channel.

Repudiation The buyer cannot deny having committed to payment in the channel. If he does not send the payment, he will not receive the service and there is nothing to deny (trivial case). If he sends the payment to the vendor, this will record the last one received containing the total amount. Because the proof is represented by a message hash and a signature, the public key of the buyer can be recovered, which proves that the buyer has signed it. On the vendor’s side, we assume he offers a service in exchange of a payment proof. Assuming he has not received the payment proof, he simply does not provide the service. A rational vendor has interest to be paid via the channel, therefore interest to acknowledge all received transactions (non-deniability).

Information Disclosure The smart contract is public, so an attacker can learn information about who is currently having a channel. This can be achieved by two means: side channel attack involving transaction inspection by crawling the blockchain and correlating which addresses interact with the contract with the publicly available transacted amounts or by inspecting contract fields themselves if they are mistakenly declared as public. Mitigation of the latter can be achieved by safe programming practices (private data members, internal functions, etc.)

Denial of Service One of the chosen approaches allows creation of channels with multiple IDs between two participants. Considering that an attacker has freedom in generating infinitely many public-private key pairs representing separate accounts, he can open infinitely many payment channels with the minimum amount (e.g., enforced minimum channel deposit of 1 ether), thus causing EVM memory exhaustion. However this is considerably expensive, but would achieve a successful DoS of the smart contract.

Elevation of Privilege There are no hierarchies in this decentralized application. There is no contract owner that has exclusive function calls available and there is no notion of privilege implied by the web interface. Therefore, we can state that there are no major risks of privilege escalation.

Smart Contracts Security Considerations

It is important to implement explicitly the fallback function such that no undesired functionality can get triggered by hidden Solidity calls, such as using call() or sending transactions directly from attacker wallets. The fallback function is implemented as empty. It only allows the buyer to top-up the channel directly from his wallet, as it is declared payable, but it does not have additional side effects. A rational agent would only send money under the assumption that there exists a previously opened channel and this channel is initiated by the agent.

The first approach involving the one-time self-destroyable channel contract was vulnerable to overwriting the channel sender and receiver. The vulnerability was mitigated through managing unique channel IDs for Contract structures.

One other consideration is the visibility of the data members, which should be internal or public, such that external calls (e.g., from other smart contracts) do not reveal channel details. These have been implemented as such.

When sending funds, the transfer function was used, as it guarantees default transaction reversal on failure. The send function requires explicit error handling.

Practical Tutorial following my GitHub Project

First install Truffle, Ganache, Metamask and run npm install to get the project dependencies.

Use the following Ganache mnemonic to generate the buyer and sender addresses used by the smart contract. Ganache mnemonic: become awake empower census float naive butter latin enlist nephew clock news

There are two modes of the application: 1) Unique self-destroyable channel contract (vulnerable to overwriting) 2) Multiple channel contracts between buyer and seller (not vulnerable to overwriting)

To select one of them, change the “multiChannel” boolean variable in src/js/index.js.

To run the payment channel:

  1. Open Ganache with the above mnemonic such that addresses are generated deterministically for the PoC
  2. The Seller’s address will be: 0xeB69331eE6C91C97FDE4B11ab0f8b69F6c7fCf2D Import this in MetaMask
  3. The Buyer’s address can be any other address
  4. Run the script ./run.sh

You should be able to replicate a scenario similar to this:

Buyer Identity and Balance retrieved from Metamask. Amount to deposit 50 ETH

alt

Channel of 50 ETH opened by Buyer

alt

Make Two Off-chain Payments of 25 ETH. Send Proof to Vendor directly. Last payment value is accumulated

alt

Vendor Initiates Channel Close: Three TXs (first contract send (buyer proof), sign, second contract send (vendor proof))

alt

Final State: Vendor approx 150 ETH and Buyer 50 ETH

alt

References:

  1. Raiden Network: https://github.com/raiden-network/microraiden
  2. Payment Channels Tutorial:

https://medium.com/@matthewdif/ethereum-payment-channel-in-50-lines-of-code-a94fad2704bc?fbclid=IwAR0gmPllY6lQQf9QiWVoRbRJ4OP0zYnmESwsJDDfGGTCqeRZVuIMkvZvE8c