A Smart Contract for a Smart Car

Pablo Ruiz
HackerNoon.com
Published in
16 min readNov 1, 2017

--

Last year while I was attending a fintech conference I listened Brett King talking about how the cars of the future would be able not only to drive by themselves, but also, thanks to Blockchain technology they would be able to work for their owners. Since I heard that there have been a few developments in this area, but we are yet very far from being able to own a piece of a car that will drive for Uber instead of accumulating dust in a parking lot and making money for me while I’m at the office.

That talk stuck with me, but as much as I’d like to build such a car, I don’t even know how a regular car works. Fortunately for me, I do know a bit about software development and smart contracts, so in this article I’d like to give some thought about how I’d build such a contract for a driverless car.

For this article I’ll layout the basics of an autonomous car whose ownership is shared by several people. The car will be available for any 3rd party to rent it for the day and then, once the rental period is over it will distribute its earnings to the owners. (Minus eth gas stipends and other expenses).

Some assumptions and considerations about this smart car and its contract

For this analysis I will be making some assumptions that will simplify the logic of the smart contract.

First, I’ll be assuming that the car, somehow, is running a full node that allows it to sign transactions. The car would own an account/address which will be the “owner” of the smart contract that interacts with the different actors.

Second, I won’t be dealing with a lot of real-world issues such as the person renting the car stealing it, or being involved in an accident that renders the car unusable.

Third, ownership of the car will be very simple. First of all, owners get a piece of the car from the get go, assuming the payment was made off-chain in the dealership. Then, each owner has an equal share of the car. Finally, we won’t be dealing with complex decisions as this article would get very extensive.

Finally, I’m also assuming that the car, somehow, provides the user with some interface that is able to interact with the smart contract. Furthermore, the car can schedule certain functions to be called later in time, such as calling the function in the smart contract that ends the rental period after 24 hours. Also, I’m assuming that the users posses a device capable of interacting with the blockchain such as a web3 enabled browser.

The purpose of these assumptions is making the smart contract as simple as possible while leaving as many decisions as possible to the car itself. I’m quite certain that what follows is possible in a real-world scenario, but may not be the optimal solution. By all means, feel free to discuss better approaches or point out parts of the contract that you think would not work at all in the real world.

The Smart Contract

The complete code for the smart car contract (v0.1) can be found in the following Github repo: https://github.com/pabloruiz55/SmartCar/blob/master/contracts/SmartCar.sol
What follows is not the complete code, but a highlight of the most important parts of it.

Initializing the car smart contract

//The address of the car, which will sign transactions made by this contract.
address public carSigner;
// Value of the car, in wei
uint public carValue;
bytes32 public licensePlate;// Owners of the car, they will be the ones that receive payments from the car.
// We assume each owner owns the car equally.
address[] public owners;
uint constant MAX_OWNERS = 100;
//Earning from driving will be distributed to each owner for them to withdraw
mapping (address => uint) public ownersBalance;
uint public balanceToDistribute;
uint constant INITIAL_CAR_SHARES = 100;
mapping (address => uint) public carShares;
DriverEntity currentDriverEntity;
DriveStatus currentDriveStatus;
//To keep track of who's currently using the car
//If the owners are driving it, it will be their address.
//If someone rented it, it will be the renter address, so he can be held accountable.
//In this case, we could even ask for a warranty which will be sent back if the car is ok.
address currentDriverAddress;
uint currentDriveStartTime = 0;
uint currentDriveRequiredEndTime = 0;
//Rates
uint constant RATE_DAILYRENTAL = 1 ether; //1 ETH
enum DriverEntity {
None,
Owner,
Autopilot,
Cab,
Uber,
DailyRental,
Other
}
enum DriveStatus {
Idle,
Driving,
TurnedOff,
Unavailable
}
// Somehow, the car should be able to communicate its "internals" to the contract.
// These internals are the ones relevant to the functioning of the contract, such as it's fuel.
// We don't care about oil or coolant for example, at this point at least.
struct CarInternals {
uint fuel; //Measured in percentage
}
CarInternals carInternals;bool carIsReady = false;modifier onlyIfReady {
require(carIsReady);
_;
}
function SmartCar(bytes32 _licensePlate, uint _carValue){
require(_licensePlate.length >0 && _carValue > 0);
carSigner = msg.sender;
carValue = _carValue;
licensePlate = _licensePlate;
carShares[address(this)] = INITIAL_CAR_SHARES;
currentDriveStatus = DriveStatus.Idle;
currentDriverEntity = DriverEntity.None;
carInternals.fuel = 100;
}

Let me explain each state variable and the constructor for the SmarCar contract:

carSigner: This is the account that represents the car. As I mentioned before, the car is supposed to be running its own node which will sign the transactions that it needs to execute. This is the account that will deploy the contract for the car. In a real life scenario, I imagine the manufacturer setting up the car node and account. We would assume that neither the dealership nor the manufacturer has access to the private keys of this account. What I’m trying to say is: The car will need to execute contract functions and the only way for it to do it would be if the car itself is an Externally Owned Account that can communicate with the smart contract without depending on human interaction.

carValue / LicensePlate: This are values that should be provided when the car contract is deployed. LicensePlate could be used to identify the car (We are not making any checks to make sure it is unique, though) and carValue sets the price the owners paid for it. We are not using carValue, but we could have a function that allows an owner to sell his share of the car to someone else, and carValue/owners could be used for establishing a base price.

owners / MAX_OWNERS = 100: Owners is an array that holds the address of all the owners of the car. MAX_OWNERS is a constant that will put a cap on how many owners the car can have.

ownersBalance / balanceToDistribute: ownersBalance will be used to store the pending balance each owner has available for withdrawal. When the car starts a paid ride it will store the ether received in its own balance, then when the ride ends it will be distributed to each owner in equal parts for the owner to manually withdraw his balance.

carShares / INITIAL_CAR_SHARES = 100: carShares is used to store how much of the car each owner has. For the time being, we made it so that each owner owns equal parts of the car, but it could be done so someone could own 50% of the car and other 10 people 5% each. That would also have to affect how earnings are distributed so it is done pro-rata.

currentDriverEntity / currentDriveStatus: These variables are part of a state machine that will control what the car is currently doing. For instance, if its being driven, the contract shouldn’t allow for someone else to rent it. We are also using DriverEntity to keep track of what the car is currently doing — Is it working for Uber? Has it been rented for the day? Is one of the owners using it? This also raises a few more questions about how autonomous the car should be and how to determine what it should be doing, which I’ll discuss at the end of the article, but that is also way out of the scope of this article.

currentDriverAddress / currentDriveStartTime / currentDriveRequiredEndTime: These variables keep track of who has currently rented the car, when the rental period started and when it is supposed to end (24 hours after the rental period started). currentDriveRequiredEndTime is used to determine if the person that rented the car returned it within the specified rental period. For the time being we are just logging this, but some action could be taken if the conditions are not met.

CarInternals: We are not doing anything with this yet, but this could be used to keep track of the internals of the car. Does it need fuel? What’s the battery status? Does it need an oil change? Coolant? If any of these internals are in critical levels, what should it do?

SmartCar constructor: The constructor of this contract is pretty straightforward. We are just setting the initial state of a few of these variables and most importantly assigning the carSigner.

Assigning the owners

