Pragma एक oracle प्रोटोकॉल है जिसे Starknet के लिए बनाया गया है, जो off-chain प्राइस डेटा को on-chain लाता है। यह प्राइस फीड और कंप्यूटेशनल फीड (जैसे yield curves और volatility डेटा) प्रदान करता है।
इस आर्टिकल में, आप सीखेंगे कि Pragma के प्राइस फीड oracle को अपने Cairo कॉन्ट्रैक्ट में कैसे इंटीग्रेट किया जाए।
Pragma कैसे काम करता है, इसका एक ओवरव्यू
प्राइस फीड को इंटीग्रेट करने से पहले, आइए समझते हैं कि Pragma उच्च स्तर (high level) पर कैसे काम करता है।
Pragma कई स्वतंत्र स्रोतों से प्राइस डेटा एकत्र करता है और विश्वसनीय, हेरफेर-मुक्त (manipulation-resistant) प्राइस फीड प्रदान करने के लिए उन्हें on-chain एग्रीगेट करता है। मुख्य अंतर यह है कि Pragma Starknet पर सीधे सभी एग्रीगेशन करता है, जिससे पूरी प्रक्रिया पारदर्शी और सत्यापन योग्य (verifiable) हो जाती है।
Pragma एक टू-टियर सिस्टम के माध्यम से डेटा को एग्रीगेट करता है:
-
Sources वास्तविक एक्सचेंज, डेटा प्रदाता और मार्केट हैं जहां से कीमतें उत्पन्न होती हैं, जैसे Binance, Coinbase, OKX, Ekubo, Chainlink, आदि।
-
Publishers वे संस्थाएं (entities) हैं जिन्हें Pragma की एडमिन-कंट्रोल्ड रजिस्ट्री द्वारा व्हाइटलिस्ट किया गया है। वे विभिन्न स्रोतों से कीमतों की निगरानी करते हैं और इस डेटा को oracle कॉन्ट्रैक्ट में सबमिट करते हैं। आप Pragma के पब्लिशर रजिस्ट्री कॉन्ट्रैक्ट में पब्लिशर्स की पूरी सूची पा सकते हैं। इस लेख को लिखते समय, वर्तमान publishers में निम्नलिखित शामिल हैं:

प्रत्येक पब्लिशर स्वतंत्र रूप से कई स्रोतों की निगरानी करता है और oracle कॉन्ट्रैक्ट में प्राइस डेटा सबमिट करता है। फिर Pragma का oracle सभी पब्लिशर्स के सबमिशन को एग्रीगेट करता है। यदि कोई पब्लिशर आउटलायर (outlier) प्राइस रिपोर्ट करता है, तो Pragma का एग्रीगेशन उसे बाहर कर देता है।
उदाहरण के लिए, यहां वे स्रोत दिए गए हैं जिनकी निगरानी ARGENT पब्लिशर करता है:

इसलिए जब ARGENT (एक पब्लिशर) किसी प्राइस को रिपोर्ट करना चाहता है, तो वह ऊपर लाल बॉक्स में हाइलाइट किए गए कई स्रोतों की निगरानी करता है और देखे गए प्राइस डेटा को Pragma के oracle कॉन्ट्रैक्ट में सबमिट करता है।
स्रोतों से आपके कॉन्ट्रैक्ट तक प्राइस डेटा कैसे फ्लो होता है
-
डेटा कलेक्शन (Data Collection)
पब्लिशर्स अपने असाइन किए गए स्रोतों (एक्सचेंज, oracles, डेटा प्रदाता) की निगरानी करते हैं और वर्तमान प्राइस ऑब्जरवेशन एकत्र करते हैं।
-
On-Chain सबमिशन
पब्लिशर्स एकत्र किए गए डेटा पर टाइमस्टैम्प लगाते हैं, फिर इसे सीधे Starknet पर Pragma के oracle कॉन्ट्रैक्ट में सबमिट करते हैं। कोई केंद्रीकृत off-chain एग्रीगेशन लेयर नहीं है; प्रत्येक पब्लिशर स्वतंत्र रूप से अपना डेटा on-chain सबमिट करता है जहां इसे सार्वजनिक रूप से सत्यापित (verify) किया जा सकता है। उदाहरण के लिए, यदि 10 पब्लिशर्स ETH प्राइस सबमिट करते हैं, तो Pragma के पास काम करने के लिए on-chain 10 डेटा पॉइंट होते हैं।
-
प्राइस कैलकुलेशन
Pragma अंतिम कीमत की गणना करने के लिए दो-चरणीय एग्रीगेशन प्रक्रिया का उपयोग करता है:
- प्रति स्रोत एग्रीगेट करना (Aggregate per source): प्रत्येक व्यक्तिगत स्रोत (जैसे Binance) के लिए, Pragma उन सभी पब्लिशर्स से मीडियन (median) कीमत की गणना करता है जिन्होंने उस स्रोत के लिए डेटा रिपोर्ट किया है। उदाहरण के लिए, यदि तीन पब्लिशर्स में से प्रत्येक ETH/USD कीमत सबमिट करता है जो उन्होंने Binance से देखी है, तो Pragma Binance के लिए एक एकल सर्वसम्मति (consensus) कीमत प्राप्त करने के लिए उन तीन मानों का मीडियन लेता है।
- स्रोतों के पार एग्रीगेट करना (Aggregate across sources): प्रत्येक स्रोत (Binance, Coinbase, OKX, आदि) से सर्वसम्मति (consensus) मूल्य प्राप्त करने के बाद, आपका स्मार्ट कॉन्ट्रैक्ट यह चुन सकता है कि इन स्रोत कीमतों को अंतिम मूल्य में कैसे संयोजित किया जाए। आप अपनी आवश्यकताओं के आधार पर मीडियन (median), मीन (mean), टाइम वेटेड एवरेज प्राइस (TWAP), या अन्य एग्रीगेशन विधियों का उपयोग कर सकते हैं।
-
स्मार्ट कॉन्ट्रैक्ट क्वेरी
आपका कॉन्ट्रैक्ट वर्तमान ETH/USD कीमत के लिए Pragma के oracle से क्वेरी करता है और एक टाइमस्टैम्प के साथ एग्रीगेटेड कीमत प्राप्त करता है।
इस पूरे फ्लो का सारांश यहां दिया गया है:

प्राइस कंडीशन के साथ एक सिंपल वॉल्ट (Vault) बनाना
आइए एक बुनियादी वॉल्ट कॉन्ट्रैक्ट बनाएं जहां उपयोगकर्ता STRK टोकन जमा (deposit) कर सकते हैं, लेकिन वे केवल तभी निकाल (withdraw) सकते हैं जब STRK की कीमत एक निश्चित सीमा (threshold) तक पहुंच जाए।
इस वॉल्ट में डिपॉजिट और विड्रॉल कैसे काम करते हैं, इसका एक विज़ुअल फ्लो यहां दिया गया है:

प्रोजेक्ट सेटअप करना
एक नया scarb प्रोजेक्ट बनाएं और डायरेक्टरी में नेविगेट करें:
scarb new simple_vault
cd simple_vault
Scarb.toml खोलें और [dependencies] अनुभाग के अंतर्गत Pragma oracle लाइब्रेरी को एक डिपेंडेंसी के रूप में जोड़ें:
[dependencies]
pragma_lib = { git = "https://github.com/astraly-labs/pragma-lib" }

अब डिपेंडेंसी डाउनलोड करने और प्रोजेक्ट सही ढंग से सेट अप होने की पुष्टि करने के लिए scarb build रन करें। पहली बार रन करने पर इसमें एक मिनट लग सकता है क्योंकि यह डिपेंडेंसीज़ डाउनलोड करता है। एक बार बिल्ड सफल हो जाने पर, हम वॉल्ट कॉन्ट्रैक्ट लिखना शुरू करने के लिए तैयार हैं।
Vault इंटरफेस को परिभाषित करना
सबसे पहले, हम अपने वॉल्ट कॉन्ट्रैक्ट के लिए इंटरफ़ेस परिभाषित करते हैं। यह उन सभी फ़ंक्शन्स को निर्दिष्ट करता है जिन्हें हमारा वॉल्ट एक्सपोज़ करेगा:
deposit(amount): वॉल्ट में STRK टोकन लॉक करने के लिएwithdraw(): STRK टोकन वापस प्राप्त करने के लिए (केवल तभी जब प्राइस कंडीशन पूरी हो)get_balance(user): यह जांचने के लिए कि किसी विशिष्ट उपयोगकर्ता ने कितना STRK जमा किया हैget_strk_price(): Pragma oracle से वर्तमान STRK/USD कीमत की क्वेरी करने के लिए
use starknet::ContractAddress;
#[starknet::interface]
trait ISimpleVault<TContractState> {
fn deposit(ref self: TContractState, amount: u256);
fn withdraw(ref self: TContractState);
fn get_balance(self: @TContractState, user: ContractAddress) -> u256;
fn get_strk_price(self: @TContractState) -> u128;
}
ERC20 इंटरफेस को परिभाषित करना
चूंकि वॉल्ट को डिपॉजिट और विड्रॉल के दौरान STRK टोकन ट्रांसफर करने की आवश्यकता होती है, इसलिए हमें उपयोगकर्ताओं से वॉल्ट में टोकन ले जाने के लिए transfer_from के साथ और वॉल्ट से उपयोगकर्ताओं को टोकन वापस करने के लिए transfer के साथ एक ERC-20 इंटरफ़ेस परिभाषित करने की आवश्यकता है:
#[starknet::interface]
trait IERC20<TContractState> {
fn transfer_from(
ref self: TContractState,
sender: ContractAddress,
recipient: ContractAddress,
amount: u256
) -> bool;
fn transfer(ref self: TContractState, recipient: ContractAddress, amount: u256) -> bool;
}
कॉन्ट्रैक्ट इम्पोट्स (Contract Imports)
कॉन्ट्रैक्ट मॉड्यूल घोषित करके और आवश्यक प्रकारों (types), विशेषताओं (traits) और फ़ंक्शन्स को इम्पोर्ट करके प्रारंभ करें:
#[starknet::contract]
mod SimpleVault {
use starknet::{ContractAddress, get_caller_address};
use pragma_lib::abi::{IPragmaABIDispatcher, IPragmaABIDispatcherTrait};
use pragma_lib::types::{DataType, PragmaPricesResponse};
use starknet::storage::{Map, StoragePathEntry, StoragePointerReadAccess, StoragePointerWriteAccess};
use super::{IERC20Dispatcher, IERC20DispatcherTrait};
ध्यान देने योग्य मुख्य इम्पोट्स pragma_lib से हैं:
IPragmaABIDispatcherऔरIPragmaABIDispatcherTrait: Pragma के oracle कॉन्ट्रैक्ट पर फ़ंक्शन्स को कॉल करने के लिए कॉन्ट्रैक्ट डिस्पैचर और ट्रेटDataType: निर्दिष्ट करता है कि हम किस प्रकार का डेटा चाहते हैं (वर्तमान बाजार मूल्य के लिए स्पॉट प्राइस)PragmaPricesResponse: Pragma द्वारा लौटाई गई प्राइस जानकारी रखता है
कॉन्ट्रैक्ट कॉन्स्टेंट्स (Constants) को परिभाषित करना
हम दो प्रमुख कॉन्स्टेंट्स परिभाषित करते हैं:
// Constants
const STRK_USD_PAIR_ID: felt252 = 6004514686061859652; // STRK/USD pair ID from Pragma
const PRICE_THRESHOLD: u128 = 16000000; // $0.16 in 8 decimals (0.16 * 10^8)
STRK_USD_PAIR_ID पहचानता है कि किस Pragma प्राइस फीड से क्वेरी करनी है। इस मामले में, हम STRK/USD फीड की क्वेरी कर रहे हैं। पेयर ID 6004514686061859652 अपरकेस टिकर स्ट्रिंग 'STRK/USD' की UTF-8 एन्कोडिंग से मेल खाता है। इसका मतलब है कि पेयर ID कॉन्स्टेंट को अधिक पठनीय (readably) रूप में इस प्रकार लिखा जा सकता है:
const STRK_USD_PAIR_ID: felt252 = 'STRK/USD';
यही पैटर्न अन्य प्राइस पेयर्स पर भी लागू होता है। प्रत्येक पेयर ID केवल उसके अपरकेस टिकर स्ट्रिंग की UTF-8 एन्कोडिंग है। उदाहरण के लिए, 'ETH/USD' को स्ट्रिंग 'ETH/USD' या इसके felt252 संख्यात्मक मान 19514442401534788 के रूप में लिखा जा सकता है, Cairo में दोनों समान हैं। अन्य एसेट पेयर IDs Pragma के price feeds डॉक्यूमेंटेशन में उपलब्ध हैं। प्रत्येक एसेट पेयर की अपनी अनूठी ID और डेसीमल सटीकता (decimal precision) होती है; एक अलग पेयर चुनते समय Decimals कॉलम की जांच करना सुनिश्चित करें। Sepolia टेस्टनेट और मेननेट दोनों के लिए समान पेयर ID का उपयोग किया जाता है।

PRICE_THRESHOLD विड्रॉल के लिए आवश्यक न्यूनतम STRK कीमत ($0.16) निर्धारित करता है। चूंकि Pragma 8 दशमलव सटीकता के साथ STRK कीमतें लौटाता है, इसलिए हम $0.16 को 16,000,000 (0.16 × 10^8) के रूप में दर्शाते हैं।
कॉन्ट्रैक्ट स्टोरेज को परिभाषित करना
स्टोरेज स्ट्रक्ट परिभाषित करता है कि हमारा कॉन्ट्रैक्ट कौन सा डेटा स्टोर करता है:
#[storage]
struct Storage {
pragma_oracle: ContractAddress, //pragma_oracle contract address
strk_token: ContractAddress, // strk token contract address
balances: Map<ContractAddress, u256>, // user balances
}
हम क्या स्टोर कर रहे हैं:
pragma_oracle: Starknet पर Pragma के oracle कॉन्ट्रैक्ट का एड्रेस, जिसका उपयोग लाइव एसेट प्राइस लाने के लिए किया जाता हैstrk_token: STRK टोकन कॉन्ट्रैक्ट का एड्रेस, जिसका उपयोग डिपॉजिट और विड्रॉल को संभालने के लिए किया जाता हैbalances: उपयोगकर्ता के एड्रेस से उनके जमा किए गए STRK अमाउंट की मैपिंग
कॉन्ट्रैक्ट को इनिशियलाइज़ (Initialize) करना
स्टोरेज परिभाषित होने के साथ, हम डिप्लॉयमेंट के दौरान कंस्ट्रक्टर को Pragma oracle और STRK टोकन एड्रेस पास करके कॉन्ट्रैक्ट को इनिशियलाइज़ करते हैं:
#[constructor]
fn constructor(
ref self: ContractState,
pragma_oracle: ContractAddress,
strk_token: ContractAddress
) {
self.pragma_oracle.write(pragma_oracle);
self.strk_token.write(strk_token);
}
ये एड्रेस वॉल्ट कॉन्ट्रैक्ट को Pragma के oracle से कीमतों की क्वेरी करने और STRK टोकन ट्रांसफर्स को संभालने की अनुमति देते हैं, जैसा कि हम तब देखेंगे जब हम deposit और withdraw फ़ंक्शन्स पर चर्चा करेंगे।
कॉन्ट्रैक्ट इवेंट्स को परिभाषित करना
आगे, हम वॉल्ट में डिपॉजिट (Deposit) और विड्रॉल (Withdrawal) को ट्रैक करने के लिए इवेंट्स को परिभाषित करते हैं:
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
Deposit: Deposit,
Withdrawal: Withdrawal,
}
#[derive(Drop, starknet::Event)]
struct Deposit {
user: ContractAddress,
amount: u256,
}
#[derive(Drop, starknet::Event)]
struct Withdrawal {
user: ContractAddress,
amount: u256,
}
प्रत्येक इवेंट उपयोगकर्ता का एड्रेस और कितना STRK जमा किया गया या निकाला गया, यह लॉग करता है।
इंटरफेस फ़ंक्शन्स को इम्प्लीमेंट करना
अब, आइए उन वॉल्ट इंटरफ़ेस फ़ंक्शन्स को इम्प्लीमेंट करें जिन्हें हमने पहले परिभाषित किया था:
deposit फ़ंक्शन
जब कोई उपयोगकर्ता deposit(amount) कॉल करता है, तो फ़ंक्शन यह सत्यापित करता है कि राशि शून्य से अधिक है, फिर यह उपयोगकर्ता के खाते से वॉल्ट में STRK टोकन ले जाने के लिए transfer_from का उपयोग करता है। इसके लिए उपयोगकर्ता को वॉल्ट कॉन्ट्रैक्ट को पहले से अप्रूव करना आवश्यक है। ट्रांसफर सफल होने के बाद, स्टोरेज में उपयोगकर्ता का बैलेंस अपडेट किया जाता है और एक Deposit इवेंट एमिट (emit) होता है।
fn deposit(ref self: ContractState, amount: u256) {
let caller = get_caller_address();
assert(amount > 0, 'Amount must be greater than 0');
// Transfer STRK from user to this contract
let strk = IERC20Dispatcher { contract_address: self.strk_token.read() };
let success = strk.transfer_from(caller, starknet::get_contract_address(), amount);
assert(success, 'Transfer failed');
// Update user balance
let current_balance = self.balances.entry(caller).read();
self.balances.entry(caller).write(current_balance + amount);
// Emit deposit event
self.emit(Deposit { user: caller, amount });
}
withdraw फ़ंक्शन
विड्रॉल फ़ंक्शन यह सुनिश्चित करता है कि उपयोगकर्ता के पास एक गैर-शून्य (non-zero) बैलेंस है, फिर यह Pragma से वर्तमान STRK कीमत प्राप्त करता है। यदि कीमत $0.16 के बराबर या उससे अधिक है, तो यह उपयोगकर्ता के बैलेंस को रीसेट करता है (checks-effects-interactions पैटर्न का पालन करते हुए), उनके STRK टोकन को वापस उनके खाते में ट्रांसफर करता है, और एक Withdrawal इवेंट एमिट करता है।
fn withdraw(ref self: ContractState) {
let caller = get_caller_address();
let balance = self.balances.entry(caller).read();
assert(balance > 0, 'No balance to withdraw');
// Get current STRK price
let current_price = self.get_strk_price();
// Check if price threshold is met
assert(current_price >= PRICE_THRESHOLD, 'Price threshold not met');
// Reset balance before transfer (CEI pattern)
self.balances.entry(caller).write(0);
// Transfer STRK back to user
let strk = IERC20Dispatcher { contract_address: self.strk_token.read() };
let success = strk.transfer(caller, balance);
assert(success, 'Transfer failed');
// Emit withdrawal event
self.emit(Withdrawal { user: caller, amount: balance });
}
get_balance फ़ंक्शन
यह लौटाता है कि किसी विशिष्ट उपयोगकर्ता ने वॉल्ट में कितना STRK जमा किया है:
fn get_balance(self: @ContractState, user: ContractAddress) -> u256 {
self.balances.entry(user).read()
}
get_strk_price फ़ंक्शन
Pragma oracle से वर्तमान STRK/USD कीमत प्राप्त करता है:
fn get_strk_price(self: @ContractState) -> u128 {
let oracle = IPragmaABIDispatcher { contract_address: self.pragma_oracle.read() };
let response: PragmaPricesResponse = oracle.get_data_median(DataType::SpotEntry(STRK_USD_PAIR_ID));
response.price
}
सबसे पहले, यह स्टोर किए गए एड्रेस का उपयोग करके Pragma oracle कॉन्ट्रैक्ट के साथ इंटरैक्ट करने के लिए एक कॉन्ट्रैक्ट डिस्पैचर बनाता है:
let oracle = IPragmaABIDispatcher { contract_address: self.pragma_oracle.read() };
फिर यह get_data_median() को कॉल करता है, जिसमें DataType::SpotEntry(STRK_USD_PAIR_ID) पास करके STRK/USD के लिए वर्तमान स्पॉट प्राइस का अनुरोध किया जाता है। यह विधि कई पब्लिशर्स से डेटा एग्रीगेट करती है और मीडियन लौटाती है, जो किसी भी एकल स्रोत को परिणाम में हेरफेर करने से रोकता है:
let response: PragmaPricesResponse = oracle.get_data_median(DataType::SpotEntry(STRK_USD_PAIR_ID));
get_data_median() निम्नलिखित फ़ील्ड्स के साथ एक PragmaPricesResponse स्ट्रक्ट लौटाता है:
struct PragmaPricesResponse {
price: u128, // The aggregated price
decimals: u32, // Number of decimal places
last_updated_timestamp: u64, // When the price was last updated
num_sources_aggregated: u32, // Number of sources used in aggregation
expiration_timestamp: Option<u64>, // Optional expiration time
}
get_strk_price इस स्ट्रक्ट से केवल price फ़ील्ड लौटाता है:
response.price
कीमत 8 दशमलव सटीकता के साथ एक u128 के रूप में लौटाई जाती है। उदाहरण के लिए, यदि STRK $0.15 पर ट्रेड कर रहा है, तो यह 15000000 लौटाता है (चूंकि Pragma 8 दशमलव स्थानों का उपयोग करता है: 0.15 × 10^8)।
get_data_median()का उपयोग करके, हम Pragma के डिफ़ॉल्ट प्रारंभिक एग्रीगेशन (सभी पब्लिशर्स द्वारा सबमिट की गई कीमतों का मीडियन) को स्वीकार कर रहे हैं। चूंकि हम एक एकल पेयर की क्वेरी कर रहे हैं, STRK/USD के लिए सभी पब्लिशर्स का मीडियन हमारी अंतिम कीमत है।
पूरा वॉल्ट कॉन्ट्रैक्ट lib.cairo में कॉपी करें, और scarb build का उपयोग करके कंपाइल करें:
use starknet::ContractAddress;
#[starknet::interface]
trait IERC20<TContractState> {
fn transfer_from(
ref self: TContractState,
sender: ContractAddress,
recipient: ContractAddress,
amount: u256
) -> bool;
fn transfer(ref self: TContractState, recipient: ContractAddress, amount: u256) -> bool;
}
#[starknet::interface]
trait ISimpleVault<TContractState> {
fn deposit(ref self: TContractState, amount: u256);
fn withdraw(ref self: TContractState);
fn get_balance(self: @TContractState, user: ContractAddress) -> u256;
fn get_strk_price(self: @TContractState) -> u128;
}
#[starknet::contract]
mod SimpleVault {
use starknet::{ContractAddress, get_caller_address};
use pragma_lib::abi::{IPragmaABIDispatcher, IPragmaABIDispatcherTrait};
use pragma_lib::types::{DataType, PragmaPricesResponse};
use starknet::storage::{Map, StoragePathEntry, StoragePointerReadAccess, StoragePointerWriteAccess};
// Add this import for the ERC20 dispatcher
use super::{IERC20Dispatcher, IERC20DispatcherTrait};
// Constants
const STRK_USD_PAIR_ID: felt252 = 6004514686061859652; // STRK/USD pair ID
const PRICE_THRESHOLD: u128 = 16000000; // $0.16 in 8 decimals(0.16 * 10^8)
#[storage]
struct Storage {
pragma_oracle: ContractAddress,
strk_token: ContractAddress,
balances: Map<ContractAddress, u256>,
}
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
Deposit: Deposit,
Withdrawal: Withdrawal,
}
#[derive(Drop, starknet::Event)]
struct Deposit {
user: ContractAddress,
amount: u256,
}
#[derive(Drop, starknet::Event)]
struct Withdrawal {
user: ContractAddress,
amount: u256,
}
#[constructor]
fn constructor(
ref self: ContractState,
pragma_oracle: ContractAddress,
strk_token: ContractAddress
) {
self.pragma_oracle.write(pragma_oracle);
self.strk_token.write(strk_token);
}
#[abi(embed_v0)]
impl SimpleVaultImpl of super::ISimpleVault<ContractState> {
fn deposit(ref self: ContractState, amount: u256) {
let caller = get_caller_address();
assert(amount > 0, 'Amount must be greater than 0');
// Transfer STRK from user to this contract
let strk = IERC20Dispatcher { contract_address: self.strk_token.read() };
let success = strk.transfer_from(caller, starknet::get_contract_address(), amount);
assert(success, 'Transfer failed');
// Update user balance
let current_balance = self.balances.entry(caller).read();
self.balances.entry(caller).write(current_balance + amount);
// Emit deposit event
self.emit(Deposit { user: caller, amount });
}
fn withdraw(ref self: ContractState) {
let caller = get_caller_address();
let balance = self.balances.entry(caller).read();
assert(balance > 0, 'No balance to withdraw');
// Get current STRK price
let current_price = self.get_strk_price();
// Check if price threshold is met
assert(current_price >= PRICE_THRESHOLD, 'Price threshold not met');
// Reset balance before transfer (CEI pattern)
self.balances.entry(caller).write(0);
// Transfer STRK back to user
let strk = IERC20Dispatcher { contract_address: self.strk_token.read() };
let success = strk.transfer(caller, balance);
assert(success, 'Transfer failed');
// Emit withdrawal event
self.emit(Withdrawal { user: caller, amount: balance });
}
fn get_balance(self: @ContractState, user: ContractAddress) -> u256 {
self.balances.entry(user).read()
}
fn get_strk_price(self: @ContractState) -> u128 {
let oracle = IPragmaABIDispatcher { contract_address: self.pragma_oracle.read() };
let response: PragmaPricesResponse = oracle.get_data_median(DataType::SpotEntry(STRK_USD_PAIR_ID));
response.price
}
}
}
Vault कॉन्ट्रैक्ट को डिप्लॉय करना
सबसे पहले, sncast का उपयोग करके कॉन्ट्रैक्ट डिक्लेयर (declare) करें:
sncast --account <YOUR_ACCOUNT_NAME> \
declare \
--url https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_10/<YOUR_API_KEY> \
--contract-name SimpleVault

Pragma डिप्लॉयमेंट के लिए आवश्यक दो एड्रेस प्रदान करता है। हम उन्हें कंस्ट्रक्टर में पैरामीटर्स के रूप में पास करेंगे:
- Pragma Oracle:
0x036031daa264c24520b11d93af622c848b2499b66b41d611bac95e13cfca131a - STRK Token:
0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d
आप नवीनतम डिप्लॉयमेंट एड्रेस Pragma’s GitHub repository में पा सकते हैं।
कंस्ट्रक्टर पैरामीटर्स के साथ कॉन्ट्रैक्ट को डिप्लॉय करें:
sncast \
--account new_account1 \
deploy \
--url https://starknet-sepolia.g.alchemy.com/starknet/version/rpc/v0_10/<YOUR_API_KEY> \
--class-hash <CLASS_HASH> \
--constructor-calldata "0x036031daa264c24520b11d93af622c848b2499b66b41d611bac95e13cfca131a" "0x04718f5a0Fc34cC1AF16A1cdee98fFB20C31f5cD61D6Ab07201858f4287c938D"
डिक्लेयर आउटपुट से <CLASS_HASH> कॉपी करें और इसे डिप्लॉय कमांड में पेस्ट करें। टर्मिनल एक ट्रांजैक्शन रसीद प्रदर्शित करेगा जिसमें डिप्लॉय किए गए वॉल्ट कॉन्ट्रैक्ट का एड्रेस होगा।

अगले चरणों के लिए एड्रेस को सेव कर लें।
Vault के साथ इंटरैक्ट करना
वॉल्ट डिप्लॉय होने के बाद, आइए Voyager का उपयोग करके STRK टोकन जमा करने और निकालने की प्रक्रिया से गुजरते हैं।
Vault को अप्रूव करना
जमा करने से पहले, वॉल्ट को STRK टोकन ट्रांसफर करने के लिए अप्रूव किया जाना चाहिए। Voyager पर STRK टोकन कॉन्ट्रैक्ट के “Write Contract” टैब पर नेविगेट करें और स्पेंडर (spender) के रूप में वॉल्ट के कॉन्ट्रैक्ट एड्रेस और जितना STRK आप जमा करना चाहते हैं, उस राशि के साथ approve फ़ंक्शन को कॉल करें। एक बार हो जाने के बाद, ट्रांजैक्शन को निष्पादित (execute) करें और पुष्टि की प्रतीक्षा करें।

डिपॉजिट करना
अप्रूवल मिलने के बाद, अब टोकन जमा किए जा सकते हैं। वॉल्ट कॉन्ट्रैक्ट के “Write Contract” टैब पर, आपके द्वारा पहले अप्रूव की गई राशि के साथ deposit फ़ंक्शन को कॉल करें। इस ट्रांजैक्शन को निष्पादित करने के बाद, STRK टोकन वॉल्ट में लॉक हो जाते हैं।

बैलेंस चेक करना
यह सत्यापित करने के लिए कि डिपॉजिट सफल रहा, “Read Contract” टैब पर नेविगेट करें और वॉलेट एड्रेस के साथ get_balance को कॉल करें। यह बैलेंस लौटाएगा, जो STRK डिपॉजिट की पुष्टि करेगा।

वर्तमान STRK प्राइस चेक करना
Pragma से वर्तमान STRK कीमत की जांच करने के लिए “Read Contract” टैब में get_strk_price को कॉल करें। फ़ंक्शन कीमत को 8 दशमलव स्थानों के साथ एक पूर्णांक (integer) के रूप में लौटाता है। इसे USD मान में बदलने के लिए, लौटाई गई संख्या को 100,000,000 से विभाजित करें।

उदाहरण के लिए, यहां फ़ंक्शन 14716561 लौटाता है। 100,000,000 से विभाजित करने पर:
14716561 ÷ 100,000,000 = 0.14716561
इसलिए क्वेरी के इस समय वर्तमान STRK कीमत $0.147 है।
विड्रॉल का प्रयास करना
अब जमा किए गए STRK को निकालने का प्रयास करें। “Write Contract” टैब में, withdraw फ़ंक्शन को कॉल करें और ट्रांजैक्शन निष्पादित करें।
परिणाम वर्तमान कीमत पर निर्भर करता है। यदि STRK $0.16 से नीचे है, तो ट्रांजैक्शन “Price threshold not met.” एरर मैसेज के साथ विफल हो जाएगा। यदि STRK $0.16 या उससे अधिक तक पहुंच गया है, तो टोकन वॉलेट में वापस आ जाएंगे।

एक सफल विड्रॉल का तुरंत परीक्षण करने के लिए, कॉन्ट्रैक्ट को फिर से डिक्लेयर किया जा सकता है और 10000000 ($0.10 का प्रतिनिधित्व करने वाले) जैसे कम थ्रेसहोल्ड के साथ फिर से डिप्लॉय किया जा सकता है, या कोई STRK की कीमत के स्वाभाविक रूप से $0.16 से ऊपर उठने की प्रतीक्षा कर सकता है।
निष्कर्ष
Pragma के प्राइस फीड्स को इंटीग्रेट करने से लेंडिंग प्रोटोकॉल, प्रेडिक्शन मार्केट्स, डायनामिक NFTs और अन्य एप्लिकेशन on-chain सत्यापित प्राइस डेटा तक पहुंचने में सक्षम होते हैं। अभी, वॉल्ट केवल कीमत के आधार पर फंड को लॉक और रिलीज़ करता है। कीमत की स्थिति के अलावा कोई यिल्ड (yield) या रिवॉर्ड मैकेनिज्म नहीं है। कॉन्ट्रैक्ट को उन सुविधाओं के साथ बढ़ाया जा सकता है जो विशिष्ट उपयोग के मामलों में फिट बैठती हैं: डिपॉजिटर्स के लिए स्टेकिंग रिवॉर्ड्स, विभिन्न उपयोगकर्ता स्तरों (tiers) के लिए कई प्राइस थ्रेसहोल्ड, या टाइम-वेटेड अनलॉक्स।
Pragma के computational feeds स्पॉट प्राइस से कहीं अधिक प्रदान करते हैं। वोलैटिलिटी फीड्स जोखिम-समायोजित (risk-adjusted) प्रोटोकॉल के लिए बाजार की उथल-पुथल को मापते हैं। TWAP फ़्लैशलोन हमलों से होने वाले हेरफेर के खिलाफ प्रतिरोधी टाइम-एवरेज्ड कीमतें प्रदान करता है। इन फीड्स को एक्सप्लोर करना, विभिन्न एसेट पेयर्स को आज़माना, और शर्तों को जोड़ना यह उजागर करता है कि oracles वास्तविक दुनिया की स्थितियों में गतिशील रूप से प्रतिक्रिया देने के लिए कॉन्ट्रैक्ट्स को कैसे बदलते हैं।