craft-nft

A standalone NFT implementation for real-world arts and crafts assets
Log | Files | Refs | README

CraftNFT.sol (19725B)


      1 pragma solidity >= 0.8.0;
      2 
      3 // SPDX-License-Identifier: AGPL-3.0-or-later
      4 
      5 contract CraftNFT {
      6 	// Defines the behavior of a single token batch.
      7 	// 
      8 	// count defines the amount of tokens there are in a batch. A count of 0 indicates a unique token.
      9 	// A batched token can never have a token count of 0 in any batch.
     10 	// 
     11 	// cursor keeps track of how many tokens have been minted in the batch.
     12 	//
     13 	// If sparse is set, token indexes in mintedToken may not be in order.
     14         // In this case a full iteration up to count is required to discover all minted tokens.
     15 	struct tokenSpec {
     16 		uint48 count;
     17 		uint48 cursor;
     18 		bool sparse;
     19 		bool capped;
     20 	}
     21 
     22 	// 0xc22876c3 - ERC721
     23 	// 0xd283ef1d - ERC721 (Metadata)
     24 	// 0xdd9d2087 - ERC721 (Enumerable)
     25 	// 0x449a52f8 - Minter
     26 	// 0xabe1f1f5 - Writer
     27 	// 0xed75b333 - Locator
     28 	// 0xf0440c0f - Msg
     29 	// 0x982ab05d - Digest
     30 	uint256 constant interfaces = 0xc22876c3d283ef1ddd9d2087449a52f8abe1f1f5ed75b333f0440c0f982ab05d;
     31 
     32 	// The owner of the token contract.
     33 	// Only the owner may mint tokens.
     34 	// Implements ERC173
     35 	address public owner;
     36 
     37 	// Addresses with access to allocate and mint tokens..
     38 	mapping ( address => bool ) writer;
     39 
     40 	// If set, ownership of the token contract cannot change.
     41 	bool ownerFinal;
     42 
     43 	// Collection of all unique token keys
     44 	bytes32[] public tokens;
     45 
     46 	// Define each batch of a token. (A unqiue token will have a single entry only).
     47 	mapping(bytes32 => tokenSpec[]) public token;
     48 
     49 	// All Minted Tokens.
     50 	// Represents both Unique Tokens and Batch Tokens.
     51 	mapping(bytes32 => bytes32) public mintedToken;
     52 
     53 	// List of tokens in order of minting
     54 	// Implements ERC721Enumerable
     55 	uint256[] public tokenByIndex;
     56 
     57 	// Registry for the approve() method
     58 	mapping(uint256 => address) tokenAllowance;
     59 
     60 	// Registry for the setApprovalForAll() method
     61 	mapping(address => address) tokenOperator;
     62 
     63 	// Implements ERC721Metadata
     64 	string public name;
     65 
     66 	// Implements ERC721Metadata
     67 	string public symbol;
     68 
     69 	// Editable base URI against which to look up token data by token id
     70 	bytes public baseURL;
     71 
     72 	// Enumerated index of all owned tokens
     73 	// Implements ERC721Enumerable
     74 	mapping ( address => mapping ( uint256 => uint256 ) ) public tokenOfOwnerByIndex;
     75 	mapping ( uint256 => uint256 ) ownerIndexReverse;
     76 	mapping ( address => uint256 ) balance;
     77 
     78 	// Implements ERC721
     79 	event Transfer(address indexed _from, address indexed _to, uint256 indexed _tokenId);
     80 	// Implements ERC721
     81 	event Approval(address indexed _owner, address indexed _approved, uint256 indexed _tokenId);
     82 	// Implements ERC721
     83 	event ApprovalForAll(address indexed _owner, address indexed _operator, bool _approved);
     84 	event TransferWithData(address indexed _from, address indexed _to, uint256 indexed _tokenId, bytes32 _data);
     85 
     86 	// Implements Minter
     87 	event Mint(address indexed _minter, address indexed _beneficiary, uint256 _value);
     88 
     89 	event Allocate(address indexed _minter, uint48 indexed _count, bool indexed _capped, bytes32 _tokenId);
     90 
     91 	// Implements ERC173
     92 	event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
     93 
     94 	// Content hashes
     95 	// Represents a multicodec item
     96 	struct MultiHash {
     97 		uint8 l;
     98 		uint8 codecRLength;
     99 		uint8 prefixRLength;
    100 		bytes16 prefix;
    101 		bytes8 codec;
    102 	}
    103 	// All registered multicodecs
    104 	mapping (uint256 => MultiHash) public multiHash;
    105 	bytes currentMsg;
    106 	// Implements Digest
    107 	uint256 public defaultDigestEncoding;
    108 
    109 	// Implements Msg
    110 	event Msg(bytes _multiHash);
    111 
    112 	constructor(string memory _name, string memory _symbol) {
    113 		owner = msg.sender;
    114 		name = _name;
    115 		symbol = _symbol;
    116 		addMultiCodec(32, 0x12, "sha256");
    117 		defaultDigestEncoding = 0x12;
    118 		currentMsg = new bytes(32);
    119 	}
    120 
    121 	// Transfer ownership of token contract to new owner.
    122 	//
    123 	// If _final is true, future ownership transfers will not be permitted.
    124 	function transferOwnership(address _newOwner) public returns(bool) {
    125 		address oldOwner;
    126 
    127 		require(msg.sender == owner);
    128 		oldOwner = owner;
    129 		owner = _newOwner;
    130 		emit OwnershipTransferred(oldOwner, owner);
    131 		return true;
    132 	}
    133 
    134 	// implements Writer
    135 	function addWriter(address _writer) public {
    136 		require(msg.sender == owner, 'ERR_ACCESS');
    137 		writer[_writer] = true;
    138 	}
    139 
    140 	// implements Writer
    141 	function deleteWriter(address _writer) public {
    142 		require(msg.sender == _writer || msg.sender == owner, 'ERR_ACCESS');
    143 		writer[_writer] = false;
    144 	}
    145 
    146 	// implements Writer
    147 	function isWriter(address _writer) public view returns(bool) {
    148 		return writer[_writer] || _writer == owner;
    149 	}
    150 
    151 	// Check bit that is always set on the content data when a token has been minted.
    152 	function isActive(bytes32 _tokenContent) private pure returns(bool) {
    153 		return uint256(_tokenContent) & 0x8000000000000000000000000000000000000000000000000000000000000000 > 0;
    154 	}
    155 
    156 	// Returns true if the content data belongs to a Unique Token
    157 	function isSingle(bytes32 _tokenContent) private pure returns(bool) {
    158 		return uint256(_tokenContent) & 0x4000000000000000000000000000000000000000000000000000000000000000 > 0;
    159 	}
    160 
    161 	// Reassemble unique token key from indexed token id
    162 	function getDigest(bytes32 _truncatedId) public view returns (bytes32) {
    163 		bytes32 digest;
    164 
    165 		digest = mintedToken[_truncatedId];
    166 		require(isActive(digest));
    167 
    168 		if (isSingle(digest)) {
    169 			return _truncatedId;
    170 		}
    171 
    172 		digest &= 0x00ffffffffffffffff0000000000000000000000000000000000000000000000;
    173 		digest >>= 184;
    174 		digest |= _truncatedId & 0xffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000;
    175 		return digest;
    176 	}
    177 
    178 	// Allocate tokens for minting.
    179 	// if count is set to 0, only a single unique token can be minted.
    180 	// if count is set a negative number, the token will be unbounded (may be capped later with setCap).
    181 	function allocate(bytes32 content, int48 count) public returns (bool) {
    182 		uint256 l;
    183 		require(msg.sender == owner || writer[msg.sender], 'ERR_ACCESS');
    184 		
    185 		tokenSpec memory _token;
    186 
    187 		l = token[content].length;
    188 		if (l > 0) {
    189 			require(token[content][0].count > 0);
    190 		}
    191 
    192 		if (count == 0) {
    193 			_token.capped = true;
    194 		} else if (count > 0) {
    195 			_token.count = uint48(count);
    196 			_token.capped = true;
    197 		}
    198 		token[content].push(_token);
    199 		tokens.push(content);
    200 
    201 		emit Allocate(msg.sender, _token.count, _token.capped, content);
    202 		return true;
    203 	}
    204 
    205 	// Find the token batch which contains the given index.
    206 	// Search scope can be controlled using the _startAt and _endAt properties.
    207 //	function batchOf(bytes32 _content, uint256 _superIndex, uint256 _startAt) public view returns(int256) {
    208 //		for (uint256 i = _startAt; i < token[_content].length; i++) {
    209 //			if (token[_content][i].cumulativeCount > uint128(_superIndex)) {
    210 //				return int256(i);
    211 //			}
    212 //		}
    213 //		return -1;
    214 //	}
    215 
    216 	// Mint a unique token. The method will fail if the token was allocated as a batch.
    217 	function mintToBytes(address _recipient, bytes32 _content) public returns (bytes32) {
    218 		uint256 right;
    219 		uint256 tokenId;
    220 		uint256 _balance;
    221 		
    222 		require(msg.sender == owner || writer[msg.sender]);
    223 		require(token[_content].length == 1);
    224 		require(token[_content][0].count == 0);
    225 		require(mintedToken[_content] == bytes32(0x00));
    226 
    227 		right = uint160(_recipient);
    228 		right |= (3 << 254);
    229 		mintedToken[_content] = bytes32(right);
    230 		
    231 		tokenId = uint256(_content);
    232 		_balance = balance[_recipient];
    233 		ownerIndexReverse[tokenId] = _balance;
    234 		tokenOfOwnerByIndex[_recipient][_balance] = tokenId;
    235 		balance[_recipient] += 1;
    236 		tokenByIndex.push(tokenId); //int256(_content));
    237 
    238 		emit Mint(msg.sender, _recipient, tokenId);
    239 
    240 		return _content;
    241 	}
    242 
    243 	// Proxy for mintToBytes
    244 	// Implements Minter
    245 	function mintTo(address _recipient, uint256 _contentNumeric) public returns (bytes32) {
    246 		bytes32 _content;
    247 		_content = bytes32(_contentNumeric);
    248 		return mintToBytes(_recipient, _content);
    249 	}
    250 
    251 	// Implements Minter
    252 	function mint(address _recipient, uint256 _tokenId, bytes calldata _data) public {
    253 		_data;
    254 		mintTo(_recipient, _tokenId);
    255 	}
    256 
    257 	// Implements Minter
    258 	function safeMint(address _recipient, uint256 _tokenId, bytes calldata _data) public {
    259 		_data;
    260 		mintTo(_recipient, _tokenId);
    261 	}
    262 
    263 	// Apply the token owner to the token content data.
    264 	function setTokenOwner(uint256 _tokenId, address _newOwner) private {
    265 		uint256 _data;
    266 		bytes32 _k;
    267 
    268 		_k = bytes32(_tokenId);
    269 	
    270 		_data = uint256(mintedToken[_k]);
    271 		require(_data != 0);
    272 
    273 		_data &= 0xffffffffffffffffffffffff0000000000000000000000000000000000000000;
    274 		_data |= uint160(_newOwner);
    275 		mintedToken[_k] = bytes32(_data);
    276 	}
    277 
    278 	// Apply cap on unbounded token
    279 	// if cap value is set to 0, cap will be set on the current count.
    280 	function setCap(bytes32 _content, uint16 _batch, uint48 _cap) public {
    281 		tokenSpec storage spec;
    282 
    283 		spec = token[_content][uint256(_batch)];
    284 		require(!spec.sparse, 'ERR_SPARSE');
    285 		require(!spec.capped, 'ERR_CAPPED');
    286 		if (_cap == 0) {
    287 			_cap = spec.cursor;
    288 		}
    289 		require(_cap >= spec.count, 'ERR_CAP_LOW');
    290 		spec.count = _cap;
    291 		spec.capped = true;
    292 	}
    293 
    294 	// Mint a token from a batch.
    295 	// Will fail if:
    296 	// * All tokens in the batch have already been minted
    297 	// * One or more tokens have been minted out of sequential order (see mintExactFromBatchTo)
    298 	//
    299 	// If the token was allocated as a single token (which has not yet been minted),
    300 	// this method will transparently alias to mintTo
    301 	function mintFromBatchTo(address _recipient, bytes32 _content, uint16 _batch) public returns (bytes32) {
    302 		tokenSpec storage spec;
    303 	
    304 		spec = token[_content][uint256(_batch)];
    305 
    306 		require(!spec.sparse, 'ERR_SPARSE');
    307 		require(msg.sender == owner || writer[msg.sender], 'ERR_ACCESS');
    308 		if (_batch == 0 && spec.count == 0 && spec.capped) {
    309 			spec.cursor += 1;
    310 			return mintToBytes(_recipient, _content);
    311 		}
    312 		if (spec.capped) {
    313 			require(spec.cursor < spec.count);
    314 		}
    315 		return mintBatchCore(_recipient, _content, _batch, spec.cursor, spec);
    316 	}
    317 
    318 
    319 	// Mint a token at a specific index of a batch
    320 	// If the index is not the next sequential index in the batch, the token will be marked as sparse.
    321 	// Sparse tokens cannot thereafter be minted using mintFromBatchTo
    322 	// The method will fail if the token at the specified index has already been minted, or if the index is out of bounds of the batch.
    323 	// This method cannot be used to mint a unique token or an unbounded token.
    324 	function mintExactFromBatchTo(address _recipient, bytes32 _content, uint16 _batch, uint48 _index) public returns (bytes32) {
    325 		tokenSpec storage spec;
    326 
    327 		spec = token[_content][_batch];
    328 		require(msg.sender == owner || writer[msg.sender], 'ERR_ACCESS');
    329 		require(spec.count > 0);
    330 		require(spec.capped);
    331 		require(_index < spec.count);
    332 		return mintBatchCore(_recipient, _content, _batch, _index, spec);
    333 	}
    334 
    335 	// Common code path for both batch mint methods.
    336 	function mintBatchCore(address _recipient, bytes32 _content, uint16 _batch, uint48 _index, tokenSpec storage _spec) private returns (bytes32) {
    337 		uint256 left;
    338 		uint256 right;
    339 		bytes32 k;
    340 		uint256 _balance;
    341 	
    342 		left = uint256(_content) & 0xffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000;
    343 		left |= ((_batch & 0xffffffffffffffff) << 48);
    344 		left |= _index;	
    345 		k = bytes32(left);
    346 	
    347 		require(mintedToken[k] == bytes32(0x00));
    348 		
    349 		if (!_spec.sparse) {
    350 			if (_index != _spec.cursor) {
    351 				_spec.sparse = true;
    352 			}
    353 		}
    354 
    355 		right = uint256(_content) & ((1 << 64) - 1);
    356 		right <<= 184;
    357 		right |= (1 << 255);
    358 		right |= uint160(_recipient);
    359 
    360 		_spec.cursor += 1;
    361 		if (!_spec.capped) {
    362 			_spec.count += 1;
    363 		}
    364 		mintedToken[k] = bytes32(right);
    365 
    366 		_balance = balance[_recipient];
    367 		ownerIndexReverse[left] = _balance;
    368 		tokenOfOwnerByIndex[_recipient][_balance] = left;
    369 
    370 		balance[_recipient] += 1;
    371 		tokenByIndex.push(left);
    372 
    373 		emit Mint(msg.sender, _recipient, left);
    374 
    375 		return k;
    376 	}
    377 	
    378 	// Implements ERC721
    379 	function balanceOf(address _owner) external view returns (uint256) {
    380 		return balance[_owner];
    381 	}	
    382 
    383 	// Implements ERC721
    384 	function setApprovalForAll(address _operator, bool _approved) external {
    385 		if (_approved) {
    386 			require(tokenOperator[msg.sender] == address(0)); // save a few bucks in gas if fail
    387 			tokenOperator[msg.sender] = _operator;
    388 		} else {
    389 			require(tokenOperator[msg.sender] != address(0));
    390 			tokenOperator[msg.sender] = address(0);
    391 		}
    392 		emit ApprovalForAll(msg.sender, _operator, _approved);
    393 	}
    394 
    395 	// Implements ERC721
    396 	function getApproved(uint256 _tokenId) external view returns (address) {
    397 		return tokenAllowance[_tokenId];
    398 	}
    399 
    400 	// Implements ERC721
    401 	function isApprovedForAll(address _owner, address _operator) external view returns (bool) {
    402 		return tokenOperator[_owner] == _operator;
    403 	}
    404 
    405 	// Implements ERC721
    406 	function ownerOf(uint256 _tokenId) external view returns (address) {
    407 		bytes32 _tokenContent;
    408 
    409 		_tokenContent = mintedToken[bytes32(_tokenId)];
    410 		return address(bytes20(_tokenContent << 96));
    411 	}
    412 
    413 	// Common code path for transfer methods
    414 	function transferCore(address _from, address _to, uint256 _tokenId) internal {
    415 		address currentTokenOwner;
    416 		uint256 reverseIndex;
    417 		uint256 currentIndex;
    418 
    419 		currentTokenOwner = this.ownerOf(_tokenId);
    420 
    421 		require(currentTokenOwner == _from);
    422 		if (_from != msg.sender) {
    423 			require(tokenAllowance[_tokenId] == msg.sender || tokenOperator[currentTokenOwner] == msg.sender);
    424 		}
    425 		
    426 		tokenAllowance[_tokenId] = address(0);
    427 		setTokenOwner(_tokenId, _to);
    428 		reverseIndex = ownerIndexReverse[_tokenId];
    429 		currentIndex = balance[_from] - 1;
    430 		if (currentIndex > reverseIndex) {
    431 			tokenOfOwnerByIndex[_from][reverseIndex] = tokenOfOwnerByIndex[_from][currentIndex];
    432 		}
    433 		tokenOfOwnerByIndex[_from][currentIndex] = uint256(0);
    434 
    435 		currentIndex = balance[_to];
    436 		tokenOfOwnerByIndex[_to][currentIndex] = _tokenId;
    437 
    438 		balance[_from] -= 1;
    439 		balance[_to] += 1;
    440 	}
    441 
    442 	// Implements ERC721
    443 	function transferFrom(address _from, address _to, uint256 _tokenId) external payable {
    444 		transferCore(_from, _to, _tokenId);
    445 		emit Transfer(_from, _to, _tokenId);
    446 	}
    447 
    448 	// Implements ERC721
    449 	function safeTransferFrom(address _from, address _to, uint256 _tokenId, bytes memory _data) external payable {
    450 		transferCore(_from, _to, _tokenId);
    451 		emit Transfer(_from, _to, _tokenId);
    452 		emit TransferWithData(_from, _to, _tokenId, bytes32(_data));
    453 	}
    454 
    455 	// Implements ERC721
    456 	function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable {
    457 		transferCore(_from, _to, _tokenId);
    458 		emit Transfer(_from, _to, _tokenId);
    459 	}
    460 
    461 	// Allow mutable explicit url base
    462 	function setBaseURL(string memory _baseString) public {
    463 		bytes memory _base;
    464 		uint256 l;
    465 		require(msg.sender == owner);
    466 		
    467 		_base = bytes(_baseString);
    468 		l = _base.length;
    469 		if (_base[l-1] != 0x2f) {
    470 			l++;
    471 		}
    472 		baseURL = new bytes(l);
    473 		for (uint256 i = 0; i < _base.length; i++) {
    474 			baseURL[i] = _base[i];
    475 		}
    476 		if (l != _base.length) {
    477 			baseURL[_base.length] = "/";
    478 		}
    479 	}
    480 
    481 	// Implements Locator
    482 	function toURL(bytes memory _data) public view returns(string memory) {
    483 		bytes memory out;
    484 		bytes memory _hexDigest;
    485 		uint256 c;
    486 
    487 		_hexDigest = toHex(_data);
    488 	
    489 		c = baseURL.length;
    490 		out = new bytes(_hexDigest.length + c);
    491 
    492 		for (uint256 i = 0; i < c; i++) {
    493 			out[i] = baseURL[i];
    494 		}
    495 		for (uint256 i = 0; i < _hexDigest.length; i++) {
    496 			out[c] = _hexDigest[i];
    497 			c++;
    498 		}
    499 		return string(out);
    500 	}
    501 
    502 	// TODO: move to internal library method
    503 	// bytes to hex conversion
    504 	function toHex(bytes memory _data) public pure returns(bytes memory) {
    505 		bytes memory out;
    506 		uint8 t;
    507 		uint256 c;
    508 
    509 		out = new bytes(_data.length * 2);
    510 		c = 0;
    511 		for (uint256 i = 0; i < 32; i++) {
    512 			t = (uint8(_data[i]) & 0xf0) >> 4;
    513 			if (t < 10) {
    514 				out[c] = bytes1(t + 0x30);
    515 			} else {
    516 				out[c] = bytes1(t + 0x57);
    517 			}
    518 			t = uint8(_data[i]) & 0x0f;
    519 			if (t < 10) {
    520 				out[c+1] = bytes1(t + 0x30);
    521 			} else {
    522 				out[c+1] = bytes1(t + 0x57);
    523 			}
    524 			c += 2;
    525 		}
    526 		return out;
    527 	}
    528 
    529 	// Implements ERC721Metadata
    530 	function tokenURI(uint256 _tokenId) public view returns (string memory) {
    531 		bytes32 _tokenIdBytesFixed;
    532 		bytes memory _tokenIdBytes;
    533 		
    534 		_tokenIdBytesFixed = bytes32(_tokenId);
    535 	
    536 		// If not direct match, check if it is a batch.
    537 		// Fail if still not found (length 0).
    538 		if (token[_tokenIdBytesFixed].length == 0) {
    539 			_tokenIdBytesFixed = getDigest(_tokenIdBytesFixed);
    540 		}
    541 		require(token[_tokenIdBytesFixed].length > 0);
    542 
    543 		_tokenIdBytes = new bytes(32);
    544 		for (uint256 i = 0; i < 32; i++) {
    545 			_tokenIdBytes[i] = _tokenIdBytesFixed[i];
    546 		}
    547 
    548 		return toURL(_tokenIdBytes);
    549 	}
    550 
    551 	// EIP-165
    552 	function supportsInterface(bytes4 interfaceID) external pure returns (bool) {
    553 		uint32 interfaceN;
    554 		uint32 masked;
    555 
    556 		interfaceN = uint32(interfaceID);
    557 
    558 		// EIP165 interface id
    559 		if (uint32(interfaceID) ==  0x01ffc9a7) {
    560 			return true;
    561 		}
    562 
    563 		for (uint256 i = 0; i < 256; i += 32) {
    564 			masked = uint32((interfaces >> i) & 0xffffffff);
    565 			if (masked == 0) {
    566 				return false;
    567 			}
    568 			if (interfaceN == masked) {
    569 				return true;
    570 			}
    571 		}
    572 
    573 		return false;
    574 	}
    575 
    576 	// Implements ERC721Enumerable
    577 	function totalSupply() public view returns(uint256) {
    578 		return tokenByIndex.length;
    579 	}
    580 
    581 	// Add a multicodec that can later be set as current codec
    582 	function addMultiCodec(uint8 _length, uint64 _codecId, string memory _uriPrefix) public {
    583 		bytes memory prefixBytes;
    584 
    585 		prefixBytes = bytes(_uriPrefix);
    586 		require(prefixBytes.length <= 16, 'ERR_PREFIX_TOO_LONG');
    587 		MultiHash memory _hsh;
    588 		uint8 c;
    589 
    590 		c = 7;
    591 		while (c >= 0) {
    592 			uint64 mask = uint64(0xff << (c * 8));
    593 			if ((mask & _codecId) > 0) {
    594 				break;
    595 			}
    596 			c--;
    597 		}
    598 		_hsh.codecRLength = c + 1;
    599 		_hsh.codec = bytes8(_codecId << ((7 - c) * 8));
    600 		_hsh.prefixRLength = uint8(prefixBytes.length);
    601 		_hsh.prefix = bytes16(prefixBytes);
    602 		_hsh.l = _length;
    603 		
    604 		multiHash[uint256(_codecId)] = _hsh;
    605 	}
    606 
    607 	// Generate a multihash from the given digest and current selected multicodec
    608 	// Implements Digest
    609 	function encodeDigest(bytes memory _digest, uint256 _codec) public view returns(bytes memory) {
    610 		MultiHash storage m;
    611 		bytes memory r;
    612 
    613 		m = multiHash[_codec];
    614 		r = new bytes(_digest.length + m.l + m.codecRLength);
    615 
    616 		uint256 i = 0;
    617 		for (i; i < m.codecRLength; i++) {
    618 			r[i] = m.codec[i];
    619 		}
    620 		r[i] = bytes1(m.l);
    621 		i++;
    622 		for (uint256 j = 0; j < _digest.length; j++) {
    623 			r[i+j] = _digest[j];	
    624 		}
    625 
    626 		return r;
    627 	}
    628 
    629 	// Implements Digest
    630 	function encodeDigest(bytes memory _digest) public view returns(bytes memory) {
    631 		return encodeDigest(_digest, defaultDigestEncoding);
    632 	}
    633 
    634 	// Generate a URI representing the digest and the string prefix representation
    635 	// of the currently selected multicodec
    636 	// Implements Locator
    637 	function toURI(bytes memory _digest) public view returns(string memory) {
    638 		MultiHash storage m;
    639 
    640 		bytes memory codecString;
    641 		bytes memory digestHex;
    642 	        uint256 l;
    643 	      
    644 	       	digestHex = toHex(_digest);	
    645 		m = multiHash[defaultDigestEncoding];
    646 		l = m.prefixRLength;
    647 		codecString = new bytes(l + digestHex.length + 1);
    648 		for (uint256 i = 0; i < l; i++) {
    649 			codecString[i] = m.prefix[i];
    650 		}
    651 		codecString[l] = 0x3a;
    652 		l++;
    653 
    654 		for (uint256 i = 0; i < digestHex.length; i++) {
    655 			codecString[l+i] = digestHex[i];
    656 		}
    657 		return string(codecString);
    658 
    659 	}
    660 
    661 
    662 	// Set the current multicodec to use for multihash generation
    663 	function setMsgCodec(uint256 _codec) public {
    664 		MultiHash storage _hsh;
    665 
    666 		_hsh = multiHash[_codec];
    667 		require(_hsh.l > 0);
    668 
    669 		defaultDigestEncoding = _codec;
    670 		currentMsg = new bytes(_hsh.l);
    671 
    672 		//emit Msg(getMsg());
    673 	}
    674 
    675 	// Set the latest pesistent message on contract
    676 	function setMsg(bytes memory _digest) public {
    677 		MultiHash storage _hsh;
    678 
    679 		_hsh = multiHash[defaultDigestEncoding];
    680 		require(_digest.length == _hsh.l);
    681 
    682 		currentMsg = _digest;
    683 		emit Msg(getMsg());
    684 	}
    685 
    686 	// Return a multihash of the latest persistent message
    687 	// Implements Msg
    688 	function getMsg() public view returns(bytes memory) {
    689 		return encodeDigest(currentMsg);
    690 	}
    691 }