//We will assume, for the time being, that the owners are set by the carSigner automatically,
//and that they can't be changed.
//We are basically doing the purchase of the car, off-chain.
//We also assume that each person payed the same amount for the car, thus owning equal shares.
function setOwners(address[] _owners) public {
require(msg.sender == carSigner);
require(_owners.length > 0 && _owners.length <= MAX_OWNERS);
//Can only set owners once.
require(owners.length == 0);
owners = _owners; //We take the total carShares the "car" owns and we distribute them equally among new owners
//If the shares are not properly divisible (I.E: 100 shares / 3 owners) the remaining shares stay with the car

uint sharesToDistribute = carShares[address(this)]/owners.length;
for (uint8 i; i<owners.length;i++){
carShares[owners[i]] = sharesToDistribute;
carShares[address(this)] -= sharesToDistribute;
}
carIsReady = true;
}

The setOwners function receives an array of addresses making them the owners of the car. After this function is called, the car will have one or more owners which will share the carShares in equal parts.
This function is meant to be called by the carSigner, which I don’t yet know if optimal, but we are assuming this is set up at the dealership. So, as you must have figured out by now, there’s a huge part of the system that still requires a lot of human interaction and coordination. In this case, the dealership would be responsible for having these owners pay their part of the deal and then, somehow, have the car register its brand new owners. I imagine the guy at the dealership using his password to unlock some kind of interface in the car that will prompt it to execute this function on the smart contract.

Renting the car for the day

// Anyone can rent the car for the day, as long as it is idle.
// In real life, the workflow could be as follows:
// 1. User calls this function from his mobile device or browser web3 dapp, sending the correct amount of eth
// 2. The system generates a PIN number (we are just using his address as PIN right now)
// 3. User gets on the car and unlocks it using the pin.
// As it stands, we assume that the car, somehow recognizes that the user
// that paid is actually in the car. We added a activateCar function that
// acts as if it was a PIN.
function rentCarDaily() public onlyIfReady payable{
//No one must be using the car
require (currentDriveStatus == DriveStatus.Idle);
require (msg.value == RATE_DAILYRENTAL);
currentDriverAddress = msg.sender;
currentDriveStatus = DriveStatus.Driving;
currentDriverEntity = DriverEntity.DailyRental;
currentDriveStartTime = now;
currentDriveRequiredEndTime = now + 1 days;
balanceToDistribute += msg.value; // ADD SafeMath Library E_RentCarDaily(currentDriverAddress,msg.value, currentDriveStartTime,currentDriveRequiredEndTime);
}

Once the car has been acquired it is ready to be used. Right now we are only implementing one rental option: anyone can rent it by the day, by paying 1 eth (yes, since its a very novel and amazing car its price is outrageous).
What this function basically does is to set its new state (being driven as a rental for the day) and registering who rented it, at what time and when he should be returning it. Also, we are adding the ether received to the contract’s internal balance so it knows how much money should be later distributed to the owners.
Once again, there’s a lot of assumptions going on here. I’m imagining the person renting the car used his web3 enabled browser to access a dapp to execute this function. But how does the car know that the person starting the car is this person. Well, we could have this function generate a receipt with a PIN number and have the car prompt for the PIN when someone tries to start it. Another solution could be to have the car prompt for payment when someone tries to drive it, but this would require a high level of trust as the driver would have to use his private key to sign the transaction in a rather public device. It would be a very risky proposition… I wouldn’t try to access my home banking from a pc in a public library, why would I unlock my Ethereum account in a “public” car?

// For the car to start it will ask the user for his PIN. Instead of generating a PIN
// we are using his address as PIN, making sure they match.
// This would be done in the car interface, of course it's a terrible user experience to as for an
// address instead of a 4 digit PIN, but it will do for now.
// We are not using this internally.
function activateCar(address _user) public view onlyIfReady returns(bool){
require (_user == currentDriverAddress);
return true;
}

Here’s a very simplistic solution. Assume the car prompts the user to enter his address each time he tries to start the car. It would check if the address entered is the same that rented the car. Simple but suboptimal. For one, anyone could scan the latest transactions to know who rented it and use his address to “steal” the rental from them — though this could be mitigated by hashing the address. Second, it’s a terrible user experience! Imagine having to enter 42 characters in the car touchscreen just to start the car each time.

Returning the car and distributing earnings

// This should be called by the end of the rental period.
// Driver would tell the car to end the rental and the car would execute this function.
// Also, the car can call it if the rental period ended. (This would be scheduled car-side)
// Here, we distribute earnings and do the necessary cleanup such as
// issuing fuel recharge if needed.
function endRentCarDaily () public onlyIfReady {
// The person renting the car can end the rental anytime.
// The carSigner can end the rental only after the renting period has ended
// in order to "claim the car back".
require ((msg.sender == carSigner && now > currentDriveRequiredEndTime)
|| msg.sender == currentDriverAddress);
//To be called only if it is being rented for the day.
require (currentDriveStatus == DriveStatus.Driving);
require (currentDriverEntity == DriverEntity.DailyRental);
bool endedWithinPeriod = now <= currentDriveRequiredEndTime; E_EndRentCarDaily(currentDriverAddress, now, endedWithinPeriod); currentDriverAddress = address(0);
currentDriveStatus = DriveStatus.Idle;
currentDriverEntity = DriverEntity.None;
currentDriveStartTime = 0;
currentDriveRequiredEndTime = 0;
//Distribute earnings of the car rental
distributeEarnings();
}

Once the customer is done with the car he can return it by calling this function. This will basically end the rental period, make the car available again for others to rent it and distribute the earnings to the owners. The car itself can end the rental period if 24 hours have passed and the driver has not done it. For this to be possible, that car would have to schedule this function call internally as there is no way as of today for a contract function to be scheduled.
Notice we are not doing anything to punish the driver for not returning the car in time, but something could be done like asking for a warranty payment beforehand and holding that in escrow until the car is returned. If they returned the car after the 24 hours rental period ended they could be charged extra.
Also, we are not taking into account the fuel level the car had when it was rented. Should the driver return the car as it was when it was rented? Should he be charged more for the fuel difference? — Or even refund money if gas was at 50% and they return it at 75%?

//Distribute earnings to owners
function distributeEarnings() internal onlyIfReady {
//If the carSigner is running out of eth for transactions, transfer before distribution
transferEthForStipends();
//ETH should also be reserved for recharging fuel at a station. Not considered yet.
//refuelCar();
uint earningsPerOwner = balanceToDistribute / owners.length;
for (uint8 i=0;i<owners.length;i++){
ownersBalance[owners[i]] += earningsPerOwner; // ADD SafeMath Library
balanceToDistribute -= earningsPerOwner; // ADD SafeMath Library
}
}

Once the car has been returned it will calculate and distribute the money to each one of the car shareholders. Before the money is distributed, it has to keep some money to pay for its own expenses, though.
For the time being we are just considering the gas stipends the carSigner has to pay for for calling each and every function throughout the day. Each transaction the car does costs some gas and the carSigned is the one that pays for them in most cases, so it should have an allocation of ether for the car to be able to function properly.
Here we could also calculate the fuel that was consumed and other expenses the car had to pay during this trip. — Tolls, public parking, etc. — and keep that money before distributing its balance to the owners.

// carSigner will need eth to pay for gas stipends being used throughout the day.
// It should be able to get it from the car contract balance.
// This would be called by the car automatically each day, for example.
function triggerTransferEthForStipends() public onlyIfReady{
require(msg.sender == carSigner);
transferEthForStipends();
}
function transferEthForStipends() internal onlyIfReady { uint amount = 1 * (10 ** 17); // 0.1 eth per day should be enough
require (carSigner.balance < amount);
require(balanceToDistribute >= amount);
balanceToDistribute -= amount; // ADD SafeMath Library
carSigner.transfer(amount);
E_TransferEthForStipends(carSigner,amount, now);
}

This function makes sure carSigner (the car) has enough eth for calling the car contract functions throughout the day. This gets called after every ride, just in case, but can also be triggered by the car if it detected it doesn’t have enough money to function properly.

Withdrawal of funds

//Each owner should call this function to withdraw the balance they have pending.
function withdrawEarnings() public onlyIfReady{
//Make sure the one calling the function is actually an owner
bool isOwner = false;
for (uint8 i=0;i<owners.length;i++){
if (owners[i] == msg.sender){
isOwner = true;
break;
}
}
require (isOwner);
uint balanceToWithdraw = ownersBalance[msg.sender];
require (balanceToWithdraw > 0);
ownersBalance[msg.sender] =0;
msg.sender.transfer(balanceToWithdraw);
}

Finally, at any time, each owner can execute this function to withdraw whatever pending balance they are owed.

Where to go from here?

There are so many improvements that could be made to this contract that it’s hard to figure out where to start. I’ve raised a few concerns and pointed several places in the code where there could be room for improvement, for instance:

  • Is there a better way to build this rather than having the car execute transactions? How can the car node be set up safely. Should the manufacturer do this? The dealership?
  • We are not using carValue. Should we allow owners to sell their share of the car? Should we use carValue or the owner can set his asking price? Should anyone be able to sell his share of the car at any moment? Should there be a voting process? Can anyone buy it?
  • We are not contemplating a case where someone could buy a bigger share of the car. Right now everyone has the same ownership percentage, and we are assuming the all paid the same amount of money at the dealership. — Well, we are also assuming a dealership is prepared to have multiple people buy a share of a car in Fiat currency and somehow that translates to this on-chain scenario seamlessly, :D —
    So, this could be done differently and not necessarily each owner should own the car in equal parts. This would also affect earnings distribution and expenses.
  • Right now we assume the car is Idle and that anyone can come and rent it for the day (or an owner use it, or have it work for Uber, though these functions have not been implemented). But how should the car decide what it should do? Should it allow someone to rent it for the day without asking the owners if they will need it today? If several owners express their need to use the car, how will it be decided who has priority over it? If the car is meant only for rental, how does it decide when it’s best to work for Uber or be rented for the day or work as a cab?
  • When the car is returned, if it was not returned within the 24 hours period, we are not taking actions. What should happen if the rental period is over and the driver didn’t return the car yet. Should the car, somehow, stop working? Should it prompt the driver to make a new payment? Should we have asked for a warranty before rental and kept the money on escrow? Should we blacklist the driver so they are not allowed to rent this car (or any other car in the network) ever?
  • The car internals: The contract will need to know, at the very least, if the car need refueling. What would be the most efficient way for the car to communicate this? We are assuming the car has every kind of sensors that would allow it to get this data and in turn, forward this data to the smart contract.
  • The way we assign the owners is suboptimal. First, we could have another entity, the car dealership for example, that upon receiving the money is authorized to call this function on the car smart contract to register the owners. Second, in this example, we are allowing owners to be set just once when the car is bought. How about letting a current owner buy another one out? What if we wanted someone else become owner of the car later on? Third, and this has to do in part with the fact that we are not allowing owners to own more shares of a car than others, if we have 3 owners they are getting 33% of the car each and the remaining 1% is held by the car itself, what should we do with that?
    Finally, so far it doesn’t even matter how much of the car someone owns as it is not being used to calculate the distribution of earnings. One more thing, maybe we don’t even have to distribute the money the car earns according to ownership.

As you can see, this articles raises a lot of questions for which I don’t have the answers yet, but I hope it starts a debate on how the Ethereum blockchain is supposed to interact with IOT projects and the other way around.

Feel free to share any suggestions or critics in the comments section below!

--

--

HackerNoon.com
HackerNoon.com

Published in HackerNoon.com

Elijah McClain, George Floyd, Eric Garner, Breonna Taylor, Ahmaud Arbery, Michael Brown, Oscar Grant, Atatiana Jefferson, Tamir Rice, Bettie Jones, Botham Jean

Pablo Ruiz
Pablo Ruiz