Skip to content
This repository was archived by the owner on Jul 19, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 70 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,74 @@
# iexec dapps samples
# OwnerChain

This is the registry for sample iexec dapps, used by the iexec-sdk cli.
### Motivation

Each branch name of this repo can be used as an argument to iexec init command.
Provenance tracking is a common problem in various areas: Jewelers want to be sure that the diamonds they are using do not originate from conflict zones. Manufacturers of organic products have to ensure that all parts of their supply chain fulfill their specific requirements. Even wine collectors might demand proof that an expensive bottle is actually authentic. Provenance tracking establishes a verifiable history and provides trust that items have not been altered, stolen or forged.

ex:
To enable provenance tracking, some sort of ledger or record needs to be kept that includes all the required information about an article or asset. Even if such a ledger exists, though, it is difficult to verify its authenticity and that it has not been tampered with. There is always a need for trust between the involved parties, which is often undesirable.

```bash
iexec init
iexec init factorial
iexec init echo
```
With blockchain technology, however, a framework is emerging that might be able to solve most if not all the problems mentioned. Using a distributed ledger that is immune to manipulation --- if configured correctly --- allows for interactions that do not require trust and can be individually verified.

### Idea Proposal
Our DApp idea is to build a provenance tracking system in the iExec/Ethereum ecosystem. The prototype, called *OwnerChain*, is focused on tracking bicycles: Users are able to register bikes using trusted third party verifiers and validators. Users can refer to the DApp on local sales sites such as craigslist to provide a proof of their ownership. The system can then be used to safely transfer funds and ownership via the Ethereum blockchain.

iExec in conjunction with smart contracts provides trusted computation and will be used to power features extending the basic ownership use case:

- transfer of ownership
- enforcing rules, such as restricting the number of bikes per user
- analysing user behaviour for fraudulent activities
- semi-automatic verification of bike ownership through third party or machine learning
- extension to other assets, using other forms of verification




### Architecture
![Components](images/component_diagram.png)
*Fig. 1: Components in the OwnerChain system*



Figure 1 shows a diagram of the components of the OwnerChain system:

- The mobile client is the gateway for the user to register their bike to the system and buy or sell it using cryptocurrencies.
- Third party verification services are used to authenticate the user and the bike.
- The iExec off-chain app will serve as a trusted middleman to check legitimacy of requests and interact with the smart contracts.
- The OwnerChain smart contract will store ownership information and handle ownership transactions.
- IPFS will serve as a store for additional bike data.
- The web frontend will serve as a simple way to view stored information on the OwnerChain, submit buy and sell requests as well as offer some admin functionalities.



![Bike registration sequence](images/sequence_diagramm.png)
*Fig. 2: Bike registration sequence diagram*



Verifying the user ID is done via a third party app, such as Civic, which returns an identity token uniquely identifying the user. Using our OwnerChain app, the user scans the bike frame number and assembles further information about the bike (e.g., bike brand, year of purchase and similar information). Users will be required to include some proof of ownership, such as purchase receipts or a national bike registry entry.

This information is encrypted and uploaded to a generic file hoster. The app sends a registration request to the iExec service, including the identity token and the URL to the previously uploaded package. The package is then retrieved by iExec. The hoster may be skipped if direct data upload to iExec becomes available in the future. To authenticate that the identity token is legitimate, it is validated at the ID verifier. The bike serial number is used to search in known databases of stolen bikes for any matches, in which case the proposal would be rejected and the user flagged. The identity information is matched with the uploaded information about the bike. If everything is valid, the bike data is uploaded to a distributed file system for long-term storage. Then the bike gets registered on the blockchain via the OwnerChain contract.

The ownership proofs for bikes will be verified by hand at first --- automation of the verification will be the topic of further research. Machine-learning approaches, specifically image recognition and OCR with fallbacks to Amazon Mechanical Turk workers for doubtful cases are conceivable. In the long run, bicycle vendors will be incentivized to participate, securely recording the ownership transfer via specialized vendor authorization features, therefore completely alleviating the user trust issue.

The app will contain features to easily buy and sell bikes or transfer ownership by directly calling smart contract methods. The mobile app will therefore have an Ethereum address directly associated with the user, which constitutes the ownership in the smart contract and can be used to handle buying and selling by payment in Ether.

