إرسال الأموال إلى عنوان خاطئ قد يؤدي إلى خسارة دائمة. يضمن التحقق من العنوان أنك لا ترسل إلا إلى عناوين قادرة على استلام الأموال والوصول إليها بشكل صحيح.
يعتمد التحقق على ما تُرسله:
- رموز SPL توفر حماية جزئية ذاتية. يرفض Token Program أي تحويل لا تتطابق حساباته مع الـ mint المتوقع، لذا يفشل التحويل المُوجَّه بشكل خاطئ دون خسارة الأموال. تغطي معظم هذه الصفحة عمليات إرسال رموز SPL.
- SOL الأصلي لا يمتلك هذه الحماية. ينجح تحويل System Program إلى أي حساب، لذا فإن مستلمًا خاطئًا يُقفل SOL بشكل دائم. انظر إرسال SOL الأصلي.
انظر كيف تعمل المدفوعات على سولانا لمفاهيم الدفع الأساسية.
فهم عناوين سولانا
تمتلك حسابات سولانا نوعين من العناوين: على المنحنى وخارج المنحنى.
العناوين على المنحنى
العناوين القياسية هي المفاتيح العامة المشتقة من keypairs من نوع Ed25519. هذه العناوين:
- تمتلك مفتاحًا خاصًا مقابلًا يمكنه التوقيع على المعاملات
- تُستخدم كعناوين محافظ
العناوين خارج المنحنى (PDAs)
Program Derived Addresses مشتقة بشكل حتمي من معرّف البرنامج والبذور. هذه العناوين:
- لا تمتلك مفتاحًا خاصًا مقابلًا
- لا يمكن التوقيع عليها إلا من قِبَل البرنامج الذي اشتُق منه العنوان
أنواع الحسابات في المدفوعات
استخدم العنوان لجلب حساب من الشبكة، وتحقق من مالك البرنامج ونوع الحساب لتحديد كيفية التعامل مع العنوان.
معرفة ما إذا كان العنوان على المنحنى أو خارجه لا تخبرك بنوع الحساب، ولا بالبرنامج الذي يمتلكه، ولا بوجود حساب في ذلك العنوان. يجب عليك جلب الحساب من الشبكة لتحديد هذه التفاصيل.
حسابات System Program (المحافظ)
الحسابات المملوكة لـ System Program هي محافظ قياسية. لإرسال رموز SPL إلى محفظة، تحتاج إلى اشتقاق واستخدام Associated Token Account (ATA) الخاص بها.
بعد اشتقاق عنوان ATA، تحقق مما إذا كان token account موجودًا على السلسلة. إذا لم يكن ATA موجودًا، يمكنك تضمين تعليمة لإنشاء token account الخاص بالمستلم في نفس المعاملة مع التحويل. غير أن هذا يستلزم دفع rent لـ token account الجديد. ونظرًا لأن المستلم يمتلك ATA، فإن SOL المدفوع مقابل rent لا يمكن استرداده من قِبَل المُرسِل.
بدون ضمانات كافية، يمكن استغلال دعم إنشاء ATA. إذ يمكن لمستخدم خبيث أن يطلب تحويلًا، وتُنشأ ATA الخاصة به على نفقتك، ثم يغلق ATA لاستعادة rent SOL، ويكرر العملية.
Token Accounts
Token accounts مملوكة لـ Token Program أو Token-2022 Program وتحتفظ بأرصدة الرموز. إذا كان العنوان الذي تستلمه مملوكًا لبرنامج رموز، فيجب عليك التحقق من أن الحساب هو token account (وليس mint account) وأنه يطابق mint account الرمز المتوقع قبل الإرسال.
يتحقق Token Programs تلقائيًا من أن كلا token accounts في التحويل يحتفظان برموز من نفس الـ mint. وإذا فشل التحقق، يُرفض التحويل ولا تُفقد أي أموال.
حسابات Mint
Mint accounts تتتبع إمداد الرمز وبيانات تعريف رمز معين. كما أن Mint accounts مملوكة لـ Token Programs ولكنها ليست مستلِمين صالحين لتحويلات الرموز. تؤدي محاولة إرسال الرموز إلى عنوان mint إلى فشل المعاملة، دون فقدان أي أموال.
حسابات أخرى
الحسابات التي تمتلكها برامج أخرى تستلزم اتخاذ قرار بشأن السياسة المتبعة. فبعض الحسابات (مثل محافظ multisig) قد تكون مالكةً صالحةً لـ token account، في حين ينبغي رفض حسابات أخرى.
إرسال SOL الأصلي
يحدد التصنيف أعلاه الوجهات المسموح بها لرموز SPL. أما SOL الأصلي فأكثر صرامةً: المستلم الآمن الوحيد هو محفظة System Program (أو عنوان غير ممول على المنحنى يتحول إلى ذلك).
تضيف عملية نقل System Program لـ lamports إلى أي حساب، بما في ذلك عمليات السك و token accounts والبرامج وعناوين PDA. ولا يمكن نقل lamports خارجاً إلا من خلال البرنامج المالك للحساب، لذا فإن إرسال SOL إلى مستلم غير صحيح قد يؤدي إلى فقدان الأموال بشكل دائم.
على خلاف عملية نقل رموز SPL، فإن المعاملة لا تفشل عندما يكون المستلم عنواناً غير متوقع.
عند إرسال SOL الأصلي، لا يُقبل سوى نتيجة IS_WALLET. أما IS_TOKEN_ACCOUNT فلا
يُقبل: إذ يحتفظ token account برموز SPL، وأي SOL يُرسل إليه يخرج عن سيطرة
المرسل.
هذه طريقة شائعة لفقدان SOL: يقوم المستخدم بلصق عنوان سك الرمز (أو عنوان برنامج) في خانة سحب SOL. تنجح عملية النقل ولا يمكن استرداد SOL. احرص دائماً على تصنيف المستلم قبل التوقيع على أي عملية نقل SOL.
تدفق التحقق
يوضح المخطط التالي شجرة قرار مرجعية للتحقق من صحة العنوان:
جلب الحساب
استخدم العنوان لجلب تفاصيل الحساب من الشبكة.
الحساب غير موجود
إذا لم يكن هناك حساب موجود على هذا العنوان، تحقق مما إذا كان العنوان على المنحنى أم خارجه:
-
خارج المنحنى (PDA): ارفض العنوان بشكل احترازي لتجنب الإرسال إلى ATA قد يكون غير قابل للوصول. دون وجود حساب قائم، لا يمكنك تحديد البرنامج الذي اشتق هذا PDA من العنوان وحده، أو ما إذا كان العنوان خاصاً بـ ATA. فاشتقاق ATA لهذا العنوان لإرسال الرموز قد يؤدي إلى تجميد الأموال في token account غير قابل للوصول.
-
على المنحنى: هذا عنوان محفظة صالح (مفتاح عام) لم يتم تمويله بعد. اشتق ATA، وتحقق من وجوده، وأرسل الرموز إليه. يجب عليك اتخاذ قرار سياسي بشأن ما إذا كنت ستموّل إنشاء ATA إذا لم يكن موجوداً.
الحساب موجود
إذا كان الحساب موجوداً، تحقق من البرنامج الذي يملكه:
-
System Program: هذه محفظة قياسية. اشتق ATA، وتحقق من وجوده، وأرسل الرموز إليه. يجب عليك اتخاذ قرار سياسي بشأن ما إذا كنت ستموّل إنشاء ATA إذا لم يكن موجوداً.
-
Token Program / Token-2022: تحقق من أن الحساب هو token account (وليس mint account) وأنه يحتوي على الرمز (mint) الذي تنوي إرساله. إذا كان صالحاً، أرسل الرموز مباشرةً إلى هذا العنوان. إذا كان mint account أو token account لـ mint مختلف، ارفض العنوان.
-
برنامج آخر: يتطلب هذا قراراً سياسياً. بعض البرامج مثل محافظ multisig قد تكون مالكين مقبولين لـ token accounts. إذا كانت سياستك تسمح بذلك، اشتق ATA وأرسل. وإلا، ارفض العنوان.
عرض توضيحي
يوضح المثال التالي منطق التحقق من صحة العنوان فقط. هذا كود مرجعي لأغراض توضيحية.
لا يوضح العرض التوضيحي كيفية اشتقاق ATA أو بناء معاملة لإرسال الرموز. راجع وثائق token account وtoken transfer للاطلاع على أمثلة الكود.
يستخدم العرض التوضيحي أدناه ثلاثة نتائج محتملة:
| النتيجة | المعنى | الإجراء |
|---|---|---|
IS_WALLET | عنوان محفظة صالح | اشتق وأرسل إلى associated token account |
IS_TOKEN_ACCOUNT | token account صالح | أرسل الرموز مباشرةً إلى هذا العنوان |
REJECT | عنوان غير صالح | لا ترسل |
ثم يُعيّن كل نتيجة إلى قابلية القبول لكل أصل باستخدام canReceiveNativeSol
(المحافظ فقط) و canReceiveSplToken (المحافظ أو token accounts). يُرجع الـ
token account القيمة IS_TOKEN_ACCOUNT، وبذلك يمكنه استقبال رموز SPL لكن
ليس SOL الأصلي — وهو الفارق الذي يمنع قفل SOL.
/*** Validates an input address and classifies it as a wallet, token account, or invalid.** @param inputAddress - The address to validate* @param rpc - Optional RPC client (defaults to mainnet)* @returns Classification result:* - IS_WALLET: Valid wallet address* - IS_TOKEN_ACCOUNT: Valid token account* - REJECT: Invalid address for transfers*/export async function validateAddress(inputAddress: Address,rpc: Rpc<GetAccountInfoApi> = defaultRpc): Promise<ValidationResult> {const account = await fetchJsonParsedAccount(rpc, inputAddress);// Log the account data for democonsole.log("\nAccount:", account);// Account doesn't exist onchainif (!account.exists) {// Off-curve = PDA that doesn't exist as an account// Reject conservatively to avoid sending to an address that may be inaccessible.if (isOffCurveAddress(inputAddress)) {return { type: "REJECT", reason: "PDA doesn't exist as an account" };}// On-curve = valid keypair address, treat as unfunded walletreturn { type: "IS_WALLET" };}// Account exists, check program ownerconst owner = account.programAddress;// System Program = walletif (owner === SYSTEM_PROGRAM) {return { type: "IS_WALLET" };}// Token Program or Token-2022, check if token accountif (owner === TOKEN_PROGRAM || owner === TOKEN_2022_PROGRAM) {const accountType = (account.data as { parsedAccountMeta?: { type?: string } }).parsedAccountMeta?.type;if (accountType === "account") {return { type: "IS_TOKEN_ACCOUNT" };}// Reject if not a token account (mint account)return {type: "REJECT",reason: "Not a token account"};}// Unknown program ownerreturn { type: "REJECT", reason: "Unknown program owner" };}/*** Native SOL is only safe to send to a wallet. Any other account locks it.*/function canReceiveNativeSol(result: ValidationResult): boolean {return result.type === "IS_WALLET";}/*** SPL tokens can go to a wallet (via its ATA) or directly to a token account.*/function canReceiveSplToken(result: ValidationResult): boolean {return result.type === "IS_WALLET" || result.type === "IS_TOKEN_ACCOUNT";}// =============================================================================// Examples// =============================================================================
Is this page helpful?