Розробка NFT-membership системи

Проєктуємо та розробляємо блокчейн-рішення повного циклу: від архітектури смарт-контрактів до запуску DeFi-протоколів, NFT-маркетплейсів та криптобірж. Аудит безпеки, токеноміка, інтеграція з наявною інфраструктурою.
Показано 1 з 1Усі 1306 послуг
Розробка NFT-membership системи
Середній
~3-5 днів
Часті запитання

Напрямки блокчейн-розробки

Етапи блокчейн-розробки

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1285
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1198
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    902
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1121
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    589
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    858

Розробка NFT-membership системи

Найчастіша помилка в NFT-membership: розробники реалізують перевірку ownerOf(tokenId) == msg.sender та вважають завдання вирішеним. Але NFT можна одолжити, flash loan-нути (на один блок) або виставити на маркетплейс, зберігши доступ через делегування. Правильна membership система вимагає розуміння цих векторів та явного вибору моделі довіри.

Контрактна архітектура

Базова модель: володіння токеном

Для простих кейсів (доступ до контенту, Discord-верифікація) достатньо ERC-721 з функцією перевірки:

function isMember(address user) public view returns (bool) {
    return balanceOf(user) > 0;
}

balanceOf дешевше ownerOf при множественних токенах та стійкіший до edge cases. Але вона не захищає від листингу: власник може виставити NFT на OpenSea, отримати доступ до закритого контенту, та зняти листинг після.

Тиерна membership через ERC-1155

Для кількох рівнів доступу (Bronze/Silver/Gold, або місяц/рік/lifetime) ERC-1155 нативно підходить краще ERC-721. Кожен tokenId — тир:

uint256 public constant TIER_BRONZE = 1;
uint256 public constant TIER_SILVER = 2;
uint256 public constant TIER_GOLD = 3;

function getMemberTier(address user) external view returns (uint256) {
    if (balanceOf(user, TIER_GOLD) > 0) return TIER_GOLD;
    if (balanceOf(user, TIER_SILVER) > 0) return TIER_SILVER;
    if (balanceOf(user, TIER_BRONZE) > 0) return TIER_BRONZE;
    return 0; // не учасник
}

Тири з накопленим доступом: Gold включает все що есть в Silver та Bronze. Перевіряємо зверху вниз.

Soulbound (нетрансферабельні) membership токени

Якщо мета — привязать доступ до конкретної людини, а не гаманця, використовуємо EIP-5192 (Minimal Soulbound NFT) або просто переопределяем transfer функції:

function _beforeTokenTransfer(
    address from,
    address to,
    uint256 tokenId,
    uint256 batchSize
) internal override {
    require(from == address(0) || to == address(0), "Soulbound: non-transferable");
    super._beforeTokenTransfer(from, to, tokenId, batchSize);
}

from == address(0) — mint, to == address(0) — burn. Все остальное заборонено. Проблема: втрата ключів = втрата membership. Рішення: передбачити recovery механізм через мультисиг або соціальне відновлення (ERC-4337 account abstraction).

Тимчасова membership

Expiring membership вимагає зберігання дат. Два підходи:

On-chain timestamp: маппинг tokenId → expiresAt. Перевірка в isMember() включає block.timestamp < memberships[tokenId].expiresAt. Renewal — транзакція з оплатою, обновляет timestamp. Газ на кожну перевірку.

Signature-based off-chain: бекенд видає підписані JWT з expiry, контракт не зберігає час. Дешевше по газу, але вимагає довіри до сервісу підписів. Підходит для Web2-hybrid систем.

Для fully on-chain — перший підхід. ERC-5643 — черновик стандарту для subscription NFT з renewSubscription(uint256 tokenId, uint64 duration).

Інтеграція з off-chain системами

Верифікація через EIP-1271

Для перевірки membership у бекенді без транзакцій: користувач підписує сообщение (EIP-191 або EIP-712), бекенд верифікує через eth_call до isValidSignature(bytes32 hash, bytes signature) для смарт-кошельків або через ecrecover для EOA.

async function verifyMembership(
  userAddress: string,
  signature: string,
  message: string,
  nftContract: ethers.Contract
): Promise<boolean> {
  const signerAddress = ethers.verifyMessage(message, signature);
  if (signerAddress.toLowerCase() !== userAddress.toLowerCase()) return false;
  const balance = await nftContract.balanceOf(userAddress);
  return balance.gt(0);
}

Делегування через delegate.xyz

delegate.cash (EIP-нет, але де-факто стандарт) дозволяє власнику NFT делегувати cold wallet → hot wallet. Важливо для membership систем: тримачі зберігають дорогий NFT у cold wallet, взаємодіють через гарячий. Інтеграція:

IDelegationRegistry constant DELEGATION_REGISTRY = 
    IDelegationRegistry(0x00000000000076A84feF008CDAbe6409d2FE638B);

function isMember(address user) public view returns (bool) {
    if (balanceOf(user) > 0) return true;
    // Перевіряємо делегування
    address[] memory delegators = DELEGATION_REGISTRY.getDelegationsByDelegate(user);
    for (uint i = 0; i < delegators.length; i++) {
        if (balanceOf(delegators[i]) > 0) return true;
    }
    return false;
}

Реальна потреба: Moonbirds, Doodles та інші крупні колекції інтегрували delegate.cash саме для цього.

Mint механізм та ціноутворення

Allowlist через Merkle Tree — стандарт для presale:

bytes32 public merkleRoot;

function allowlistMint(bytes32[] calldata proof) external payable {
    bytes32 leaf = keccak256(abi.encodePacked(msg.sender));
    require(MerkleProof.verify(proof, merkleRoot, leaf), "Invalid proof");
    require(msg.value >= PRICE, "Insufficient payment");
    _safeMint(msg.sender, _nextTokenId());
}

Proof генерується off-chain (merkletreejs), root завантажується в контракт. Список на 10,000 адрес — proof з ~14 хешей, calldata ~450 байтів.

Орієнтири по строкам

ERC-721 membership з тирами та Merkle allowlist — 2 дні. Додавання тимчасової підписки (ERC-5643 стиль) + бекенд верифікація — ще 1-2 дні. Повна система з делегуванням, soulbound recovery та фронтендом — 4-5 днів.