ERC-7730 के साथ अपने प्रोटोकॉल में स्पष्ट हस्ताक्षर करना (clear signing) जोड़ें
अधिकांश प्रमुख इथेरियम कारनामों (exploits) का अंतिम चरण एक ही था: एक उपयोगकर्ता द्वारा ऐसे लेन-देन को स्वीकृति देना जिसे वे सार्थक रूप से समझ नहीं सकते थे। हार्डवेयर वॉलेट रॉ हेक्स कॉल डेटा (raw hex calldata) दिखाते हैं, और इससे भी बदतर, आपको ब्लाइंड साइनिंग (blind signing) चालू रखने के लिए मजबूर करते हैं। सॉफ़्टवेयर वॉलेट डिकोड किए गए फ़ील्ड दिखाते हैं, लेकिन केवल तभी जब वे अनुबंध को पहचानते हैं। जब वे ऐसा नहीं करते हैं, चाहे इसलिए कि प्रोटोकॉल नया है, ऐप से समझौता किया गया है, या डिवाइस ऑफ़लाइन है, तो उपयोगकर्ता बिना देखे (blind) हस्ताक्षर करते हैं।
ERC-7730 (एक नए टैब में खुलता है) आपके अनुबंध के फ़ंक्शन कॉल का अर्थ क्या है, इसका वर्णन करने के लिए एक मानक JSON प्रारूप को परिभाषित करता है।
एक वॉलेट जो ERC-7730 का समर्थन करता है, वह आपके डिस्क्रिप्टर को पढ़ता है और दिखाता है:
स्वैप
भेजें: 1,000 USDC
न्यूनतम प्राप्त करें: 0.42 WETH
प्रोटोकॉल: यूनिस्वैप V3
या मनुष्यों और एजेंटों दोनों के द्वारा पढ़ने योग्य एक एकल निर्मित वाक्य:
कम से कम 0.42 WETH के लिए 1,000 USDC स्वैप करें
फ़ंक्शन चयनकर्ता (selector) और रॉ पूर्णांक मानों की सूची के बजाय।
यह स्पष्ट हस्ताक्षर करना (एक नए टैब में खुलता है) है — "आप जो देखते हैं वही आप हस्ताक्षर करते हैं।" यह ट्यूटोरियल आपको अपने स्वयं के अनुबंध के लिए एक डिस्क्रिप्टर लिखने, आधिकारिक CLI टूल के साथ इसे मान्य करने और इसे ओपन रजिस्ट्री में सबमिट करने की प्रक्रिया के बारे में बताता है।
पूर्वापेक्षाएँ
- Solidity और स्मार्ट अनुबंध ABI से परिचित होना
- एक सत्यापित ABI के साथ तैनात किया गया स्मार्ट अनुबंध (डिस्क्रिप्टर को रजिस्ट्री में स्वीकार किए जाने से पहले Sourcify (एक नए टैब में खुलता है) सत्यापन आवश्यक है)
- सत्यापन CLI के लिए Python 3.12+
- बुनियादी JSON ज्ञान
ERC-7730 डिस्क्रिप्टर क्या है?
डिस्क्रिप्टर तीन खंडों वाली एक एकल JSON फ़ाइल है:
| खंड | उद्देश्य |
|---|---|
context | चेन ID और पते के आधार पर डिस्क्रिप्टर को विशिष्ट अनुबंध तैनाती से बांधता है |
metadata | प्रोजेक्ट का नाम देता है और पुन: प्रयोज्य स्थिरांक (constants) को परिभाषित करता है |
display | प्रत्येक फ़ंक्शन हस्ताक्षर को मानव-पठनीय लेबल और फ़ील्ड प्रारूपों में मैप करता है |
चूँकि डिस्क्रिप्टर अनुबंध से अलग होता है, इसलिए आप बिना पुन: तैनाती के किसी भी मौजूदा प्रोटोकॉल में स्पष्ट हस्ताक्षर करने का समर्थन जोड़ सकते हैं। वॉलेट रजिस्ट्री से डिस्क्रिप्टर प्राप्त करते हैं और हस्ताक्षर करने के समय उनका उपयोग करते हैं।
चरण 1: फ़ाइल का ढांचा (skeleton) बनाएँ
calldata-<contractname>-<descriptorversion>.json नाम की एक फ़ाइल बनाएँ। calldata- उपसर्ग (prefix) रजिस्ट्री को बताता है कि यह डिस्क्रिप्टर अनुबंध फ़ंक्शन कॉल को कवर करता है, न कि टाइप-डेटा संदेशों के लिए eip712- को। descriptorversion रजिस्ट्री को डिस्क्रिप्टर फ़ाइल का संस्करण बताता है, यदि कोई संस्करण प्रदान नहीं किया गया है तो डिफ़ॉल्ट रूप से 0 होता है।
{
"$schema": "https://eips.ethereum.org/assets/eip-7730/erc7730-v2.schema.json",
"context": {},
"metadata": {},
"display": {
"formats": {}
}
}
चरण 2: संदर्भ (context) खंड लिखें
context खंड डिस्क्रिप्टर को एक या अधिक अनुबंध तैनाती से बांधता है। वॉलेट इसका उपयोग आने वाले लेन-देन को सही डिस्क्रिप्टर से मिलाने के लिए करते हैं।
"context": {
"$id": "uniswap-v3-router-mainnet",
"contract": {
"deployments": [
{ "chainId": 1, "address": "0xYourContractAddressOnMainnet" },
{ "chainId": 137, "address": "0xYourContractAddressOnPolygon" }
]
}
}
संदर्भ फ़ील्ड
context.$id— इस डिस्क्रिप्टर दस्तावेज़ या तैनाती कॉन्फ़िगरेशन के लिए एक विशिष्ट पहचानकर्ता।contract.deployments— तैनाती का वह सेट जिस पर यह डिस्क्रिप्टर लागू होता है।deployments[].chainId— तैनाती के लिए EVM चेन ID। हर उस चेन को शामिल करें जहाँ आपका अनुबंध तैनात है।deployments[].address— वह अनुबंध पता जिसे वॉलेट को इस डिस्क्रिप्टर के साथ जोड़ना चाहिए। उस कार्यान्वयन पते (implementation address) का उपयोग करें जिसमें निष्पादन तर्क (execution logic) होता है।
चरण 3: मेटाडेटा खंड लिखें
मेटाडेटा खंड इस फ़ाइल द्वारा वर्णित प्रोजेक्ट और अनुबंध के बारे में मानव-पठनीय जानकारी प्रदान करता है। वॉलेट हस्ताक्षर करने के दौरान प्रोटोकॉल नाम, लिंक और अन्य प्रासंगिक विवरण प्रदर्शित करने के लिए इस जानकारी का उपयोग कर सकते हैं।
"metadata": {
"owner": "Example Swap Protocol",
"info": { "url": "https://example.xyz" },
"contractName": "SwapRouter"
}
मेटाडेटा फ़ील्ड
owner— इस डिस्क्रिप्टर के लिए ज़िम्मेदार प्रोजेक्ट, प्रोटोकॉल, संगठन या मेंटेनर।info.url— एक विहित (canonical) प्रोजेक्ट या दस्तावेज़ URL जिसे वॉलेट अतिरिक्त संदर्भ के लिए उपयोगकर्ताओं को प्रदर्शित कर सकते हैं।contractName— इस फ़ाइल द्वारा वर्णित अनुबंध या कार्यान्वयन का नाम, जो आमतौर पर सत्यापित स्रोत कोड या ABI से मेल खाता है।
यदि आपकी ERC-7730 फ़ाइल किसी ERC-20 अनुबंध का वर्णन करती है, तो आपको एक टोकन ऑब्जेक्ट भी जोड़ना चाहिए।
चरण 4: प्रदर्शन प्रारूप (display formats) खंड लिखें
display.formats ऑब्जेक्ट फ़ंक्शन हस्ताक्षरों को मानव-पठनीय हस्ताक्षर निर्देशों में मैप करता है। इस तरह वॉलेट उपयोगकर्ताओं द्वारा लेन-देन को स्वीकृति देने से पहले आपके फ़ंक्शन को दिखाते हैं!
प्रत्येक कुंजी एक मानव-पठनीय ABI अंश है — फ़ंक्शन हस्ताक्षर जिसमें पैरामीटर नाम और पैरामीटर प्रकार दोनों ठीक वैसे ही शामिल होते हैं जैसे वे आपके ABI में दिखाई देते हैं।
उदाहरण: टोकन स्वैप का वर्णन करना
"display": {
"formats": {
"swapExactTokensForTokens(uint256 amountIn,uint256 amountOutMin,address[] path,address to,uint256 deadline)": {
"intent": "Swap",
"interpolatedIntent": "Swap {amountIn} for at least {amountOutMin}",
"fields": [
{
"path": "#.amountIn",
"label": "Send",
"format": "tokenAmount",
"params": {
"tokenPath": "#.path[0]"
}
},
{
"path": "#.amountOutMin",
"label": "Receive minimum",
"format": "tokenAmount",
"params": {
"tokenPath": "#.path[1]"
}
},
{
"path": "#.to",
"label": "Recipient",
"format": "addressName",
"params": {
"types": ["eoa", "contract"],
"sources": ["local", "ens"]
}
},
{
"path": "#.deadline",
"label": "Expires",
"format": "date",
"params": {
"encoding": "timestamp"
}
}
]
}
}
}
प्रदर्शन फ़ील्ड
intent— (आवश्यक) कार्रवाई का एक संक्षिप्त, उपयोगकर्ता के अनुकूल विवरण, जैसे "स्वैप"।interpolatedIntent— (अनुशंसित) एक अधिक समृद्ध वाक्य टेम्पलेट जो स्वरूपित फ़ील्ड मानों को एम्बेड करता है, जैसे"Swap {amountIn} for at least {amountOutMin}"। इसेintentके साथ शामिल करें ताकि एक और भी अधिक उपयोगकर्ता के अनुकूल डिस्क्रिप्टर प्रदान किया जा सके जिसे वॉलेट किसी भी प्रदर्शन बाधाओं को देखते हुए दिखाना चुन सकते हैं।fields— (आवश्यक) लेन-देन फ़ील्ड की क्रमित सूची जिसे वॉलेट को उपयोगकर्ताओं को प्रदर्शित करना चाहिए।-
path— (आवश्यक) लेन-देन डेटा का संदर्भ।#.fieldNameABI में नाम के आधार पर डिकोड किए गए कॉल डेटा पैरामीटर को इंगित करता है।@.valueलेन-देन के साथ भेजे गए ETH मान को संदर्भित करता है। -
label— (आवश्यक) मान के बगल में दिखाया गया मानव-पठनीय लेबल। -
format— (अनुशंसित) यह नियंत्रित करता है कि मान को कैसे प्रस्तुत किया जाना चाहिए। सामान्य प्रारूपों में शामिल हैं:tokenAmountaddressNamedate
जब किसी अतिरिक्त स्वरूपण की आवश्यकता न हो तो
rawका उपयोग करें। कुछ प्रारूप अतिरिक्तparamsकॉन्फ़िगरेशन स्वीकार करते हैं। उदाहरण के लिए:tokenAmountयह पहचानने के लिएtokenPathका उपयोग कर सकता है कि कौन सा टोकन पता दशमलव और टिकर मेटाडेटा प्रदान करता है।dateयह वर्णन करने के लिएencodingका उपयोग कर सकता है कि टाइमस्टैम्प को कैसे एन्कोड किया गया है।
यदि चयनित प्रारूप को अतिरिक्त जानकारी की आवश्यकता नहीं है, तो
paramsको छोड़ दें।
-
संपूर्ण डिस्क्रिप्टर
{
"$schema": "https://eips.ethereum.org/assets/eip-7730/erc7730-v2.schema.json",
"context": {
"$id": "uniswap-v3-router-mainnet",
"contract": {
"deployments": [
{
"chainId": 1,
"address": "0xYourContractAddressOnMainnet"
},
{
"chainId": 137,
"address": "0xYourContractAddressOnPolygon"
}
]
}
},
"metadata": {
"owner": "Example Swap Protocol",
"info": {
"url": "https://example.xyz"
},
"contractName": "SwapRouter"
},
"display": {
"formats": {
"swapExactTokensForTokens(uint256 amountIn,uint256 amountOutMin,address[] path,address to,uint256 deadline)": {
"intent": "Swap",
"interpolatedIntent": "Swap {amountIn} for at least {amountOutMin}",
"fields": [
{
"path": "#.amountIn",
"label": "Send",
"format": "tokenAmount",
"params": {
"tokenPath": "#.path[0]"
}
},
{
"path": "#.amountOutMin",
"label": "Receive minimum",
"format": "tokenAmount",
"params": {
"tokenPath": "#.path[1]"
}
},
{
"path": "#.to",
"label": "Recipient",
"format": "addressName",
"params": {
"types": ["eoa", "contract"],
"sources": ["local", "ens"]
}
},
{
"path": "#.deadline",
"label": "Expires",
"format": "date",
"params": {
"encoding": "timestamp"
}
}
]
}
}
}
}
चरण 5: रजिस्ट्री में सबमिट करें
ERC-7730 रजिस्ट्री (एक नए टैब में खुलता है) एक तटस्थ प्रबंधक (steward) के रूप में एथेरियम फाउंडेशन द्वारा होस्ट की गई एक ओपन रिपॉजिटरी है। कोई भी इसे क्लोन करने और स्वयं-होस्ट करने के लिए स्वतंत्र है — वॉलेट स्वतंत्र रूप से तय करते हैं कि वे किन रजिस्ट्री इंस्टेंस पर भरोसा करते हैं।
- GitHub पर रिपॉजिटरी को फ़ोर्क करें
registry/<your-project-name>/पर एक फ़ोल्डर बनाएँ- अपनी फ़ाइल को इसके अंदर रखें:
registry/myproject/calldata-mycontract-0_0.json $schemaफ़ील्ड को रेपो के भीतर उपयोग किए गए सापेक्ष पथ (relative path) में अपडेट करें:"../../specs/erc7730-v2.schema.json"- एक पुल रिक्वेस्ट (pull request) खोलें
जब आप PR खोलते हैं, तो CI स्वचालित रूप से स्कीमा सत्यापन चलाता है, यह जाँचता है कि फ़ंक्शन हस्ताक्षर मान्य चयनकर्ता (selectors) उत्पन्न करते हैं, पुष्टि करता है कि अनुबंध पता Sourcify पर सत्यापित है, और ABI विसंगतियों को फ़्लैग करता है। जाँच के परिणाम PR पर इनलाइन दिखाई देते हैं। रजिस्ट्री मेंटेनर विकृत या संभावित रूप से दुर्भावनापूर्ण डिस्क्रिप्टर के लिए सबमिशन की जाँच करते हैं। रजिस्ट्री में शामिल होने का मतलब ऑडिट या समर्थन नहीं है।
मर्ज करने के बाद क्या होता है?
रजिस्ट्री में सभी डिस्क्रिप्टर ऑडिटर्स के लिए खुले हैं। आपके PR के मर्ज होने के बाद, कोई भी ऑडिटर आपके डिस्क्रिप्टर की समीक्षा कर सकता है और इसकी सटीकता की पुष्टि करते हुए एक क्रिप्टोग्राफ़िक अनुप्रमाणन (ERC-8176 (एक नए टैब में खुलता है) के तहत) प्रकाशित कर सकता है।
ये अनुप्रमाणन संकेत वॉलेट को अपनी स्वयं की विश्वास नीतियां लागू करने देते हैं — कई स्वतंत्र अनुप्रमाणन वाले डिस्क्रिप्टर का महत्व बिना अनुप्रमाणन वाले डिस्क्रिप्टर से अधिक होता है। आप clearsigning.org (एक नए टैब में खुलता है) के माध्यम से ऑडिटर समुदाय तक पहुँच सकते हैं।
वॉलेट चुनते हैं कि वे किस रजिस्ट्री का समर्थन करेंगे। एक बार जब आपका डिस्क्रिप्टर रजिस्ट्री में आ जाता है, तो ERC-7730 का समर्थन करने वाले वॉलेट इसे प्राप्त करना शुरू कर देंगे यदि यह उनकी रजिस्ट्री में है और जब उपयोगकर्ता आपके अनुबंध के साथ इंटरैक्ट करेंगे तो मानव-पठनीय डेटा प्रदर्शित करेंगे।