Created
September 10, 2021 08:03
-
-
Save nampdn/0f20fdc400ac26e5543e12309544b6fd 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.8.7+commit.e28d00a7.js&optimize=false&runs=200&gist=
This file contains hidden or 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
// SPDX-License-Identifier: GPL-3.0 | |
pragma solidity >=0.7.0 <0.9.0; | |
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.3/contracts/token/ERC721/ERC721.sol"; | |
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.3/contracts/token/ERC721/extensions/ERC721Enumerable.sol"; | |
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.3/contracts/token/ERC721/extensions/ERC721URIStorage.sol"; | |
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.3/contracts/access/AccessControl.sol"; | |
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.3/contracts/utils/Counters.sol"; | |
import "./IVGMSmartDevice.sol"; | |
contract VGMSmartDeviceStorage { | |
event ActivityUpdated(uint256 deviceId, uint256 activityType); | |
event LocationUpdated(uint256 deviceId, uint256 longtitude, uint256 latitude); | |
event StatusUpdated(uint256 deviceId, uint256 status); | |
bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE"); | |
bytes32 public constant TRACKER_ROLE = keccak256("TRACKER_ROLE"); | |
bytes32 public constant STAFF_ROLE = keccak256("STAFF_ROLE"); | |
mapping(string => uint256) _byImei; | |
struct Info { | |
uint256 longtitude; | |
uint256 latitude; | |
uint256 status; | |
uint256 createdAt; | |
uint256 lastActivity; | |
} | |
mapping(uint256 => Info) _devicesInfo; | |
} | |
contract VGMSmartDevice is ERC721, ERC721Enumerable, ERC721URIStorage, AccessControl, IVGMSmartDevice, VGMSmartDeviceStorage { | |
using Counters for Counters.Counter; | |
Counters.Counter private _tokenIdCounter; | |
modifier onlyUniqueImei(string memory imei) { | |
require(_byImei[imei] == 0, "imei registered"); | |
_; | |
} | |
function userByImei(string memory imei) external view returns (address) { | |
return ownerOf(_byImei[imei]); | |
} | |
constructor() ERC721("VGM Smart Devices", "VGMSD") { | |
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender); | |
_setupRole(MINTER_ROLE, msg.sender); | |
_setupRole(TRACKER_ROLE, msg.sender); | |
} | |
function setupRole(bytes32 role, address user) public onlyRole(DEFAULT_ADMIN_ROLE) { | |
_setupRole(role, user); | |
} | |
function safeMint( | |
address to, | |
string memory imei, | |
uint256 createdAt, | |
uint256 longtitude, | |
uint256 latitude, | |
uint256 status, | |
uint256 lastActivity | |
) | |
public | |
onlyRole(MINTER_ROLE) | |
onlyUniqueImei(imei) | |
{ | |
uint256 tokenId = _tokenIdCounter.current(); | |
_safeMint(to, tokenId); | |
_tokenIdCounter.increment(); | |
_byImei[imei] = tokenId; | |
_setTokenURI(tokenId, imei); | |
_devicesInfo[tokenId] = Info({ | |
longtitude: longtitude, | |
latitude: latitude, | |
status: status, | |
createdAt: createdAt, | |
lastActivity: lastActivity | |
}); | |
} | |
function updateStatus(uint256 deviceId, uint256 status) external override { | |
require(hasRole(STAFF_ROLE, msg.sender), "invalid permission"); | |
_devicesInfo[deviceId].status = status; | |
emit StatusUpdated(deviceId, status); | |
} | |
function updateLocation(uint256 deviceId, uint256 lon, uint256 lat) external override { | |
require(hasRole(TRACKER_ROLE, msg.sender), "invalid permission"); | |
_devicesInfo[deviceId].longtitude = lon; | |
_devicesInfo[deviceId].latitude = lat; | |
emit LocationUpdated(deviceId, lon, lat); | |
} | |
function updateActivity(uint256 deviceId, uint256 activity) external override { | |
require(hasRole(TRACKER_ROLE, msg.sender), "invalid permission"); | |
_devicesInfo[deviceId].lastActivity = activity; | |
emit ActivityUpdated(deviceId, activity); | |
} | |
function getDevice(uint256 deviceId) external view returns (string memory, uint256, uint256, uint256, uint256, uint256) { | |
Info memory info = _devicesInfo[deviceId]; | |
return (tokenURI(deviceId), info.longtitude, info.latitude, info.status, info.createdAt, info.lastActivity); | |
} | |
// The following functions are overrides required by Solidity. | |
function _beforeTokenTransfer(address from, address to, uint256 tokenId) | |
internal | |
override(ERC721, ERC721Enumerable) | |
{ | |
super._beforeTokenTransfer(from, to, tokenId); | |
} | |
function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) { | |
super._burn(tokenId); | |
} | |
function tokenURI(uint256 tokenId) | |
public | |
view | |
override(ERC721, ERC721URIStorage) | |
returns (string memory) | |
{ | |
return super.tokenURI(tokenId); | |
} | |
function supportsInterface(bytes4 interfaceId) | |
public | |
view | |
override(ERC721, ERC721Enumerable, AccessControl) | |
returns (bool) | |
{ | |
return super.supportsInterface(interfaceId); | |
} | |
} | |
This file contains hidden or 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
// SPDX-License-Identifier: GPL-3.0 | |
pragma solidity >=0.7.0 <0.9.0; | |
interface IVGMSmartDevice { | |
function updateStatus(uint256 deviceId, uint256 status) external; | |
function updateLocation(uint256 deviceId, uint256 lon, uint256 lat) external; | |
function updateActivity(uint256 deviceId, uint256 activity) external; | |
} |
This file contains hidden or 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
// SPDX-License-Identifier: GPL-3.0 | |
pragma solidity >=0.7.0 <0.9.0; | |
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.3/contracts/access/AccessControl.sol"; | |
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.3/contracts/access/Ownable.sol"; | |
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.3/contracts/utils/Counters.sol"; | |
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.3/contracts/token/ERC721/utils/ERC721Holder.sol"; | |
import "https://github.com/OpenZeppelin/openzeppelin-contracts/blob/release-v4.3/contracts/token/ERC721/IERC721.sol"; | |
import "./IVGMSmartDevice.sol"; | |
contract VGMUser is Ownable, ERC721Holder { | |
address _referrer; | |
address _smartDeviceNFT; | |
string _name; | |
mapping(bytes32 => string) props; | |
constructor(string memory name_, address smartDeviceNFT_) { | |
_name = name_; | |
_smartDeviceNFT = smartDeviceNFT_; | |
IERC721(_smartDeviceNFT).setApprovalForAll(msg.sender, true); | |
} | |
function setReferrer(address referrer_) public onlyOwner { | |
_referrer = referrer_; | |
} | |
function setProp(bytes32 _key, string memory _value) public onlyOwner { | |
props[_key] = _value; | |
} | |
function setApprovalForAll(address token_, address operator_) public onlyOwner { | |
IERC721(token_).setApprovalForAll(operator_, true); | |
} | |
function getProp(bytes32 _key) public view returns (string memory) { | |
return props[_key]; | |
} | |
function name() public view returns (string memory) { | |
return _name; | |
} | |
} | |
contract VGMUserFactoryStorage { | |
event UserRegistered(uint256 userId, bytes32 slug, string name); | |
event DeviceTransfered(uint256 deviceId, address fromUser, address toUser, uint256 status); | |
bytes32 public constant TRACKER_ROLE = keccak256("TRACKER_ROLE"); | |
bytes32 public constant STAFF_ROLE = keccak256("STAFF_ROLE"); | |
address _smartDeviceNFT; | |
mapping(uint256 => VGMUser) _users; | |
address[] _userList; | |
mapping(bytes32 => uint256) _userBySlug; | |
uint256 constant PAGE_SIZE = 50; | |
uint256 public lastPage; | |
} | |
contract VGMUserFactory is Ownable, AccessControl, VGMUserFactoryStorage { | |
using Counters for Counters.Counter; | |
Counters.Counter private _userIds; | |
modifier notExisted(bytes32 slug) { | |
require(_userBySlug[slug] == 0, "user slug existed"); | |
_; | |
} | |
constructor (address smartDeviceNFT_) { | |
_smartDeviceNFT = smartDeviceNFT_; | |
_setupRole(DEFAULT_ADMIN_ROLE, msg.sender); | |
_setupRole(TRACKER_ROLE, msg.sender); | |
_setupRole(STAFF_ROLE, msg.sender); | |
} | |
function registerUser(bytes32 slug_, string memory name_, address referrer_) public onlyOwner notExisted(slug_) returns (address) { | |
_userIds.increment(); | |
uint256 userId = _userIds.current(); | |
_users[userId] = new VGMUser(name_, _smartDeviceNFT); | |
_userBySlug[slug_] = userId; | |
if (referrer_ != address(0)) { | |
_users[userId].setReferrer(referrer_); | |
} | |
emit UserRegistered(userId, slug_, name_); | |
return address(_users[userId]); | |
} | |
function getUserById(uint256 userId_) public view returns (address, string memory) { | |
require(userId_ < _userIds.current(), "user not exist"); | |
VGMUser user = _users[userId_]; | |
return (address(user), user.name()); | |
} | |
function getUserBySlug(bytes32 slug_) public view returns (address) { | |
uint256 userId = _userBySlug[slug_]; | |
(address userAddress, ) = getUserById(userId); | |
return userAddress; | |
} | |
function setApprovalForAll(uint256 userId_, address token_) public onlyOwner { | |
VGMUser(_users[userId_]).setApprovalForAll(token_, address(this)); | |
} | |
function setProp(uint256 userId_, bytes32 _key, string memory _value) public onlyOwner { | |
require(hasRole(STAFF_ROLE, msg.sender), "invalid permission"); | |
VGMUser(_users[userId_]).setProp(_key, _value); | |
} | |
function setReferrer(uint256 userId_, address referrer_) public onlyOwner { | |
require(hasRole(STAFF_ROLE, msg.sender), "invalid permission"); | |
VGMUser(_users[userId_]).setReferrer(referrer_); | |
} | |
function transferDevice(uint256 deviceId_, address fromUser_, address toUser_, uint256 status_) public { | |
require(hasRole(STAFF_ROLE, msg.sender), "invalid permission"); | |
IERC721(_smartDeviceNFT).safeTransferFrom(fromUser_, toUser_, deviceId_); | |
IVGMSmartDevice(_smartDeviceNFT).updateStatus(deviceId_, status_); | |
emit DeviceTransfered(deviceId_, fromUser_, toUser_, status_); | |
} | |
function totalUsers() public view returns (uint256) { | |
return _userIds.current(); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment