Skip to content

Instantly share code, notes, and snippets.

@gaiazov
Created April 11, 2018 16:20
Show Gist options
  • Save gaiazov/b8e7d4def8a4513f6edc22f72eba46aa to your computer and use it in GitHub Desktop.
Save gaiazov/b8e7d4def8a4513f6edc22f72eba46aa to your computer and use it in GitHub Desktop.
AppianWorld 2018 - Ethereum Car Service smart contracts
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;
}
}
pragma solidity ^0.4.2;
contract Authority {
function canCall(address caller, address callee, bytes4 sig) public constant returns (bool);
}
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;
}
}
pragma solidity ^0.4.2;
import "Auth.sol";
import "Authority.sol";
import "GroupInterface.sol";
contract CarRegistryAuthority is Authority, Auth {
GroupInterface public owners;
GroupInterface public maintenanceShops;
GroupInterface public manufacturers;
function setOwners(address groupAddress) public auth() {
owners = GroupInterface(groupAddress);
}
function setMaintenanceShops(address groupAddress) public auth() {
maintenanceShops = GroupInterface(groupAddress);
}
function setManufacturers(address groupAddress) public auth() {
manufacturers = GroupInterface(groupAddress);
}
function canCall(address caller_address, address code_address, bytes4 sig) public constant returns (bool) {
if (sig == bytes4(keccak256("addEvent(uint24,uint8,uint32,uint24,string,string)"))) {
return maintenanceShops.contains(caller_address);
}
if (sig == bytes4(keccak256("addCar(string,string,string,uint16,uint24,uint24)")) ||
sig == bytes4(keccak256("updateCar(string,string,string,uint16,uint24,uint24)"))) {
return manufacturers.contains(caller_address);
}
return owners.contains(caller_address);
}
}
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;
}
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];
}
}
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];
}
}
pragma solidity ^0.4.2;
import "Auth.sol";
import "Authority.sol";
import "GroupInterface.sol";
contract GroupAuthority is Authority, Auth {
GroupInterface public group;
function setGroup(address groupAddress) public auth() {
group = GroupInterface(groupAddress);
}
function canCall(address caller_address, address code_address, bytes4 sig) public constant returns (bool) {
return group.contains(caller_address);
}
}
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;
}
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);
}
}
pragma solidity ^0.4.2;
import "Auth.sol";
import "Authority.sol";
import "GroupInterface.sol";
contract MaintenanceAuthority is Authority, Auth {
GroupInterface public technicians;
GroupInterface public managers;
function setManagers(address groupAddress) public auth() {
managers = GroupInterface(groupAddress);
}
function setTechnicians(address groupAddress) public auth() {
technicians = GroupInterface(groupAddress);
}
function canCall(address caller_address, address code_address, bytes4 sig) public constant returns (bool) {
if (sig == bytes4(keccak256("addMaintenanceEvent(uint24,uint8,uint32,uint24,string,string)"))) {
return technicians.contains(caller_address);
}
return managers.contains(caller_address);
}
}
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