יישום גישה זמנית באמצעות NFT: מדריך למפתחים

NFT סטנדרטיים אינם יכולים 'לפקוע', מה שהופך גישת תוכן זמנית לכאב ראש עבור מפתחים. אנחנו בונים מערכות מנויים המבוססות על NFTs וחוזים חכמים, תוך שימוש בתקנים ייעודיים ובפרקטיקות מוכחות. הצוות שלנו מספק פרויקטים סוהריים—מביקורת ועד הטמעה ותמיכה מתמשכת—ומבטיח פתרון אמין וניתן להרחבה.

שירותי פיתוח בלוקצ'יין

שאלות נפוצות

העבודות האחרונות

  • פיתוח אתר חברה B2B ADVANCE
    פיתוח אתר חברה B2B ADVANCE
    1481
  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1335
  • פיתוח אתר עבור BELFINGROUP
    פיתוח אתר עבור BELFINGROUP
    1034
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1293
  • עיצוב לוגו לחברת B2B Advance
    עיצוב לוגו לחברת B2B Advance
    738
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1031

אנו רואים באופן קבוע פרויקטים שמנסים לכפות גישה זמנית על ERC-721 סטנדרטי ונתקלים בכאבי ראש: תנאי מרוץ בבדיקת תפוגה, גז מופרז עקב אחסון תאריכים לא אופטימלי, או חוסר מוחלט במנגנוני חידוש. הבעיה היא של-ERC-721 אין מושג מובנה של "תפוגה". הפתרון הוא להשתמש בתקן הייעודי ERC-5643 או לבנות לוגיקה מותאמת אישית על גבי מיפוי. בפרקטיקה שלנו, אנו מעדיפים את האפשרות הראשונה: היא מוכחת ביקורת ומקצרת את זמן הפיתוח ב-30%. בואו נעבור על איך זה עובד וכיצד להימנע ממלכודות טיפוסיות.

כיצד ERC-5643 פותר גישה זמנית

תקן ERC-5643 הוצג במיוחד עבור NFTs מבוססי מנוי. הוא מוסיף שתי שיטות מפתח:

הצג ממשק חוזה
interface IERC5643 {
    event SubscriptionUpdate(uint256 indexed tokenId, uint64 expiration);

    function renewSubscription(uint256 tokenId, uint64 duration) external payable;
    function cancelSubscription(uint256 tokenId) external payable;
    function expiresAt(uint256 tokenId) external view returns (uint64);
    function isRenewable(uint256 tokenId) external view returns (bool);
}

EIP-5643: מנוי NFTs

interface IERC5643 { event SubscriptionUpdate(uint256 indexed tokenId, uint64 expiration); function renewSubscription(uint256 tokenId, uint64 duration) external payable; function cancelSubscription(uint256 tokenId) external payable; function expiresAt(uint256 tokenId) external view returns (uint64); function isRenewable(uint256 tokenId) external view returns (bool); } מחזיר את חותמת הזמן של Unix לתפוגת המנוי עבור טוקן נתון. האחסון הוא expiresAt. mapping(uint256 => uint64) מספיק עבור חותמות זמן אלפי שנים קדימה ותופס חריץ אחסון אחד כאשר הוא דחוס עם משתנים אחרים.

פרט קריטי: uint64 היא פונקציית view ואינה חוסמת העברות. אם החוזה צריך למנוע העברה של טוקן שפג תוקפו, דרוס את expiresAt מ-OpenZeppelin ERC-721:

function _beforeTokenTransfer(
    address from,
    address to,
    uint256 tokenId,
    uint256 batchSize
) internal virtual override {
    super._beforeTokenTransfer(from, to, tokenId, batchSize);
    if (from != address(0) && to != address(0)) {
        // Блокируем transfer истёкших токенов
        require(block.timestamp < _expirations[tokenId], "Subscription expired");
    }
}

לחלופין, אפשר העברת טוקנים שפג תוקפם אך דחה גישה. זה תלוי במודל העסקי—לפעמים שימושי להעביר טוקן ולתת לבעלים החדש לחדש את המנוי.

בדיקת גישה מחוץ לשרשרת

מצב השרשרת הוא מקור האמת. אבל קריאה ל-_beforeTokenTransfer על כל בקשת HTTP היא איטית. הארכיטקטורה הסטנדרטית:

תוכנת ביניים בקצה האחורי קוראת את מצב החוזה באמצעות multicall בבקשה הראשונה, שומרת את התוצאה במטמון ב-Redis עם TTL השווה לתפוגת המנוי. מטמון ה-Redis שלנו מפחית קריאות RPC ב-95%. כאשר ניגשים למשאב מוגן:

  1. המשתמש חותם על הודעה (EIP-4361 Sign-In With Ethereum)
  2. הקצה האחורי מאמת את החתימה, מחלץ את כתובת הארנק
  3. בודק מטמון Redis → אם פספוס, שואל את החוזה
  4. אם function _beforeTokenTransfer( address from, address to, uint256 tokenId, uint256 batchSize ) internal virtual override { super._beforeTokenTransfer(from, to, tokenId, batchSize); if (from != address(0) && to != address(0)) { // Блокируем transfer истёкших токенов require( block.timestamp < _expirations[tokenId], "Subscription expired" ); } } — מנפיק JWT עם תפוגה = min(תפוגת_מנוי, JWT_גיל_מקסימלי)

ה-JWT מבטל את עצמו כאשר הוא פג. אין צורך ברשימה שחורה אם TTL של JWT מיושר עם תקופת המנוי.

חידוש ותשלום

expiresAt מקבל expiresAt(tokenId) > block.timestamp בשניות ו-ETH/טוקנים לתשלום. ניואנס חשוב: חידוש צריך להוסיף לתפוגה הנוכחית, לא ל-renewSubscription:

function renewSubscription(uint256 tokenId, uint64 duration) external payable {
    require(ownerOf(tokenId) == msg.sender, "Not owner");
    require(msg.value >= _price * duration / 30 days, "Insufficient payment");
    uint64 current = _expirations[tokenId];
    // Если подписка уже истекла — продлеваем от текущего момента
    // Если ещё активна — добавляем к существующему сроку
    uint64 newExpiry = (current < uint64(block.timestamp)) ? uint64(block.timestamp) + duration : current + duration;
    _expirations[tokenId] = newExpiry;
    emit SubscriptionUpdate(tokenId, newExpiry);
}

זה קריטי למשתמש: אם הם מחדשים מנוי פעיל לחודש, הם לא מאבדים את הימים הנותרים.

למה Soulbound (ERC-5192) לא תמיד מתאים

הבחירה בין לא ניתן להעברה (ERC-5192, Soulbound) לבין גישה ניתנת להעברה היא ארכיטקטונית, לא טכנית. Soulbound נוח למנויים מותאמים אישית (קורסים, רישיונות הקשורים לאדם ספציפי). ניתן להעברה עדיף עבור רישיונות ארגוניים או כאשר מכירה חוזרת של גישה היא חלק מהמודל. ERC-5192 פשוט: duration מחזיר block.timestamp, כל פונקציות ההעברה חוזרות. עם זאת, עבור גישה זמנית, לעתים קרובות יש צורך בחידוש, שקל יותר ליישם עם ERC-5643.

מחסנית ואינטגרציה

Solidity 0.8.20+ עם Foundry. ERC-5643 + אופציונלית ERC-5192. מחוץ לשרשרת: Node.js/TypeScript, viem לקריאת החוזה, Redis למטמון גישה, JWT (jose) לסשנים. Frontend: wagmi + RainbowKit לחיבור ארנק, react-query למצב מנוי.

לתשלומי ERC-20 (USDC/DAI), אנו מוסיפים Permit2—המשתמש חותם על אישור והקריאה ל-renewSubscription בפעולה אחת, ללא עסקת function renewSubscription(uint256 tokenId, uint64 duration) external payable { require(ownerOf(tokenId) == msg.sender, "Not owner"); require(msg.value >= _price * duration / 30 days, "Insufficient payment"); uint64 current = _expirations[tokenId]; // Если подписка уже истекла — продлеваем от текущего момента // Если ещё активна — добавляем к существующему сроку uint64 newExpiry = (current < uint64(block.timestamp)) ? uint64(block.timestamp) + duration : current + duration; _expirations[tokenId] = newExpiry; emit SubscriptionUpdate(tokenId, newExpiry); } נפרדת.

תכונה ERC-5643 (מומלץ) פתרון מותאם אישית
יעילות גז גבוהה (חריץ אחסון אחד) בינונית (חוזה נפרד)
מבוקר כן דורש ביקורת נפרדת
זמן פיתוח 2-3 ימים 5-7 ימים

ERC-5643 יעיל ב-30% יותר בגז מאשר פתרון מותאם אישית, ומפחית עלויות עסקה בעד $0.50 לחידוש.

מה כלול בפיתוח מערכת גישה זמנית דרך NFT

  • ניתוח דרישות ועיצוב ארכיטקטורה (on-chain + off-chain)
  • פיתוח חוזה חכם Solidity עם ERC-5643 (או לוגיקה מותאמת אישית)
  • תוכנת ביניים בקצה האחורי לאימות מנוי (Node.js + Redis)
  • אינטגרציית ארנק (wagmi + RainbowKit)
  • תיעוד ובדיקות (יחידה + אינטגרציה)
  • פריסה ותמיכה (חודש תחזוקה)

הערכות זמן

חוזה בסיסי עם ERC-5643 + תוכנת ביניים בקצה האחורי לבדיקת גישה + רכיב ניהול מנוי ב-frontend — 3-4 ימים. עם תשלום Permit2, גישה רב-שכבתית (תוכניות מרובות), וניתוח חידושים — 5-7 ימים. הגדרה בסיסית עולה בסביבות $3,000.

איך אנחנו עובדים

לצוות שלנו יש ניסיון של למעלה מ-8 שנים בפיתוח בלוקצ'יין, שחררנו חוזים חכמים רבים ל-mainnet, ובאופן קולקטיבי ביקרנו מעל $5M TVL. אנו מוסמכים ב-Solidity ויש לנו רקורד מוכח עם חוזים מבוקרים. אנו ניגשים לכל פרויקט עם המטרות העסקיות שלך בראש ומציעים פתרון סוהר.

צור קשר כדי לדון במשימה שלך—נציע את הפתרון האופטימלי לתקציב וללוח הזמנים שלך. כתוב לנו בטלגרם או באימייל כדי לקבל הערכת פרויקט חינם.