### Roadmap
- OwnerChain smart contract implementation (ownership registration, transfer, escrow): *Q1 2018*
- implementation of off-chain application on iExec: *Q2 2018*
- interaction with the OwnerChain smart contract
- retrieval and storage of data on IPFS
- API access point for mobile app
- implementation of simple web frontend: *Q2 2018*
- web frontend for buy/sell/lookup functionality
- offer simple bike registration procedure in interaction with iExec off-chain app (to be replaced by a mobile app later on)
- implement mobile app beta: *Q3 2018*
- implement UI (upload forms for bike data)
- integrate identity verification
- interaction with offchain app
- direct interaction with smart contracts
- implement bike ownership verification: *Q3 2018*
- productive release on main net: *Q4 2018*
- expand to other assets

### Background
We are two postgrad CS students and have previously developed academic prototypes of the smart contracts in this proposal. We want to use our experience to implement a working system usable in everyday life.
267 changes: 267 additions & 0 deletions contracts/Bicycle.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
pragma solidity ^0.4.11;

import "./OwnerChain.sol";
import "./StorageContracts.sol";

/// Per-bicycle contract containing methods for transferring ownership,
// buying & selling and uploading files associated ẃith the bike.
contract Bicycle {

///////////////////////////
///// public members //////
///////////////////////////

// Essential bike information
bytes32 public serialNumber;
string public manufacturer;
address public owner;

// States of the buy/sell cycle, inactive is the default state.
enum State { Inactive, Acknowledged, Locked }
State public purchaseState;

// Address which has been authorized by selling to proceed with purchase
address public acknowledgedBuyer;

// Requested price for bike
uint public requestedValue;

///////////////////////////
///// private members /////
///////////////////////////

// List of all previous and current bike owners
address[] private ownerlist;

// Swarm Data Structures, adapted from:
// https://bitbucket.org/rhitchens2/soliditycrud/src/83703dcaf4d0c4b0d6adc0377455c4f257aa29a7/contracts/SolidityCRUD-part2.sol
struct FileStruct {
bytes32 hash;
uint timestamp;
uint index;
}
mapping(bytes32 => FileStruct) private fileStructs;
bytes32[] private fileIndex;

// Reference to storage is needed to retrieve current version of ownerchain
AbstractStorageContract private storageContract;

///////////////////////////
//////// modifiers ////////
///////////////////////////

modifier condition(bool _condition) {
if (!_condition) throw;
_;
}

modifier onlyBuyer() {
if (msg.sender != acknowledgedBuyer) throw;
_;
}

modifier onlyOwner() {
if (msg.sender != owner) throw;
_;
}

modifier inState(State _state) {
if (purchaseState != _state) throw;
_;
}

////////////////////////
//////// events ////////
////////////////////////

event aborted();
event rejected();
event purchaseConfirmed(address newOwner);
event itemReceived();
event ownershipTransferred;
event fileAdded(bytes32 hash, uint timestamp, uint index);

/////////////////////////
//////// methods ////////
/////////////////////////

// Create a new bicycle contract
function Bicycle(bytes32 _serialNumber, string _manufacturerName, address _owner, address _storageContract) {
serialNumber = _serialNumber;
manufacturer = _manufacturerName;
owner = _owner;
ownerlist.push(owner);
purchaseState = State.Inactive;
storageContract = AbstractStorageContract(_storageContract);
}

/// Returns if hash is in file list
function hasFile(bytes32 _hash)
public
constant
returns(bool _hasIndeed)
{
if (fileIndex.length == 0) return false;
return (fileIndex[fileStructs[_hash].index] == _hash);
}

/// Adds hash of file to list of files, used for swarm file uploads.
function addFile(bytes32 _hash)
onlyOwner
{
if (hasFile(_hash)) return;
fileStructs[_hash].timestamp = block.timestamp;
fileStructs[_hash].index = fileIndex.push(_hash) - 1;
fileStructs[_hash].hash = _hash;
fileAdded(_hash, block.timestamp, fileStructs[_hash].index);
}

/// Returns number of stored files
function getFileCount()
public
constant
returns (uint _count)
{
return fileIndex.length;
}

/// Returns hash of file or 0 not present
function getFile(uint _i)
public
constant
returns (bytes32 _hash)
{
return fileIndex[_i];
}

/// Abort the purchase and reclaim the ether.
/// Can only be called by the seller before
/// the contract is locked.
function abortPurchase()
onlyOwner
inState(State.Acknowledged)
{
aborted();
purchaseState = State.Inactive;
acknowledgedBuyer = address(0);
requestedValue = 0;
}


/// Reject and offer from the seller
/// Can only be called by the buyer before confirming
/// the purchase
function rejectOffer()
onlyBuyer
inState(State.Acknowledged)
{
rejected();
purchaseState = State.Inactive;
acknowledgedBuyer = address(0);
requestedValue = 0;
}

/// Confirm the purchase as buyer.
/// Transaction has to include `requestedValue` ether.
/// The ether will be locked until confirmReceived
/// is called.
function confirmPurchase()
onlyBuyer
inState(State.Acknowledged)
condition(msg.value == requestedValue)
payable
{
purchaseConfirmed(msg.sender);
purchaseState = State.Locked;
}

// Confirm the purchase and directly pay out the ether
// without needing to confirm receipt
function confirmPurchaseNoEscrow()
onlyBuyer
inState(State.Acknowledged)
condition(msg.value == requestedValue)
payable
{
purchaseConfirmed(msg.sender);
// It is important to change the state first because
// otherwise, the contracts called using `send` below
// can call in again here.
purchaseState = State.Inactive;

if (ownerlist.length <= 1) {
if (!owner.send(this.balance)) throw;
} else {
// send incentive of 5% to previous owner
if (!owner.send(this.balance * 19 / 20)) throw;
if (!ownerlist[ownerlist.length - 2].send(uint(this.balance))) throw;
}

// Retrieve the current ownerchain address from the storage contract
OwnerChain ownerchain = OwnerChain(storageContract.ownerchainAddress());
// Let ownerchain update its data structures
ownerchain.bikeOwnershipTransferred(owner, acknowledgedBuyer, serialNumber);

owner = acknowledgedBuyer;
ownerlist.push(owner);
acknowledgedBuyer = address(0);
}

/// Allow a particular address to purchase the bike for the requested value.
function allowPurchase(address allowedBuyer, uint _requestedValue)
onlyOwner
inState(State.Inactive)
{
acknowledgedBuyer = allowedBuyer;
requestedValue = _requestedValue;
purchaseState = State.Acknowledged;
}

/// Confirm that the buyer received the item.
/// This will release the locked ether.
function confirmReceived()
onlyBuyer
inState(State.Locked)
{
itemReceived();
// It is important to change the state first because
// otherwise, the contracts called using `send` below
// can call in again here.
purchaseState = State.Inactive;

if (ownerlist.length <= 1) {
if (!owner.send(this.balance)) throw;
} else {
// send incentive of 5% to previous owner
if (!owner.send(this.balance * 19 / 20)) throw;
if (!ownerlist[ownerlist.length - 2].send(uint(this.balance))) throw;
}

// Retrieve the current ownerchain address from the storage contract
OwnerChain ownerchain = OwnerChain(storageContract.ownerchainAddress());
ownerchain.bikeOwnershipTransferred(owner, msg.sender, serialNumber);

owner = acknowledgedBuyer;
ownerlist.push(owner);
acknowledgedBuyer = address(0);
}

/// Direct transfer of ownership without no payment
function transferOwnership(address to)
onlyOwner
{
ownershipTransferred();

owner = to;
ownerlist.push(to);

OwnerChain ownerchain = OwnerChain(storageContract.ownerchainAddress());
ownerchain.bikeOwnershipTransferred(msg.sender, to, serialNumber);
}

/// Get essential values for buyer
function getBuyDetails() constant returns (address _ownerAddr, address _acknowledgedBuyerAddr, uint _requestedValue) {
return (owner, acknowledgedBuyer, requestedValue);
}

}
1 change: 1 addition & 0 deletions contracts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The shown bicycle contract is an exemplary prototype for the bicycle contract. This contract and the corresponding OwnerChain contract will be reworked, as some notions will change. For example, the original draft focused heavily on manufacturers, a user group which will not be present in the first version of the OwnerChain DApp.
Binary file added images/component_diagram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/sequence_diagramm.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.