परिचय (Introduction)
शुरुआत में NFTs को डिजिटल या भौतिक संपत्तियों, जैसे कलेक्टिबल्स (collectibles), के स्वामित्व को दर्शाने के लिए बनाया गया था। हालांकि, वे केवल एक ID और उसके संबंधित मेटाडेटा के स्वामित्व को ट्रैक करने तक ही सीमित थे; वे अन्य NFTs या ERC-20 टोकन्स के मालिक नहीं हो सकते थे, और न ही वे सामान्य Ethereum अकाउंट्स की तरह DeFi प्रोटोकॉल्स के साथ इंटरैक्ट कर सकते थे। ERC-6551 हर NFT को अपना खुद का स्मार्ट कॉन्ट्रैक्ट अकाउंट देकर इसे बदल देता है, जिसे Token Bound Account (TBA) के रूप में जाना जाता है। TBAs यह कर सकते हैं:
- ERC-20 टोकन्स, ETH, ERC-721, ERC-1155 और आपके वॉलेट द्वारा स्वीकार किए जाने वाले किसी भी अन्य टोकन जैसी संपत्तियों को होल्ड करना
- NFT के मालिक (EOA) द्वारा शुरू किए जाने पर ऑन-चेन ट्रांज़ेक्शन्स को एग्जीक्यूट करना
- किसी भी अन्य Ethereum अकाउंट की तरह ट्रांज़ेक्शन हिस्ट्री बनाए रखना
उदाहरण के लिए, किसी ब्लॉकचेन गेम में, गेमप्ले तक पहुंचने के लिए आपको एक कैरेक्टर NFT खरीदना पड़ सकता है। ERC-6551 के साथ, उस कैरेक्टर के NFT को अपना खुद का TBA (एक स्मार्ट कॉन्ट्रैक्ट अकाउंट) मिल जाता है। जैसे-जैसे आप गेमप्ले में आगे बढ़ते हैं, आपके कैरेक्टर का TBA आपकी जमा की गई संपत्तियों को होल्ड करता है।
यदि आप इस कैरेक्टर NFT को बेचने का निर्णय लेते हैं, तो खरीदार को न केवल NFT मिलता है बल्कि उसका TBA भी मिलता है, जिसमें आपकी सभी जमा की गई संपत्तियां होती हैं - जब तक कि आप उन्हें पहले ही बाहर ट्रांसफर न कर लें। यह बिल्कुल शुरुआत से शुरू करने के बजाय पूरी तरह से सुसज्जित और अनुभवी कैरेक्टर खरीदने जैसा है।
ERC-6551 मानक के अंतर्गत:
- प्रत्येक NFT को एक या अधिक नियतात्मक (deterministic) TBA एड्रेसेस दिए जाते हैं, जिनकी गणना रजिस्ट्री कॉन्ट्रैक्ट द्वारा की जाती है।
- TBA एक स्मार्ट कॉन्ट्रैक्ट अकाउंट के रूप में कार्य करता है जो NFT के मालिक द्वारा नियंत्रित होता है।
- सभी कार्य (actions) TBA के माध्यम से एग्जीक्यूट किए जाते हैं।
- ट्रांज़ेक्शन हिस्ट्री और संपत्तियां TBA से जुड़ी होती हैं।
ये स्मार्ट कॉन्ट्रैक्ट अकाउंट्स NFTs के लिए बनाए जाते हैं और इसके लिए मौजूदा NFT कॉन्ट्रैक्ट्स में बदलाव करने की आवश्यकता नहीं होती है। क्योंकि वे NFT से अलग (decoupled) होते हैं, वे वर्तमान और भविष्य के NFT मानकों के साथ फॉरवर्ड और बैकवर्ड कम्पैटिबल (संगत) होते हैं।
इस लेख में, आप ERC-6551 मानक के कोर फ्लो और मैकेनिज्म के बारे में जानेंगे।
पूर्व-आवश्यकताएं (Prerequisites)
यह लेख मानकर चलता है कि पाठक निम्नलिखित से परिचित है:
- ERC-721 standard
- EIP-1167 minimal proxy standard
- EIP-1014 (
CREATE2) - कॉन्ट्रैक्ट्स के लिए ERC-1271 सिग्नेचर वैलिडेशन मेथड
ERC-6551 Standard की मुख्य विशेषताएं
ERC-6551 पैटर्न CREATE2 के नियतात्मक (deterministic) एड्रेस मैकेनिज्म का उपयोग करके NFTs को स्मार्ट कॉन्ट्रैक्ट एड्रेसेस के साथ अंतर्निहित रूप से मैप करता है।
विशेष रूप से, NFTs को ट्यूपल (tuple) (chainId, tokenContract, tokenId) द्वारा विशिष्ट रूप से पहचाना जाता है। केवल इन पैरामीटर्स का उपयोग करने में यह कमी है कि प्रत्येक NFT केवल एक ही अकाउंट तक सीमित रह जाएगा।
कुछ मामलों में, एक NFT को कई TBAs की आवश्यकता हो सकती है, ठीक सामान्य Ethereum उपयोगकर्ताओं की तरह जिनके पास अलग-अलग उद्देश्यों (hot/cold storage) के लिए अलग-अलग वॉलेट होते हैं। यहीं पर salt पैरामीटर काम आता है।
प्रत्येक यूनीक salt वैल्यू एक ही NFT के लिए एक अलग TBA उत्पन्न करने में मदद करती है, जिससे एक NFT कई TBAs को मैनेज कर सकता है। यह ट्यूपल को इस प्रकार विस्तारित करता है: (chainId, tokenContract, tokenId, salt)।
याद करें कि CREATE2 जिस एड्रेस को डिप्लॉय करता है, उसकी गणना इस प्रकार की जाती है:
predictedAddress = address(uint160(uint256(keccak256(abi.encodePacked(
bytes1(0xff),
deployer,
salt,
keccak256(_initCode)
)))));
चूंकि डिप्लॉयर (deployer) का एड्रेस CREATE2 एड्रेस की गणना को प्रभावित करता है, इसलिए सभी TBAs को एक कॉमन डिप्लॉयर (factory) से आना चाहिए। अन्यथा, यह ट्रैक करना आवश्यक होगा कि किस फैक्ट्री ने कौन सा TBA डिप्लॉय किया है।
हालांकि, यह आवश्यकता एक चुनौती पैदा करती है: एड्रेस के पूर्वानुमान (predictable addressing) के लिए, एक ही फैक्ट्री से डिप्लॉय किए गए TBAs में समान इनिशियलाइज़ेशन बाइटकोड (_initCode) होना चाहिए। प्रत्येक TBA में अलग-अलग कस्टम लॉजिक एम्बेड करने से इनिशियलाइज़ेशन बाइटकोड बदल जाएगा और एड्रेस का पूर्वानुमान टूट जाएगा।
इसे हल करने के लिए, प्रत्येक TBA को एक कस्टम EIP-1167 minimal proxy clone के रूप में डिप्लॉय किया जाता है, जो अकाउंट बाइंडिंग के लिए अतिरिक्त इम्यूटेबल डेटा (chainId, tokenContract, tokenId, और salt) को शामिल करने के लिए अपने बाइटकोड का विस्तार करता है, जबकि एग्जीक्यूशन को एक अलग इम्प्लीमेंटेशन कॉन्ट्रैक्ट को डेलीगेट (delegate) करता है। यह एड्रेस के पूर्वानुमान के लिए सुसंगत इनिशियलाइज़ेशन कोड बनाए रखता है और साथ ही एक ही फैक्ट्री से TBAs को अलग-अलग इम्प्लीमेंटेशन का उपयोग करने की अनुमति देता है।
TBA Bytecode की संरचना
फैक्ट्री से डिप्लॉय किए गए प्रत्येक TBA का बाइटकोड स्ट्रक्चर निम्नलिखित होता है:
[EIP-1167 Minimal Proxy]
├── Header (10 bytes) - Standard proxy initialization
├── Implementation (20 bytes) - Target contract address
└── Footer (15 bytes) - Delegation logic
[Immutable Account Data] (data that binds the TBA to a specific NFT)
├── Salt (32 bytes) - For create2 address derivation
├── ChainID (32 bytes) - chain identifier where NFT exists
├── TokenContract (32 bytes) - NFT contract address
└── TokenID (32 bytes) - NFT identifier
उदाहरण के लिए, बाइटकोड की संरचना कुछ इस तरह दिखेगी:
// ERC-1167 Proxy Section
363d3d373d3d3d363d73 // Header - copy calldata
bebebebebebebebebebebebebebebebebebebebe //Implementation
5af43d82803e903d91602b57fd5bf3 // Footer - delegate call section
// Immutable Data Section
0000...0000 // Salt (32 bytes of zeros)
0000...0001 // ChainID (1 for Ethereum mainnet)
cfcf...cfcf // NFT contract address
0000...007b // TokenID (123 in hex)
जब कोई NFT मालिक अपने TBA के साथ इंटरैक्ट करता है, तो TBA (proxy clone) अपनी खुद की स्टेट (जैसे जमा किए गए NFTs या इन-गेम संपत्तियां) बनाए रखता है, जबकि लॉजिक को उस इम्प्लीमेंटेशन कॉन्ट्रैक्ट को डेलीगेट करता है जिसका वह उपयोग करता है।
इस प्रॉक्सी आर्किटेक्चर को देखते हुए, एक अतिरिक्त पैरामीटर की आवश्यकता होती है: implementation एड्रेस। नतीजतन, TBA एड्रेस की पहचान करने के लिए पूरा ट्यूपल (implementation, salt, chainId, tokenContract, tokenId) बन जाता है।
यह पहचान विधि, CREATE2 के साथ मिलकर, किसी को भी मैपिंग्स को स्टोर किए बिना आवश्यकतानुसार TBA के एड्रेस की गणना करने की अनुमति देती है। इसके परिणामस्वरूप, यह स्टोरेज लागत को समाप्त कर देता है और यह सुनिश्चित करता है कि प्रत्येक TBA का एक यूनीक, पूर्वानुमान योग्य एड्रेस हो।
Registry Contract
कैनोनिकल (canonical) रजिस्ट्री उस फैक्ट्री के रूप में कार्य करती है जो इन TBAs को डिप्लॉय करती है। चूंकि TBAs एग्जीक्यूशन को डेलीगेट करते हैं, इसलिए उनके इम्प्लीमेंटेशन को पहले डिप्लॉय किया जाना चाहिए।
TBA बनाने के लिए, रजिस्ट्री का createAccount() फंक्शन सभी ट्यूपल पैरामीटर्स (implementation, salt, chainId, tokenContract, tokenId) लेता है और एक प्रॉक्सी क्लोन डिप्लॉय करता है।

रजिस्ट्री के createAccount() फंक्शन में नीचे हाईलाइट किया गया असेंबली कोड ही वह है जो मेमोरी में NFT बाइंडिंग डेटा के साथ EIP-1167 पैटर्न को मिलाकर विशेष प्रॉक्सी बाइटकोड बनाता है:

इस डिज़ाइन के साथ, कोई भी कॉन्ट्रैक्ट आसानी से इसके बाइटकोड डेटा को पढ़कर यह वेरिफाई कर सकता है कि कोई अकाउंट किस NFT से बंधा (bound) है। इसे इस लेख में आगे TBA निर्माण वाकथ्रू के दौरान अधिक विस्तार से समझाया जाएगा।
Registry Contract के फंक्शन्स
रजिस्ट्री को IERC6551Registry को इम्प्लीमेंट करना चाहिए जो दो मुख्य फंक्शन्स को परिभाषित करता है:
createAccount()
यह एक विशिष्ट NFT के लिए एक टोकन बाउंड अकाउंट (TBA) बनाता है।

यदि कोई अकाउंट पहले से मौजूद है, तो createAccount() केवल CREATE2 को कॉल किए बिना गणना किया गया अकाउंट एड्रेस लौटा देता है। यह नीचे लाल तीर के साथ हाईलाइट किए गए iszero(extcodesize(computed)) का उपयोग करके गणना किए गए एड्रेस पर मौजूदा कोड की जांच करके ऐसा करता है; यदि कोई कोड नहीं है (size = 0), तो इसका मतलब है कि अभी तक कोई अकाउंट मौजूद नहीं है, इसलिए रजिस्ट्री उस सटीक एड्रेस पर एक नया TBA बनाती है, फिर createAccount() लाइन 121 पर नए बनाए गए TBA का एड्रेस लौटा देता है। हालांकि, यदि कोड पहले से मौजूद है (size > 0), तो यह नया डिप्लॉय किए बिना मौजूदा अकाउंट का एड्रेस लौटा देता है।

हालांकि किसी भी salt वैल्यू का उपयोग किया जा सकता है, अधिकांश TBAs को डिफ़ॉल्ट salt bytes32(0) के साथ डिप्लॉय किया जाता है। जैसा कि “ERC-6551 Standard की मुख्य विशेषताएं” सेक्शन में बताया गया है, अलग-अलग salt वैल्यूज़ का उपयोग करने से एक NFT को अलग-अलग उद्देश्यों के लिए कई TBAs का मालिक होने की अनुमति मिलती है।
account()
यह किसी दिए गए NFT के लिए एक TBA के नियतात्मक एड्रेस की गणना करता है और उसे बिना बनाए ही लौटा देता है।

AccountCreated() Event
रजिस्ट्री को एक इवेंट, ERC6551AccountCreated एमिट (emit) करना आवश्यक है, जिसे केवल तभी एमिट किया जाता है जब createAccount() सफलतापूर्वक एक नया TBA बनाता है:

यह dApps और इंडेक्सर्स को यह ट्रैक करने में मदद करता है कि प्रत्येक TBA किस इम्प्लीमेंटेशन का उपयोग करता है, और TBA के निर्माण की निगरानी करता है।
Registry Contract डिप्लॉयमेंट
ERC-6551 रजिस्ट्री कॉन्ट्रैक्ट को सभी EVM कम्पैटिबल चेन्स पर एक फिक्स्ड एड्रेस (0x000000006551c19487814612e58FE06813775758) पर डिप्लॉय किया गया है।
विशेष रूप से, एड्रेस के “6551” हिस्से को जानबूझकर एक वैनिटी (vanity) पैटर्न के रूप में चुना गया था, जिसे वांछित एड्रेस प्राप्त होने तक विभिन्न साल्ट्स के माध्यम से इटरेट करके प्राप्त किया गया।
विभिन्न चेन्स पर डिप्लॉय किए गए रजिस्ट्री एड्रेसेस की सूची यहां पाई जा सकती है।
क्रॉस-चेन रजिस्ट्री डिप्लॉयमेंट मैकेनिज्म
यह सुनिश्चित करने के लिए कि रजिस्ट्री कॉन्ट्रैक्ट सभी चेन्स पर एक ही एड्रेस पर डिप्लॉय किया गया है, रजिस्ट्री Nick’s factory का उपयोग करती है: Nick’s factory एक CREATE2 फैक्ट्री कॉन्ट्रैक्ट है जिसे सभी चेन्स पर एक ही एड्रेस (0x4e59b44847b379578588920cA78FbF26c0B4956C) पर डिप्लॉय किया गया है। यह विभिन्न चेन्स पर नियतात्मक (deterministic) कॉन्ट्रैक्ट डिप्लॉयमेंट को संभव बनाता है।
Nick’s factory अन्य कॉन्ट्रैक्ट्स को पूर्वानुमान योग्य एड्रेसेस पर डिप्लॉय करने के लिए CREATE2 का उपयोग करती है जहां डिप्लॉय किए गए एड्रेस की गणना इससे की जाती है: फैक्ट्री का एड्रेस, एक salt वैल्यू, और कॉन्ट्रैक्ट का बाइटकोड (इस मामले में, रजिस्ट्री)।
इस प्रकार, सभी चेन्स पर एक सुसंगत एड्रेस पर रजिस्ट्री कॉन्ट्रैक्ट को डिप्लॉय करने के लिए, Nick’s factory का सभी चेन्स पर एड्रेस 0x4e59b44847b379578588920cA78FbF26c0B4956C पर मौजूद होना आवश्यक है।
उस चेन पर रजिस्ट्री डिप्लॉय करने के लिए जहां इसे अभी तक डिप्लॉय नहीं किया गया है, निम्नलिखित डिप्लॉयमेंट ट्रांज़ेक्शन सबमिट करें:
{
"to": "0x4e59b44847b379578588920ca78fbf26c0b4956c",
"value": "0x0",
"data": "0x0000000000000000000000000000000000000000fd8eb4e1dca713016c518e31608060405234801561001057600080fd5b5061023b806100206000396000f3fe608060405234801561001057600080fd5b50600436106100365760003560e01c8063246a00211461003b5780638a54c52f1461006a575b600080fd5b61004e6100493660046101b7565b61007d565b6040516001600160a01b03909116815260200160405180910390f35b61004e6100783660046101b7565b6100e1565b600060806024608c376e5af43d82803e903d91602b57fd5bf3606c5285605d52733d60ad80600a3d3981f3363d3d373d3d3d363d7360495260ff60005360b76055206035523060601b60015284601552605560002060601b60601c60005260206000f35b600060806024608c376e5af43d82803e903d91602b57fd5bf3606c5285605d52733d60ad80600a3d3981f3363d3d373d3d3d363d7360495260ff60005360b76055206035523060601b600152846015526055600020803b61018b578560b760556000f580610157576320188a596000526004601cfd5b80606c52508284887f79f19b3655ee38b1ce526556b7731a20c8f218fbda4a3990b6cc4172fdf887226060606ca46020606cf35b8060601b60601c60005260206000f35b80356001600160a01b03811681146101b257600080fd5b919050565b600080600080600060a086880312156101cf57600080fd5b6101d88661019b565b945060208601359350604086013592506101f46060870161019b565b94979396509194608001359291505056fea2646970667358221220ea2fe53af507453c64dd7c1db05549fa47a298dfb825d6d11e1689856135f16764736f6c63430008110033",
}
रजिस्ट्री के डिप्लॉयमेंट ट्रांज़ेक्शन को समझना:
to:0x4e59b44847b379578588920ca78fbf26c0b4956c(Nick’s factory एड्रेस)value:0x0(डिप्लॉयमेंट के साथ कोई ETH नहीं भेजा गया)data: इसमें पहले 32 बाइट्स शामिल हैं जो salt पैरामीटर का प्रतिनिधित्व करते हैं:0x0000000000000000000000000000000000000000fd8eb4e1dca713016c518e31, और शेष बाइट्स जो रजिस्ट्री कॉन्ट्रैक्ट का बाइटकोड है।
यह डिप्लॉयमेंट ट्रांज़ेक्शन Nick’s factory को डेटा भेजता है, जो पूर्व-निर्धारित एड्रेस पर रजिस्ट्री को डिप्लॉय करने के लिए salt और कॉन्ट्रैक्ट बाइटकोड निकालता है। यह दृष्टिकोण एक सिंगल, कैनोनिकल रजिस्ट्री सुनिश्चित करता है जिसे कोई भी डिप्लॉय कर सकता है।
रजिस्ट्री द्वारा टोकनबाउंड अकाउंट्स के निर्माण को संभालने के साथ, अगला फोकस TBAs के इम्प्लीमेंटेशन पर है।
प्रत्येक TBA को विशिष्ट इंटरफेसेस का पालन करना चाहिए जो ERC-6551 मानक के साथ कम्पैटिबिलिटी के लिए आवश्यक कोर फंक्शन्स को परिभाषित करते हैं। ये इंटरफेसेस वॉलेट्स, मार्केटप्लेसेस और एप्लिकेशन्स के साथ उचित इंटीग्रेशन सुनिश्चित करते हैं।
TBA इंटरफेसेस
ERC-6551 मानक के अनुपालन के लिए, प्रत्येक टोकन बाउंड अकाउंट (TBA) इम्प्लीमेंटेशन को अकाउंट पहचान और ऑथराइजेशन के लिए IERC6551Account, ऑपरेशन एग्जीक्यूशन के लिए IERC6551Executable, इंटरफेस डिटेक्शन के लिए IERC165, और सिग्नेचर वैलिडेशन के लिए IERC1271 को इम्प्लीमेंट करना होगा।
प्रत्येक इंटरफेस के फंक्शन्स—
IERC6551Account,IERC6551Executable, औरIERC165के साथ-साथIERC1271, को व्यक्तिगत रूप से समझाया गया है। उनके इंटीग्रेशन को “ये इंटरफेसेस एक साथ कैसे काम करते हैं” सब-सेक्शन में संबोधित किया जाएगा।
Account Interface (IERC6551Account)
जब एक TBA अन्य कॉन्ट्रैक्ट्स या प्रोटोकॉल्स के साथ इंटरैक्ट करता है, तो उन कॉन्ट्रैक्ट्स और प्रोटोकॉल्स को महत्वपूर्ण जानकारी को वेरिफाई करने के लिए एक मानकीकृत तरीके की आवश्यकता होती है जैसे कि: यह TBA किस NFT से जुड़ा है, क्या ट्रांज़ेक्शन साइन करने वाला अधिकृत (authorized) है, और TBA की वर्तमान एग्जीक्यूशन स्टेट (nonce) क्या है।
IERC6551Account इंटरफेस उपर्युक्त वेरिफिकेशन आवश्यकताओं को संबोधित करने के लिए कोर फंक्शन्स का एक सेट परिभाषित करता है:

TBA इंटरफेसेस की हमारी चर्चा के लिए निम्नलिखित तीन प्रासंगिक हैं:
token()- यह कॉलिंग अकाउंट के बाइटकोड से एम्बेडेड डेटा को पढ़ता है और एक ट्यूपल लौटाता है जिसमें NFT (chainId, contract address, tokenId) होता है जो अकाउंट से बंधा होता है।isValidSigner()- यह वैलिडेट करता है कि क्या कोई एड्रेस अकाउंट के लिए साइन करने के लिए अधिकृत है।state()- एक uint256 वैल्यू लौटाता है जो अकाउंट के ऑपरेशन nonce को ट्रैक करता है।
इंटरफेस का उद्देश्य उन बुनियादी फंक्शन्स को परिभाषित करना है जो हर TBA इम्प्लीमेंटेशन में होने चाहिए, जबकि इम्प्लीमेंटेशन्स के लिए विस्तारित कार्यक्षमता जोड़ने की गुंजाइश छोड़ना है।
प्रत्येक TBA इम्प्लीमेंटेशन को निम्नलिखित का भी समर्थन करना चाहिए:
ERC-165 Interface Detection

यह अन्य कॉन्ट्रैक्ट्स को उनके साथ इंटरैक्ट करने से पहले रनटाइम पर यह वेरिफाई करने की अनुमति देता है कि वे आवश्यक IERC6551Account और IERC6551Executable इंटरफेसेस को इम्प्लीमेंट करते हैं या नहीं।
ERC-1271 Signature Validation Interface

official EIP-6551 page से संदर्भ इम्प्लीमेंटेशन (reference implementation) यह संबोधित करने के लिए ERC-1271 का उपयोग करता है कि प्रोटोकॉल कैसे यह वेरिफाई कर सकते हैं कि एक TBA ने एक ट्रांज़ेक्शन को अधिकृत किया है। यह isValidSignature() फंक्शन को इम्प्लीमेंट करता है जो जांचता है कि क्या सिग्नेचर NFT मालिक के लिए वैध है, यदि वैध है तो 0x1626ba7e लौटाता है या यदि अवैध है तो bytes4(0) लौटाता है।
0x1626ba7e को isValidSignature(bytes32,bytes) के फंक्शन सेलेक्टर से प्राप्त किया गया है, जिसकी गणना इस प्रकार की गई है:
keccak256("isValidSignature(bytes32,bytes)")
फिर, हैश के पहले 4 बाइट्स (bytes4) को रिटर्न वैल्यू के रूप में लिया जाता है।

Execution Interface (IERC6551Executable)

IERC6551Executable में एक ही आवश्यक फंक्शन execute() होता है जो एक वैध साइनर द्वारा कॉल किए जाने पर TBA इम्प्लीमेंटेशन्स को लो-लेवल ऑपरेशन्स (low-level operations) करने में सक्षम बनाता है।
इस इंटरफेस में एमिट किए जाने वाले कोई अनिवार्य इवेंट्स नहीं हैं।
execute() के माध्यम से, TBA इम्प्लीमेंटेशन्स परिभाषित करते हैं कि वे किन ऑपरेशन्स का समर्थन करते हैं। operation पैरामीटर एक uint8 वैल्यू है जो यह संकेत देता है कि कौन सा लो-लेवल एक्शन किया जाना चाहिए:
0 = CALL // Regular calls (sending ETH, interacting with contracts)
1 = DELEGATECALL // Execute code from another contract in TBA's context
2 = CREATE // Deploy new contracts
3 = CREATE2 // Deploy contracts with deterministic addresses
एक ऐसे परिदृश्य (scenario) पर विचार करें जहां एक NFT मालिक चाहता है कि उसका TBA किसी प्रोटोकॉल में ERC-20 टोकन जमा करे। इसके लिए NFT मालिक को प्रत्येक ऑपरेशन के लिए TBA पर execute() कॉल करने की आवश्यकता होती है, जो तब ट्रांज़ेक्शन्स को करने के लिए इम्प्लीमेंटेशन कॉन्ट्रैक्ट को डेलीगेट करता है।
टोकन्स को अप्रूव करना:
execute(
to: tokenContract, // ERC20 token address
value: 0, // No ETH sent
data: abi.encodeWithSignature(
"approve(address,uint256)",
spender, // Protocol address to approve
amount // Amount to approve
),
operation: 0 // CALL operation
);
प्रोटोकॉल में जमा करना:
execute(
to: protocol address,
value: 0, // no ETH sent
data: depositData,// encoded deposit() call
operation: 0 // operation: CALL
);
या केवल ETH भेजने के लिए:
execute(
to: recipient,
value: 2 ether,
data: "", // empty for ETH transfer
operation: 0 // operation: CALL
);
प्रत्येक ऑपरेशन को एक वैध साइनर द्वारा कॉल किया जाना चाहिए और इसमें उचित एरर हैंडलिंग (error handling) शामिल होनी चाहिए।
IERC6551Executable इंटरफेस इस मायने में लचीला है कि ट्रांज़ेक्शन को संभालने के लिए एक विशिष्ट तरीके को लागू करने के बजाय, इसे केवल यह आवश्यक है कि TBA इम्प्लीमेंटेशन्स स्पष्ट रूप से संकेत दें (ERC-165 के माध्यम से) कि वे किस एग्जीक्यूशन इंटरफेस का समर्थन करते हैं, चाहे वह मानक IERC6551Executable इंटरफेस हो या उनका अपना कस्टम एग्जीक्यूशन मैकेनिज्म।
ये इंटरफेसेस एक साथ कैसे काम करते हैं
संदर्भ इम्प्लीमेंटेशन यह रेखांकित करता है कि कैसे IERC6551Account, IERC6551Executable, IERC165, और ERC-1271 एक साथ मिलकर TBAs को ट्रांज़ेक्शन्स को एग्जीक्यूट करने और यह वेरिफाई करने देते हैं कि संदेश को उनके NFT मालिक (EOA) द्वारा साइन किया गया था। ये इंटरफेसेस यह बनाते हैं कि एक TBA कैसे कार्य करता है, जैसा कि संदर्भ इम्प्लीमेंटेशन में दिखाया गया है:

जब किसी TBA को ट्रांज़ेक्शन एग्जीक्यूट करने की आवश्यकता होती है, तो ये वेरिफिकेशन फंक्शन्स काम आते हैं:
isValidSignature() (ERC-1271 से) यह वैलिडेट करता है कि बाउंड NFT के मालिक के लिए एक सिग्नेचर वैध है या नहीं।

- यह जांचता है कि क्या TBA के
owner()(EOA) ने सिग्नेचर बनाया है। संदर्भ इम्प्लीमेंटेशन इस वेरिफिकेशन के लिए OpenZeppelin के SignatureChecker का उपयोग करता है।
isValidSigner() (IERC6551Account से) यह जांचता है कि क्या कोई दिया गया एड्रेस (कॉल करने वाला) TBA की ओर से ट्रांज़ेक्शन्स को एग्जीक्यूट करने के लिए अधिकृत है।

- यह NFT के मालिक के खिलाफ एड्रेस को वेरिफाई करता है। इसका उपयोग मुख्य रूप से कॉल करने वाले को वैलिडेट करने के लिए
execute()फंक्शन (IERC6551Executable से) में किया जाता है।

