UNPKG

@albert-mr/genlayer-mcp-server

Version:

MCP server for generating GenLayer Intelligent Contracts with AI-native blockchain capabilities

781 lines (657 loc) 22.6 kB
export class TypesAndStorageTools { static async explainGenLayerTypes(params) { try { const typeExplanations = { primitive_types: `# GenLayer Primitive Types GenLayer supports various primitive types for blockchain storage and computation: ## Integer Types - **Unsigned Integers**: u8, u16, u32, u64, u128, u256 - **Signed Integers**: i8, i16, i32, i64, i128, i256 - **bigint**: Arbitrary precision integer (use with caution) ${params.include_examples ? `### Examples: \`\`\`python class Contract(gl.Contract): balance: u256 # Large unsigned integer for token balances user_count: u32 # Smaller integer for counters temperature: i16 # Signed integer for temperatures def __init__(self): self.balance = u256(1000000) self.user_count = u32(0) self.temperature = i16(-10) \`\`\` ` : ''} ## Other Primitive Types - **bool**: Boolean values (True/False) - **str**: UTF-8 encoded strings - **bytes**: Raw byte sequences - **Address**: Blockchain addresses (20 bytes) ${params.include_examples ? `### Examples: \`\`\`python class Contract(gl.Contract): is_active: bool name: str data: bytes owner: Address def __init__(self): self.is_active = True self.name = "My Contract" self.data = b"\\x00\\x01\\x02" self.owner = gl.message.sender_address \`\`\` ` : ''} ${params.include_comparisons ? `## Differences from Python Types - Use **u256** instead of **int** for most numeric operations - **Address** type ensures proper blockchain address handling - All storage types must be explicitly sized for gas optimization ` : ''}`, collection_types: `# GenLayer Collection Types GenLayer provides blockchain-optimized collection types: ## Dynamic Arrays (DynArray) - Replaces Python's list[T] - Dynamic sizing with gas-efficient storage - Implements MutableSequence interface ${params.include_examples ? `### DynArray Examples: \`\`\`python class Contract(gl.Contract): users: DynArray[str] # Array of strings balances: DynArray[u256] # Array of integers addresses: DynArray[Address] # Array of addresses def __init__(self): self.users = DynArray[str]() @gl.public.write def add_user(self, name: str): self.users.append(name) @gl.public.view def get_user_count(self) -> u256: return u256(len(self.users)) \`\`\` ` : ''} ## Tree Maps (TreeMap) - Replaces Python's dict[K, V] - Ordered key-value storage - Implements MutableMapping interface ${params.include_examples ? `### TreeMap Examples: \`\`\`python class Contract(gl.Contract): user_balances: TreeMap[Address, u256] # Address -> Balance metadata: TreeMap[str, str] # String -> String permissions: TreeMap[Address, bool] # Address -> Permission def __init__(self): self.user_balances = TreeMap[Address, u256]() @gl.public.write def set_balance(self, user: Address, amount: u256): self.user_balances[user] = amount @gl.public.view def get_balance(self, user: Address) -> u256: return self.user_balances.get(user, u256(0)) \`\`\` ` : ''}`, custom_types: `# GenLayer Custom Types You can create custom types using Python classes with special decorators: ## @allow_storage Decorator Custom classes must use @allow_storage for blockchain storage: ${params.include_examples ? `### Custom Type Examples: \`\`\`python from dataclasses import dataclass from genlayer import allow_storage @allow_storage @dataclass class User: name: str balance: u256 active: bool @allow_storage @dataclass class Proposal: id: u256 title: str votes_for: u256 votes_against: u256 metadata: TreeMap[str, str] class Contract(gl.Contract): users: DynArray[User] proposals: TreeMap[u256, Proposal] def __init__(self): self.users = DynArray[User]() self.proposals = TreeMap[u256, Proposal]() @gl.public.write def create_user(self, name: str) -> u256: user = User( name=name, balance=u256(100), active=True ) self.users.append(user) return u256(len(self.users) - 1) \`\`\` ` : ''} ## Memory Allocation for Custom Types Use gl.storage_inmem_allocate for complex nested types: ${params.include_examples ? `\`\`\`python # Allocating custom types with complex fields user_data = User( name="Alice", balance=u256(1000), metadata=gl.storage_inmem_allocate(TreeMap[str, str]) ) \`\`\` ` : ''}`, storage_restrictions: `# GenLayer Storage Restrictions ## Critical Rules for Storage Types ### ❌ Forbidden Types in Storage: - **list[T]** Use **DynArray[T]** instead - **dict[K, V]** Use **TreeMap[K, V]** instead - **int** Use sized integers (**u256**, **i64**, etc.) - **Generic types without full specification** TreeMap (forbidden), TreeMap[str, u256] (allowed) ### ✅ Required Patterns: 1. **All storage fields must be declared in class body** 2. **All fields must have type annotations** 3. **No instance variables outside class definition** ${params.include_examples ? `### Correct Storage Patterns: \`\`\`python class Contract(gl.Contract): # ✅ Correct declarations name: str balances: TreeMap[Address, u256] users: DynArray[str] count: u32 def __init__(self): self.name = "MyContract" # ❌ This would be lost after execution: # self.temp_var = "temporary" \`\`\` ### Field Declaration Rules: \`\`\`python class Contract(gl.Contract): # ❌ Wrong - not fully specified # data: TreeMap # items: DynArray # ✅ Correct - fully specified data: TreeMap[str, u256] items: DynArray[str] # ❌ Wrong - Python primitives # count: int # active: bool # This one is actually OK # ✅ Correct - GenLayer types count: u256 active: bool \`\`\` ` : ''}`, type_conversions: `# GenLayer Type Conversions ## Calldata to Storage Type Conversion When calling contract methods, GenLayer automatically converts between calldata and storage types: ### Automatic Conversions: - **JavaScript numbers** **u256, i64, etc.** - **JavaScript arrays** **DynArray[T]** - **JavaScript objects** **TreeMap[str, V]** (string keys only) - **Hex strings** **Address** (with 0x prefix) ${params.include_examples ? `### Conversion Examples: \`\`\`python # Contract method @gl.public.write def update_user(self, user_addr: Address, balance: u256, metadata: TreeMap[str, str]): # Implementation pass # JavaScript call (automatically converted) await contract.update_user( "0x1234567890123456789012345678901234567890", // Address 1000000, // u256 {"level": "premium", "region": "US"} // TreeMap[str, str] ); \`\`\` ` : ''} ## Manual Type Construction For complex scenarios, construct types explicitly: ${params.include_examples ? `### Manual Construction: \`\`\`python # In contract constructor or methods def __init__(self): # Explicit type construction self.balances = TreeMap[Address, u256]() self.user_list = DynArray[str]() # With initial values self.metadata = TreeMap[str, str]() self.metadata["version"] = "1.0" self.metadata["author"] = "Developer" \`\`\` ` : ''}`, all_types: `# Complete GenLayer Type System ## Primitive Types - **Integers**: u8, u16, u32, u64, u128, u256, i8, i16, i32, i64, i128, i256, bigint - **Other**: bool, str, bytes, Address ## Collection Types - **DynArray[T]**: Dynamic arrays (replaces list[T]) - **TreeMap[K, V]**: Ordered mappings (replaces dict[K, V]) ## Custom Types - Python classes with @allow_storage decorator - Supports dataclasses and complex nested structures ## Storage Rules - All fields must be declared in class body with type annotations - Use GenLayer-specific types, not Python primitives - Generic types must be fully specified ${params.include_examples ? `### Complete Example: \`\`\`python from dataclasses import dataclass from genlayer import * @allow_storage @dataclass class UserProfile: name: str balance: u256 preferences: TreeMap[str, str] class ComprehensiveContract(gl.Contract): # Primitive types total_supply: u256 is_paused: bool contract_name: str admin: Address # Collection types user_list: DynArray[Address] balances: TreeMap[Address, u256] # Custom types profiles: TreeMap[Address, UserProfile] def __init__(self, name: str): self.total_supply = u256(1000000) self.is_paused = False self.contract_name = name self.admin = gl.message.sender_address self.user_list = DynArray[Address]() self.balances = TreeMap[Address, u256]() self.profiles = TreeMap[Address, UserProfile]() \`\`\` ` : ''}` }; const explanation = typeExplanations[params.type_category]; if (!explanation) { return { content: `Error: Unknown type category '${params.type_category}'. Available categories: primitive_types, collection_types, custom_types, storage_restrictions, type_conversions, all_types`, isError: true }; } return { content: explanation, isError: false }; } catch (error) { return { content: `Error explaining GenLayer types: ${error.message}`, isError: true }; } } static async explainStoragePatterns(params) { try { const storageGuides = { storage_basics: `# GenLayer Storage Basics ## How Storage Works in GenLayer Intelligent Contracts store data persistently on the blockchain. Unlike traditional applications, blockchain storage has special requirements: ### Key Principles: 1. **Public Storage**: All contract data is publicly readable 2. **Gas Costs**: Storage operations consume gas 3. **Persistence**: Data survives contract executions 4. **Zero Initialization**: Storage starts at zero values ${params.include_examples ? `### Basic Storage Example: \`\`\`python class SimpleStorage(gl.Contract): # Storage field declarations owner: Address value: u256 message: str def __init__(self, initial_value: u256): # Initialize storage in constructor self.owner = gl.message.sender_address self.value = initial_value self.message = "Hello GenLayer" @gl.public.write def set_value(self, new_value: u256): # Only owner can modify if gl.message.sender_address != self.owner: raise Exception("Not authorized") self.value = new_value @gl.public.view def get_value(self) -> u256: return self.value \`\`\` ` : ''} ### Default Values: - **Numbers**: 0 - **Booleans**: False - **Strings**: "" - **Collections**: Empty ([], {}) - **Custom Types**: Zero-initialized recursively`, dynarray_usage: `# DynArray Usage Patterns DynArray is GenLayer's dynamic array type, replacing Python's list: ## Common Operations ${params.include_examples ? `### Basic DynArray Operations: \`\`\`python class ArrayContract(gl.Contract): items: DynArray[str] numbers: DynArray[u256] def __init__(self): self.items = DynArray[str]() self.numbers = DynArray[u256]() @gl.public.write def add_item(self, item: str): self.items.append(item) @gl.public.write def remove_item(self, index: u256): if index < len(self.items): del self.items[int(index)] @gl.public.view def get_item(self, index: u256) -> str: if index < len(self.items): return self.items[int(index)] return "" @gl.public.view def get_all_items(self) -> DynArray[str]: return self.items @gl.public.view def item_count(self) -> u256: return u256(len(self.items)) \`\`\` ` : ''} ## Advanced Patterns ${params.complexity_level === 'advanced' && params.include_examples ? `### Complex DynArray Usage: \`\`\`python @allow_storage @dataclass class Task: id: u256 title: str completed: bool assignee: Address class TaskManager(gl.Contract): tasks: DynArray[Task] user_task_count: TreeMap[Address, u256] @gl.public.write def create_task(self, title: str, assignee: Address) -> u256: task_id = u256(len(self.tasks)) task = Task( id=task_id, title=title, completed=False, assignee=assignee ) self.tasks.append(task) # Update user task count current_count = self.user_task_count.get(assignee, u256(0)) self.user_task_count[assignee] = current_count + u256(1) return task_id @gl.public.write def complete_task(self, task_id: u256): if task_id < len(self.tasks): self.tasks[int(task_id)].completed = True @gl.public.view def get_user_tasks(self, user: Address) -> DynArray[Task]: user_tasks = DynArray[Task]() for task in self.tasks: if task.assignee == user: user_tasks.append(task) return user_tasks \`\`\` ` : ''} ## Performance Considerations: - Appending is O(1) amortized - Indexing is O(1) - Deletion by index is O(n) - Iteration is O(n)`, treemap_usage: `# TreeMap Usage Patterns TreeMap provides ordered key-value storage, replacing Python's dict: ## Key Features: - **Ordered**: Keys maintain sorted order - **Efficient**: O(log n) operations - **Typed**: Both keys and values are strongly typed ${params.include_examples ? `### Basic TreeMap Operations: \`\`\`python class MappingContract(gl.Contract): balances: TreeMap[Address, u256] metadata: TreeMap[str, str] permissions: TreeMap[Address, bool] def __init__(self): self.balances = TreeMap[Address, u256]() self.metadata = TreeMap[str, str]() self.permissions = TreeMap[Address, bool]() @gl.public.write def set_balance(self, user: Address, amount: u256): self.balances[user] = amount @gl.public.view def get_balance(self, user: Address) -> u256: return self.balances.get(user, u256(0)) @gl.public.view def has_balance(self, user: Address) -> bool: return user in self.balances @gl.public.write def remove_user(self, user: Address): if user in self.balances: del self.balances[user] @gl.public.view def get_metadata(self, key: str) -> str: return self.metadata.get(key, "") \`\`\` ` : ''} ${params.complexity_level === 'advanced' && params.include_examples ? `### Advanced TreeMap Patterns: \`\`\`python class AdvancedMapping(gl.Contract): # Nested mappings user_preferences: TreeMap[Address, TreeMap[str, str]] category_items: TreeMap[str, DynArray[str]] def __init__(self): self.user_preferences = TreeMap[Address, TreeMap[str, str]]() self.category_items = TreeMap[str, DynArray[str]]() @gl.public.write def set_user_preference(self, user: Address, key: str, value: str): if user not in self.user_preferences: self.user_preferences[user] = gl.storage_inmem_allocate(TreeMap[str, str]) self.user_preferences[user][key] = value @gl.public.write def add_item_to_category(self, category: str, item: str): if category not in self.category_items: self.category_items[category] = gl.storage_inmem_allocate(DynArray[str]) self.category_items[category].append(item) \`\`\` ` : ''} ## Common Patterns: - **Default Values**: Use .get(key, default) for safe access - **Existence Checks**: Use 'key in mapping' before operations - **Iteration**: TreeMap maintains key ordering for predictable iteration`, storage_optimization: `# Storage Optimization Techniques ## Gas-Efficient Storage Patterns ### 1. Pack Related Data ${params.include_examples ? `\`\`\`python # ❌ Inefficient - separate storage slots class Inefficient(gl.Contract): user_active: TreeMap[Address, bool] user_balance: TreeMap[Address, u256] user_timestamp: TreeMap[Address, u256] # ✅ Efficient - packed into custom type @allow_storage @dataclass class UserData: active: bool balance: u256 last_activity: u256 class Efficient(gl.Contract): users: TreeMap[Address, UserData] \`\`\` ` : ''} ### 2. Use Appropriate Integer Sizes ${params.include_examples ? `\`\`\`python class OptimizedSizes(gl.Contract): # Use smallest sufficient type user_count: u32 # Instead of u256 for counters percentage: u8 # For 0-100 values large_balance: u256 # For token amounts small_id: u16 # For small identifiers \`\`\` ` : ''} ### 3. Lazy Initialization ${params.include_examples ? `\`\`\`python class LazyInit(gl.Contract): user_data: TreeMap[Address, UserData] @gl.public.write def update_user(self, user: Address, balance: u256): # Only create storage when needed if user not in self.user_data: self.user_data[user] = UserData( active=True, balance=balance, last_activity=gl.block.timestamp ) else: self.user_data[user].balance = balance \`\`\` ` : ''} ### 4. Batch Operations ${params.include_examples ? `\`\`\`python @gl.public.write def batch_update_balances(self, users: DynArray[Address], amounts: DynArray[u256]): # Process multiple updates in single transaction for i in range(len(users)): if i < len(amounts): self.balances[users[i]] = amounts[i] \`\`\` ` : ''}`, storage_best_practices: `# GenLayer Storage Best Practices ## Security Guidelines ### 1. Validate All Inputs ${params.include_examples ? `\`\`\`python @gl.public.write def set_user_data(self, user: Address, name: str, age: u8): # Validate address if user == Address('0x0000000000000000000000000000000000000000'): raise Exception("Invalid address") # Validate string length if len(name) == 0 or len(name) > 50: raise Exception("Name must be 1-50 characters") # Validate range if age > 150: raise Exception("Invalid age") # Safe to store self.user_profiles[user] = UserProfile(name=name, age=age) \`\`\` ` : ''} ### 2. Implement Access Control ${params.include_examples ? `\`\`\`python class SecureContract(gl.Contract): owner: Address admins: TreeMap[Address, bool] def __init__(self): self.owner = gl.message.sender_address self.admins = TreeMap[Address, bool]() def _only_owner(self): if gl.message.sender_address != self.owner: raise Exception("Only owner allowed") def _only_admin(self): if (gl.message.sender_address != self.owner and not self.admins.get(gl.message.sender_address, False)): raise Exception("Admin access required") @gl.public.write def add_admin(self, admin: Address): self._only_owner() self.admins[admin] = True \`\`\` ` : ''} ### 3. Handle Edge Cases ${params.include_examples ? `\`\`\`python @gl.public.view def get_user_balance(self, user: Address) -> u256: # Safe access with default return self.balances.get(user, u256(0)) @gl.public.write def transfer(self, to: Address, amount: u256): sender = gl.message.sender_address sender_balance = self.balances.get(sender, u256(0)) # Check sufficient balance if sender_balance < amount: raise Exception("Insufficient balance") # Check for overflow on recipient recipient_balance = self.balances.get(to, u256(0)) if recipient_balance + amount < recipient_balance: raise Exception("Overflow detected") # Safe transfer self.balances[sender] = sender_balance - amount self.balances[to] = recipient_balance + amount \`\`\` ` : ''} ## Performance Guidelines ### 1. Minimize Storage Reads/Writes - Cache frequently accessed values - Batch operations when possible - Use local variables for calculations ### 2. Efficient Data Structures - Choose appropriate collection types - Consider access patterns when designing storage - Use custom types to group related data ### 3. Gas Optimization - Use smallest adequate integer types - Avoid unnecessary storage operations - Consider storage layout for related fields` }; const explanation = storageGuides[params.storage_topic]; if (!explanation) { return { content: `Error: Unknown storage topic '${params.storage_topic}'. Available topics: storage_basics, dynarray_usage, treemap_usage, custom_storage_types, storage_optimization, storage_patterns, storage_best_practices`, isError: true }; } return { content: explanation, isError: false }; } catch (error) { return { content: `Error explaining storage patterns: ${error.message}`, isError: true }; } } } //# sourceMappingURL=typesAndStorage.js.map