NFT Asset Integration into Metaverse

We design and develop full-cycle blockchain solutions: from smart contract architecture to launching DeFi protocols, NFT marketplaces and crypto exchanges. Security audits, tokenomics, integration with existing infrastructure.
Showing 1 of 1 servicesAll 1306 services
NFT Asset Integration into Metaverse
Medium
~1-2 weeks
FAQ
Blockchain Development Services
Blockchain Development Stages
Latest works
  • image_website-b2b-advance_0.png
    B2B ADVANCE company website development
    1214
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    852
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823

NFT Assets Integration in Metaverse

NFT assets in a metaverse are not just pictures attached to an account. They are interactive objects with verifiable ownership rights: land that can be developed, weapons with real game characteristics, an avatar carrying the owner's social status. Integration requires solving several non-trivial technical problems.

NFT-in-Game-World Architecture

On-chain Verification of Rights

Before using an NFT in a metaverse, ownership rights must be verified:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;

interface IMetaverseAssets {
    function canUseInWorld(
        address user,
        address nftContract,
        uint256 tokenId
    ) external view returns (bool);
}

contract MetaverseAssetRegistry is IMetaverseAssets {
    // Registry of approved NFT collections
    mapping(address => bool) public approvedCollections;

    // Custom rules for collections
    mapping(address => address) public collectionAdapters;

    function canUseInWorld(
        address user,
        address nftContract,
        uint256 tokenId
    ) external view override returns (bool) {
        if (!approvedCollections[nftContract]) {
            return false;
        }

        // Check ERC-721 or ERC-4907 (rentable)
        try IERC721(nftContract).ownerOf(tokenId) returns (address owner) {
            if (owner == user) return true;
        } catch {}

        // ERC-4907: check user role (rental)
        try IERC4907(nftContract).userOf(tokenId) returns (address renter) {
            if (renter == user && block.timestamp <= IERC4907(nftContract).userExpires(tokenId)) {
                return true;
            }
        } catch {}

        return false;
    }
}

Mapping NFT Properties to Game Characteristics

interface NFTAttributeMapper {
  mapAttributes(
    nftContract: string,
    tokenId: number,
    metadata: NFTMetadata
  ): GameAssetProperties;
}

class WeaponNFTMapper implements NFTAttributeMapper {
  mapAttributes(nftContract, tokenId, metadata): GameAssetProperties {
    const attrs = metadata.attributes;
    const getAttr = (name: string) =>
      attrs.find(a => a.trait_type === name)?.value;

    return {
      assetType: 'weapon',
      mesh3dUrl: metadata.animation_url,  // GLB file
      textures: this.extractTextures(metadata),
      gameStats: {
        damage: this.normalizeValue(getAttr('Power'), 1, 100, 10, 500),
        speed: this.normalizeValue(getAttr('Speed'), 1, 100, 0.5, 2.0),
        range: this.normalizeValue(getAttr('Range'), 1, 100, 1, 50),
        rarity: getAttr('Rarity') as RarityTier,
      },
      visualEffects: this.getEffectsForRarity(getAttr('Rarity')),
    };
  }
}

Cross-Collection Interoperability

Different NFT collections have different metadata formats. Adapter pattern solves this:

class NFTAdapterFactory {
  private adapters: Map<string, NFTAttributeMapper> = new Map();

  register(contractAddress: string, adapter: NFTAttributeMapper) {
    this.adapters.set(contractAddress.toLowerCase(), adapter);
  }

  async getGameProperties(
    contractAddress: string,
    tokenId: number
  ): Promise<GameAssetProperties | null> {
    const metadata = await this.fetchMetadata(contractAddress, tokenId);
    const adapter = this.adapters.get(contractAddress.toLowerCase());

    if (!adapter) {
      // Fallback: try generic adapter by standard fields
      return this.genericAdapter.mapAttributes(contractAddress, tokenId, metadata);
    }

    return adapter.mapAttributes(contractAddress, tokenId, metadata);
  }
}

3D Rendering of NFT Objects

Most NFTs are 2D images. For a metaverse, a 3D representation is needed:

Strategies:

  1. 3D Native NFT: collection originally provides GLB/VRM file in metadata (animation_url)
  2. 2D-to-3D billboard: 2D NFT displayed as texture on 3D plane (for PFP collections)
  3. Procedural generation: 3D model generated on-the-fly from NFT traits
class NFT3DRenderer {
  async renderAsset(
    asset: GameAssetProperties,
    scene: THREE.Scene
  ): Promise<THREE.Object3D> {
    if (asset.mesh3dUrl) {
      // Load ready 3D model
      const loader = new GLTFLoader();
      const gltf = await loader.loadAsync(asset.mesh3dUrl);
      return gltf.scene;
    }

    // Fallback: billboard from 2D image
    const texture = await new THREE.TextureLoader().loadAsync(asset.imageUrl);
    const geometry = new THREE.PlaneGeometry(1, 1);
    const material = new THREE.MeshStandardMaterial({
      map: texture,
      transparent: true,
      alphaTest: 0.5
    });
    return new THREE.Mesh(geometry, material);
  }
}

Session Rights and Transfer Restrictions

NFT in a metaverse should not always be transferable during use. If a player uses a sword — it cannot be sold during a fight:

contract InWorldLock {
    mapping(address => mapping(uint256 => bool)) public isLockedInWorld;
    mapping(address => mapping(uint256 => address)) public lockedBy;

    event AssetLocked(address nftContract, uint256 tokenId, address world);
    event AssetUnlocked(address nftContract, uint256 tokenId);

    function lockAsset(address nftContract, uint256 tokenId) external onlyRegisteredWorld {
        require(!isLockedInWorld[nftContract][tokenId], "Already locked");
        isLockedInWorld[nftContract][tokenId] = true;
        lockedBy[nftContract][tokenId] = msg.sender;
        emit AssetLocked(nftContract, tokenId, msg.sender);
    }

    function unlockAsset(address nftContract, uint256 tokenId) external {
        require(lockedBy[nftContract][tokenId] == msg.sender, "Not locker");
        isLockedInWorld[nftContract][tokenId] = false;
        delete lockedBy[nftContract][tokenId];
        emit AssetUnlocked(nftContract, tokenId);
    }
}

ERC-5192 (Soulbound Token) is a standard for non-transferable NFTs (achievements, reputation). Useful for in-game rewards that should not be traded.

Marketplace Integration

NFTs within a metaverse should be bought and sold directly from the game interface. Integration with OpenSea SDK or custom marketplace contract:

const buyNFTInWorld = async (
  nftContract: string,
  tokenId: number,
  listingId: string
) => {
  // Check there is an active listing
  const listing = await seaport.getListing(listingId);

  // Execute purchase via Seaport
  const { executeAllActions } = await seaport.fulfillOrder({
    order: listing.order,
    accountAddress: userWallet
  });

  await executeAllActions();

  // After purchase — instant appearance in player's inventory
  await gameClient.refreshInventory(userWallet);
};

Good NFT integration in a metaverse turns digital assets from speculative instruments into utility objects with real game meaning. This is true utility NFT — the foundation for sustainable game project tokenomics.