273 lines
12 KiB
Solidity
273 lines
12 KiB
Solidity
|
///SPDX-License-Identifier: CC0-1.0
|
||
|
|
||
|
pragma solidity ^0.8.0;
|
||
|
|
||
|
import "./smartNFT_interface.sol";
|
||
|
import "./ERC721_interface.sol";
|
||
|
|
||
|
contract smartNFT_SC is ERC721,smartNFT{
|
||
|
enum States { waitingForOwner, engagedWithOwner, waitingForUser, engagedWithUser }
|
||
|
|
||
|
address manufacturer; //Address of manufacturer and owner of Smart Contract
|
||
|
uint256 tokenCounter; //To give a genuine tokenID based on the number of tokens created
|
||
|
mapping(uint256 => address) ownerOfSD; //To khow who is the owner of a specific owner
|
||
|
mapping(address => uint256) tokenIDOfBCA; //To khow which is the tokenID associated to a secure device from the address
|
||
|
mapping(address => uint256) ownerBalance; //To know how many tokens an owner has
|
||
|
mapping(address => uint256) userBalance; //To know how many tokens a user can use
|
||
|
|
||
|
struct Token_Struct{
|
||
|
address approved; //Indicate who can transfer this token, 0 if no one
|
||
|
address SD; //Indicate the address of the secure device associated to this token
|
||
|
address user; //Indicate who can use this secure device
|
||
|
States state; //If blocked (false) then token should be verified by a new user or a new owner
|
||
|
uint256 hashK_OD; //Hash of the Key shared between owner and device
|
||
|
uint256 hashK_UD; //Hash of the Key shared between user and device
|
||
|
uint256 dataEngagement; //Public Key to create K_OD or K_UD depending on token state
|
||
|
uint256 timestamp; //Last time that device updated its proof of live
|
||
|
uint256 timeout; //timeout to verify a device error
|
||
|
}
|
||
|
|
||
|
Token_Struct[] Secure_Token;
|
||
|
|
||
|
constructor() {
|
||
|
manufacturer = msg.sender;
|
||
|
tokenCounter = 1;
|
||
|
Secure_Token.push(Token_Struct(address(0), address(0), address(0), States.waitingForOwner,0,0,0,0,0));
|
||
|
|
||
|
}
|
||
|
|
||
|
function createToken(address _addressSD, address _addressOwner) public virtual override returns (uint256){
|
||
|
//Check if the sender of message is the manufacturer
|
||
|
require(manufacturer == msg.sender);
|
||
|
//Check if the Blockchain Account of the secure device is in the SmartContract
|
||
|
if(tokenFromBCA(_addressSD)==0){
|
||
|
//Create a new token
|
||
|
Secure_Token.push(Token_Struct(address(0), _addressSD, address(0), States.waitingForOwner,0,0,0,block.timestamp,86400));
|
||
|
//Assigning a new tokenId
|
||
|
uint256 _tokenId = tokenCounter ++;
|
||
|
tokenIDOfBCA[_addressSD] = _tokenId;
|
||
|
//Assigning the owner
|
||
|
ownerOfSD[_tokenId] = _addressOwner;
|
||
|
ownerBalance[_addressOwner]++;
|
||
|
//Return tokenId obtained
|
||
|
return(_tokenId);
|
||
|
}else{
|
||
|
//If the BCA already exists then return the _tokenId
|
||
|
return(tokenFromBCA(_addressSD));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function setUser(uint256 _tokenId, address _addressUser) public virtual override{
|
||
|
//Check the sender and the token state
|
||
|
require((ownerOfSD[_tokenId] == msg.sender) && (Secure_Token[_tokenId].state >= States.engagedWithOwner));
|
||
|
if((Secure_Token[_tokenId].timestamp + Secure_Token[_tokenId].timeout) > block.timestamp){
|
||
|
//Only to avoid overflow, for example, in address 0.
|
||
|
if(userBalance[Secure_Token[_tokenId].user]>0){
|
||
|
//Update the balance of tokens assigned to the old user
|
||
|
userBalance[Secure_Token[_tokenId].user]--;
|
||
|
}
|
||
|
//Update the balance of tokens assigned to the new user
|
||
|
userBalance[_addressUser]++;
|
||
|
//Assign the new user to the token
|
||
|
Secure_Token[_tokenId].user = _addressUser;
|
||
|
//Update the state of the token
|
||
|
Secure_Token[_tokenId].state = States.waitingForUser;
|
||
|
//Erase old key exchange data between device with old user assigned
|
||
|
Secure_Token[_tokenId].dataEngagement =0;
|
||
|
Secure_Token[_tokenId].hashK_UD = 0;
|
||
|
emit UserAssigned(_tokenId,_addressUser);
|
||
|
}else{
|
||
|
Secure_Token[_tokenId].user = address(0);
|
||
|
emit TimeoutAlarm(_tokenId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function startOwnerEngagement(uint256 _tokenId, uint256 _dataEngagement, uint256 _hashK_O) public virtual override{
|
||
|
//Check if sender is the Owner of token and the State of token
|
||
|
require(ownerOfSD[_tokenId] == msg.sender);
|
||
|
if((Secure_Token[_tokenId].timestamp + Secure_Token[_tokenId].timeout) > block.timestamp){
|
||
|
Secure_Token[_tokenId].dataEngagement = _dataEngagement;
|
||
|
Secure_Token[_tokenId].hashK_OD = _hashK_O;
|
||
|
}else{
|
||
|
Secure_Token[_tokenId].user = address(0);
|
||
|
emit TimeoutAlarm(_tokenId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function ownerEngagement(uint256 _hashK_D) public virtual override{
|
||
|
uint256 _tokenId = tokenFromBCA(msg.sender);
|
||
|
//Check if public key owner-device exists from tokenID of BCA sender
|
||
|
require(Secure_Token[_tokenId].dataEngagement != 0);
|
||
|
require (Secure_Token[_tokenId].hashK_OD == _hashK_D);
|
||
|
require (Secure_Token[_tokenId].state == States.waitingForOwner);
|
||
|
//Erase PK_Owner-Device and update timestamp
|
||
|
Secure_Token[_tokenId].dataEngagement = 0;
|
||
|
Secure_Token[_tokenId].timestamp = block.timestamp;
|
||
|
//Update the state of token
|
||
|
Secure_Token[_tokenId].state = States.engagedWithOwner;
|
||
|
//Send a notification to owner and device
|
||
|
emit OwnerEngaged(_tokenId);
|
||
|
}
|
||
|
|
||
|
function startUserEngagement(uint256 _tokenId, uint256 _dataEngagement, uint256 _hashK_U) public virtual override{
|
||
|
//Check the sender and the state of token
|
||
|
require(Secure_Token[_tokenId].user == msg.sender);
|
||
|
if((Secure_Token[_tokenId].timestamp + Secure_Token[_tokenId].timeout) > block.timestamp){
|
||
|
Secure_Token[_tokenId].dataEngagement = _dataEngagement;
|
||
|
Secure_Token[_tokenId].hashK_UD = _hashK_U;
|
||
|
}else{
|
||
|
Secure_Token[_tokenId].user = address(0);
|
||
|
emit TimeoutAlarm(_tokenId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function userEngagement(uint256 _hashK_D) public virtual override{
|
||
|
uint256 _tokenId = tokenFromBCA(msg.sender);
|
||
|
//Check if public key user-device exists from tokenID of BCA sender
|
||
|
require(Secure_Token[_tokenId].dataEngagement != 0);
|
||
|
require (Secure_Token[_tokenId].hashK_UD == _hashK_D);
|
||
|
require (Secure_Token[_tokenId].state == States.waitingForUser);
|
||
|
//Erase PK_User-Device and update timestamp
|
||
|
Secure_Token[_tokenId].dataEngagement = 0;
|
||
|
Secure_Token[_tokenId].timestamp = block.timestamp;
|
||
|
//Update the state of token
|
||
|
Secure_Token[_tokenId].state = States.engagedWithUser;
|
||
|
//Send a notification to user and device
|
||
|
emit UserEngaged(_tokenId);
|
||
|
}
|
||
|
|
||
|
|
||
|
function tokenFromBCA(address _addressSD) public virtual view override returns (uint256){
|
||
|
return(tokenIDOfBCA[_addressSD]);
|
||
|
}
|
||
|
|
||
|
function ownerOfFromBCA(address _addressSD) public virtual view override returns (address){
|
||
|
return(ownerOfSD[tokenIDOfBCA[_addressSD]]);
|
||
|
}
|
||
|
|
||
|
function userOf(uint256 _tokenId) public virtual view override returns (address){
|
||
|
return(Secure_Token[_tokenId].user);
|
||
|
}
|
||
|
|
||
|
function userOfFromBCA(address _addressSD) public virtual override view returns (address){
|
||
|
return(Secure_Token[tokenIDOfBCA[_addressSD]].user);
|
||
|
}
|
||
|
|
||
|
function userBalanceOf(address _addressUser) public virtual override view returns (uint256){
|
||
|
return(userBalance[_addressUser]);
|
||
|
}
|
||
|
|
||
|
function userBalanceOfAnOwner(address _addressUser, address _addressOwner) public virtual override view returns (uint256){
|
||
|
//TODO
|
||
|
}
|
||
|
|
||
|
function getInfoToken(uint256 _tokenId) public view returns ( address _BCA_OWNER,
|
||
|
address _BCA_USER,
|
||
|
address _BCA_SD,
|
||
|
uint8 _state){
|
||
|
_BCA_OWNER = ownerOfSD[_tokenId];
|
||
|
_BCA_USER = Secure_Token[_tokenId].user;
|
||
|
_BCA_SD = Secure_Token[_tokenId].SD;
|
||
|
if(Secure_Token[_tokenId].state == States.waitingForOwner){
|
||
|
_state = 0;
|
||
|
}else if(Secure_Token[_tokenId].state == States.engagedWithOwner){
|
||
|
_state = 1;
|
||
|
}else if(Secure_Token[_tokenId].state == States.waitingForUser){
|
||
|
_state = 2;
|
||
|
}else {
|
||
|
_state = 3;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function getInfoTokenFromBCA(address _addressSD) public view returns ( address _BCA_OWNER,
|
||
|
address _BCA_USER,
|
||
|
uint256 _tokenId,
|
||
|
uint8 _state){
|
||
|
_tokenId = tokenIDOfBCA[_addressSD];
|
||
|
_BCA_OWNER = ownerOfSD[_tokenId];
|
||
|
_BCA_USER = Secure_Token[_tokenId].user;
|
||
|
if(Secure_Token[_tokenId].state == States.waitingForOwner){
|
||
|
_state = 0;
|
||
|
}else if(Secure_Token[_tokenId].state == States.engagedWithOwner){
|
||
|
_state = 1;
|
||
|
}else if(Secure_Token[_tokenId].state == States.waitingForUser){
|
||
|
_state = 2;
|
||
|
}else {
|
||
|
_state = 3;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function balanceOf(address _owner) public virtual override view returns (uint256){
|
||
|
return(ownerBalance[_owner]);
|
||
|
}
|
||
|
|
||
|
function ownerOf(uint256 _tokenId) public virtual override view returns (address){
|
||
|
return(ownerOfSD[_tokenId]);
|
||
|
}
|
||
|
|
||
|
function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes memory data) public virtual override payable{
|
||
|
|
||
|
}
|
||
|
|
||
|
function safeTransferFrom(address _from, address _to, uint256 _tokenId) public virtual override payable{
|
||
|
transferFrom(_from, _to, _tokenId);
|
||
|
}
|
||
|
|
||
|
function transferFrom(address _from, address _to, uint256 _tokenId) public virtual override payable{
|
||
|
require((ownerOfSD[_tokenId] == msg.sender)||(Secure_Token[_tokenId].approved == msg.sender));
|
||
|
require(ownerOfSD[_tokenId] == _from);
|
||
|
if((Secure_Token[_tokenId].timestamp + Secure_Token[_tokenId].timeout) > block.timestamp){
|
||
|
ownerOfSD[_tokenId] = _to;
|
||
|
ownerBalance[_from]--;
|
||
|
ownerBalance[_to]++;
|
||
|
//Secure_Token[_tokenId].approved = address(0);
|
||
|
Secure_Token[_tokenId].user = address(0);
|
||
|
Secure_Token[_tokenId].state = States.waitingForOwner;
|
||
|
//Erase old key exchange data between device with old Owner
|
||
|
Secure_Token[_tokenId].dataEngagement = 0;
|
||
|
Secure_Token[_tokenId].hashK_UD = 0;
|
||
|
Secure_Token[_tokenId].hashK_OD = 0;
|
||
|
emit Transfer(_from,_to,_tokenId);
|
||
|
}else{
|
||
|
Secure_Token[_tokenId].user = address(0);
|
||
|
emit TimeoutAlarm(_tokenId);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function approve(address _approved, uint256 _tokenId) public virtual override payable{
|
||
|
|
||
|
}
|
||
|
|
||
|
function setApprovalForAll(address _operator, bool _approved) public virtual override{
|
||
|
|
||
|
}
|
||
|
|
||
|
function getApproved(uint256 _tokenId) public virtual override view returns (address){
|
||
|
|
||
|
}
|
||
|
|
||
|
function isApprovedForAll(address _owner, address _operator) public virtual override view returns (bool){
|
||
|
|
||
|
}
|
||
|
|
||
|
function checkTimeout(uint256 _tokenId) public virtual override returns (bool){
|
||
|
require(ownerOfSD[_tokenId] == msg.sender);
|
||
|
if((Secure_Token[_tokenId].timestamp + Secure_Token[_tokenId].timeout) > block.timestamp){
|
||
|
return true;
|
||
|
}else{
|
||
|
Secure_Token[_tokenId].user = address(0);
|
||
|
emit TimeoutAlarm(_tokenId);
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function updateTimestamp() public virtual override{
|
||
|
Secure_Token[tokenFromBCA(msg.sender)].timestamp = block.timestamp;
|
||
|
}
|
||
|
|
||
|
function setTimeout(uint256 _tokenId, uint256 _timeout) public virtual override{
|
||
|
require(ownerOfSD[_tokenId] == msg.sender);
|
||
|
Secure_Token[_tokenId].timeout = _timeout;
|
||
|
}
|
||
|
}
|