Skip to main content
Glama
ZETRIX_CONTRACT_DEVELOPMENT_RULES.md14.8 kB
# Zetrix Smart Contract Development Rules **CRITICAL: These rules MUST be followed for ALL contract generation requests** ## Rule 1: Project Initialization **ALWAYS use npx create-zetrix-tool:** ```bash npx create-zetrix-tool <CONTRACT_NAME> cd <CONTRACT_NAME> npm install ``` **NEVER manually create folder structure** - The official tool provides: - Complete project structure with all utilities - Official BasicOperation, merge.js, deploy/upgrade scripts - Testing infrastructure (unit and integration) - Example contracts (ZTP20, ZTP721, ZTP1155) ## Rule 2: File Organization ### Main Contract Location **MUST be in contracts/ root, NOT in specs/ folder:** ``` ✅ CORRECT: contracts/GovernanceDAO.js ❌ WRONG: contracts/specs/GovernanceDAO.js ``` ### Library Test Specs **MUST be in contracts/specs/ folder:** ``` ✅ CORRECT: contracts/specs/proposal-management-spec.js ❌ WRONG: contracts/library/proposal-management-spec.js ``` ### Complete Structure ``` contracts/ ├── YourMainContract.js # Main deployable contract (ROOT!) ├── library/ │ ├── your-library.js # Reusable library │ └── another-library.js └── specs/ ├── your-library-spec.js # Test spec for library └── another-library-spec.js ``` ## Rule 3: Environment Configuration ### .env File - NODE_URL Format **CRITICAL: Remove https:// protocol from NODE_URL:** ```bash ✅ CORRECT: NODE_URL=test-node.zetrix.com TESTNET_RPC_URL=test-node.zetrix.com MAINNET_RPC_URL=node.zetrix.com ❌ WRONG: NODE_URL=https://test-node.zetrix.com # SDK adds https:// automatically ``` **Reason:** The zetrix-sdk-nodejs automatically adds the protocol. Including it causes connection errors. ## Rule 4: Loop Syntax - Zetrix JSLint Requirements ### ✅ CORRECT - Loop Pattern: ```javascript // Declare iterator variable first let i; // Use separate initialization, i += 1 (NOT i++) for (i = 0; i < array.length; i += 1) { // Loop body } ``` ### ❌ WRONG - Common Mistakes: ```javascript // Don't use inline declaration for (let i = 0; i < array.length; i++) { } // WRONG! // Don't use i++ for (let i = 0; i < array.length; i++) { } // WRONG! // Don't use var in loop for (var i = 0; i < array.length; i += 1) { } // WRONG! ``` **Reason:** Zetrix blockchain JSLint validator requires: 1. Variable declared on separate line with `let` 2. Iterator increment using `i += 1` not `i++` 3. This is the official pattern used in ZTP1155 and other token contracts ## Rule 5: Array Validation - No Array.isArray() ### ✅ CORRECT - Check .length property: ```javascript if (!params.targets || !params.targets.length || params.targets.length === 0) { return { valid: false, error: 'Invalid targets' }; } // Check array length match if (params.values.length !== params.targets.length) { return { valid: false, error: 'Array length mismatch' }; } ``` ### ❌ WRONG - Using Array.isArray(): ```javascript if (!Array.isArray(params.targets)) { } // WRONG! Undeclared 'Array' ``` **Reason:** Zetrix VM doesn't allow access to global `Array` object. Use `.length` property checks instead. ## Rule 6: Function Declaration Order - Avoid Forward References ### ✅ CORRECT - Define functions before use: ```javascript const MyLibrary = function () { // Define helper functions FIRST const _helperFunction = function() { // Implementation }; const _anotherHelper = function() { // Implementation }; // Then define functions that use them const _mainFunction = function() { _helperFunction(); // OK - defined above _anotherHelper(); // OK - defined above }; // Public API self.publicMethod = function() { _mainFunction(); }; }; ``` ### ❌ WRONG - Forward references: ```javascript const _mainFunction = function() { _helperFunction(); // ERROR: '_helperFunction' is out of scope }; const _helperFunction = function() { // Defined too late! // Implementation }; ``` **Reason:** Zetrix JSLint validator doesn't allow forward references. All functions must be declared before they are called. ## Rule 7: Code Pattern - ES5 Constructor (NOT IIFE) ### ✅ CORRECT - ES5 Constructor Pattern: ```javascript const MyLibrary = function () { const BasicOperationUtil = new BasicOperation(); const self = this; // Private methods const _privateMethod = function() { // Implementation }; // Public methods self.publicMethod = function() { // Can call _privateMethod() }; }; ``` ### ❌ WRONG - IIFE Pattern: ```javascript var MyLibrary = (function() { return { publicMethod: function() {} }; })(); ``` ## Rule 8: Storage Operations - ALWAYS Use BasicOperation ### ✅ CORRECT - Using BasicOperation: ```javascript const BasicOperationUtil = new BasicOperation(); // Store object BasicOperationUtil.saveObj(key, objectValue); // Load object let obj = BasicOperationUtil.loadObj(key); if (obj === false) { // Not found } // Build composite keys let key = BasicOperationUtil.getKey('prefix', param1, param2, param3); // Results in: 'prefix_param1_param2_param3' ``` ### ❌ WRONG - Direct Chain.store for objects: ```javascript Chain.store('myObj', JSON.stringify(obj)); // Inconsistent! ``` ### Exception - Simple string values: ```javascript // OK for simple strings Chain.store('simpleKey', 'stringValue'); let value = Chain.load('simpleKey'); ``` ## Rule 9: Reuse Existing Libraries **ALWAYS check and reuse official libraries:** ### Available from template: - `utils/basic-operation.js` - **MUST USE** for object storage - `library/pausable.js` - Emergency pause - `library/nonces.js` - Nonce management - `library/math.js` - 256-bit arithmetic - `library/bytes.js` - Byte manipulation - `library/logic-op.js` - Logic operations ### Token Standards: - `library/ztp20/*` - Fungible tokens - `library/ztp721/*` - NFTs - `library/ztp1155/*` - Multi-token **NEVER recreate what already exists!** ## Rule 10: Main Contract Structure **MUST follow this exact pattern:** ```javascript 'use strict'; import 'library/my-library'; import 'library/pausable'; const MyLib = new MyLibrary(); const PausableMgmt = new Pausable(); function init(input) { let params = JSON.parse(input).params; // Validate and initialize Utils.assert(params.name, 'Name required'); Chain.store('name', params.name); return true; } // Individual method functions function myMethod(paramObj) { PausableMgmt.requireNotPaused(); return MyLib.doSomething(paramObj.value); } function myQuery(paramObj) { return MyLib.getSomething(paramObj.id); } function main(input_str) { let funcList = { 'myMethod': myMethod }; let inputObj = JSON.parse(input_str); Utils.assert( funcList.hasOwnProperty(inputObj.method) && typeof funcList[inputObj.method] === 'function', 'Cannot find func:' + inputObj.method ); funcList[inputObj.method](inputObj.params); } function query(input_str) { let funcList = { 'myQuery': myQuery }; let inputObj = JSON.parse(input_str); Utils.assert( funcList.hasOwnProperty(inputObj.method) && typeof funcList[inputObj.method] === 'function', 'Cannot find func:' + inputObj.method ); return JSON.stringify(funcList[inputObj.method](inputObj.params)); } ``` **Key Requirements:** - ✅ Use `import` statements (resolved by merge.js) - ✅ Instantiate libraries at top - ✅ Define individual method functions - ✅ Use `funcList` routing in main/query - ✅ NEVER use switch-case for routing ## Rule 11: Library Test Spec Pattern **Create in contracts/specs/ for EACH library:** ```javascript 'use strict'; import 'library/my-library'; const MyLib = new MyLibrary(); function init() { // Initialize test data Chain.store('testKey', 'testValue'); Chain.tlog('MyLibrarySpecInitialized'); return true; } function testMethod(paramObj) { return MyLib.publicMethod(paramObj.param1); } function main(input_str) { let funcList = { 'testMethod': testMethod }; let inputObj = JSON.parse(input_str); Utils.assert( funcList.hasOwnProperty(inputObj.method) && typeof funcList[inputObj.method] === 'function', 'Cannot find func:' + inputObj.method ); funcList[inputObj.method](inputObj.params); } function query(input_str) { let funcList = { 'testQuery': function(paramObj) { return MyLib.queryMethod(paramObj.id); } }; let inputObj = JSON.parse(input_str); Utils.assert( funcList.hasOwnProperty(inputObj.method) && typeof funcList[inputObj.method] === 'function', 'Cannot find func:' + inputObj.method ); return JSON.stringify(funcList[inputObj.method](inputObj.params)); } ``` ## Rule 12: Token Standard Contracts - Implement Interfaces **For ZTP20/ZTP721/ZTP1155, MUST implement proper interfaces:** ```javascript import 'interface/IZEP165'; import 'interface/ztp20/IZTP20'; import 'interface/ztp20/IZTP20Metadata'; const ZTP20Inst = new ZTP20(); function init() { ZTP20Inst.p.init('Token Name', 'SYMBOL', 'Description', '6', '1000000000000', '1.0.0'); // Verify interface implementation Utils.assert(implementsInterface(ZTP20Inst, IZTP20), "Does not implement IZTP20"); Utils.assert(implementsInterface(ZTP20Inst, IZTP20Metadata), "Does not implement IZTP20Metadata"); Utils.assert(implementsInterface(ZTP20Inst, IZEP165), "Does not implement IZEP165"); return true; } ``` ## Rule 13: Testing Before Completion **ALWAYS test deployment before considering task complete:** ```bash # Test deployment node scripts/deploy-<contract-name>.js # Check for: # ✅ No merge errors # ✅ Generated file created in generated/ # ✅ No syntax errors # ✅ Contract ready for blockchain ``` ## Rule 14: Common Mistakes to AVOID ### ❌ DON'T: Use inline loop declaration or i++ ```javascript for (let i = 0; i < array.length; i++) { } // WRONG! for (var i = 0; i < array.length; i += 1) { } // WRONG! ``` ### ❌ DON'T: Use Array.isArray() ```javascript if (Array.isArray(params.targets)) { } // WRONG! Undeclared 'Array' ``` ### ❌ DON'T: Forward reference functions ```javascript const _main = function() { _helper(); // ERROR: out of scope }; const _helper = function() { }; // Too late! ``` ### ❌ DON'T: Use IIFE pattern ```javascript var MyLib = (function() { return {}; })(); ``` ### ❌ DON'T: Use arrow functions ```javascript const myFunc = () => { }; ``` ### ❌ DON'T: Use ES6+ classes ```javascript class MyContract { } ``` ### ❌ DON'T: Place main contract in specs/ ```javascript contracts/specs/MyMainContract.js // WRONG! ``` ### ❌ DON'T: Manually handle object storage ```javascript Chain.store('obj', JSON.stringify(obj)); // Use BasicOperation! ``` ### ❌ DON'T: Pass context objects ```javascript function myMethod(context, params) { // WRONG! Chain.load(context.contractAddress + ':key'); } ``` ### ❌ DON'T: Use switch-case for routing ```javascript function main(input) { switch(data.method) { // WRONG! Use funcList case 'method1': ... } } ``` ## Rule 15: Deployment Checklist Before deployment, verify: - [ ] Used `npx create-zetrix-tool` for setup - [ ] Main contract in `contracts/` root (not specs/) - [ ] All libraries use ES5 constructor pattern - [ ] Using `BasicOperation` for object storage - [ ] Reused existing libraries where applicable - [ ] **NODE_URL in .env has NO https:// protocol** (just domain) - [ ] **Loop syntax: `let i; for (i = 0; i < len; i += 1)`** - [ ] **NO Array.isArray() - use `.length` checks instead** - [ ] **Functions defined BEFORE they are called** (no forward refs) - [ ] Implemented interfaces if token standard - [ ] Main contract uses funcList routing - [ ] No ES6+ syntax (arrow functions, classes, etc.) - [ ] Import paths are correct - [ ] Tested deployment successfully - [ ] Generated merged contract has no JSLint errors ## Quick Reference ### Project Setup ```bash npx create-zetrix-tool <CONTRACT_NAME> ``` ### File Structure ``` contracts/<ContractName>.js # Main (ROOT!) contracts/library/<library-name>.js # Libraries contracts/specs/<library-name>-spec.js # Test specs ``` ### Code Pattern ```javascript const MyLib = function () { const BasicOperationUtil = new BasicOperation(); const self = this; self.method = function() { }; }; ``` ### Storage ```javascript BasicOperationUtil.saveObj(key, obj); let obj = BasicOperationUtil.loadObj(key); let key = BasicOperationUtil.getKey('pre', p1, p2); ``` ### Loop Syntax ```javascript let i; for (i = 0; i < array.length; i += 1) { // body } ``` ### Array Validation ```javascript // Check array exists and has length if (!params.targets || !params.targets.length) { // Invalid } ``` ### Main Contract ```javascript import 'library/my-lib'; const Lib = new MyLibrary(); function init(input) { } function main(input_str) { /* funcList */ } function query(input_str) { /* funcList */ } ``` ## Error Messages to Watch For If you see these during development, you made a mistake: ### JSLint Errors (from blockchain validator): - **"Unexpected 'let'"** (in for loop) → Use `let i;` on separate line, then `for (i = 0; ...)` - **"Expected 'let' and instead saw 'var'"** → Use `let` not `var` for variables - **"Undeclared 'Array'"** → Don't use `Array.isArray()`, use `.length` checks - **"'_functionName' is out of scope"** → Define helper functions BEFORE functions that call them - **"expected_a_b"** with i++ → Use `i += 1` instead of `i++` ### Deployment Errors: - "Cannot find module 'basic-operation'" → Wrong import path - "deployOperation is not a function" → Wrong import syntax - "IIFE detected" → Need ES5 constructor - "Arrow function found" → Use function expressions - "getaddrinfo EAI_AGAIN" → Network issue or wrong NODE_URL format - Merge errors → Check import paths - "context is not defined" → Don't pass context, use Chain directly ## Remember **These rules exist because:** 1. Zetrix VM requires ES5 compatibility 2. Official tools handle imports/merging correctly 3. BasicOperation ensures consistent storage 4. File organization helps testing and maintenance 5. Patterns are proven in official contracts (ZTP20, etc.) **When in doubt, refer to official examples:** - `contracts/library/ztp20/ztp20.js` - Library pattern - `contracts/specs/ztp20/ztp20-core-spec.js` - Main contract pattern - `contracts/library/pausable.js` - Simple library - `contracts/utils/basic-operation.js` - Storage utility --- **These rules are MANDATORY for all Zetrix contract development through this MCP server.**

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Zetrix-Chain/zetrix-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server