الاتصال بمحفظة المستخدم: كتابة كود يطلب من الزائر ربط محفظة MetaMask بموقعك
الاتصال بمحفظة المستخدم: لماذا تعد هذه الخطوة حجر الأساس في تطبيقات Web3؟
عند بناء أي واجهة لامركزية، فإن أول نقطة تفاعل حقيقية بين المستخدم وموقعك هي طلب ربط محفظته، وغالباً عبر MetaMask. هذه العملية لا تعني إرسال أموال أو تنفيذ معاملة، بل تعني منح الموقع صلاحية قراءة عنوان المحفظة والحسابات المصرح بها داخل المتصفح.
من الناحية المعمارية، تعمل MetaMask كموفر Provider يحقن الكائن window.ethereum داخل الصفحة. ومن خلاله يستطيع تطبيقك التحدث مع شبكة Ethereum أو أي شبكة متوافقة مع EVM.
إذا كنت تريد فهم الخلفية الأعمق لفكرة الويب اللامركزي، فمقال مدخل إلى Web3: ما هو البلوكتشين ولماذا يغير شكل الإنترنت والأنظمة المالية؟ يمنحك الصورة المفاهيمية الكاملة. أما تجهيز المحفظة نفسها فيبدأ عملياً من إعداد بيئة التطوير: تثبيت محفظة MetaMask والاتصال بشبكات الاختبار (Testnets).
كيف تعمل آلية طلب الاتصال تقنياً؟
حين يضغط المستخدم زر “ربط المحفظة”، يقوم موقعك بإرسال طلب إلى Provider باستخدام الاستدعاء eth_requestAccounts. عندها تظهر نافذة منبثقة من MetaMask تطلب من المستخدم الموافقة على مشاركة عنوانه مع الموقع.
إذا وافق المستخدم، يعيد الطلب مصفوفة من الحسابات، وعادة يتم استخدام أول عنصر فيها بوصفه الحساب النشط. هذا العنوان لا يمنح تطبيقك حق التوقيع التلقائي، بل يظل كل توقيع أو معاملة لاحقة بحاجة إلى موافقة صريحة من المستخدم.
هذه النقطة مرتبطة مباشرة بمفاهيم المفاتيح العامة والخاصة، والتي تم شرحها بعمق في مقال التشفير والمفاتيح: كيف تعمل المحافظ الرقمية (Public & Private Keys) برمجياً؟. فهم هذا المبدأ مهم حتى لا تخلط بين “الاتصال” و”التحكم الكامل” بالمحفظة.
المتطلبات العملية قبل كتابة الكود
قبل بناء زر الاتصال، تأكد من توفر العناصر التالية داخل مشروعك أو صفحتك الثابتة في WordPress:
- وجود إضافة
MetaMaskداخل متصفح المستخدم. - استدعاء مكتبة
Ethers.jsأو التعامل المباشر معwindow.ethereum. - تحديد الشبكة المستهدفة مثل
EthereumأوPolygon. - معرفة ما إذا كنت ستكتفي بإظهار العنوان، أم ستربطه لاحقاً بعقد ذكي أو واجهة سك أو شراء أو تصويت.
إذا كنت تبني الواجهة بطريقة منظمة، فأنصح بمراجعة هندسة الويب اللامركزي (Web3.js & Ethers.js): كيف نربط الواجهات بالعقود الذكية؟، ثم الانتقال إلى إعداد واجهة React.js وتثبيت مكتبة Ethers.js للاتصال بالبلوكتشين إذا كان مشروعك متقدماً.
كود عملي لطلب ربط محفظة MetaMask
الكود التالي يوضح سيناريو شائعاً: زر لطلب الاتصال، ثم إظهار عنوان المستخدم المختصر، مع التحقق من وجود المحفظة، والتعامل مع الأخطاء المتوقعة. ورغم أن هذا كود JavaScript للواجهة، فسيتم إدراجه ضمن قالب الكود المطلوب ليتوافق مع بنية النشر لديك.
<button id="connectWalletBtn">ربط محفظة MetaMask</button>
<p id="walletStatus">المحفظة غير متصلة</p>
<script src="https://cdn.jsdelivr.net/npm/ethers@6.13.1/dist/ethers.umd.min.js"></script>
<script>
const connectWalletBtn = document.getElementById("connectWalletBtn");
const walletStatus = document.getElementById("walletStatus");
function formatAddress(address) {
return `${address.slice(0, 6)}...${address.slice(-4)}`;
}
async function connectWallet() {
try {
if (!window.ethereum) {
walletStatus.textContent = "لم يتم العثور على MetaMask. الرجاء تثبيتها أولاً.";
return;
}
const provider = new ethers.BrowserProvider(window.ethereum);
const accounts = await window.ethereum.request({
method: "eth_requestAccounts"
});
if (!accounts || accounts.length === 0) {
walletStatus.textContent = "لم يتم اختيار أي حساب.";
return;
}
const userAddress = accounts[0];
const signer = await provider.getSigner();
walletStatus.textContent = `تم الاتصال: ${formatAddress(userAddress)}`;
console.log("Connected address:", userAddress);
console.log("Signer object:", signer);
} catch (error) {
if (error.code === 4001) {
walletStatus.textContent = "تم رفض طلب الاتصال من قبل المستخدم.";
} else {
walletStatus.textContent = "حدث خطأ أثناء الاتصال بالمحفظة.";
}
console.error("Connection error:", error);
}
}
connectWalletBtn.addEventListener("click", connectWallet);
if (window.ethereum) {
window.ethereum.on("accountsChanged", (accounts) => {
if (accounts.length === 0) {
walletStatus.textContent = "تم فصل المحفظة أو لا توجد حسابات متاحة.";
} else {
walletStatus.textContent = `الحساب الحالي: ${formatAddress(accounts[0])}`;
}
});
window.ethereum.on("chainChanged", () => {
window.location.reload();
});
}
</script>
شرح مكونات الكود خطوة بخطوة
1) التحقق من وجود window.ethereum
هذا التحقق أساسي لأنه يحدد إن كان المتصفح يحتوي على مزود محفظة متوافق. إذا لم يكن موجوداً، فلا فائدة من محاولة استدعاء eth_requestAccounts، ويجب بدلاً من ذلك إظهار رسالة واضحة تدعو المستخدم لتثبيت المحفظة.
2) إنشاء BrowserProvider
في الإصدارات الحديثة من Ethers.js، يتم تغليف مزود المتصفح داخل ethers.BrowserProvider. هذه الطبقة تمنحك وصولاً منظماً إلى الحساب الحالي وعمليات القراءة والتوقيع وإرسال المعاملات لاحقاً.
3) طلب الحسابات باستخدام eth_requestAccounts
هذا هو قلب العملية. بمجرد استدعائه، تطلب المحفظة من المستخدم الإذن. إذا قبل، تحصل على المصفوفة التي تحتوي على العناوين المصرح بها. وإذا رفض، يظهر الخطأ الشهير برمز 4001.
4) الاستفادة من Signer
بعد الاتصال، تستطيع الحصول على كائن Signer. هذا الكائن مهم جداً لأن أي تفاعل لاحق مع عقد ذكي قابل للكتابة، مثل استدعاء دالة payable أو تنفيذ عملية mint، يحتاج إليه.
إذا كنت تربط هذا الزر بعقد ذكي لاحقاً، فستحتاج فهماً أعمق لبنية الدوال من مقال الدوال (Functions) في Solidity: من يمكنه قراءة وتعديل بيانات العقد؟، وكذلك لفكرة استقبال وإرسال الأموال من مقال استلام وإرسال الأموال (Ether) برمجياً: فهم الدوال payable و fallback.
التعامل مع تغيّر الحساب أو الشبكة
من الأخطاء الشائعة أن يكتفي المطور بطلب الاتصال مرة واحدة ثم يفترض أن الحالة ستظل ثابتة. عملياً، المستخدم قد يبدل الحساب النشط أو ينتقل من شبكة إلى أخرى أثناء وجوده داخل الصفحة. لهذا السبب يجب الاستماع إلى الحدثين accountsChanged وchainChanged.
هذا مهم خصوصاً عندما يكون تطبيقك مخصصاً لعقد منشور على شبكة بعينها عبر Hardhat أو شبكة اختبار. ويمكنك مراجعة أتمتة نشر العقود (Deployment): كتابة سكربت لرفع العقد إلى شبكة Ethereum و Polygon لفهم أثر اختلاف الشبكات على عنوان العقد نفسه.
لا تعتمد على عنوان المحفظة الذي حصلت عليه مرة واحدة فقط داخل الواجهة. يجب دائماً إعادة التحقق من الشبكة والحساب النشط قبل تنفيذ أي عملية حساسة مثل الشراء أو التصويت أو استدعاء دوال تعدّل حالة العقد. هذا جزء أساسي من ممارسات
Security Auditingعلى مستوى الواجهة.
ربط المحفظة ليس بديلاً عن أمان العقود الذكية
كثير من المطورين المبتدئين يظنون أن بناء واجهة اتصال جيدة كافٍ لحماية التطبيق، لكن الحقيقة أن الواجهة الآمنة لا تعني عقداً آمناً. فحتى لو كان زر الاتصال مثالياً، فإن أي ثغرة داخل العقد مثل Reentrancy أو سوء استخدام الصلاحيات قد يؤدي إلى خسائر حقيقية.
لهذا من المفيد ربط هذه المرحلة بالمحتوى الأمني مثل أمن العقود الذكية (1): ثغرة إعادة الدخول (Reentrancy Attack) الشهيرة وكيفية استغلالها وأمن العقود الذكية (2): الحماية من ثغرة Reentrancy باستخدام ReentrancyGuard.
هل توجد اعتبارات خاصة بالأداء وGas Fees؟
عملية ربط المحفظة نفسها لا تستهلك Gas لأنها ليست معاملة على السلسلة. لكنها غالباً ما تسبق عمليات لاحقة قد تكلّف المستخدم رسوماً حقيقية، مثل شراء رمز أو سك NFT أو إرسال Ether.
لذلك من الجيد أن تشرح للمستخدم مبكراً طبيعة العمليات القادمة، وأن تراجع بنفسك مفاهيم الرسوم من مقال التكاليف (Gas Fees): كيف يحسب البلوكتشين تكلفة تنفيذ الأكواد؟، وكذلك تحسينات الاستدعاءات غير المعدلة للحالة في أنواع الدوال : فهم view و pure لتوفير رسوم الـ Gas.
من أفضل ممارسات
Gas Optimizationأن تفصل بين عمليات القراءة وعمليات الكتابة. اطلب من الواجهة قراءة البيانات عبر دوالviewأولاً، ثم اسمح بإرسال المعاملة فقط عندما يصبح المستخدم متأكداً من الإجراء الذي سينفذه.
أفضل ممارسات تجربة المستخدم عند زر ربط المحفظة
- اجعل نص الزر واضحاً مثل: “ربط محفظة
MetaMask”. - أظهر رسالة فورية عند عدم وجود المحفظة مع رابط تثبيت إن لزم.
- اختصر العنوان المعروض للمستخدم بدلاً من طباعة العنوان الكامل.
- تحقق من الشبكة المستهدفة قبل تمكين الأزرار الحساسة.
- تعامل مع رفض الاتصال بوصفه سلوكاً طبيعياً لا خطأ كارثياً.
- حدّث الحالة مباشرة إذا تغير الحساب أو تم قطع الاتصال.
خلاصة عملية
كتابة كود يطلب من الزائر ربط محفظة MetaMask بموقعك هي أول لبنة حقيقية في بناء أي DApp. نجاح هذه الخطوة يعتمد على فهمك للدور الذي يلعبه Provider، وطريقة طلب الحسابات، وكيفية إدارة تغير الشبكة والحسابات داخل الواجهة.
وعندما تُبنى هذه الطبقة بشكل صحيح، يصبح من السهل بعد ذلك ربط المستخدم بعقود ERC-20 أو ERC-721 أو أي منطق أعمال لامركزي متقدم. باختصار: زر الاتصال ليس مجرد عنصر واجهة، بل هو بوابة الثقة الأولى بين المستخدم وتطبيقك اللامركزي.
7 comments