معيار رمز ERC-223
آخر تحديث للصفحة: 6 سبتمبر 2025
مقدمة
ما هو ERC-223؟
ERC-223 هو معيار للرموز القابلة للتبادل، مشابه لمعيار ERC-20. الفرق الرئيسي هو أن ERC-223 يحدد ليس فقط واجهة برمجة التطبيقات للرمز ولكن أيضًا المنطق الخاص بنقل الرموز من المرسل إلى المستلم. يقدم نموذج اتصال يسمح بتعامل مع نقل الرموز على جانب المستلم.
Differences from ERC-20
عنوان ERC-223 يعالج بعض قيود ERC-20 ويقدم طريقة جديدة للتفاعل بين عقد الرمز وعقد قد يتلقى الرموز. هناك بعض الأشياء الممكنة مع ERC-223 ولكن لا يمكن تحقيقها مع ERC-20:
- معالجة تحويل الرمز على جانب المستلم: يمكن للمستلمين اكتشاف أنه يتم إيداع رمز ERC-223.
- رفض الرموز المرسلة بشكل غير صحيح: إذا أرسل مستخدم رموز ERC-223 إلى عقد لا يُفترض أن يستقبل الرموز، يمكن للعقد رفض المعاملة، مما يمنع فقدان الرموز.
- البيانات الوصفية في التحويلات: يمكن أن تتضمن رموز ERC-223 بيانات وصفية، مما يسمح بإرفاق معلومات عشوائية بعمليات نقل الرموز.
المتطلبات الأساسية
- الحسابات
- العقود الذكية
- معايير الرمز
- ERC-20
الجسد
ERC-223 هو معيار توكن ينفذ واجهة برمجة التطبيقات للتوكنات ضمن العقود الذكية. كما يعلن عن واجهة برمجة التطبيقات للعقود التي من المفترض أن تتلقى رموز ERC-223. العقود التي لا تدعم واجهة برمجة الاستقبال ERC-223 لا يمكنها استقبال رموز ERC-223، مما يمنع حدوث أخطاء من قبل المستخدم.
إذا كان العقد الذكي ينفذ الطرق والأحداث التالية، يمكن أن يسمى عقد رمزي متوافق مع ERC-223. بمجرد نشره، سيكون مسؤولاً عن تتبع الرموز المنشأة على الإيثيريوم.
العقد ليس ملزماً بأن يحتوي فقط على هذه الدوال، ويمكن للمطور إضافة أي ميزة أخرى من معايير الرموز المختلفة إلى هذا العقد. على سبيل المثال، فإن دالتي approve و transferFrom ليستا جزءاً من معيار ERC-223، لكن يمكن تنفيذ هذه الدوال إذا تطلب الأمر.
من EIP-223 (opens in a new tab):
طرق
يجب على توكن ERC-223 تنفيذ الأساليب التالية:
1function name() public view returns (string)2function symbol() public view returns (string)3function decimals() public view returns (uint8)4function totalSupply() public view returns (uint256)5function balanceOf(address _owner) public view returns (uint256 balance)6function transfer(address _to, uint256 _value) public returns (bool success)7function transfer(address _to, uint256 _value, bytes calldata _data) public returns (bool success)يجب أن ينفذ العقد الذي من المفترض أن يتلقى توكنات ERC-223 الطريقة التالية:
1function tokenReceived(address _from, uint _value, bytes calldata _data)إذا تم إرسال رموز ERC-223 إلى عقد لا ينفذ وظيفة tokenReceived(..)، يجب أن تفشل عملية الإرسال ويجب ألا تتحرك الرموز من رصيد المرسل.
الأحداث
1event Transfer(address indexed _from, address indexed _to, uint256 _value, bytes calldata _data)أمثلة
واجهة برمجة التطبيقات لرمز ERC-223 مشابهة لواجهة ERC-20، لذلك من وجهة نظر تطوير واجهة المستخدم لا يوجد فرق. الاستثناء الوحيد هنا هو أن رموز ERC-223 قد لا تحتوي على دالتي approve + transferFrom حيث إن هذه الدوال اختيارية لهذا المعيار.
أمثلة سوليديتي
المثال التالي يوضح كيفية عمل عقد توكن ERC-223 الأساسي:
1pragma solidity ^0.8.19;2abstract contract IERC223Recipient {3 function tokenReceived(address _from, uint _value, bytes memory _data) public virtual;4}5contract VeryBasicERC223Token {6 event Transfer(address indexed from, address indexed to, uint value, bytes data);7 string private _name;8 string private _symbol;9 uint8 private _decimals;10 uint256 private _totalSupply;11 mapping(address => uint256) private balances;12 function name() public view returns (string memory) { return _name; }13 function symbol() public view returns (string memory) {return _symbol; }14 function decimals() public view returns (uint8) { return _decimals; }15 function totalSupply() public view returns (uint256) { return _totalSupply; }16 function balanceOf(address _owner) public view returns (uint256) { return balances[_owner]; }17 function isContract(address account) internal view returns (bool) {18 uint256 size;19 assembly { size := extcodesize(account) }20 return size > 0;21 }22 function transfer(address _to, uint _value, bytes calldata _data) public returns (bool success){23 balances[msg.sender] = balances[msg.sender] - _value;24 balances[_to] = balances[_to] + _value;25 if(isContract(_to)) {26 IERC223Recipient(_to).tokenReceived(msg.sender, _value, _data);27 }28 emit Transfer(msg.sender, _to, _value, _data);29 return true;30 }31 function transfer(address _to, uint _value) public returns (bool success){32 bytes memory _empty = hex"00000000";33 balances[msg.sender] = balances[msg.sender] - _value;34 balances[_to] = balances[_to] + _value;35 if(isContract(_to)) {36 IERC223Recipient(_to).tokenReceived(msg.sender, _value, _empty);37 }38 emit Transfer(msg.sender, _to, _value, _empty);39 return true;40 }41}الآن نريد عقدًا آخر لقبول ودائع من tokenA على افتراض أن tokenA هو رمز ERC-223. يجب على العقد قبول tokenA فقط ورفض أي توكنات أخرى. عندما يتلقى العقد tokenA يجب أن يبث حدث Deposit() ويزيد من قيمة المتغير الداخلي deposits.
إليك الشيفرة:
1contract RecipientContract is IERC223Recipient {2 event Deposit(address whoSentTheTokens);3 uint256 deposits = 0;4 address tokenA; // الرمز الوحيد الذي نريد قبوله.5 function tokenReceived(address _from, uint _value, bytes memory _data) public override6 {7 // من المهم أن نفهم أنه ضمن هذه الدالة8 // msg.sender هو عنوان الرمز الذي يتم استلامه،9 // msg.value هي دائمًا 0 لأن عقد الرمز لا يمتلك أو يرسل الإيثر في معظم الحالات،10 // _from هو مرسل تحويل الرمز،11 // _value هي كمية الرموز التي تم إيداعها.12 require(msg.sender == tokenA);13 deposits += _value;14 emit Deposit(_from);15 }16}الأسئلة الشائعة
ماذا سيحدث إذا أرسلنا بعض توكنB إلى العقد؟
ستفشل المعاملة، ولن يتم نقل الرموز. ستعود الرموز إلى عنوان المرسل.
كيف يمكننا إيداع مبلغ في هذا العقد؟
استدعِ دالة transfer(address,uint256) أو transfer(address,uint256,bytes) من توكن ERC-223، مع تحديد عنوان RecipientContract.
ماذا سيحدث إذا قمنا بنقل رمز ERC-20 إلى هذا العقد؟
إذا تم إرسال رمز ERC-20 إلى RecipientContract، سيتم نقل الرموز، ولكن لن يتم التعرف على النقل (لن يتم إطلاق حدث Deposit()، ولن تتغير قيمة الإيداعات). لا يمكن تصفية أو منع الودائع غير المرغوب فيها من نوع ERC-20.
ماذا لو أردنا تنفيذ بعض الوظائف بعد انتهاء إيداع الرمز؟
هناك طرق متعددة للقيام بذلك. في هذا المثال، سنتبع الطريقة التي تجعل تحويلات ERC-223 متطابقة مع تحويلات الإيثير:
1contract RecipientContract is IERC223Recipient {2 event Foo();3 event Bar(uint256 someNumber);4 address tokenA; // الرمز الوحيد الذي نريد قبوله.5 function tokenReceived(address _from, uint _value, bytes memory _data) public override6 {7 require(msg.sender == tokenA);8 address(this).call(_data); // تعامل مع المعاملة الواردة وقم بإجراء استدعاء دالة لاحق.9 }10 function foo() public11 {12 emit Foo();13 }14 function bar(uint256 _someNumber) public15 {16 emit Bar(_someNumber);17 }18}عند استلام RecipientContract لرمز ERC-223، ستقوم العقدة بتنفيذ دالة مشفرة كمعامل _data من معاملّة الرمز، كما هو الحال في كيفية تشفير معاملات الإيثير لدعوات الدوال كبيانات معاملات.
اقرأ حقل البيانات للمزيد من المعلومات.
في المثال أعلاه، يجب نقل رمز ERC-223 إلى عنوان RecipientContract باستخدام دالة transfer(address,uint256,bytes calldata _data). إذا كانت قيمة معامل البيانات ستكون 0xc2985578 (توقيع دالة foo()) فسوف يتم استدعاء الدالة foo() بعد استلام إيداع الرمز وسيتم إطلاق حدث Foo().
يمكن ترميز المعلمات في data الخاصة بنقل الرمز أيضًا، على سبيل المثال يمكننا استدعاء دالة bar() مع قيمة 12345 لـ _someNumber. في هذه الحالة يجب أن تكون data هي 0x0423a13200000000000000000000000000000000000000000000000000000000000004d2 حيث أن 0x0423a132 هو توقيع دالة bar(uint256) و 00000000000000000000000000000000000000000000000000000000000004d2 هو 12345 كـ uint256.
القيود
بينما تعالج ERC-223 العديد من المشكلات الموجودة في معيار ERC-20، إلا أنها ليست خالية من قيودها الخاصة:
- التبني والتوافق: لم يتم تبني ERC-223 على نطاق واسع بعد، مما قد يحد من توافقه مع الأدوات والمنصات القائمة.
- التوافق العكسي: لا يتوافق ERC-223 مع ERC-20، مما يعني أن العقود والأدوات الحالية لـ ERC-20 لن تعمل مع رموز ERC-223 دون تعديلات.
- تكاليف الغاز: قد تؤدي الفحوص والوظائف الإضافية في تحويلات ERC-223 إلى تكاليف غاز أعلى مقارنة بمعاملات ERC-20.