ध्यान दें कि संदर्भ इम्प्लीमेंटेशन एक इंटरनल फंक्शन _isValidSigner() का उपयोग करता है जो केवल यह जांचता है कि दिया गया एड्रेस NFT का मालिक है, लेकिन मालिक के अलावा अन्य एड्रेसेस को अधिकृत करने के लिए अतिरिक्त वेरिफिकेशन लॉजिक शामिल किया जा सकता है।
NFT मालिकों के लिए जो अपने TBAs के साथ इंटरैक्ट करना चाहते हैं, या विकेन्द्रीकृत एक्सचेंजों (DEXs) और मार्केटप्लेसेस के लिए जो TBAs के साथ इंटीग्रेट हो रहे हैं, वर्कफ़्लो आमतौर पर इस तरह दिखता है:
-
Direct Transaction:
- उपयोगकर्ता (NFT मालिक)
execute()को कॉल करते हुए अपने TBA को एक ट्रांज़ेक्शन भेजता है। execute()फंक्शन यह वेरिफाई करता है कि कॉल करने वाला_isValidSigner(msg.sender)के माध्यम से अधिकृत है।- यदि अधिकृत है, तो TBA अनुरोधित ऑपरेशन (जैसे ERC-20 टोकन्स ट्रांसफर करना) करता है।
- प्रत्येक एग्जीक्यूशन के बाद स्टोरेज में
stateबढ़ा दी जाती है, जिससे रिप्ले (replay) अटैक से बचाव होता है।
- उपयोगकर्ता (NFT मालिक)
-
Signature-Based:
ध्यान दें कि इसके लिए प्रोटोकॉल्स को ERC-1271 का समर्थन लागू करने की आवश्यकता है, जिसे तब व्यापक रूप से नहीं अपनाया गया था जब कई DEXs डिज़ाइन किए गए थे और हो सकता है कि वे मूल रूप से कॉन्ट्रैक्ट सिग्नेचर वेरिफिकेशन विधि का समर्थन न करें।-
उपयोगकर्ता अपने वॉलेट (जिसके पास NFT है) के साथ एक संदेश पर हस्ताक्षर करता है जिसमें ट्रांज़ेक्शन विवरण (जैसे, “मेरे TBA से 0.05 ETH के लिए 100 USDC ट्रेड करें”) होता है।
-
DEX दोनों को वेरिफाई करने के लिए संदेश हैश और NFT मालिक के सिग्नेचर का उपयोग करके TBA पर
isValidSignature()को कॉल करता है:- सिग्नेचर की वैधता
- और यह कि सिग्नेचर TBA से बंधे NFT के वर्तमान मालिक द्वारा तैयार किया गया था, यह पुष्टि करते हुए कि उनका TBA के अकाउंट पर अधिकार है।
-
यदि वेरिफाई हो जाता है, तो DEX जानता है कि ट्रांज़ेक्शन अधिकृत है, लेकिन वास्तव में ट्रेड को एग्जीक्यूट करने के लिए, TBA को
execute()कॉल के माध्यम से DEX को टोकन अप्रूवल देना होगा।
-
execute(
to: tokenContract, // USDC token address
value: 0, // No ETH sent
data: abi.encodeWithSignature(
"approve(address,uint256)",
spender, // Protocol address to approve
100 // Amount to approve
),
operation: 0 // CALL operation
);
IERC6551Account, IERC6551Executable, और ERC-1271 इंटरफेसेस सामूहिक रूप से TBAs के लिए सिग्नेचर को वेरिफाई करने और अधिकृत ट्रांज़ेक्शन्स को एग्जीक्यूट करने के लिए एक मानकीकृत तरीका प्रदान करते हैं, जिससे वे डायरेक्ट फंक्शन कॉल्स और ERC-1271 सिग्नेचर वेरिफिकेशन का उपयोग करने वाले प्रोटोकॉल दोनों के साथ संगत (compatible) हो जाते हैं।
किसी NFT के लिए TBA कैसे बनाएं
TBA बनाने के लिए, इन सरल स्टेप्स का पालन करें:
- एक इम्प्लीमेंटेशन कॉन्ट्रैक्ट बनाएं और डिप्लॉय करें।
- आवश्यक पैरामीटर्स:
(implementation, salt, chainId, tokenContract, tokenId)को पास करके औरcreateAccount()को कॉल करके0x000000006551c19487814612e58FE06813775758पर रजिस्ट्री के साथ इंटरैक्ट करें।- यदि आपके पास पहले से ही एक उपयुक्त डिप्लॉय किया गया इम्प्लीमेंटेशन कॉन्ट्रैक्ट है, तो आप नया बनाने के बजाय सीधे उसके एड्रेस को
implementationआर्गुमेंट के रूप में पास कर सकते हैं।
- यदि आपके पास पहले से ही एक उपयुक्त डिप्लॉय किया गया इम्प्लीमेंटेशन कॉन्ट्रैक्ट है, तो आप नया बनाने के बजाय सीधे उसके एड्रेस को
इस वाकथ्रू के लिए, संदर्भ इम्प्लीमेंटेशन को एक परमिशन फंक्शन के साथ बढ़ाया गया है जो एक NFT मालिक को अन्य एड्रेसेस को अपने TBA की ओर से ट्रांज़ेक्शन्स को एग्जीक्यूट करने की अनुमति देने देगा।
कस्टमाइज़ किया गया संदर्भ इम्प्लीमेंटेशन कॉन्ट्रैक्ट:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "@openzeppelin/contracts/utils/introspection/IERC165.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/interfaces/IERC1271.sol";
import "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
interface IERC6551Account {
receive() external payable;
function token() external view returns (uint256 chainId, address tokenContract, uint256 tokenId);
function state() external view returns (uint256);
function isValidSigner(address signer, bytes calldata context) external view returns (bytes4 magicValue);
}
interface IERC6551Executable {
function execute(address to, uint256 value, bytes calldata data, uint8 operation)
external payable returns (bytes memory);
}
contract ERC6551Account is IERC165, IERC1271, IERC6551Account, IERC6551Executable {
uint256 public state;
/// @notice Mapping to store addresses permitted to act on behalf of the account
mapping(address => bool) public isPermitted;
receive() external payable {}
function execute(address to, uint256 value, bytes calldata data, uint8 operation)
external payable virtual returns (bytes memory result) {
require(_isValidSigner(msg.sender), "Invalid signer");
require(operation == 0, "Only call operations are supported");
++state;
bool success;
(success, result) = to.call{value: value}(data);
if (!success) {
assembly {
revert(add(result, 32), mload(result))
}
}
}
/// @notice Allows the NFT owner to grant or revoke permission for another address
function setPermission(address user, bool permitted) external {
require(msg.sender == owner(), "Only owner can set permissions");
require(user != msg.sender, "Cannot set permission for yourself");
isPermitted[user] = permitted;
}
function isValidSigner(address signer, bytes calldata) external view virtual returns (bytes4) {
return _isValidSigner(signer) ? IERC6551Account.isValidSigner.selector : bytes4(0);
}
function isValidSignature(bytes32 hash, bytes memory signature)
external view virtual returns (bytes4 magicValue) {
return SignatureChecker.isValidSignatureNow(owner(), hash, signature)
? IERC1271.isValidSignature.selector
: bytes4(0);
}
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId
|| interfaceId == type(IERC6551Account).interfaceId
|| interfaceId == type(IERC6551Executable).interfaceId;
}
function token() public view virtual returns (uint256, address, uint256) {
bytes memory footer = new bytes(0x60);
assembly {
extcodecopy(address(), add(footer, 0x20), 0x4d, 0x60)
}
return abi.decode(footer, (uint256, address, uint256));
}
function owner() public view virtual returns (address) {
(uint256 chainId, address tokenContract, uint256 tokenId) = token();
return (chainId == block.chainid) ? IERC721(tokenContract).ownerOf(tokenId) : address(0);
}
function _isValidSigner(address signer) internal view virtual returns (bool) {
return signer == owner() || isPermitted[signer];
}
}
संदर्भ इम्प्लीमेंटेशन कॉन्ट्रैक्ट में निम्नलिखित नए जोड़े गए हैं:
mapping(address => bool) isPermitted: ट्रैक करता है कि किन एड्रेसेस को अकाउंट की ओर से कार्य करने की अनुमति है।setPermission(address user, bool permitted): बाहरी (external) फंक्शन जो NFT मालिक को परमिशन देने या रद्द करने देता है।- एक अपडेटेड
_isValidSigner()फंक्शन जो अब यह जांचता है कि साइनर NFT का मालिक है या कोई अधिकृत एड्रेस है।
किसी NFT के लिए TBA बनाने के लिए इन स्टेप्स का पालन करें:
- इस repository को क्लोन करें:
git clone https://github.com/Sayrarh/ERC-6551-Reference-Implementation.git - निर्भरताएँ (dependencies) इन्स्टॉल करें:
npm install .env.exampleकी सामग्री को कॉपी करके और अपनी API कुंजियों को भरकर अपनी.envफ़ाइल बनाएं।scripts/interaction.tsफ़ाइल में जाएँ औरnftContractAddressको अपने वास्तविक NFT एड्रेस से बदलें, साथ हीnfttokenIdऔरchainIdपैरामीटर्स को भी बदलें।

फिर कॉन्ट्रैक्ट्स के साथ इंटरैक्ट करने के लिए स्क्रिप्ट चलाएँ: npx hardhat run scripts/interaction.ts --network sepolia :

आप इस डिप्लॉय किए गए TBA एड्रेस को Sepolia नेटवर्क पर पा सकते हैं और एक्सप्लोरर पर इसके ट्रांज़ेक्शन विवरण यहां देख सकते हैं।
इसके बाइटकोड का विश्लेषण पहले वर्णित प्रॉक्सी संरचना को प्रकट करता है:

EIP-1167 Proxy Section
Header (10 bytes) -> 0x363d3d373d3d3d363d
Implementation Address (20 bytes) -> 311e822a099fae1ef8fc961ddf61fafd5392e7a9 (Implementation Address)
Footer (15 bytes) -> 5af43d82803e903d91602b57fd5bf3
Immutable Data Section (account binding)
salt (32 bytes) -> 0000000000000000000000000000000000000000000000000000000000000000
chainID (32 bytes) -> 00000000000000000000000000000000000000000000000000000000aa36a7 // chainID -> 11155111 (sepolia)
tokenContract (32 bytes) -> 0000000000000000000000006b57b7edf751829dfb2aeccf578d6d24c33a45a2 (NFT contract address)
tokenID (32 bytes) -> 0000000000000000000000000000000000000000000000000000000000000001 //token ID -> 1
TBA का पूरा बाइटकोड दिखाता है कि 0x97212622cbdb6f1aa96c4abceaebb2b1b47d2bbe पर नया बनाया गया TBA 0x311e822a099fae1ef8fc961ddf61fafd5392e7a9 पर इम्प्लीमेंटेशन कॉन्ट्रैक्ट को कॉल्स फ़ॉरवर्ड करता है जिसमें TBA NFT से बंधा होता है:
- NFT contract address:
0x6b57b7edf751829dfb2aeccf578d6d24c33a45a2 - tokenID: 1
- chainID: 11155111 (Sepolia testnet)
- salt: 0 (default salt)
इसलिए, जब token() फंक्शन को कॉल किया जाता है, तो यह TBA के बाइटकोड को पढ़ता है:

और फिर ट्यूपल लौटाता है जैसा कि नीचे देखा गया है:

ये वैल्यूज़ (chainId, tokenContract, tokenId) विशिष्ट रूप से उस NFT की पहचान करते हैं जिससे अकाउंट बंधा है, जिससे कॉन्ट्रैक्ट्स या एप्लिकेशन्स के लिए संबंधित NFT को निर्धारित करना आसान हो जाता है।
NFT ट्रांसफर को हैंडल करना
जब TBA वाले NFT को ट्रांसफर किया जाता है, तो TBA का स्वामित्व भी स्वचालित रूप से ट्रांसफर हो जाता है। ऐसा इसलिए होता है क्योंकि TBA का स्वामित्व owner() फंक्शन के माध्यम से वर्तमान NFT मालिक द्वारा गतिशील रूप से निर्धारित किया जाता है।

- TBA अपनी सभी संपत्तियां (ETH, टोकन्स, NFTs) बरकरार रखता है
- TBA का नियंत्रण नए NFT मालिक के पास चला जाता है
- NFT के ट्रांसफर होने के बाद पिछला मालिक TBA के स्वामित्व वाली संपत्तियों तक अपनी पूरी पहुँच खो देता है, जब तक कि उन संपत्तियों को पहले ही बाहर न निकाल लिया गया हो, जैसा कि गेमिंग उदाहरण में दर्शाया गया है।
इस सेक्शन में उपयोग किया गया इम्प्लीमेंटेशन एक सरल है। EIP-6551 के लेखकों ने अपने GitHub repository में एक संदर्भ अपग्रेडेबल इम्प्लीमेंटेशन भी प्रदान किया है, जो आपको जरूरत पड़ने पर TBA के लॉजिक को एक नए इम्प्लीमेंटेशन कॉन्ट्रैक्ट की ओर इशारा करके अपग्रेड करने की अनुमति देता है।
TBAs में ओनरशिप साइकिल्स (Ownership Cycles) को रोकना
अपग्रेडेबल इम्प्लीमेंटेशन में ओनरशिप साइकिल्स (ownership cycles) के खिलाफ सुरक्षा उपाय शामिल हैं, जो तब हो सकते हैं जब TBA ओनरशिप की एक श्रृंखला एक लूप बनाती है।
ओनरशिप साइकिल्स ऐसी स्थितियाँ पैदा करते हैं जहाँ किसी भी अकाउंट के पास ट्रांज़ेक्शन्स शुरू करने का अधिकार नहीं होता है क्योंकि प्रत्येक TBA को एक मालिक (EOA) से अनुमति की आवश्यकता होती है जो साइकिल में फँस गया हो। इसे इस प्रकार दर्शाया जा सकता है:

ये असुरक्षित क्यों हैं:
- प्रत्येक TBA को ऑपरेट करने के लिए अपने NFT मालिक (EOA) की अनुमति की आवश्यकता होती है।
- जब EOA साइकिल में मौजूद किसी एक TBA में NFT को ट्रांसफर करता है, तो वह सारा नियंत्रण खो देता है क्योंकि वह प्रभावी रूप से स्वामित्व छोड़ देता है।
- एक साइकिल में, कोई भी अन्य पार्टी ट्रांज़ेक्शन्स शुरू नहीं कर सकती है क्योंकि EOA अब श्रृंखला में किसी भी NFT का मालिक नहीं है।
- साइकिल को तोड़ने के किसी तरीके के बिना सभी संपत्तियां स्थायी रूप से लॉक हो जाती हैं।
चूंकि जटिल साइकिल्स (depth > 1) गहरे ओनरशिप लूप्स का प्रतिनिधित्व करते हैं जिनमें कई नेस्टेड (nested) TBAs शामिल हो सकते हैं, इसलिए उनका पता लगाने के लिए संभावित रूप से अनंत रिकर्सिव चेक्स (recursive checks) की आवश्यकता होगी - जिससे ऑन-चेन डिटेक्शन को कम्प्यूटेशनल रूप से अव्यावहारिक (unfeasible) बना दिया जाएगा। इसलिए, एप्लिकेशन्स के लिए इन ओनरशिप साइकिल्स के खिलाफ सुरक्षा उपायों को लागू करना आवश्यक है।
TBA फ्रॉड से बचाव (Mitigation)
दुर्भावनापूर्ण TBA मालिकों द्वारा किए जाने वाले कपटपूर्ण कार्यों (fraudulent actions) को रोकने के लिए NFT मार्केटप्लेसेस को सुरक्षा उपाय लागू करने होंगे।
एक परिदृश्य (scenario) पर विचार करें जिसमें Bob एक कैरेक्टर NFT का मालिक है जिसके TBA में 0.5 ETH, 2 ड्रैगन NFTs और गेमप्ले रिवार्ड्स से $50 USDC हैं। Bob कैरेक्टर NFT को मार्केटप्लेस पर 1 ETH के लिए सूचीबद्ध करता है, जिसमें सौदे (deal) के हिस्से के रूप में TBA की सभी संपत्तियां शामिल हैं।
Alice, जो गेम को शुरुआत से शुरू नहीं करना चाहती, NFT खरीदने के लिए सहमत हो जाती है। बिक्री पक्की होने से ठीक पहले, Bob जल्दी से TBA से $50 USDC निकाल लेता है।
जब ट्रांज़ेक्शन पूरा हो जाता है, तो Alice को TBA में केवल 0.5 ETH और 2 ड्रैगन NFTs के साथ कैरेक्टर NFT मिलता है, जबकि Bob को बिक्री से 1 ETH और उसके द्वारा निकाले गए $50 USDC मिलते हैं।
इस तरह के कपटपूर्ण कार्यों को संबोधित करने के लिए, NFT मार्केटप्लेसेस को मार्केटप्लेस स्तर पर सुरक्षा लागू करने की आवश्यकता है, और इस मानक को लागू करने वाले कॉन्ट्रैक्ट्स में सुरक्षा उपाय भी शामिल होने चाहिए। कुछ बचाव (mitigation) रणनीतियों में शामिल हैं:
- मार्केटप्लेस ऑर्डर्स के साथ एसेट कमिटमेंट्स की एक सूची (जैसे कि विशेष ERC-20 बैलेंस, NFTs आदि) संलग्न करना और यदि पूरा होने से पहले कमिटेड एसेट्स हटा दिए जाते हैं तो प्रस्ताव को रद्द करना।
- मार्केटप्लेस द्वारा लिस्टिंग अवधि के दौरान अस्थायी रूप से NFT का स्वामित्व लेना (केवल अप्रूवल अधिकारों के बजाय), जो विक्रेता को TBA की संपत्तियों में हेरफेर करने से रोकता है।
सारांश (Summary)
ERC-6551 NFTs को स्मार्ट कॉन्ट्रैक्ट अकाउंट्स (TBAs) से जोड़ने की अनुमति देता है, जिससे वे संपत्तियों (assets) के मालिक बनने और प्रोटोकॉल्स के साथ इंटरैक्ट करने में सक्षम होते हैं। यह नियतात्मक एड्रेसेस (create2), बाइटकोड में NFT बाइंडिंग डेटा स्टोर करने वाले कस्टम मॉडिफाइड मिनिमल प्रॉक्सीज़, और एक कैनोनिकल रजिस्ट्री के माध्यम से, मौजूदा NFT कॉन्ट्रैक्ट्स में कोई बदलाव किए बिना इसे प्राप्त करता है।
कुछ प्रोजेक्ट्स पहले से ही इन-गेम इन्वेंटरी (आइटम्स, आउटफिट्स और इक्विपमेंट का मालिक होना), कम्युनिटी लॉयल्टी सिस्टम्स, रेपुटेशन ट्रैकिंग और आदि के लिए TBAs का लाभ उठा रहे हैं।
जैसे-जैसे एडॉप्शन (adoption) बढ़ेगा, ERC-6551 NFTs को DeFi में और इंटीग्रेट करेगा, जिससे उनके यूज़ केसेस का विस्तार होगा। इसके वर्तमान एडॉप्शन के बावजूद, ERC-6551 अभी भी समीक्षा के अधीन है और लिखे जाने के समय तक इसे अंतिम रूप (finalized) नहीं दिया गया है।
इम्प्लीमेंटेशन उदाहरण के लिए, Tokenbound दस्तावेज़ (docs) देखें या frontend SDK और iframe जैसे टूल्स का पता लगाएं। ERC-6551 अकाउंट्स को देखने और उनके साथ इंटरैक्ट करने के लिए एक explorer भी उपलब्ध है।
संदर्भ (References)
EIP-6551 standard page
ERC-721 standard
EIP-1167 Minimal Proxy
EIP-1967 storage slot
ERC-6551 Source Code
List of Projects that have adopted ERC6551
TBA Explorer