Skip to content

Instantly share code, notes, and snippets.

@viswanathkgp12
Last active June 29, 2018 09:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save viswanathkgp12/9e8a93fbb346b227febbfdf2fbd36f81 to your computer and use it in GitHub Desktop.
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=
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