Skip to content

Instantly share code, notes, and snippets.

@nampdn
Created September 10, 2021 08:03
Show Gist options
  • Save nampdn/0f20fdc400ac26e5543e12309544b6fd to your computer and use it in GitHub Desktop.
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=
// 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);
}
}
// 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;
}
// 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