Created
April 11, 2018 16:20
-
-
Save gaiazov/b8e7d4def8a4513f6edc22f72eba46aa to your computer and use it in GitHub Desktop.
AppianWorld 2018 - Ethereum Car Service smart contracts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.2; | |
import "Authority.sol"; | |
contract Auth { | |
enum AuthMode { | |
Owner, | |
Authority | |
} | |
AuthMode public authMode; | |
Authority public authority; | |
function Auth() public { | |
authority = Authority(msg.sender); | |
authMode = AuthMode.Owner; | |
} | |
modifier auth { | |
require(isAuthorized(msg.sender, msg.sig)); | |
_; | |
} | |
function isAuthorized(address senderAddress) public constant returns (bool is_authorized) { | |
return isAuthorized(senderAddress, msg.sig); | |
} | |
function isAuthorized(address senderAddress, bytes4 signature) public constant returns (bool is_authorized) { | |
if (authMode == AuthMode.Owner) { | |
return senderAddress == address(authority); | |
} | |
if (authMode == AuthMode.Authority) { | |
return authority.canCall(senderAddress, address(this), signature); | |
} | |
return false; | |
} | |
function setAuthorityContract(address new_authority) public auth() { | |
authority = Authority(new_authority); | |
authMode = AuthMode.Authority; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.2; | |
import "Auth.sol"; | |
import "CarRegistryInterface.sol"; | |
contract CarRegistry is CarRegistryInterface, Auth { | |
struct Car { | |
string vin; | |
string make; | |
string model; | |
uint16 modelYear; | |
uint24 mileage; | |
uint24 titleStatus; | |
uint24 numberofevents; | |
address manufacturer; | |
mapping (int => Event) events; | |
} | |
struct Event { | |
uint24 eventType; | |
uint8 severity; | |
uint32 date; | |
uint24 mileage; | |
address source; | |
string eventDataIPFSHash; /// where to find the information on ipfs | |
} | |
event CarEvent( | |
string vin, | |
int number, | |
uint32 date, | |
uint24 mileage, | |
address source | |
); | |
event CarAddedEvent( | |
string vin, | |
string make, | |
string model, | |
uint16 modelYear, | |
address manufacturer | |
); | |
mapping (bytes32 => Car) public cars; | |
modifier carExists(string vin) { | |
Car storage car = cars[keccak256(vin)]; | |
require(bytes(car.vin).length != 0); | |
_; | |
} | |
modifier carDoesNotExists(string vin) { | |
Car storage car = cars[keccak256(vin)]; | |
require(bytes(car.vin).length == 0); | |
_; | |
} | |
function getCar(string _vin) public view returns (string vin, string make, string model, uint16 modelYear, address manufacturer, uint24 mileage, uint24 titleStatus, uint24 numberofevents) { | |
Car storage car = cars[keccak256(_vin)]; | |
return ( | |
car.vin, | |
car.make, | |
car.model, | |
car.modelYear, | |
car.manufacturer, | |
car.mileage, | |
car.titleStatus, | |
car.numberofevents | |
); | |
} | |
function addCar(string vin, string make, string model, uint16 modelYear, uint24 mileage, uint24 titleStatus) public auth carDoesNotExists(vin) { | |
cars[keccak256(vin)] = Car(vin, make, model, modelYear, mileage, titleStatus, 0, msg.sender); | |
emit CarAddedEvent(vin, make, model, modelYear, msg.sender); | |
} | |
function updateCar(string vin, string make, string model, uint16 modelYear, uint24 mileage, uint24 titleStatus) public auth carExists(vin) { | |
Car storage car = cars[keccak256(vin)]; | |
car.make = make; | |
car.model = model; | |
car.modelYear = modelYear; | |
car.mileage = mileage; | |
car.titleStatus = titleStatus; | |
} | |
function getEvent(string vin, int eventNumber) public view returns (uint24 eventType, uint8 severity, uint32 date, uint24 mileage, address source, string eventDataIPFSHash) { | |
Event storage _event = cars[keccak256(vin)].events[eventNumber]; | |
return ( | |
_event.eventType, | |
_event.severity, | |
_event.date, | |
_event.mileage, | |
_event.source, | |
_event.eventDataIPFSHash | |
); | |
} | |
function addEvent(uint24 eventType, uint8 severity, uint32 date, uint24 mileage, string eventDataIPFSHash, string vin) public auth carExists(vin) { | |
Car storage car = cars[keccak256(vin)]; | |
car.events[car.numberofevents] = Event(eventType, severity, date, mileage, msg.sender, eventDataIPFSHash); | |
if (mileage > car.mileage) { | |
car.mileage = mileage; | |
} | |
emit CarEvent(car.vin, car.numberofevents, date, mileage, msg.sender); | |
car.numberofevents += 1; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.2; | |
contract CarRegistryInterface { | |
function getCar(string _vin) public view returns (string vin, string make, string model, uint16 modelYear, address manufacturer, uint24 mileage, uint24 titleStatus, uint24 numberofevents); | |
function addCar(string vin, string make, string model, uint16 modelYear, uint24 mileage, uint24 titleStatus) public; | |
function updateCar(string vin, string make, string model, uint16 modelYear, uint24 mileage, uint24 titleStatus) public; | |
function getEvent(string vin, int eventNumber) public view returns (uint24 eventType, uint8 severity, uint32 date, uint24 mileage, address source, string eventDataIPFSHash); | |
function addEvent(uint24 eventType, uint8 severity, uint32 date, uint24 mileage, string eventDataIPFSHash, string vin) public; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.2; | |
import "GroupInterface.sol"; | |
import "Auth.sol"; | |
contract ContractGroup is GroupInterface, Auth { | |
struct MemberStruct { | |
address member; | |
string name; | |
uint listPointer; | |
} | |
mapping(address => MemberStruct) public memberMap; | |
address[] public memberList; | |
function contains(address lookupAddress) public constant returns (bool) { | |
if (memberList.length == 0) { | |
return false; | |
} | |
return (memberList[memberMap[lookupAddress].listPointer] == lookupAddress); | |
} | |
function count() public constant returns (uint) { | |
return memberList.length; | |
} | |
function addInternal(address contractAddress, string contractName) internal { | |
require(!contains(contractAddress)); | |
memberMap[contractAddress] = MemberStruct({ | |
member: contractAddress, | |
name: contractName, | |
listPointer: memberList.push(contractAddress) - 1 | |
}); | |
} | |
function add(address newAddress) public auth() { | |
addInternal(newAddress, ""); | |
} | |
function add(address newAddress, string newName) public auth() { | |
addInternal(newAddress, newName); | |
} | |
function remove(address removedAddress) public auth() { | |
require(contains(removedAddress)); | |
uint listPointerToDelete = memberMap[removedAddress].listPointer; | |
address keyToMove = memberList[memberList.length-1]; | |
memberList[listPointerToDelete] = keyToMove; | |
memberMap[keyToMove].listPointer = listPointerToDelete; | |
memberList.length--; | |
delete memberMap[removedAddress]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.2; | |
import "GroupInterface.sol"; | |
import "Auth.sol"; | |
contract Group is GroupInterface, Auth { | |
struct MemberStruct { | |
address member; | |
string signature; | |
uint listPointer; | |
} | |
mapping(address => MemberStruct) public memberMap; | |
address[] public memberList; | |
function contains(address lookupAddress) public constant returns (bool) { | |
if (memberList.length == 0) { | |
return false; | |
} | |
return (memberList[memberMap[lookupAddress].listPointer] == lookupAddress); | |
} | |
function count() public constant returns (uint) { | |
return memberList.length; | |
} | |
function hashMessage(address userAddress, string userSignature) public pure returns (bytes32) { | |
return keccak256( | |
keccak256("address User Address", "string User Signature"), | |
keccak256(userAddress, userSignature) | |
); | |
} | |
function recoverSigner(bytes32 hash, bytes32 r, bytes32 s, uint8 v) public pure returns (address) { | |
return ecrecover(hash, v, r, s); | |
} | |
function addInternal(address userAddress, string userSignature) internal { | |
require(!contains(userAddress)); | |
memberMap[userAddress] = MemberStruct({ | |
member: userAddress, | |
signature: userSignature, | |
listPointer: memberList.push(userAddress) - 1 | |
}); | |
} | |
function add(address newAddress) public auth() { | |
addInternal(newAddress, ""); | |
} | |
function addSigned(address userAddress, string userSignature, address signer, bytes32 r, bytes32 s, uint8 v) public { | |
bytes32 hash = hashMessage(userAddress, userSignature); | |
address recoveredSignerAddress = recoverSigner(hash, r, s, v); | |
require(recoveredSignerAddress == signer); | |
require(isAuthorized(signer)); | |
addInternal(userAddress, userSignature); | |
} | |
function remove(address removedAddress) public auth() { | |
require(contains(removedAddress)); | |
uint listPointerToDelete = memberMap[removedAddress].listPointer; | |
address keyToMove = memberList[memberList.length-1]; | |
memberList[listPointerToDelete] = keyToMove; | |
memberMap[keyToMove].listPointer = listPointerToDelete; | |
memberList.length--; | |
delete memberMap[removedAddress]; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.2; | |
contract GroupInterface { | |
function contains(address lookupAddress) public constant returns (bool); | |
function count() public constant returns(uint); | |
function add(address newAddress) public; | |
function remove(address removedAddress) public; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.2; | |
import "CarRegistryInterface.sol"; | |
import "Auth.sol"; | |
contract Maintenance is Auth { | |
CarRegistryInterface public registry; | |
function setRegistry(address newRegistry) public auth { | |
registry = CarRegistryInterface(newRegistry); | |
} | |
function hashMessage(uint24 eventType, uint8 severity, uint32 date, uint24 mileage, string eventDataIPFSHash, string vin) public pure returns (bytes32) { | |
return keccak256( | |
keccak256( | |
"uint24 Event Type", | |
"uint8 Severity", | |
"uint32 Date", | |
"uint24 Mileage", | |
"string IPFS Hash", | |
"string VIN" | |
), | |
keccak256( | |
eventType, | |
severity, | |
date, | |
mileage, | |
eventDataIPFSHash, | |
vin | |
) | |
); | |
} | |
function recoverSigner(bytes32 hash, bytes32 r, bytes32 s, uint8 v) public pure returns (address) { | |
return ecrecover(hash, v, r, s); | |
} | |
function addMaintenanceEventSigned(uint24 eventType, uint8 severity, uint32 date, uint24 mileage, string eventDataIPFSHash, string vin, address signer, bytes32 r, bytes32 s, uint8 v) public { | |
bytes32 hash = hashMessage(eventType, severity, date, mileage, eventDataIPFSHash, vin); | |
address recoveredSignerAddress = recoverSigner(hash, r, s, v); | |
require(recoveredSignerAddress == signer); | |
require(isAuthorized(signer, bytes4(keccak256("addMaintenanceEvent(uint24,uint8,uint32,uint24,string,string)")))); | |
registry.addEvent(eventType, severity, date, mileage, eventDataIPFSHash, vin); | |
} | |
function addMaintenanceEvent(uint24 eventType, uint8 severity, uint32 date, uint24 mileage, string eventDataIPFSHash, string vin) public auth { | |
registry.addEvent(eventType, severity, date, mileage, eventDataIPFSHash, vin); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pragma solidity ^0.4.2; | |
import "CarRegistryInterface.sol"; | |
import "Auth.sol"; | |
contract Manufacturer is Auth { | |
CarRegistryInterface public registry; | |
string public manufacturerMake; | |
function setRegistry(address newRegistry) public auth { | |
registry = CarRegistryInterface(newRegistry); | |
} | |
function setManufacturerMake(string make) public auth { | |
manufacturerMake = make; | |
} | |
function hashMessage(string vin, string make, string model, uint16 modelYear, uint24 mileage, uint24 titleStatus) public pure returns (bytes32) { | |
return keccak256( | |
keccak256( | |
"string VIN", | |
"string Make", | |
"string Model", | |
"uint16 Model Year", | |
"uint24 Mileage", | |
"uint24 Title Status" | |
), | |
keccak256( | |
vin, | |
make, | |
model, | |
modelYear, | |
mileage, | |
titleStatus | |
) | |
); | |
} | |
function recoverSigner(bytes32 hash, bytes32 r, bytes32 s, uint8 v) public pure returns (address) { | |
return ecrecover(hash, v, r, s); | |
} | |
function manufactureCarSigned(string vin, string model, uint16 modelYear, address signer, bytes32 r, bytes32 s, uint8 v) public { | |
bytes32 hash = hashMessage(vin, manufacturerMake, model, modelYear, 0, 0); | |
address recoveredSignerAddress = recoverSigner(hash, r, s, v); | |
require(recoveredSignerAddress == signer); | |
require(isAuthorized(signer, bytes4(keccak256("manufactureCar(string,string,uint16)")))); | |
registry.addCar(vin, manufacturerMake, model, modelYear, 0, 0); | |
} | |
function manufactureCar(string vin, string model, uint16 modelYear) public auth { | |
registry.addCar(vin, manufacturerMake, model, modelYear, 0, 0); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment