A Winding Tree tutorial

There is one project that really caught my eye in the travel industry recently which is Winding Tree. This open-source project aims at nothing less than replacing the backbone of the travel industry by a blockchain.

According to their white paper:

Five companies in the travel industry control the most of the travel market. The two largest OTAs (Online Travel Agencies), Priceline Group and Expedia Inc., control 95% of OTA market in the U.S. Amadeus, Sabre, and Travelport, the top three GDSs (Global Distribution Systems), have 99% combined market share in non-direct inventory in the air market.

Boom, problem stated. And they partnered with some big names like Lufthansa Group. As someone working in the travel technology area I had a lot of questions: how the project team plans to disrupt a trillion dollar industry? How the economics work? How do they solve the technology challenges? In order to get answers to my questions, I decided to get a first hand experience, experiment with the open source code they have released and share my feedback in a tutorial.


For this tutorial we are going to use the Minimum Viable Product (MVP) for hotels that is available on Winding Tree’s Github. It is expected to change a lot but that’s already good to get an understanding of the potential of the technology.

Our goal will be to:

  • Create an Hotel on the blockchain with one room
  • Book this room for 5 days.

We will need some tools to interact with the smart contracts: git, node (≥7.6), npm and truffle. If you don’t have them already just follow the instructions from their respective pages.

We clone the contracts and install the dependencies:

$ cd /tmp
$ git clone https://github.com/windingtree/wt-contracts --recursive
$ cd wt-contracts
$ npm install

We just want to test the contracts without actually interacting with the live blockchain, so we will use a specific testrpc server that simulates the blockchain and brings some benefits:

  • We don’t have to pay real money to interact with the blockchain,
  • We do not have to synchronize all the blockchain on our computer,
  • We do not need to wait for the mining processes

In a live environment we would need first to to import our Ethereum account address on the Ethereum node and unlock it using the private key, but here testrpc has already unlocked the first account for us.

Also Truffle has a Javascript interpreter with a web3 provider injected, so for the purpose of this tutorial we will simplify the setup and just execute Javascript code in the command line. The same code could be run by a Node.js server or in a Web Browser.

We enter the truffle development console:

$ truffle develop
Truffle Develop started at http://localhost:9545/
Accounts:
(0) 0x627306090abab3a6e1400e9345bc60c78a8bef57
(1) 0xf17f52151ebef6c7334fad080c5704d77216b732
(2) 0xc5fdf4076b8f3a5357c5e395ab970b5b54098fef
(3) 0x821aea9a577a9b44299b9c15c88cf3087f3b5544
(4) 0x0d1d4e623d10f9fba5db95830f7d3839406c6af2
(5) 0x2932b7a2355d6fecc4b5c0b6bd44cc31df247a2e
(6) 0x2191ef87e392377ec08e7c08eb105ef5448eced5
(7) 0x0f4f2ac550a1b4e2280d04c21cea7ebd822934b5
(8) 0x6330a553fc93768f612722bb8c2ec78ac90b3bbc
(9) 0x5aeda56215b167893e80b4fe645ba6d5bab767de
Mnemonic: candy maple cake sugar pudding cream honey rich smooth crumble sweet treat
truffle(develop)>

Truffle automatically starts an Ethereum node and creates some test accounts for us with free ETH (unfortunately only valid within our testrpc instance) and we have the mnemonic associated. During the tutorial we will not bother to change accounts for the different roles: WT Foundation, Hotel Manager, Travel Agency.

Let’s compile the contracts:

> compile
> deploy

We are now ready to start using the Winding Tree contracts!


Here is a very simplified diagram showing the contract hierarchy:

WT Hotel MVP Contract Hierarchy (simplified)

The WTIndex contract is at the root of the hierarchy and created by the Winding Tree Foundation. For this tutorial, our testrpc instance completely simulates the Ethereum blockchain so the contract does not exist and we need to create it:

> WTIndex.new().then(instance => wt = instance)

In a real Ethereum network, we should now wait for the transaction to be picked up by an Ethereum miner, have it included in a block and confirmed several times. However here thanks to our magic testrpc node we do not have to wait and we can get the contract address immediately:

> wt.address
'0xf25186b5081ff5ce73482ad761db0eb0d25abfbf'

Great, our WTIndex contract is now deployed!


Now that we have our WTIndex contract, let’s create an Hotel.

Hotels contracts are created automatically by the WTIndex contract when calling the registerHotel() function. They are not supposed to be deployed directly by the Hotel manager, and they are owned by the WTIndex.

> wt.registerHotel('My Hotel','A very nice Hotel')

We can check that we have our hotel created by calling some other functions, for example to filter only the hotels we manage from the current ethereum account:


> wt.getHotelsByManager(web3.eth.coinbase)
[ '0xf2beae25b23f0ccdd234410354cb42d08ed54981']

The Hotel Contract is created and we have its address. Let’s create a variable h with the instance for convenience:

> wt.getHotelsByManager(web3.eth.coinbase).then(addr => h = Hotel.at(addr[0]))

Let’s check that we are able to access the name and description:

> h.name()
'My Hotel'
> h.description()
'A very nice Hotel'

Cool we have an hotel, but our hotel is completely empty. This is like just having the land without having started the construction. We now need to create rooms and describe how the rooms are like.

For this, we will create a UnitType and a Unit for our room. Contrary to what we did for the Hotel which was created by the WTIndex contract, we need to deploy these contracts ourselves, and we need to give the ownership to the Hotel address.

Let’s create a Basic Room:

> UnitType.new(h.address, 'BASIC_ROOM').then(i => ut = i)
> Unit.new(h.address, 'BASIC_ROOM').then(i => u = i)

Now to add the Unit and UnitType in your Hotel, the trick is the Hotel contract is not owned by our address but by the WTIndex contract. If we attempt to modify it, we will be rejected:

> h.addUnitType(ut.address)
Error: VM Exception while processing transaction: invalid opcode

To add the UnitType and Unit, and in general for all modifications to the Hotel contract, we will need to use the callHotel() function. Fortunately this is protected so that only us as manager can call this function:

> wt.callHotel(0, h.contract.addUnitType.getData(ut.address))
> wt.callHotel(0, h.contract.addUnit.getData(u.address))

To accept bookings, hoteliers have two options:

  • Instantly with Winding Tree native token LIF
  • With a confirmation mechanism with other payment options.

For this tutorial we will use the confirmation mechanism, so let’s configure it:

> wt.callHotel(0, h.contract.changeConfirmation.getData(true))

All set! Our Hotel is created and we are ready to receive bookings from customers! Please note that here we have over simplified the process as naturally we would need to customize the room with description, amenities, price, availability, images, and so on.


Now switching perspective, we will assume we are a Travel Agency (or a very tech-savvy traveller!) and we are going to book the hotel room we created.

Searching for Hotels requires a great deal of indexing in order to avoid duplicated entries, and be able to find the hotel prices, availabilities and amenities in line with the traveller expectations. The current design is quite simple with one index containing all hotels addresses but we can safely assume better indexing mechanisms will be available in the future (for example a tree with countries and cities). The search itself is completely free and fast as all the inventory data is decentralized in each Ethereum node and is only a read access. If you think about it, that’s a great deal for both Travel Agencies and Hotels!

For this tutorial we will assume we already found the hotel and unit we would like to book (that’s easy we have only one!).

In the Winding Tree ecosystem the reservation is made of two parts:

  • A private one with the guest details
  • A public one with the details of the hotel being booked and the dates.

The private one is not specified yet, but the idea is that it’s a JSON structure. An example of such structure freely inspired from the Winding Tree code repository could be:

Example of guest private data

