الورقة البيضاء · 05
المواصفات التقنية
ملخص معياري لـ A-REX Core: المطابقة، والواجهات، ودلالات العمليات، وعقد الخطاف، والإفادات، وقواعد التخزين والترقية. والنص المرجعي هو standard/AREX-CORE.md؛ ويعيد هذا الفصل صياغته لقراء الورقة البيضاء.
المطابقة
يجب على الرمز المطابق أن ينفّذ ERC-1155 وERC-165 وIERC7943MultiToken (0x41c4fbad) وIARexBatch (0xe22639e0) وأن يتيح مساره عبر IARexHookManager.getHooks() (0x964f4861). وينبغي أن ينفّذ IARexAttest (0xad603a6c) مباشرةً أو عبر عقد مرافق. ويجب على الخطاف المطابق أن ينفّذ IARexHook (0x332afcbb) وERC-165. ويمكن إعادة توليد جميع المعرّفات بالأمر npm run interface-ids.
الثوابت المحددة
| الثابت | القيمة | المعنى |
|---|---|---|
OP_MINT | 1 | كميات جديدة (createBatch) |
OP_TRANSFER | 2 | تحويل يبدؤه الحامل |
OP_BURN | 3 | الاسترداد، أو التسليم، أو الشطب |
OP_FORCED_TRANSFER | 4 | الإنفاذ |
OP_TRANSFORM | 5 | مدخلات transform (to = 0) ومخرجاتها (from = 0) |
HOOK_CHECK | 1 | الخطاف يطلب check |
HOOK_EXECUTED | 2 | الخطاف يطلب onExecuted |
HOOK_ELIGIBILITY | 4 | يجيب الخطاف عن canSend / canReceive |
STATUS_ACTIVE | 0 | الافتراضي |
STATUS_RETIRED | 255 | نهائي |
كل ما عدا ذلك — أكواد السلع، وأكواد وحدات القياس، والحالات 1..254، وأكواد الرفض، ومواضيع الإفادات — مفتوح. وتوجد الأعراف الموصى بها في ARexCodes.
الطبقة 1 — IARexBatch
interface IARexBatch is IERC165 {
struct BatchInit { bytes32 commodity; bytes32 unit; uint64 producedAt; uint64 expiresAt; bytes32 originRef; bytes32 metadataHash; string uri; }
struct Batch { address issuer; uint64 createdAt; uint8 status; bytes32 commodity; bytes32 unit; uint64 producedAt; uint64 expiresAt; bytes32 originRef; bytes32 metadataHash; string uri; }
event BatchCreated(uint256 indexed id, address indexed issuer, bytes32 indexed commodity, bytes32 unit, uint256 quantity, address to);
event BatchStatusChanged(uint256 indexed id, uint8 previousStatus, uint8 newStatus, bytes32 reason);
event BatchMetadataUpdated(uint256 indexed id, bytes32 metadataHash, string uri);
event BatchTransformed(address indexed operator, uint256[] inputIds, uint256[] inputAmounts, uint256[] outputIds, uint256[] outputAmounts, bytes32 processRef);
error ARexBatchNotFound(uint256 id);
error ARexBatchRetired(uint256 id);
error ARexInvalidBatch(bytes32 reason);
error ARexInvalidStatusTransition(uint256 id, uint8 from, uint8 to);
error ARexLengthMismatch();
function createBatch(BatchInit calldata init, uint256 quantity, address to, bytes calldata data) external returns (uint256 id);
function batchOf(uint256 id) external view returns (Batch memory);
function batchExists(uint256 id) external view returns (bool);
function totalSupply(uint256 id) external view returns (uint256);
function setBatchStatus(uint256 id, uint8 status, bytes32 reason) external;
function setBatchMetadata(uint256 id, bytes32 metadataHash, string calldata uri) external;
function transform(address from, address to, uint256[] calldata inputIds, uint256[] calldata inputAmounts, BatchInit[] calldata outputs, uint256[] calldata outputAmounts, bytes32 processRef) external returns (uint256[] memory outputIds);
function parentsOf(uint256 id) external view returns (uint256[] memory);
}
الدلالات
createBatch
- يجب تقييدها بحسابات مخوّلة؛ ويجب ألا يُشتق التخويل من رصيد الرمز.
- يجب أن تتراجع بالخطأ
ARexInvalidBatchعندما تكونquantity == 0أوcommodity == 0أوunit == 0أوexpiresAt != 0 && producedAt != 0 && expiresAt <= producedAt. - يجب قبول
producedAt == 0(ما قبل الحصاد). - يجب أن تشغّل المسار مع
OP_MINT؛ ويجب أن تُصدرBatchCreatedثمTransferSingle.
setBatchStatus
- يجب تقييدها بدور. وتمثل
255حالة نهائية. الدفعات المسحوبة من التداول: لا سك ولا تحويل (ARexBatchRetired)، والحرق مسموح.
transform
- يجب أن يكون
msg.senderهوfromأو معتمَدًا من قِبلfromعلى جميع الرموز. - يجب أن تتراجع بالخطأ
ARexLengthMismatchعند عدم اتساق الأطوال، ويجب أن تتراجع عند خلو قائمة المدخلات أو المخرجات. - يجب أن تحرق المدخلات وتسك المخرجات وتضبط
parentsOf(output) = inputIdsوتضبطissuer = msg.senderعلى المخرجات. - يجب أن تشغّل المسار مع
OP_TRANSFORMلكل حرق ولكل سك، معdata = abi.encode(processRef). - يجب أن تُصدر
BatchCreatedلكل مخرج، وأحداث ERC-1155، وحدثًا واحدًا هوBatchTransformed. - حفظ الكمية غير مطلوب. ويميّز المرجع بين إعادة تكوين الدفعة (السلعة ووحدة القياس نفسهما،
Σin == Σout؛ أي حامل) والمعالجة (TRANSFORMER_ROLE).
metadata
- يجب أن يكون
metadataHashهوkeccak256للمستند بصيغته القياسية الموجود فيuri. وينبغي أن يتبع المستندstandard/schema/batch-metadata.schema.json. - يجب ألا يحتوي
originRefعلى إحداثيات خام أو معرّفات لأشخاص طبيعيين.
الطبقة 0 — IERC7943MultiToken
حرفيًا من ERC-7943 (forcedTransfer، وsetFrozenTokens، وcanSend، وcanReceive، وgetFrozenTokens، وcanTransfer؛ والأحداث ForcedTransfer وFrozen؛ والأخطاء ERC7943CannotSend وERC7943CannotReceive وERC7943CannotTransfer وERC7943InsufficientUnfrozenBalance). وتضيف A-REX التوضيحات التالية:
- يجب أن تكون
canTransferمساوية false عند الإيقاف المؤقت، أو عند عدم وجود الدفعة أو سحبها من التداول، أو عند فشل الأهلية، أو عندما تكونamount > balance − frozen، أو عندما يرفض أي خطاف CHECK العمليةOP_TRANSFER. - يجب ألا تنجح التحويلات العامة حيث تكون
canTransferfalse. - يجب تقييد
forcedTransferبدور، ويجب أن تتجاوز الأهلية، ويجب أن تخفض المقدار المجمّد بحيث لا يتجاوز أبدًا الرصيد المتبقي (مع إصدارFrozen)، ويجب أن تشغّل الخطافات معOP_FORCED_TRANSFER، ويجب أن تُصدرForcedTransfer، وينبغي أن تعمل أثناء الإيقاف المؤقت. canSend/canReceiveهما الاقتران المنطقي لجميع خطافاتHOOK_ELIGIBILITY.- ينبغي أن يتيح الرمز
transferCheck(from, to, id, amount) → bytes32.
الطبقة 2 — الخطافات
interface IARexHook is IERC165 {
error ARexHookRejected(address hook, bytes32 code);
function hookFlags() external view returns (uint8);
function check(uint8 op, address operator, address from, address to, uint256 id, uint256 amount, bytes calldata data) external view returns (bytes32 code);
function onExecuted(uint8 op, address operator, address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
function canSend(address account) external view returns (bool);
function canReceive(address account) external view returns (bool);
}
interface IARexHookManager {
event HookRegistered(address indexed hook, uint8 flags, uint256 position);
event HookRemoved(address indexed hook);
error ARexHookAlreadyRegistered(address hook);
error ARexHookNotRegistered(address hook);
error ARexInvalidHook(address hook);
function getHooks() external view returns (address[] memory);
function hookFlagsOf(address hook) external view returns (uint8);
function registerHook(address hook) external;
function removeHook(address hook) external;
}
التزامات الرمز: قائمة مرتبة؛ والتحقق من supportsInterface(0x332afcbb) وتخزين الأعلام غير الصفرية مؤقتًا عند التسجيل؛ واستدعاء check لكل معرّف ولكل خطاف CHECK والتراجع بالخطأ ARexHookRejected(hook, code) عند أول كود غير صفري قبل أي تغيير في الأرصدة؛ واستدعاء onExecuted لكل معرّف ولكل خطاف EXECUTED بعد تحديث الأرصدة؛ ومنع إعادة الدخول أثناء التسلسل؛ وتمرير data؛ وإبقاء القائمة والأعلام عامة.
التزامات الخطاف: أعلام ثابتة؛ وcheck دالة عرض تُرجع الأكواد ولا تتراجع أبدًا لأسباب تتعلق بالسياسة؛ والرمز المستدعي هو msg.sender؛ وإرجاع 0 لـ OP_FORCED_TRANSFER ما لم تكن القاعدة تحكم الإنفاذ؛ ولا تستدعي onExecuted أبدًا دوالًا تغيّر الأرصدة.
الطبقة 3 — IARexAttest
interface IARexAttest is IERC165 {
struct Attestation { address issuer; bytes32 ref; uint64 issuedAt; uint64 expiresAt; bool revoked; }
event Attested(uint256 indexed id, bytes32 indexed topic, address indexed issuer, bytes32 ref, uint64 expiresAt);
event AttestationRevoked(uint256 indexed id, bytes32 indexed topic, address indexed issuer, bytes32 reason);
event TrustedIssuerUpdated(bytes32 indexed topic, address indexed issuer, bool trusted);
error ARexUntrustedIssuer(bytes32 topic, address issuer);
error ARexAttestationNotFound(uint256 id, bytes32 topic);
function attest(uint256 id, bytes32 topic, bytes32 ref, uint64 expiresAt) external;
function revokeAttestation(uint256 id, bytes32 topic, bytes32 reason) external;
function getAttestation(uint256 id, bytes32 topic) external view returns (Attestation memory);
function isAttested(uint256 id, bytes32 topic) external view returns (bool);
function isTrustedIssuer(bytes32 topic, address issuer) external view returns (bool);
}
تتطلب attest جهة إصدار موثوقة للموضوع ودفعة موجودة. وتكون isAttested مساوية false إذا كانت الإفادة غائبة أو مُبطَلة أو منتهية الصلاحية، أو إذا لم تعد جهة الإصدار موثوقة. وتبطل جهات الإصدار إفاداتها الخاصة؛ ويجوز للمسؤول إبطال أي إفادة.
أكواد الرفض (الموصى بها)
keccak256("AREX:" + NAME) لكل من PAUSED وFROZEN وSENDER_INELIGIBLE وRECEIVER_INELIGIBLE وSANCTIONED وBATCH_NOT_FOUND وBATCH_RETIRED وBATCH_INACTIVE وBATCH_EXPIRED وBATCH_NOT_PRODUCED وLIMIT_EXCEEDED وDOCUMENT_MISSING وSEASON_CLOSED وIN_TRANSIT وATTESTATION_MISSING. الأكواد المخصصة: keccak256("NAMESPACE:NAME").
حقائق التنفيذ المرجعي
| الخاصية | القيمة |
|---|---|
| الأساس | OpenZeppelin 5.3.0 القابل للترقية: ERC1155 وERC1155Supply وAccessControl وPausable وUUPS |
| التخزين | فضاء أسماء ERC-7201 arex.storage.token، والخانة 0x8ed599b6be05dec05297c009a1279a71df771ad996fe924d0b5a47326ff60900 |
| المترجم | solc 0.8.22، وviaIR، وEVM paris؛ وoptimizer.runs = 1 لـ ARexToken (24,136 بايت بعد النشر)، و200 في غيره |
| الأدوار | ISSUER وTRANSFORMER وSTATUS وENFORCER وHOOK_ADMIN وPAUSER وUPGRADER وDEFAULT_ADMIN؛ وATTEST_ADMIN في ARexAttestations |
| إعادة الدخول | قفل تخزين حول تسلسل _update بأكمله؛ يجري اختباره بواسطة اختبار ReentrantHook |
| تمرير البيانات | تحفظ safeTransferFrom / safeBatchTransferFrom / createBatch القيمة data للخطافات؛ وتمرّر transform القيمة abi.encode(processRef) |
| البيانات الوصفية | تُرجع uri(id) عنوان URI الخاص بالدفعة إذا ضُبط، وإلا فعنوان URI الأساسي |
| الاختبارات | 46 اختبارًا في test/standard: دورة الحياة، والنسب، والتجميد والتحويل القسري، وترتيب الخطافات، والرفض، والبيانات وإعادة الدخول، والإفادات، ومعرّفات الواجهات، وتفويض الترقية، وخطافات المجال، والامتدادات، والثوابت العشوائية، ودليل التنفيذ منفَّذًا من البداية إلى النهاية |
إصدارات المعيار
أي تغيير في توقيع دالة أو حدث أو بند MUST يمثل إصدارًا رئيسيًا مع ملاحظة ترحيل. أما التوصيات الإضافية (الأكواد وحقول المخطط) فتمثل إصدارًا ثانويًا. ولا تُقبل التغييرات إلا حين يؤكد منفّذان مستقلان تبنّيها. ولن تُرفع الواجهات بوصفها ERC قبل أن يعمل نشر إنتاجي واحد ستة أشهر، وتوجد ثلاثة تنفيذات مستقلة للخطافات، ويُنشر تدقيق من طرف ثالث.