Non-fungible tokens (NFTs) are digital assets stored on the blockchain that prove the authenticity of each digital art. Each unit is not interchangeable so the underlying asset remains unique and ownable, and the blockchain network acts as a mediator to certify authenticity and prove ownership. All digital art and products sold on the 3space platform will be represented by NFTs, and digital art involved in exhibitions and events organized or attended by 3space will be addressed by its current owner and creator’s public key.

3space will implement the following standards: KIP-17 and KIP-7 on Klaytn, ERC-721 and ERC-20 on Ethereum.

Klaytn Network

KIP-17 is the standard interface for non-fungible tokens (NFTs), also known as deeds. The contract used by 3space to mint and transfer NFT tokens on Klaytn can be found here: ThreeSpaceFlattenNew.sol

KIP-17 is derived from Ethereum's ERC-721 and is implemented to make most functions compatible with ERC-721. Some of the key features can be found below:

  • All tokens must track event logs for issuance/transmission/burn. This means that Transfer events must be exported for all operations related to Transfer/mint/burn.

  • KIP-17 also supports the wallet interface of ERC-721 (IERC721 Token Receiver)

  • More optional extensions are defined (minting extension, minting with URI extension, Burning extension, Pushing extension).


The images, videos, and metadata of all NFTs are uploaded to cloud storage, while issued NFTs are protected by the Klaytn network. The Metadata Extension is used to investigate the details of the assets represented by the NFT and use tokenURI for JSON schema information.

The Enumeration Extension is used to post and search NFTs and make while IKIP17MetadataMintable is used to mint tokens through TokenURI.

3space is a verified service provider for the KLIP wallet. To mint mobile compatible NFTs, 3space is required to use Minting API and App2App APIs to mint and transfer tokens.

The metadata for Klaytn NFT will contain some or all of the following:

name, description, image, animation_url, background_color, sendable, send_friend_only, group_name, group_icon, attributes (artist name, dimensions, year created, edition, art description)


Wallet Interface : The owner or authorized user of the token can send the NFT to another address.

Pausing Extension: The pause function allows the contract to be temporarily suspended from being transferred.


The owner or authorized user of the token can burn and permanently remove the NFT.


KIP-17 tokens can be stored on web-based Klaytn wallets such as Kaikas, or the KLIP wallet, which is the cryptocurrency wallet for mobile app Kakaotalk. Users will be able to connect their Kaikas or KLIP wallet by signing up and entering the public address in their account.


3space follows the ERC-721 standard for minting and transferring NFTs. Source code for 3space is as follows:

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

import './interfaces/IThreeSpace.sol';
import './interfaces/IERC20BurnableUpgradeable.sol';
import './extensions/ERC721NameChangeUpgradeable.sol';
import './extensions/ERC721TradableUpgradeable.sol';
import '@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol';
import '@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol';
import '@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol';
import '@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721EnumerableUpgradeable.sol';
import '@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721URIStorageUpgradeable.sol';
import '@openzeppelin/contracts-upgradeable/utils/CountersUpgradeable.sol';
import '@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol';

 * @title ThreeSpace
contract ThreeSpace is
  using CountersUpgradeable for CountersUpgradeable.Counter;

  bytes32 public constant MINTER_ROLE = keccak256('MINTER_ROLE');

  CountersUpgradeable.Counter private _tokenIdCounter;

  /// @custom:oz-upgrades-unsafe-allow constructor
  constructor() initializer {}

  function initialize(
    address proxyRegistryAddress_,
    address nameChangeToken_,
    uint256 nameChangePrice_
  ) external initializer {
    __ERC721_init('ThreeSpace', 'SPACE');
    __ERC721Tradable_init('ThreeSpace', proxyRegistryAddress_);
    __ERC721NameChange_init(nameChangeToken_, nameChangePrice_);

    _setupRole(DEFAULT_ADMIN_ROLE, msg.sender);
    _setupRole(MINTER_ROLE, msg.sender);

  function updateNameChangeToken(address token) external {
    require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'Only Admin can update');
    _nameChangeToken = token;

  function updateNameChangePrice(uint256 price) external {
    require(hasRole(DEFAULT_ADMIN_ROLE, msg.sender), 'Only Admin can update');
    _nameChangePrice = price;

  function changeName(uint256 tokenId, string memory newName) public override {
    super.changeName(tokenId, newName);


  function safeMint(address to, string memory uri) public onlyRole(MINTER_ROLE) {
    _safeMint(to, _tokenIdCounter.current());
    _setTokenURI(_tokenIdCounter.current(), uri);

  function _beforeTokenTransfer(
    address from,
    address to,
    uint256 tokenId
  ) internal override(ERC721Upgradeable, ERC721EnumerableUpgradeable, ERC721TradableUpgradeable) {
    super._beforeTokenTransfer(from, to, tokenId);

  function _burn(uint256 tokenId)
    override(ERC721Upgradeable, ERC721URIStorageUpgradeable)

  function tokenURI(uint256 tokenId)
    override(ERC721Upgradeable, ERC721URIStorageUpgradeable)
    returns (string memory)
    return super.tokenURI(tokenId);

  function supportsInterface(bytes4 interfaceId)
    returns (bool)
    return super.supportsInterface(interfaceId);

  function isApprovedForAll(address owner, address operator)
    override(ERC721Upgradeable, ERC721TradableUpgradeable)
    returns (bool)
    return super.isApprovedForAll(owner, operator);

  function _msgSender()
    override(ContextUpgradeable, ERC721TradableUpgradeable)
    returns (address sender)
    return super._msgSender();


3space Art allows users to embed data directly into the Bitcoin blockchain, leveraging the immutability and security of the Bitcoin network. We provide a simple Flask API service capable of running Python applications connected to the Bitcoin Core node.

from flask import Flask, request, jsonify from bitcoin_rpc import get_rpc_client import binascii
app = Flask(name)
@app.route('/create_address', methods=['GET']) def create_address(): client = get_rpc_client() address = client.getnewaddress() return jsonify({"address": address})
@app.route('/inscribe', methods=['POST']) def inscribe(): data = request.json.get('data') address = request.json.get('address')

hex_data = binascii.hexlify(data.encode('utf-8')).decode('utf-8')

client = get_rpc_client()

utxo = client.listunspent(1, 9999999, [address])[0]
txid = utxo['txid']
vout = utxo['vout']
amount = utxo['amount']

rawtx = client.createrawtransaction([{"txid": txid, "vout": vout}], {"data": hex_data})

fundedtx = client.fundrawtransaction(rawtx)

signedtx = client.signrawtransactionwithwallet(fundedtx['hex'])

txid = client.sendrawtransaction(signedtx['hex'])
return jsonify({"txid": txid})

if name == 'main':, debug=True)


To collect and transfer NFTs at 3space, the user has two options: 1) sign-up and enter a private wallet's public address in account settings or 2) connect Metamask and other third-party Ethereum wallets to perform direct swaps with Ethereum and NFTs in the marketplace.

Last updated