There’s a technical detail here: potentially not all hotels will require the same data and accept the same payment methods so how can the Travel Agency know which fields are mandatory or not?

The decision by the Hotelier to accept or not the booking based on the private data is not relevant for this tutorial, so let’s simply consider an arbitrary string for now.

The mechanism to book is based on Ethereum Events which allow asynchronous interactions over the blockchain. The Travel Agency can initiate the booking request and this creates an event:

> privateData = "PRIVATE_GUEST_DATA"
> publicData = h.contract.book.getData(u.address, web3.eth.coinbase, 20150, 5)
> h.beginCall(publicData, privateData).then(i => beginCalltx = i)

Note: 20150 is the number of day after January 1st,1970: March 3rd, 2025

The Hotel can watch the blockchain for booking events. When an event is received, the Hotel can retrieve the public and private details:

> abiDecoder = require('abi-decoder')
> abiDecoder.addABI(Hotel._json.abi)
> beginCallEvent = abiDecoder.decodeLogs(beginCalltx.receipt.logs)[0]
> beginCalltxCode = web3.eth.getTransaction(beginCalltx.tx).input
> transferDecoded = abiDecoder.decodeMethod(beginCalltxCode)
> abiDecoder.decodeMethod(transferDecoded.params[0].value)
{ name: 'book',
params:
[ { name: 'unitAddress',
value: '0xf25186b5081ff5ce73482ad761db0eb0d25abfbf',
type: 'address' },
{ name: 'from',
value: '0x627306090abab3a6e1400e9345bc60c78a8bef57',
type: 'address' },
{ name: 'fromDay', value: '20150', type: 'uint256' },
{ name: 'daysAmount', value: '5', type: 'uint256' } ] }
> web3.toAscii(transferDecoded.params[1].value)
'PRIVATE_GUEST_DATA'

And accept the booking:

> pendingCallHash = beginCallEvent.events[1].value
> wt.callHotel(0, h.contract.continueCall.getData(pendingCallHash))

Everyone can then see that this room is booked for that day and by which address, and it can not be booked again:

> u.getReservation(20150)
[ BigNumber { s: 1, e: 0, c: [ 0 ] },
BigNumber { s: 1, e: 0, c: [ 0 ] },
'0x627306090abab3a6e1400e9345bc60c78a8bef57' ]
> h.beginCall(publicData, privateData)
Error: VM Exception while processing transaction: invalid opcode

Success!


In this tutorial, we have seen how to use the Winding Tree MVP Contract for Hotel and we have been able to get a feeling of the potential of the platform.

Yet a number of points are still open and require further developments from the Winding Tree team and its community:

  • Scalability: The current cost to setup an hotel is quite high (in gas fees) as we need to send multiple transactions to create each unit type and units and configure them. Frequent updates to the inventory are also required when some works are being done in a given room. A descriptive file stored out of the contract for example in IPFS or SWARM would be much better. Also some general evolutions of Ethereum with the move to Proof-of-Stake and State Channels should greatly improve the situation.
  • Privacy: With the current mechanism, it’s relatively trial with the Hotel Contract ABI to retrieve the guest private data. We have voluntary put in the example a credit card to raise the question of PCI-DSS Compliancy. There is also GDPR in Europe. How is this data going to be secured? Also some Travel Agencies have private rates as a result of business negotiations, should this data be public?
  • Duplicates and Fake listings: Nothing prevents a bad actor to create a fake Index, fake Hotels and so on. They can even generate a lot of dummy reservations to make it appear legit. How is the Travel Agency and ultimately the traveller protected from this situation? It’s not acceptable to have a traveller getting to an Hotel to find there is nothing here, or worst. Any serious implementation will need to put in place a great deal of measures to ensure they have the good contract address to an hotel that do exist in the physical world.

My personal opinion is that the platform in itself does work even if there are many challenges ahead. The platform could completely disrupt the Travel Industry in the coming years, wait and see!