Ethereum पर, आप एक कॉन्ट्रैक्ट को सिंगल ट्रांज़ैक्शन में डिप्लॉय करते हैं। Starknet एक अलग दृष्टिकोण अपनाता है: डिप्लॉयमेंट को दो अलग-अलग ट्रांज़ैक्शन में बांटा जाता है, डिक्लेरेशन (declaration) और डिप्लॉयमेंट (deployment)।
डिक्लेरेशन ट्रांज़ैक्शन कॉन्ट्रैक्ट बाइटकोड को ऑन-चेन रजिस्टर करता है और एक क्लास हैश उत्पन्न करता है, जबकि डिप्लॉयमेंट ट्रांज़ैक्शन उस क्लास हैश का उपयोग करके एक कॉन्ट्रैक्ट इंस्टेंस बनाता है जिसका अपना एड्रेस और स्टोरेज होता है। हम इस सीरीज़ के दौरान इस दो-चरणीय प्रक्रिया को डिक्लेयर-डिप्लॉय (declare-deploy) मॉडल कहेंगे।
इस लेख में, आप सीखेंगे कि कैसे:
- Starknet का डिक्लेयर-डिप्लॉय मॉडल पर्दे के पीछे कैसे काम करता है
- रेगुलर (Regular) कॉन्ट्रैक्ट्स को Universal Deployer Contract (UDC) के माध्यम से डिप्लॉय किया जाता है, हालांकि UDC अकाउंट कॉन्ट्रैक्ट्स को भी डिप्लॉय कर सकता है, जैसा कि इस लेख में आगे बताया गया है
- अकाउंट कॉन्ट्रैक्ट्स को
DEPLOY_ACCOUNTट्रांज़ैक्शन प्रकार के माध्यम से डिप्लॉय किया जाता है (कॉन्ट्रैक्ट बाइटकोड कोDECLAREट्रांज़ैक्शन के माध्यम से ऑन-चेन घोषित किए जाने के बाद)
Ethereum बनाम Starknet पर Deployment
मान लीजिए कि आप कई ERC-20 टोकन लॉन्च करना चाहते हैं। Ethereum पर, प्रत्येक डिप्लॉयमेंट के लिए पूरा कॉन्ट्रैक्ट बाइटकोड अपलोड करने और उस सभी डेटा को स्टोर करने के लिए गैस (gas) का भुगतान करने की आवश्यकता होती है। आप हर एक टोकन कॉन्ट्रैक्ट के लिए इस प्रक्रिया को दोहराते हैं, भले ही कोड लगभग समान हो। इसका मतलब है कि आप बार-बार डुप्लिकेट कोड को स्टोर करने के लिए भुगतान कर रहे हैं।
Starknet कॉन्ट्रैक्ट क्लास (बाइटकोड) को कॉन्ट्रैक्ट इंस्टेंस से अलग करके इससे बचता है। कॉन्ट्रैक्ट क्लास को डिक्लेयर करने से बाइटकोड एक बार ऑन-चेन स्टोर हो जाता है, फिर आप जितने चाहें उतने इंस्टेंस डिप्लॉय कर सकते हैं जो उस डिक्लेयर की गई क्लास को रेफरेंस (reference) करते हैं।
यह अलगाव (separation) कॉन्ट्रैक्ट अपग्रेडिबिलिटी को भी सक्षम बनाता है: डिप्लॉय किए गए कॉन्ट्रैक्ट के लॉजिक को उसके एड्रेस और स्टोरेज को बदले बिना स्वैप किया जा सकता है। इसे “Upgrading Contracts” लेख में विस्तार से कवर किया गया है।
इस अलगाव को लागू करने के लिए, Starknet विशिष्ट ट्रांज़ैक्शन प्रकारों का उपयोग करता है जो डिक्लेरेशन और डिप्लॉयमेंट को अलग-अलग ऑपरेशन्स के रूप में संभालते हैं।
Starknet पर Deployment के लिए Transaction Types
Starknet वर्तमान में प्रोटोकॉल स्तर पर चार ट्रांज़ैक्शन प्रकारों को परिभाषित करता है: DECLARE, DEPLOY_ACCOUNT, INVOKE, और L1_HANDLER। आप इन सभी को explorer पर देख सकते हैं, जो बैकवर्ड कम्पैटिबिलिटी (backward compatibility) के लिए पुराने (deprecated) DEPLOY ट्रांज़ैक्शन प्रकार को भी दिखा सकता है। हम कॉन्ट्रैक्ट डिप्लॉयमेंट से संबंधित तीन प्रकारों पर ध्यान केंद्रित करेंगे (जिन्हें नीचे लाल बॉक्स में हाइलाइट किया गया है):

DECLARE: कॉन्ट्रैक्ट कोड को ऑन-चेन रजिस्टर करता हैDEPLOY_ACCOUNT: एक अकाउंट कॉन्ट्रैक्ट को डिप्लॉय करता है।INVOKE: रेगुलर कॉन्ट्रैक्ट्स को डिप्लॉय करता है और पहले से डिप्लॉय किए गए कॉन्ट्रैक्ट्स पर फंक्शन कॉल्स निष्पादित करता है। यह टोकन भेजने, DEXs पर स्वैप (swap) करने या किसी अन्य कॉन्ट्रैक्ट इंटरैक्शन को करने के लिए उपयोग किया जाने वाला ट्रांज़ैक्शन प्रकार है।
डिक्लेरेशन के लिए हमेशा DECLARE का उपयोग किया जाता है, जबकि डिप्लॉयमेंट स्टेप रेगुलर कॉन्ट्रैक्ट्स के लिए INVOKE या अकाउंट कॉन्ट्रैक्ट्स के लिए DEPLOY_ACCOUNT का उपयोग करता है।
इससे पहले कि हम डिक्लेरेशन और डिप्लॉयमेंट प्रक्रिया को समझें, हमें Starknet पर दो प्रकार के कॉन्ट्रैक्ट्स, रेगुलर कॉन्ट्रैक्ट्स और अकाउंट कॉन्ट्रैक्ट्स को समझने की आवश्यकता है, क्योंकि उनमें से प्रत्येक अलग डिप्लॉयमेंट दृष्टिकोण का उपयोग करता है।
| Regular Contract | Account Contract |
|---|---|
| एक रेगुलर कॉन्ट्रैक्ट वह स्मार्ट कॉन्ट्रैक्ट है जो ERC-20 टोकन, NFTs आदि जैसे एप्लिकेशन लॉजिक को लागू करता है। रेगुलर कॉन्ट्रैक्ट्स अपने आप ट्रांज़ैक्शन शुरू नहीं कर सकते हैं और उन्हें अकाउंट कॉन्ट्रैक्ट्स द्वारा कॉल किया जाना चाहिए। | दूसरी ओर, एक अकाउंट कॉन्ट्रैक्ट एक प्रकार का स्मार्ट कॉन्ट्रैक्ट है जो यह वैलिडेट (validate) कर सकता है कि कोई ट्रांज़ैक्शन ऑथराइज़्ड (authorized) है या नहीं और ट्रांज़ैक्शन को निष्पादित (execute) कर सकता है। अकाउंट कॉन्ट्रैक्ट्स Starknet पर सभी ट्रांज़ैक्शन के लिए एंट्री पॉइंट के रूप में कार्य करते हैं। Ready या Braavos वॉलेट पर आपका अकाउंट एक ऑन-चेन डिप्लॉय किया गया अकाउंट कॉन्ट्रैक्ट है। |
इन दो कॉन्ट्रैक्ट प्रकारों को ध्यान में रखते हुए, आइए डिक्लेयर-डिप्लॉय प्रक्रिया के प्रत्येक चरण को समझें।
एक Contract Class को Declare करना
एक कॉन्ट्रैक्ट को डिक्लेयर करने के लिए, हमें पहले अपने Cairo सोर्स कोड को उस फॉर्मेट में कंपाइल करना होगा जिसकी Starknet अपेक्षा करता है। कंपाइलेशन प्रक्रिया के दो चरण होते हैं। सबसे पहले, कंपाइलर Cairo कोड को Sierra (Safe Intermediate Representation) में परिवर्तित करता है। फिर, डिक्लेरेशन के दौरान, सीक्वेंसर (sequencer - वह नोड जो Starknet पर ट्रांज़ैक्शन को ऑर्डर करता है और ब्लॉक बनाता है) Sierra को ऑन-चेन CASM (Cairo Assembly) में कंपाइल करता है।
Sierra और CASM
- Sierra, Cairo कोड और CASM के बीच एक इंटरमीडिएट रिप्रेजेंटेशन (intermediate representation) है। यह गारंटी देता है कि हर कॉन्ट्रैक्ट निष्पादन (execution) या Cairo प्रोग्राम को साबित (prove) किया जा सकता है, भले ही कोई ट्रांज़ैक्शन रिवर्ट (revert) हो जाए।
- A Sierra class Sierra फॉर्मेट में आपका कॉन्ट्रैक्ट कोड है। Sierra और Sierra क्लास के बीच का अंतर इस बात के समान है कि JSON एक फॉर्मेट है और एक JSON फ़ाइल उस फॉर्मेट में एक विशिष्ट दस्तावेज़ है। Sierra क्लास ही ऑन-चेन डिक्लेयर की जाती है क्योंकि यह स्थिर और सत्यापन योग्य (verifiable) है, जो यह सुनिश्चित करती है कि सभी कॉन्ट्रैक्ट कोड को हमेशा साबित किया जा सकता है।
- CASM वह लो-लेवल बाइटकोड है जिसे Cairo VM कॉन्ट्रैक्ट को निष्पादित करने के लिए इंटरप्रेट (interpret) करता है। यह हमारे कॉन्ट्रैक्ट का अंतिम कंपाइल किया गया रूप है, जो Sierra क्लास से जनरेट होता है।

Build Artifacts
जब हम किसी भी कॉन्ट्रैक्ट को scarb build के साथ कंपाइल करते हैं, उदाहरण के लिए, हमारा ERC‑20 कॉन्ट्रैक्ट, तो यह (target/dev) डायरेक्टरी में दो बिल्ड आर्टिफैक्ट (build artifacts) तैयार करता है:
1. Sierra file (नाम ...contract_class.json)
यह वह फ़ाइल है जिसमें Sierra क्लास होती है, जो उस ब्लूप्रिंट (blueprint) के रूप में कार्य करती है जिसका उपयोग नेटवर्क डिक्लेरेशन के लिए करता है। इसमें चार प्रमुख फ़ील्ड शामिल हैं:
sierra_program: Sierra बाइटकोड में कंपाइल किया गया कॉन्ट्रैक्ट लॉजिकentry_points_by_type: कॉन्ट्रैक्ट के कॉलेबल (callable) एंट्री पॉइंट, जिन्हें प्रकार के अनुसार ग्रुप किया गया है। एक एंट्री पॉइंट एकselector(फ़ंक्शन नाम काstarknet_keccakहैश, जिसका उपयोग यह पहचानने के लिए किया जाता है कि कौन सा फ़ंक्शन कॉल करना है) और एकfunction_idx(sierra_programऐरे में उस फ़ंक्शन के इम्प्लीमेंटेशन की स्थिति) का एक जोड़ा (pair) है, जो नेटवर्क को बताता है कि कौन सा फ़ंक्शन इनवोक (invoke) करना है और इसे Sierra प्रोग्राम में कहां खोजना है। तीन प्रकार हैं:- constructor
- external functions of the contract
- l1 handler: वे फ़ंक्शन जो Ethereum से Starknet भेजे गए मैसेज को हैंडल करते हैं। यह फ़ील्ड हर कॉन्ट्रैक्ट के लिए Sierra फ़ाइल स्ट्रक्चर का हिस्सा है, लेकिन यह ERC-20 जैसे कॉन्ट्रैक्ट्स के लिए खाली रहता है जो L1 के साथ इंटरैक्ट नहीं करते हैं।
abi: कॉन्ट्रैक्ट का इंटरफ़ेस जिसमें फ़ंक्शन सिग्नेचर (signatures), पैरामीटर के प्रकार, रिटर्न प्रकार, इवेंट्स और स्ट्रक्ट्स (structs) शामिल हैं।contract_class_version: कॉन्ट्रैक्ट क्लास फॉर्मेट का वर्ज़न
2. Starknet artifacts file (नाम ...starknet_artifacts.json)
इस फ़ाइल में कॉन्ट्रैक्ट का मेटाडेटा होता है और यह इसे इसकी कंपाइल की गई Sierra फ़ाइल से लिंक करता है। इसका उपयोग स्थानीय रूप से sncast जैसे टूल द्वारा किसी दिए गए कॉन्ट्रैक्ट नाम के लिए सही Sierra फ़ाइल का पता लगाने के लिए किया जाता है:

जैसा कि आप ऊपर दी गई इमेज में आर्टिफैक्ट्स फ़ाइल में देख सकते हैं, कंपाइल के समय "casm" फ़ील्ड null होती है। ऐसा इसलिए है क्योंकि ऑन-चेन डिक्लेरेशन प्रक्रिया के दौरान Sierra क्लास से CASM जनरेट किया जाएगा।
DECLARE transaction के दौरान क्या होता है
कंपाइल की गई Sierra क्लास तैयार होने के साथ, हम इसे नेटवर्क पर रजिस्टर करने के लिए एक DECLARE ट्रांज़ैक्शन का उपयोग करते हैं। sncast या Starknet.js जैसे टूल कॉन्ट्रैक्ट के लिए Sierra क्लास फ़ाइल का पता लगाने के लिए starknet_artifacts.json फ़ाइल को पढ़ते हैं, फिर उस Sierra क्लास को DECLARE ट्रांज़ैक्शन में सबमिट करते हैं, जिसे हमारा अकाउंट साइन करता है। सीक्वेंसर फिर Sierra को CASM में कंपाइल करता है और दो हैश की गणना करता है:
- Class hash: निम्नलिखित फॉर्मूले का उपयोग करके Sierra फ़ाइल में सभी चार फ़ील्ड से गणना की जाती है:
जहांclass_hash = h( contract_class_version, external_entry_points, l1_handler_entry_points, constructor_entry_points, abi_hash, sierra_program_hash )hPoseidon हैश फ़ंक्शन है: एक हैश फ़ंक्शन जिसे STARK प्रूफ़्स (proofs) के अंदर उपयोग के लिए ऑप्टिमाइज़ किया गया है। ध्यान दें किentry_points_by_typeफॉर्मूले में तीन अलग-अलग इनपुट का योगदान देता है:external_entry_points,l1_handler_entry_points, औरconstructor_entry_points।
इससे पहले कि ABI और Sierra प्रोग्राम गणना में शामिल हों, प्रत्येक को पहले हैश किया जाता है:- ABI हैश (
abi_hash) उत्पन्न करने के लिए ABI कोstarknet_keccak(bytes(ABI, "UTF-8"))का उपयोग करके हैश किया जाता है, - Sierra प्रोग्राम हैश (
sierra_program_hash) उत्पन्न करने के लिए Sierra प्रोग्राम को हैश किया जाता है।
चूंकि कॉन्ट्रैक्ट और पैकेज का नाम पूरे ABI में, इवेंट प्रकार के नामों जैसेerc20::ERC20::Transferऔर इंटरफ़ेस नामों जैसेerc20::IERC20में दिखाई देता है, इसलिए समान Cairo कोड लेकिन अलग-अलग कॉन्ट्रैक्ट या पैकेज नाम वाले दो कॉन्ट्रैक्ट अलग-अलग ABI हैश और इसलिए अलग-अलग क्लास हैश उत्पन्न करेंगे, जिसका अर्थ है कि दोनों को सफलतापूर्वक डिक्लेयर किया जा सकता है। इसी तरह, अलग-अलग कंपाइलर वर्ज़न के साथ कंपाइल किए गए दो कॉन्ट्रैक्ट अलग-अलगsierra_program_hashमान और इसलिए अलग-अलग क्लास हैश उत्पन्न करेंगे, भले ही Cairo सोर्स कोड समान हो। हालांकि, अगर इनमें से कोई भी फैक्टर अलग नहीं है, तो परिणामी क्लास हैश पहले से ऑन-चेन मौजूद क्लास हैश के समान होगा, और नेटवर्क “contract has already been declared” एरर के साथ डिक्लेरेशन को अस्वीकार कर देगा।
- ABI हैश (
- Compiled class hash: Sierra क्लास से जनरेट हुए CASM कोड से गणना की जाती है। यह सटीक मशीन कोड को लॉक कर देता है जिसे Cairo VM निष्पादित करेगा।
एक बार जब सीक्वेंसर DECLARE ट्रांज़ैक्शन को प्रोसेस कर लेता है, तो Sierra क्लास, क्लास हैश और कंपाइल्ड क्लास हैश सभी ऑन-चेन स्टोर हो जाते हैं, जिससे कॉन्ट्रैक्ट क्लास डिप्लॉयमेंट के लिए उपलब्ध हो जाती है।
Contract Instance को Deploy करना
एक बार कॉन्ट्रैक्ट क्लास डिक्लेयर हो जाने के बाद, हम इसके कई इंस्टेंस बना सकते हैं। प्रत्येक इंस्टेंस समान कोड साझा करता है लेकिन उसका अपना एड्रेस और स्टोरेज होता है। उदाहरण के लिए, Ready (पहले Argent) जैसे अकाउंट इम्प्लीमेंटेशन Starknet पर एक बार डिक्लेयर किए जाते हैं। जब आप एक नया Ready अकाउंट बनाते हैं, तो किसी नए डिक्लेरेशन की आवश्यकता नहीं होती है क्योंकि Ready class पहले से ही ऑन-चेन मौजूद है। आप केवल अकाउंट डिप्लॉयमेंट के लिए भुगतान करते हैं, कोड को फिर से स्टोर करने के लिए नहीं। आपका नया डिप्लॉय किया गया अकाउंट अपना खुद का यूनीक (unique) एड्रेस और स्टोरेज प्राप्त करता है लेकिन यह अन्य सभी Ready अकाउंट्स की तरह ही अंडरलाइंग (underlying) Ready कोड का उपयोग करता है।
प्रत्येक डिप्लॉय किए गए कॉन्ट्रैक्ट इंस्टेंस एड्रेस की गणना निम्नलिखित फॉर्मूले से की जाती है:
contract_address = pedersen(
"STARKNET_CONTRACT_ADDRESS",
deployer_address,
salt,
class_hash,
constructor_calldata_hash)
जहां pedersen STARK प्रूफ़्स के लिए संगत एक क्रिप्टोग्राफ़िक हैश फ़ंक्शन है। यह पांच इनपुट लेता है: एक कॉन्सटेंट प्रीफिक्स (constant prefix), डिप्लॉयर (deployer) का एड्रेस, एक सॉल्ट (salt) वैल्यू, क्लास हैश, और कंस्ट्रक्टर आर्ग्यूमेंट्स का एक हैश। इनमें से किसी भी एक इनपुट को बदलने से एक अलग एड्रेस उत्पन्न होता है, यही कारण है कि आप सॉल्ट, कंस्ट्रक्टर आर्ग्यूमेंट्स या डिप्लॉयर एड्रेस को बदलकर एक ही क्लास हैश के कई इंस्टेंस डिप्लॉय कर सकते हैं।
कॉन्ट्रैक्ट इंस्टेंस को डिप्लॉय करने के लिए चार प्रमुख कंपोनेंट्स (components) की आवश्यकता होती है:
- Reference: किस कॉन्ट्रैक्ट क्लास का उपयोग करना है
- Input: कंस्ट्रक्टर को कौन सा डेटा पास करना है
- Fee Payment: कौन सा अकाउंट डिप्लॉयमेंट के लिए भुगतान करता है
- Creates: नए कॉन्ट्रैक्ट इंस्टेंस को कौन सा एड्रेस मिलता है
हालांकि, ये कंपोनेंट्स इस बात पर निर्भर करते हुए अलग तरह से काम करते हैं कि आप रेगुलर कॉन्ट्रैक्ट डिप्लॉय कर रहे हैं या अकाउंट कॉन्ट्रैक्ट:
Regular Contracts (INVOKE via Universal Deployer Contract)
├── Reference: Contract class hash (already declared)
├── Input: Constructor calldata + salt
├── Fee Payment: From the sender's account
└── Creates: New contract instance at a deterministic address
Account Contracts (DEPLOY_ACCOUNT)
├── Reference: Account class hash (already declared)
├── Input: Constructor calldata + salt
├── Fee Payment: From the deployed account's own pre-funded address
└── Creates: New account contract at a counterfactual address (calculated before deployment)
Account Contracts (INVOKE via Universal Deployer Contract)
├── Reference: Account class hash (already declared)
├── Input: Constructor calldata + salt
├── Fee Payment: From the deployer's account
└── Creates: New account contract at a deterministic address, linked to the deployer
रेगुलर कॉन्ट्रैक्ट्स (Regular contracts) को Universal Deployer Contract (UDC) के माध्यम से एक INVOKE ट्रांज़ैक्शन के ज़रिए डिप्लॉय किया जाता है। एक मौजूदा अकाउंट कॉन्ट्रैक्ट UDC को कॉल करता है, जो फिर नया कॉन्ट्रैक्ट बनाने के लिए deploy_syscall को कॉल करता है। कॉलर (caller) ट्रांज़ैक्शन फ़ीस का भुगतान करता है। (हम अगले भाग में UDC को विस्तार से कवर करेंगे)।
नीचे दिया गया डायग्राम रेगुलर कॉन्ट्रैक्ट्स के लिए संपूर्ण डिप्लॉयमेंट फ्लो को दर्शाता है। नंबर दिए गए स्टेप्स ऑपरेशन्स के क्रम को दर्शाते हैं:
DECLAREट्रांज़ैक्शन कॉन्ट्रैक्ट क्लास को ऑन-चेन रजिस्टर करता है और एक क्लास हैश उत्पन्न करता है- आपका अकाउंट पैरामीटर्स के रूप में क्लास हैश, सॉल्ट, कॉलडेटा (calldata), और
not_from_zeroको पास करते हुए UDC को एकINVOKEट्रांज़ैक्शन भेजता है।not_from_zeroएक बूलियन (boolean) है जो यह निर्धारित करता है कि डिप्लॉयर का एड्रेस कॉन्ट्रैक्ट एड्रेस गणना में शामिल है या नहीं, इसे UDC सेक्शन में विस्तार से कवर किया गया है। - फिर UDC कॉन्ट्रैक्ट इंस्टेंस बनाने के लिए आंतरिक रूप से
deploy_syscallको कॉल करता है, जिसमें प्रत्येक को अपना यूनीक एड्रेस मिलता है।
डायग्राम का बायां हिस्सा डिक्लेरेशन स्टेप को दिखाता है, जबकि दायां हिस्सा दिखाता है कि कैसे एक ही क्लास हैश का उपयोग कई स्वतंत्र इंस्टेंस को डिप्लॉय करने के लिए फिर से किया जा सकता है:

अकाउंट कॉन्ट्रैक्ट्स को दो तरह से डिप्लॉय किया जा सकता है:
DEPLOY_ACCOUNTट्रांज़ैक्शन का उपयोग करके: इस प्रकार के डिप्लॉयमेंट में, अकाउंट कॉन्ट्रैक्ट अपने डिप्लॉयमेंट के लिए स्वयं भुगतान करता है। परिणामी (resulting) एड्रेस की गणना पहले से की जाती है और उसे STRK टोकन से फंड (fund) किया जाता है। फिर एकDEPLOY_ACCOUNTट्रांज़ैक्शन कॉन्ट्रैक्ट को डिप्लॉय करता है और उस प्री-फंडेड (pre-funded) एड्रेस से फ़ीस चार्ज करता है।- UDC के माध्यम से INVOKE: इस प्रकार के डिप्लॉयमेंट में, एक मौजूदा अकाउंट कॉन्ट्रैक्ट रेगुलर कॉन्ट्रैक्ट्स की तरह ही एक
INVOKEट्रांज़ैक्शन के माध्यम से नया अकाउंट कॉन्ट्रैक्ट डिप्लॉय करने के लिए UDC को कॉल करता है। डिप्लॉयर ट्रांज़ैक्शन फ़ीस का भुगतान करता है।
अब जब हमने डिक्लेयर-डिप्लॉय मॉडल को हाई लेवल पर समझ लिया है, तो आइए प्रत्येक डिप्लॉयमेंट विधि की विस्तार से जांच करें।
Universal Deployer Contract (UDC) के माध्यम से Contracts Deploy करना
UDC, OpenZeppelin द्वारा बनाया गया एक सिंगलटन (singleton) कॉन्ट्रैक्ट है जो deploy_syscall फ़ंक्शन को रैप (wrap) करता है, इसे एक कॉलेबल इंटरफ़ेस के रूप में प्रदर्शित करता है जिसे अकाउंट कॉन्ट्रैक्ट्स इनवोक कर सकते हैं। यह Starknet कॉन्ट्रैक्ट्स के लिए एक स्टैण्डर्डाइज़्ड (standardized) जेनेरिक फ़ैक्टरी के रूप में कार्य करता है। इसे Starknet sepolia और mainnet दोनों पर एड्रेस 0x02ceed65a4bd731034c01113685c831b01c15d7d432f71afb1cf1634b53a2125 पर डिप्लॉय किया गया है।
UDC यह इंटरफ़ेस प्रदान करता है:
#[starknet::interface]
pub trait IUniversalDeployer {
fn deploy_contract(
class_hash: ClassHash,
salt: felt252,
not_from_zero: bool, // Determines deployment type
calldata: Span<felt252> // Constructor parameters
) -> ContractAddress;
}
पैरामीटर्स के साथ:
class_hash: डिप्लॉय किए जाने वाले कॉन्ट्रैक्ट का क्लास हैशsalt: एड्रेस गणना के लिए सॉल्ट वैल्यूnot_from_zero: एक बूलियन जो यह निर्धारित करता है कि डिप्लॉयर का एड्रेस कॉन्ट्रैक्ट एड्रेस की गणना में शामिल है या नहीं। जब यहtrueहोता है, तो इसे शामिल किया जाता है। जब यहfalseहोता है, तो इसे शामिल नहीं किया जाता है।calldata: नए डिप्लॉय किए गए कॉन्ट्रैक्ट के लिए कंस्ट्रक्टर पैरामीटर्स
ध्यान दें: वर्तमान UDC वर्ज़न में पुराने वर्ज़न्स के बदलाव शामिल हैं:
deployContractको snake_casedeploy_contractसे बदल दिया गया थाuniqueपैरामीटर कोnot_from_zero(इनवर्टेड (inverted) अर्थ के साथ) से बदल दिया गया था
UDC Deployment के प्रकार
UDC दो डिप्लॉयमेंट प्रकार प्रदान करता है जो यह निर्धारित करते हैं कि कॉन्ट्रैक्ट एड्रेस की गणना कैसे की जाती है, जिन्हें not_from_zero पैरामीटर द्वारा नियंत्रित किया जाता है:
- ओरिजिन-डिपेंडेंट डिप्लॉयमेंट (Origin-Dependent Deployment)
- ओरिजिन-इंडिपेंडेंट डिप्लॉयमेंट (Origin-Independent Deployment)
UDC, OpenZeppelin की कॉन्ट्रैक्ट्स लाइब्रेरी के एक यूटिलिटी फ़ंक्शन calculate_contract_address_from_udc का उपयोग करता है, जो स्टैण्डर्ड एड्रेस गणना को कॉल करने से पहले not_from_zero को UDC के एड्रेस या 0 पर मैप करता है:

- Origin-Dependent Deployment (
not_from_zero = true)
ओरिजिन-डिपेंडेंट डिप्लॉयमेंट का उपयोग करते समय, डिप्लॉयर का एड्रेस (udc_address) एड्रेस गणना का हिस्सा बन जाता है। यह एक “रिज़र्वड एड्रेस स्पेस (reserved address space)” बनाता है जहां केवल डिप्लॉय करने वाले अकाउंट का मालिक (caller_address) ही उन विशिष्ट एड्रेस पर कॉन्ट्रैक्ट्स को डिप्लॉय कर सकता है।
UDC पास किए गए salt को Pedersen हैश का उपयोग करके caller's address के साथ हैश करके मॉडिफाई करता है: hashed_salt = pedersen(caller_address, salt), फिर यह इस मॉडिफाइड सॉल्ट (hashed_salt) का उपयोग स्टैण्डर्ड कॉन्ट्रैक्ट एड्रेस गणना में निम्नलिखित के साथ करता है:
class_hash(डिप्लॉय की जा रही कॉन्ट्रैक्ट क्लास)constructor_calldata(कंस्ट्रक्टर पैरामीटर्स)deployer_info.udc_address(डिप्लॉयर के रूप में UDC कॉन्ट्रैक्ट का एड्रेस)
यह दृष्टिकोण एड्रेस रिज़र्वेशन प्रदान करता है, जिससे दूसरों को “आपके” एड्रेस पर डिप्लॉय करने से रोका जा सकता है। प्रत्येक डिप्लॉयर को अपना स्वयं का एड्रेस स्पेस मिलता है, और केवल आप ही अपने अकाउंट से प्राप्त (derived) एड्रेस पर डिप्लॉय कर सकते हैं। आप इस विधि को तब चुनेंगे जब आप यह सुनिश्चित करना चाहते हैं कि कोई और आपके इच्छित एड्रेस पर डिप्लॉय न कर सके।
- Origin-Independent Deployment (
not_from_zero = false)
ओरिजिन-इंडिपेंडेंट डिप्लॉयमेंट के साथ, कॉन्ट्रैक्ट एड्रेस की गणना इस बात से स्वतंत्र रूप से की जाती है कि उन्हें कौन डिप्लॉय करता है। एड्रेस केवल सॉल्ट, क्लास हैश और कंस्ट्रक्टर पैरामीटर्स पर निर्भर करता है।
UDC उस मूल (original) सॉल्ट का उपयोग करता है जिसे बिना किसी बदलाव के पास किया गया था और स्टैण्डर्ड कॉन्ट्रैक्ट एड्रेस गणना में डिप्लॉयर के रूप में 0 पास करता है।
यह डिप्लॉयर के पार (across) डिप्लॉयमेंट को डिटरमिनिस्टिक (deterministic) बनाता है, समान मापदंडों (parameters) के साथ समान कॉन्ट्रैक्ट को डिप्लॉय करने वाले किसी भी व्यक्ति को समान एड्रेस मिलता है। हालांकि, केवल पहला डिप्लॉयमेंट सफल होगा; समान मापदंडों के साथ बाद के प्रयास सफल नहीं होंगे क्योंकि एड्रेस पहले ही लिया जा चुका है। यह विधि तब अच्छी तरह से काम करती है जब आप चाहते हैं कि कॉन्ट्रैक्ट एड्रेस पूरी तरह से अनुमानित (predictable) हों, भले ही उन्हें कोई भी डिप्लॉय करे, जैसे कि कई नेटवर्क्स पर स्टैण्डर्ड कॉन्ट्रैक्ट्स डिप्लॉय करना।
UDC Deployment कैसे काम करता है
नया कॉन्ट्रैक्ट बनाने के लिए आपका अकाउंट कॉन्ट्रैक्ट UDC के deployContract फ़ंक्शन को एक INVOKE कॉल करता है:

deployContract फ़ंक्शन (नीचे नीले बॉक्स में दिखाया गया है) एक कैमेलकेस (camelcase) रैपर है जो अंडरलाइंग deploy_contract फ़ंक्शन (ऊपर मुख्य कोड ब्लॉक में दिखाया गया है) को कॉल करता है, जो पैरामीटर प्राप्त करता है: class_hash, salt, not_from_zero, calldata।
सीक्वेंसर आपके अकाउंट के INVOKE ट्रांज़ैक्शन को वैलिडेट करता है, UDC फिर get_caller_address() का उपयोग करके कॉलर का एड्रेस कैप्चर करता है, यह आपके उस अकाउंट का एड्रेस है जिसने INVOKE ट्रांज़ैक्शन शुरू किया था, और डिप्लॉयमेंट प्रकार के आधार पर सॉल्ट को मॉडिफाई करता है:
let final_salt = if not_from_zero {
pedersen(caller_address.into(), salt) // Origin-dependent: hash caller + salt
} else {
salt // Origin-independent: use original salt
};
मॉडिफाइड (अंतिम) सॉल्ट तैयार होने के साथ, UDC वास्तविक कॉन्ट्रैक्ट इंस्टेंस बनाने के लिए क्लास हैश, अंतिम सॉल्ट, कंस्ट्रक्टर कॉलडेटा, और डिप्लॉयमेंट प्रकार का उपयोग करके deploy_syscall() (लाल रंग में हाइलाइट किया गया) को रैप करता है।
सीक्वेंसर प्रदान किए गए आर्ग्यूमेंट्स के साथ कॉन्ट्रैक्ट के कंस्ट्रक्टर को निष्पादित करता है, और कॉल करने वाले अकाउंट (न कि नए डिप्लॉय किए गए कॉन्ट्रैक्ट) से डिप्लॉयमेंट फ़ीस चार्ज करता है।
सफल डिप्लॉयमेंट पर, UDC ट्रैकिंग उद्देश्यों के लिए नए कॉन्ट्रैक्ट एड्रेस, डिप्लॉयर, डिप्लॉयमेंट प्रकार, क्लास हैश, कॉलडेटा, और मूल सॉल्ट सहित डिप्लॉयमेंट जानकारी वाला एक ContractDeployed इवेंट (गुलाबी रंग में हाइलाइट किया गया) एमिट (emit) करता है। फिर फ़ंक्शन कॉलर को नया डिप्लॉय किया गया कॉन्ट्रैक्ट एड्रेस लौटाता है।
ध्यान दें: जब आप ऐसे कॉन्ट्रैक्ट्स डिप्लॉय करते हैं जो अपने कंस्ट्रक्टर में get_caller_address() का उपयोग करते हैं, तो याद रखें कि UDC कॉन्ट्रैक्ट को डिप्लॉय करता है, आपका अकाउंट सीधे नहीं। इसलिए, get_caller_address() UDC का एड्रेस लौटाता है, आपके अकाउंट का एड्रेस नहीं। यही कारण है कि हमने अपने टोकन कॉन्ट्रैक्ट उदाहरण में मालिक (owner) के एड्रेस को एक पैरामीटर के रूप में पास किया था।

Account Contracts के लिए UDC
हालांकि UDC का उपयोग मुख्य रूप से रेगुलर कॉन्ट्रैक्ट्स को डिप्लॉय करने के लिए किया जाता है, यह अकाउंट कॉन्ट्रैक्ट्स को भी डिप्लॉय कर सकता है जैसा कि पहले बताया गया है। इस मामले में, डिप्लॉय करने वाला अकाउंट फ़ीस का भुगतान करता है और नया अकाउंट कॉन्ट्रैक्ट ऑन-चेन डिप्लॉयर से लिंक हो जाता है। यह दृष्टिकोण तब उपयोगी होता है जब आपको नए अकाउंट के एकदम फ्रेश (pristine) होने की आवश्यकता नहीं होती है।
Account Contracts को Deploy करना: The DEPLOY_ACCOUNT Transaction
अपना पहला अकाउंट कॉन्ट्रैक्ट डिप्लॉय करना एक बूटस्ट्रैप समस्या (bootstrap problem) प्रस्तुत करता है: यदि आपके पास अभी तक कोई अकाउंट नहीं है तो आप डिप्लॉयमेंट के लिए भुगतान कैसे करेंगे?
Starknet इसे काउंटरफैक्चुअल (counterfactual) डिप्लॉयमेंट के माध्यम से हल करता है, जहां कॉन्ट्रैक्ट डिप्लॉय होने से पहले अकाउंट एड्रेस की गणना की जाती है और उसे फंड (fund) किया जाता है। “काउंटरफैक्चुअल” का अर्थ है कि एड्रेस को ऐसे माना जाता है जैसे कि वह ऑन-चेन वास्तव में अस्तित्व में आने से पहले से ही मौजूद है। सॉल्ट, क्लास हैश और कंस्ट्रक्टर कॉलडेटा पर आधारित एक डिटरमिनिस्टिक फॉर्मूले का उपयोग करके, आप पहले से एड्रेस की गणना कर सकते हैं, इसे फंड कर सकते हैं, और फिर कॉन्ट्रैक्ट को उसी सटीक एड्रेस पर डिप्लॉय कर सकते हैं।
प्रक्रिया:
- गणना करें कि डिप्लॉयमेंट से पहले अकाउंट एड्रेस क्या होगा
- प्री-कंप्यूटेड (pre-computed) एड्रेस को टोकन के साथ फंड करें (टेस्टनेट के लिए faucet के माध्यम से)
- एक
DEPLOY_ACCOUNTट्रांज़ैक्शन सबमिट करें
जब सीक्वेंसर को यह ट्रांज़ैक्शन प्राप्त होता है, तो यह:
- डिप्लॉयमेंट सिग्नेचर (signature) को वैलिडेट करता है
- प्रदान किए गए आर्ग्यूमेंट्स के साथ कंस्ट्रक्टर को चलाता है
- नए डिप्लॉय किए गए अकाउंट के एड्रेस से फ़ीस चार्ज करता है (बूटस्ट्रैप समाधान को पूरा करते हुए!)
यह विधि पहली बार अकाउंट बनाने के लिए आदर्श है क्योंकि अकाउंट प्री-फंडेड बैलेंस का उपयोग करके अपने स्वयं के डिप्लॉयमेंट के लिए भुगतान करता है, जिससे डिप्लॉयमेंट को स्पॉन्सर (sponsor) करने के लिए किसी मौजूदा अकाउंट कॉन्ट्रैक्ट की आवश्यकता समाप्त हो जाती है। अकाउंट कॉन्ट्रैक्ट्स को डिप्लॉय करने के लिए यह पसंदीदा तरीका है जब आप चाहते हैं कि अकाउंट बिल्कुल फ्रेश (pristine) हो, किसी अन्य अकाउंट से जुड़ा न हो, जैसे कि Ready या Braavos अकाउंट्स।
नीचे दी गई टेबल दोनों कॉन्ट्रैक्ट डिप्लॉयमेंट विधियों के बीच मुख्य अंतरों को संक्षेप में प्रस्तुत करती है:
| पहलू (Aspect) | DEPLOY_ACCOUNT transaction |
UDC विधि (Method) |
|---|---|---|
| उपयोग (Use case) | अकाउंट कॉन्ट्रैक्ट डिप्लॉयमेंट (स्वतंत्र, किसी भी डिप्लॉयर से लिंक नहीं) | रेगुलर कॉन्ट्रैक्ट डिप्लॉयमेंट, या अकाउंट कॉन्ट्रैक्ट डिप्लॉयमेंट (डिप्लॉयर से लिंक) |
| फ़ीस भुगतानकर्ता (Fee payer) | डिप्लॉय किया जा रहा अकाउंट (प्री-फंडेड) | आपका मौजूदा अकाउंट |
| Transaction type | DEPLOY_ACCOUNT |
INVOKE |
| deploy_syscall एक्सेस | प्रोटोकॉल-स्तर का मैकेनिज्म | UDC रैपर के माध्यम से |
| बूटस्ट्रैप समस्या | इसे हल करता है (किसी पूर्व अकाउंट की आवश्यकता नहीं) | मौजूदा अकाउंट की आवश्यकता है |
| एड्रेस का प्रकार | काउंटरफैक्चुअल (Counterfactual) | डिटरमिनिस्टिक (Deterministic) |
| परिणामी (Resulting) अकाउंट | बिल्कुल फ्रेश (Pristine), किसी अन्य अकाउंट से लिंक नहीं | ऑन-चेन डिप्लॉयर से लिंक |
निष्कर्ष (Wrapping Up)
इस लेख में, हमने यह पता लगाया कि कैसे Starknet का डिक्लेयर-डिप्लॉय मॉडल कॉन्ट्रैक्ट कोड को स्टेट (state) से अलग करता है, जो DECLARE, INVOKE, और DEPLOY_ACCOUNT ट्रांज़ैक्शन प्रकारों के माध्यम से कुशल डिप्लॉयमेंट को सक्षम करता है। हमने जांच की कि डिक्लेरेशन के दौरान Sierra और CASM एक साथ कैसे काम करते हैं, और डिप्लॉयमेंट के दोनों तरीके (स्वतंत्र रूप से मौजूद अकाउंट्स के लिए DEPLOY_ACCOUNT और रेगुलर कॉन्ट्रैक्ट्स के लिए Universal Deployer Contract) विभिन्न उपयोग के मामलों को कैसे संभालते हैं।
अगले लेख में, हम sncast और Starknet.js दोनों का उपयोग करके हमारे पिछले गाइड से ERC-20 कॉन्ट्रैक्ट को डिप्लॉय करने की प्रक्रिया से गुजरेंगे, और आपको दिखाएंगे कि अपने डिप्लॉय किए गए कॉन्ट्रैक्ट्स के साथ कैसे इंटरैक्ट (interact) करना है।