Розробка системи верифікації підлинності через NFT
Фізичний товар з QR-кодом «підтвердженим блокчейном» — це маркетинг, не безпека. Справжня проблема в тому, що NFT зберігає ссилку на щось, але не саме це щось. Підробити фізичний предмет та переклеїти QR-код з оригіналу на копію — тривіально, якщо система не вирішує завдання криптографічної привязки фізичного об'єкта до цифрового токена. Це те, що потрібно проектувати в першу чергу.
Привязка фізичного об'єкта до NFT
NFC-чипи з криптографією
Найнадійніший підхід для фізичних товарів — NFC-чипи з підтримкою ECC підписів (NTAG 424 DNA від NXP або аналоги Kong Halo). Чип містить приватний ключ, який не може бути витягнутий з пристрою фізично. При сканованні чип підписує challenge-ответ приватним ключем.
Схема верифікації:
- При виробництві товара чип генерує keypair. Публічний ключ записується в NFT метаданні та контрактом верифікації.
- Для верифікації користувач сканує NFC → чип підписує
keccak256(randomChallenge || timestamp)→ підпис відправляється в backend або прямо в контракт. - Контракт перевіряє підпис через
ecrecover— якщоrecovered_address == chip_public_keyтаchip_public_keyзареєстрований як такий, що належить конкретному tokenId — товар автентичний.
function verifyChip(
uint256 tokenId,
bytes32 challenge,
bytes memory signature
) external view returns (bool) {
address chipAddress = _chipAddresses[tokenId];
require(chipAddress != address(0), "Token not registered");
bytes32 messageHash = keccak256(
abi.encodePacked("\x19Ethereum Signed Message:\n32", challenge)
);
address recovered = ECDSA.recover(messageHash, signature);
return recovered == chipAddress;
}
Протокол Kong (ERC-7015 / Kong Halo) стандартизує саме цю схему. Для люксових товарів, годинників, кроссовок — production-ready рішення.
QR-код без фізичної криптографії
Якщо NFC не підходить (паперові документи, упаковка), використовується інша схема. Виробник створює пару (publicId, secretKey) — publicId вшивається в QR-код та зберігається в NFT, secretKey видруковується всередину упаковки під захисним шаром. При перевірці користувач вскривает упаковку, вводит secretKey — backend перевіряє що keccak256(secretKey) == storedHash.
Це одноразова схема: після першої перевірки секрет розкритий. Для повторних верифікацій потрібен інший механізм. Підходит для предметів колекціонування, алкоголю, фармацевтики.
On-chain реєстр автентичності
Структура контракту
Реєстр зберігає маппинг tokenId → AuthRecord:
struct AuthRecord {
address chipAddress; // публічний ключ NFC чипа або нульова адреса
bytes32 secretHash; // keccak256 від secret для QR схеми
uint256 mintedAt; // timestamp створення
uint256 verificationCount; // скільки разів верифікували
bool activated; // активирован ли (для одноразових)
string productSku; // SKU виробника
}
mapping(uint256 => AuthRecord) private _authRecords;
verificationCount — корисна аналітика. Товар, якого верифікували 500 разів — либо дуже популярний, либо хтось пробує brute-force. Threshold alert на backend при аномальному кількості верифікацій.
Статусы жизненного цикла
Для більш складних сценаріїв додається статус:
| Статус | Опис |
|---|---|
MINTED |
Токен створений, товар не активирован |
ACTIVATED |
Товар вскрыт/активирован першим власником |
TRANSFERRED |
Токен передан, історія передач збережена |
FLAGGED |
Помічений як можлива підробка |
BURNED |
Товар знищений або утилізований |
Історія передач прозора через стандартні ERC-721 Transfer события — не потрібно зберігати окремо.
Верифікація без on-chain транзакції
Верифікація не повинна вимагати газ від користувача — це бар'єр для adoption. Два підходи:
Off-chain з on-chain доказом. Backend робит eth_call до контракту верифікації (безплатно), результат повертає користувачу. Джерело істини — блокчейн, газ не платиться.
Gasless верифікація через підпис. Користувач підписує запит верифікації (EIP-712), backend перевіряє підпис чипа та підпис користувача, записує подію верифікації в off-chain лог (з cryptographic proof). Для критичних верифікацій (страхові, юридичні) — періодична on-chain запис Merkle root від batch верифікацій.
Інтеграція з маркетплейсами
Стандарт ERC-721 + додаткові метаданні. У tokenURI JSON додаються поля:
{
"name": "Product #12345",
"attributes": [
{"trait_type": "Authenticity", "value": "Verified"},
{"trait_type": "Manufacturer", "value": "Brand XYZ"},
{"trait_type": "SKU", "value": "PROD-2024-001"},
{"trait_type": "Chip Type", "value": "NXP NTAG 424 DNA"}
],
"verification_contract": "0x...",
"chip_public_key": "0x..."
}
OpenSea та інші маркетплейси відображають ці атрибути. Покупацьі на вторинному ринку можуть верифікувати товар перед покупкою.
Ролі та права доступу
Контракт використовує OpenZeppelin AccessControl:
-
MANUFACTURER_ROLE— право мінтити нові токени та реєструвати чипи -
VERIFIER_ROLE— право записувати результати верифікації on-chain (для enterprise клієнтів) -
FLAGGING_ROLE— право помічати токени як спірні (антиподдельна служба бренда) -
DEFAULT_ADMIN_ROLE— управління ролями
Виробник може делегувати авторизованим дистрибьюторам право реєструвати продукти в своєму сегменті.
Stack розробки
Solidity 0.8.20+ + Foundry + OpenZeppelin 5.x. ERC-721 + кастомний контракт верифікації. Backend: Node.js + TypeScript + viem, API для mobile верифікації. Mobile SDK: React Native або Flutter для сканування NFC/QR. Деплой: Polygon або Base (низький газ для частих операцій мінту).
Орієнтири по строкам
Система з QR-кодами та on-chain реєстром без NFC — 1 тиждень. З підтримкою NFC-чипів (Kong/NTAG 424 DNA), ролевою моделлю, mobile SDK для сканування та analytics dashboard — 2-3 тижні.







