Last active
June 29, 2018 09:07
-
-
Save viswanathkgp12/9e8a93fbb346b227febbfdf2fbd36f81 to your computer and use it in GitHub Desktop.
Created using remix-ide: Realtime Ethereum Contract Compiler and Runtime. Load this file by pasting this gists URL or ID at https://remix.ethereum.org/#version=soljson-v0.4.24+commit.e67f0147.js&optimize=false&gist=
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.11; | |
/** | |
* @title Ownable | |
* @dev The Ownable contract has an owner address, and provides basic authorization control | |
* functions, this simplifies the implementation of "user permissions". | |
*/ | |
contract Ownable { | |
address public owner; | |
/** | |
* @dev The Ownable constructor sets the original `owner` of the contract to the sender | |
* account. | |
*/ | |
function Ownable() { | |
owner = msg.sender; | |
} | |
/** | |
* @dev Throws if called by any account other than the owner. | |
*/ | |
modifier onlyOwner() { | |
require(msg.sender == owner); | |
_; | |
} | |
/** | |
* @dev Allows the current owner to transfer control of the contract to a newOwner. | |
* @param newOwner The address to transfer ownership to. | |
*/ | |
function transferOwnership(address newOwner) onlyOwner { | |
if (newOwner != address(0)) { | |
owner = newOwner; | |
} | |
} | |
} | |
/** | |
* @title Pausable | |
* @dev Base contract which allows children to implement an emergency stop mechanism. | |
*/ | |
contract Pausable is Ownable { | |
event Pause(); | |
event Unpause(); | |
bool public paused = false; | |
/** | |
* @dev modifier to allow actions only when the contract IS paused | |
*/ | |
modifier whenNotPaused() { | |
require(!paused); | |
_; | |
} | |
/** | |
* @dev modifier to allow actions only when the contract IS NOT paused | |
*/ | |
modifier whenPaused { | |
require(paused); | |
_; | |
} | |
/** | |
* @dev called by the owner to pause, triggers stopped state | |
*/ | |
function pause() onlyOwner whenNotPaused returns (bool) { | |
paused = true; | |
Pause(); | |
return true; | |
} | |
/** | |
* @dev called by the owner to unpause, returns to normal state | |
*/ | |
function unpause() onlyOwner whenPaused returns (bool) { | |
paused = false; | |
Unpause(); | |
return true; | |
} | |
} | |
/// @title Interface for contracts conforming to ERC-721: Non-Fungible Tokens | |
/// @author Dieter Shirley <dete@axiomzen.co> (https://github.com/dete) | |
contract ERC721 { | |
// Required methods | |
function totalSupply() public view returns (uint256 total); | |
function balanceOf(address _owner) public view returns (uint256 balance); | |
function ownerOf(uint256 _tokenId) external view returns (address owner); | |
function approve(address _to, uint256 _tokenId) external; | |
function transfer(address _to, uint256 _tokenId) external; | |
function transferFrom(address _from, address _to, uint256 _tokenId) external; | |
// Events | |
event Transfer(address from, address to, uint256 tokenId); | |
event Approval(address owner, address approved, uint256 tokenId); | |
// Optional | |
// function name() public view returns (string name); | |
// function symbol() public view returns (string symbol); | |
// function tokensOfOwner(address _owner) external view returns (uint256[] tokenIds); | |
// function tokenMetadata(uint256 _tokenId, string _preferredTransport) public view returns (string infoUrl); | |
// ERC-165 Compatibility (https://github.com/ethereum/EIPs/issues/165) | |
function supportsInterface(bytes4 _interfaceID) external view returns (bool); | |
} | |
/// @title Base contract for Cars24. | |
contract CarOwnershipControl is Ownable { | |
/*** EVENTS ***/ | |
/// @dev This event fired each time new car is blockchained | |
event LogCarAdded(address owner, uint256 carId, bytes32 modelNum, bytes32 carType, uint256 mfdDate); | |
/// @dev Transfer event as defined in current draft of ERC721. Emitted every time a car | |
/// ownership is assigned. | |
event Transfer(address from, address to, uint256 tokenId); | |
/*** DATA TYPES ***/ | |
enum carType { | |
Diesel, | |
CNG, | |
Electric | |
} | |
/// @dev Car struct | |
/** | |
* @param modelNum - Model Number of the Car | |
* @param sizeClass - Size Class of each car (SUV, Small sized) | |
* @param mfdDate - Car manufactured Date | |
* @param carType - Diesel, CNG.Electric | |
* @param carPrice - Price of car in ETH | |
**/ | |
struct Car { | |
bytes32 modelNum; | |
bytes32 sizeClass; | |
uint256 mfdDate; | |
carType _carType; | |
uint256 carPrice; | |
} | |
/*** STORAGE ***/ | |
Car[] cars; | |
/// @dev A mapping from car IDs to the address that owns them. Each car has a unique ID. | |
mapping (uint256 => address) public carToOwner; | |
// @dev A mapping from owner address to count of tokens that address owns. | |
mapping (address => uint256) ownershipTokenCount; | |
// @dev A mapping from carID to the address authorized to call transferFrom() | |
mapping (uint256 => address) public carIndexToApproved; | |
/// @dev Assigns ownership of a specific car to an address. | |
function _transfer(address _from, address _to, uint256 _tokenId) internal { | |
ownershipTokenCount[_to]++; | |
// transfer ownership | |
carToOwner[_tokenId] = _to; | |
// Emit the transfer event. | |
// When adding new car to blockchain database, _from would be 0x0 | |
Transfer(_from, _to, _tokenId); | |
} | |
/** @dev A method that allows car addition to database. | |
* Cars24 will add cars to its database | |
* Initially Cars24 will set price to all the cars owned | |
**/ | |
function _addCar( | |
bytes32 _modelNum, | |
bytes32 _sizeClass, | |
uint256 _mfdDate, | |
bytes32 _carType, | |
uint256 _carPrice | |
) | |
onlyOwner | |
returns (uint) | |
{ | |
assert(_modelNum != 0x0); | |
assert(_sizeClass != 0x0); | |
assert(_mfdDate != 0); | |
assert(_carPrice != 0); | |
assert(keccak256(_carType) != keccak256(0x0)); | |
carType _enumCarType; | |
if(keccak256(_carType) == keccak256("Diesel")) { | |
_enumCarType = carType.Diesel; | |
} else if(keccak256(_carType) == keccak256("Electric")) { | |
_enumCarType = carType.Electric; | |
} else if(keccak256(_carType) == keccak256("CNG")) { | |
_enumCarType = carType.CNG; | |
} else throw; | |
Car memory _car = Car({ | |
modelNum: _modelNum, | |
sizeClass: _sizeClass, | |
mfdDate: _mfdDate, | |
_carType: _enumCarType, | |
carPrice: _carPrice | |
}); | |
cars.push(_car); | |
uint carId = cars.length - 1; | |
// emit the addition event | |
LogCarAdded( | |
address(this), carId, _modelNum, _carType, _mfdDate | |
); | |
// This will assign ownership, and also emit the Transfer event as | |
// per ERC721 draft | |
_transfer(0, address(this), carId); | |
return carId; | |
} | |
} | |
contract ERC721Metadata { | |
/// @dev Given a token Id, returns a byte array that is supposed to be converted into string. | |
function getMetadata(uint256 _tokenId, string) public view returns (bytes32[4] buffer, uint256 count) { | |
if (_tokenId == 1) { | |
buffer[0] = "Hello World! :D"; | |
count = 15; | |
} else if (_tokenId == 2) { | |
buffer[0] = "I would definitely choose a medi"; | |
buffer[1] = "um length string."; | |
count = 49; | |
} else if (_tokenId == 3) { | |
buffer[0] = "Lorem ipsum dolor sit amet, mi e"; | |
buffer[1] = "st accumsan dapibus augue lorem,"; | |
buffer[2] = " tristique vestibulum id, libero"; | |
buffer[3] = " suscipit varius sapien aliquam."; | |
count = 128; | |
} | |
} | |
} | |
/// @title Core Contract for cars24 ERC 721 Compliant | |
contract Cars24Core is ERC721, Pausable, CarOwnershipControl { | |
/// @notice Name and symbol of the non fungible token, as defined in ERC721. | |
string public constant name = "Cars24"; | |
string public constant symbol = "eCARZ"; | |
ERC721Metadata public erc721Metadata; | |
bytes4 constant InterfaceSignature_ERC165 = | |
bytes4(keccak256('supportsInterface(bytes4)')); | |
bytes4 constant InterfaceSignature_ERC721 = | |
bytes4(keccak256('name()')) ^ | |
bytes4(keccak256('symbol()')) ^ | |
bytes4(keccak256('totalSupply()')) ^ | |
bytes4(keccak256('balanceOf(address)')) ^ | |
bytes4(keccak256('ownerOf(uint256)')) ^ | |
bytes4(keccak256('approve(address,uint256)')) ^ | |
bytes4(keccak256('transfer(address,uint256)')) ^ | |
bytes4(keccak256('transferFrom(address,address,uint256)')) ^ | |
bytes4(keccak256('tokensOfOwner(address)')) ^ | |
bytes4(keccak256('tokenMetadata(uint256,string)')); | |
/// @notice Introspection interface as per ERC-165 (https://github.com/ethereum/EIPs/issues/165). | |
/// Returns true for any standardized interfaces implemented by this contract. We implement | |
/// ERC-165 (obviously!) and ERC-721. | |
function supportsInterface(bytes4 _interfaceID) external view returns (bool) | |
{ | |
// DEBUG ONLY | |
//require((InterfaceSignature_ERC165 == 0x01ffc9a7) && (InterfaceSignature_ERC721 == 0x9a20483d)); | |
return ((_interfaceID == InterfaceSignature_ERC165) || (_interfaceID == InterfaceSignature_ERC721)); | |
} | |
/// @dev Set the address of the sibling contract that tracks metadata. | |
/// CEO only. | |
function setMetadataAddress(address _contractAddress) public onlyOwner { | |
erc721Metadata = ERC721Metadata(_contractAddress); | |
} | |
// Internal utility functions: These functions all assume that their input arguments | |
// are valid. We leave it to public methods to sanitize their inputs and follow | |
// the required logic. | |
/// @dev Checks if a given address is the current owner of a particular car | |
function _owns(address _claimant, uint256 _tokenId) internal view returns (bool) { | |
return carToOwner[_tokenId] == _claimant; | |
} | |
function _approvedFor(address _claimant, uint256 _tokenId) internal view returns (bool) { | |
return carIndexToApproved[_tokenId] == _claimant; | |
} | |
function _approve(uint256 _tokenId, address _approved) internal { | |
carIndexToApproved[_tokenId] = _approved; | |
} | |
/// @notice Returns the number of Cars owned by a specific address. | |
function balanceOf(address _owner) public view returns (uint256 count) { | |
return ownershipTokenCount[_owner]; | |
} | |
/// @notice Transfers a Car to another address. | |
function transfer( | |
address _to, | |
uint256 _tokenId | |
) | |
external | |
whenNotPaused | |
{ | |
// Safety check to prevent against an unexpected 0x0 default. | |
require(_to != address(0)); | |
// Disallow transfers to this contract to prevent accidental misuse. | |
require(_to != address(this)); | |
// You can only send your own car. | |
require(_owns(msg.sender, _tokenId)); | |
// Reassign ownership, clear pending approvals, emit Transfer event. | |
_transfer(msg.sender, _to, _tokenId); | |
} | |
/// @notice Grant another address the right to transfer a specific car via | |
/// transferFrom() | |
function approve( | |
address _to, | |
uint256 _tokenId | |
) | |
external | |
whenNotPaused | |
{ | |
// Only an owner can grant transfer approval. | |
require(_owns(msg.sender, _tokenId)); | |
// Register the approval (replacing any previous approval). | |
_approve(_tokenId, _to); | |
// Emit approval event. | |
Approval(msg.sender, _to, _tokenId); | |
} | |
/// @notice Transfer a Car owned by another address, for which the calling address | |
/// has previously been granted transfer approval by the owner. | |
function transferFrom( | |
address _from, | |
address _to, | |
uint256 _tokenId | |
) | |
external | |
whenNotPaused | |
{ | |
// Safety check to prevent against an unexpected 0x0 default. | |
require(_to != address(0)); | |
// Disallow transfers to this contract to prevent accidental misuse. | |
require(_to != address(this)); | |
// Check for approval and valid ownership | |
require(_approvedFor(msg.sender, _tokenId)); | |
require(_owns(_from, _tokenId)); | |
// Reassign ownership (also clears pending approvals and emits Transfer event). | |
_transfer(_from, _to, _tokenId); | |
} | |
/// @notice Returns the total number of Cars currently in existence. | |
/// @dev Required for ERC-721 compliance. | |
function totalSupply() public view returns (uint) { | |
return cars.length - 1; | |
} | |
/// @notice Returns the address currently assigned ownership of a given car. | |
/// @dev Required for ERC-721 compliance. | |
function ownerOf(uint256 _tokenId) | |
external | |
view | |
returns (address owner) | |
{ | |
owner = carToOwner[_tokenId]; | |
require(owner != address(0)); | |
} | |
/// @notice Returns a list of all Car IDs assigned to an address. | |
function tokensOfOwner(address _owner) external view returns(uint256[] ownerTokens) { | |
uint256 tokenCount = balanceOf(_owner); | |
if (tokenCount == 0) { | |
// Return an empty array | |
return new uint256[](0); | |
} else { | |
uint256[] memory result = new uint256[](tokenCount); | |
uint256 totalCars = totalSupply(); | |
uint256 resultIndex = 0; | |
// We count on the fact that all cars have IDs starting at 1 and increasing | |
// sequentially up to the totalCars count. | |
uint256 carId; | |
for (carId = 1; carId <= totalCars; carId++) { | |
if (carToOwner[carId] == _owner) { | |
result[resultIndex] = carId; | |
resultIndex++; | |
} | |
} | |
return result; | |
} | |
} | |
/// @dev Adapted from memcpy() by @arachnid (Nick Johnson <arachnid@notdot.net>) | |
/// This method is licenced under the Apache License. | |
/// Ref: https://github.com/Arachnid/solidity-stringutils/blob/2f6ca9accb48ae14c66f1437ec50ed19a0616f78/strings.sol | |
function _memcpy(uint _dest, uint _src, uint _len) private view { | |
// Copy word-length chunks while possible | |
for(; _len >= 32; _len -= 32) { | |
assembly { | |
mstore(_dest, mload(_src)) | |
} | |
_dest += 32; | |
_src += 32; | |
} | |
// Copy remaining bytes | |
uint256 mask = 256 ** (32 - _len) - 1; | |
assembly { | |
let srcpart := and(mload(_src), not(mask)) | |
let destpart := and(mload(_dest), mask) | |
mstore(_dest, or(destpart, srcpart)) | |
} | |
} | |
/// @dev Adapted from toString(slice) by @arachnid (Nick Johnson <arachnid@notdot.net>) | |
/// This method is licenced under the Apache License. | |
/// Ref: https://github.com/Arachnid/solidity-stringutils/blob/2f6ca9accb48ae14c66f1437ec50ed19a0616f78/strings.sol | |
function _toString(bytes32[4] _rawBytes, uint256 _stringLength) private view returns (string) { | |
var outputString = new string(_stringLength); | |
uint256 outputPtr; | |
uint256 bytesPtr; | |
assembly { | |
outputPtr := add(outputString, 32) | |
bytesPtr := _rawBytes | |
} | |
_memcpy(outputPtr, bytesPtr, _stringLength); | |
return outputString; | |
} | |
/// @notice Returns a URI pointing to a metadata package for this token conforming to | |
/// ERC-721 (https://github.com/ethereum/EIPs/issues/721) | |
/// @param _tokenId The ID number of the Car whose metadata should be returned. | |
function tokenMetadata(uint256 _tokenId, string _preferredTransport) external view returns (string infoUrl) { | |
require(erc721Metadata != address(0)); | |
bytes32[4] memory buffer; | |
uint256 count; | |
(buffer, count) = erc721Metadata.getMetadata(_tokenId, _preferredTransport); | |
return _toString(buffer, count); | |
} | |
/** | |
* @param _carId - ID of car the sender wishes to buy | |
* Check if msg.val > carPrice | |
* If so, transfer ownership from Cars24 | |
**/ | |
function buy(uint256 _carId) external whenNotPaused payable { | |
if(msg.value >= cars[_carId].carPrice) { | |
_transfer(address(this), msg.sender, _carId); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment