360 lines
11 KiB
Dart
360 lines
11 KiB
Dart
/// Synor Compiler SDK Examples for Flutter/Dart
|
|
///
|
|
/// Demonstrates smart contract compilation and analysis:
|
|
/// - WASM contract compilation and optimization
|
|
/// - ABI extraction and encoding
|
|
/// - Contract analysis and security scanning
|
|
/// - Validation and verification
|
|
library;
|
|
|
|
import 'dart:io';
|
|
import 'dart:typed_data';
|
|
import 'package:synor_compiler/synor_compiler.dart';
|
|
|
|
Future<void> main() async {
|
|
// Initialize client
|
|
final config = CompilerConfig(
|
|
apiKey: Platform.environment['SYNOR_API_KEY'] ?? 'your-api-key',
|
|
endpoint: 'https://compiler.synor.io/v1',
|
|
timeout: const Duration(seconds: 60),
|
|
retries: 3,
|
|
debug: false,
|
|
defaultOptimizationLevel: OptimizationLevel.size,
|
|
maxContractSize: 256 * 1024,
|
|
useWasmOpt: true,
|
|
validate: true,
|
|
extractMetadata: true,
|
|
generateAbi: true,
|
|
);
|
|
|
|
final compiler = SynorCompiler(config);
|
|
|
|
try {
|
|
// Check service health
|
|
final healthy = await compiler.healthCheck();
|
|
print('Service healthy: $healthy\n');
|
|
|
|
// Run examples
|
|
await compileContractExample(compiler);
|
|
await compilationModesExample(compiler);
|
|
await abiExample(compiler);
|
|
await analysisExample(compiler);
|
|
await validationExample(compiler);
|
|
await securityExample(compiler);
|
|
} finally {
|
|
await compiler.close();
|
|
}
|
|
}
|
|
|
|
/// Create a minimal valid WASM module for testing.
|
|
Uint8List createMinimalWasm() {
|
|
return Uint8List.fromList([
|
|
0x00, 0x61, 0x73, 0x6d, // Magic: \0asm
|
|
0x01, 0x00, 0x00, 0x00, // Version: 1
|
|
// Type section
|
|
0x01, 0x07, 0x01, 0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f,
|
|
// Function section
|
|
0x03, 0x02, 0x01, 0x00,
|
|
// Export section
|
|
0x07, 0x08, 0x01, 0x04, 0x61, 0x64, 0x64, 0x00, 0x00,
|
|
// Code section
|
|
0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b,
|
|
]);
|
|
}
|
|
|
|
Future<void> compileContractExample(SynorCompiler compiler) async {
|
|
print('=== Contract Compilation ===');
|
|
|
|
final wasm = createMinimalWasm();
|
|
|
|
final result = await compiler.compile(
|
|
wasm,
|
|
options: CompileOptions(
|
|
optimizationLevel: OptimizationLevel.size,
|
|
useWasmOpt: true,
|
|
validate: true,
|
|
extractMetadata: true,
|
|
generateAbi: true,
|
|
stripOptions: StripOptions(
|
|
stripDebug: true,
|
|
stripProducers: true,
|
|
stripNames: true,
|
|
stripCustom: true,
|
|
stripUnused: true,
|
|
preserveSections: [],
|
|
),
|
|
),
|
|
);
|
|
|
|
print('Compilation result:');
|
|
print(' Contract ID: ${result.contractId}');
|
|
print(' Code hash: ${result.codeHash}');
|
|
print(' Original size: ${result.originalSize} bytes');
|
|
print(' Optimized size: ${result.optimizedSize} bytes');
|
|
print(' Size reduction: ${result.sizeReduction.toStringAsFixed(1)}%');
|
|
print(' Estimated deploy gas: ${result.estimatedDeployGas}');
|
|
|
|
if (result.metadata != null) {
|
|
print('\nMetadata:');
|
|
print(' Name: ${result.metadata!.name}');
|
|
print(' Version: ${result.metadata!.version}');
|
|
print(' SDK Version: ${result.metadata!.sdkVersion}');
|
|
}
|
|
|
|
if (result.abi != null) {
|
|
print('\nABI:');
|
|
print(' Functions: ${result.abi!.functions?.length ?? 0}');
|
|
print(' Events: ${result.abi!.events?.length ?? 0}');
|
|
print(' Errors: ${result.abi!.errors?.length ?? 0}');
|
|
}
|
|
|
|
print('');
|
|
}
|
|
|
|
Future<void> compilationModesExample(SynorCompiler compiler) async {
|
|
print('=== Compilation Modes ===');
|
|
|
|
final wasm = createMinimalWasm();
|
|
|
|
// Development mode: fast compilation, debugging support
|
|
print('Development mode:');
|
|
final devResult = await compiler.contracts.compileDev(wasm);
|
|
print(' Size: ${devResult.optimizedSize} bytes');
|
|
print(' Optimization: none');
|
|
|
|
// Production mode: maximum optimization
|
|
print('\nProduction mode:');
|
|
final prodResult = await compiler.contracts.compileProduction(wasm);
|
|
print(' Size: ${prodResult.optimizedSize} bytes');
|
|
print(' Optimization: aggressive');
|
|
print(' Size savings: ${devResult.optimizedSize - prodResult.optimizedSize} bytes');
|
|
|
|
// Custom optimization levels
|
|
print('\nOptimization levels:');
|
|
final levels = [
|
|
OptimizationLevel.none,
|
|
OptimizationLevel.basic,
|
|
OptimizationLevel.size,
|
|
OptimizationLevel.aggressive,
|
|
];
|
|
|
|
for (final level in levels) {
|
|
final result = await compiler.compile(
|
|
wasm,
|
|
options: CompileOptions(optimizationLevel: level),
|
|
);
|
|
print(' $level: ${result.optimizedSize} bytes');
|
|
}
|
|
|
|
print('');
|
|
}
|
|
|
|
Future<void> abiExample(SynorCompiler compiler) async {
|
|
print('=== ABI Operations ===');
|
|
|
|
final wasm = createMinimalWasm();
|
|
|
|
// Extract ABI from WASM
|
|
final abi = await compiler.abi.extract(wasm);
|
|
print('Contract: ${abi.name}');
|
|
print('Version: ${abi.version}');
|
|
|
|
// List functions
|
|
if (abi.functions != null && abi.functions!.isNotEmpty) {
|
|
print('\nFunctions:');
|
|
for (final func in abi.functions!) {
|
|
final inputs = func.inputs
|
|
?.map((i) => '${i.name}: ${i.type.typeName}')
|
|
.join(', ') ??
|
|
'';
|
|
final outputs = func.outputs?.map((o) => o.type.typeName).join(', ') ?? 'void';
|
|
final modifiers = [
|
|
if (func.view) 'view',
|
|
if (func.payable) 'payable',
|
|
].join(' ');
|
|
print(' ${func.name}($inputs) -> $outputs $modifiers');
|
|
print(' Selector: ${func.selector}');
|
|
}
|
|
}
|
|
|
|
// List events
|
|
if (abi.events != null && abi.events!.isNotEmpty) {
|
|
print('\nEvents:');
|
|
for (final event in abi.events!) {
|
|
final params = event.params
|
|
?.map((p) =>
|
|
'${p.indexed ? "indexed " : ""}${p.name}: ${p.type.typeName}')
|
|
.join(', ') ??
|
|
'';
|
|
print(' ${event.name}($params)');
|
|
print(' Topic: ${event.topic}');
|
|
}
|
|
}
|
|
|
|
// Encode a function call
|
|
if (abi.functions != null && abi.functions!.isNotEmpty) {
|
|
final func = abi.functions!.first;
|
|
final encoded = await compiler.abi.encodeCall(func, ['arg1', 'arg2']);
|
|
print('\nEncoded call to ${func.name}: $encoded');
|
|
|
|
// Decode a result
|
|
final decoded = await compiler.abi.decodeResult(func, encoded);
|
|
print('Decoded result: $decoded');
|
|
}
|
|
|
|
print('');
|
|
}
|
|
|
|
Future<void> analysisExample(SynorCompiler compiler) async {
|
|
print('=== Contract Analysis ===');
|
|
|
|
final wasm = createMinimalWasm();
|
|
|
|
// Full analysis
|
|
final analysis = await compiler.analysis.analyze(wasm);
|
|
|
|
// Size breakdown
|
|
if (analysis.sizeBreakdown != null) {
|
|
print('Size breakdown:');
|
|
print(' Code: ${analysis.sizeBreakdown!.code} bytes');
|
|
print(' Data: ${analysis.sizeBreakdown!.data} bytes');
|
|
print(' Functions: ${analysis.sizeBreakdown!.functions} bytes');
|
|
print(' Memory: ${analysis.sizeBreakdown!.memory} bytes');
|
|
print(' Exports: ${analysis.sizeBreakdown!.exports} bytes');
|
|
print(' Imports: ${analysis.sizeBreakdown!.imports} bytes');
|
|
print(' Total: ${analysis.sizeBreakdown!.total} bytes');
|
|
}
|
|
|
|
// Function analysis
|
|
if (analysis.functions != null && analysis.functions!.isNotEmpty) {
|
|
print('\nFunction analysis:');
|
|
for (final func in analysis.functions!.take(5)) {
|
|
print(' ${func.name}:');
|
|
print(' Size: ${func.size} bytes');
|
|
print(' Instructions: ${func.instructionCount}');
|
|
print(' Locals: ${func.localCount}');
|
|
print(' Exported: ${func.exported}');
|
|
print(' Estimated gas: ${func.estimatedGas}');
|
|
}
|
|
}
|
|
|
|
// Import analysis
|
|
if (analysis.imports != null && analysis.imports!.isNotEmpty) {
|
|
print('\nImports:');
|
|
for (final imp in analysis.imports!) {
|
|
print(' ${imp.module}.${imp.name} (${imp.kind})');
|
|
}
|
|
}
|
|
|
|
// Gas analysis
|
|
if (analysis.gasAnalysis != null) {
|
|
print('\nGas analysis:');
|
|
print(' Deployment: ${analysis.gasAnalysis!.deploymentGas}');
|
|
print(' Memory init: ${analysis.gasAnalysis!.memoryInitGas}');
|
|
print(' Data section: ${analysis.gasAnalysis!.dataSectionGas}');
|
|
}
|
|
|
|
// Extract metadata
|
|
final metadata = await compiler.analysis.extractMetadata(wasm);
|
|
print('\nContract metadata:');
|
|
print(' Name: ${metadata.name}');
|
|
print(' Version: ${metadata.version}');
|
|
print(' Build timestamp: ${metadata.buildTimestamp}');
|
|
|
|
// Estimate deployment gas
|
|
final gas = await compiler.analysis.estimateDeployGas(wasm);
|
|
print('\nEstimated deployment gas: $gas');
|
|
|
|
print('');
|
|
}
|
|
|
|
Future<void> validationExample(SynorCompiler compiler) async {
|
|
print('=== Contract Validation ===');
|
|
|
|
final wasm = createMinimalWasm();
|
|
|
|
// Full validation
|
|
final result = await compiler.validation.validate(wasm);
|
|
print('Valid: ${result.valid}');
|
|
print('Exports: ${result.exportCount}');
|
|
print('Imports: ${result.importCount}');
|
|
print('Functions: ${result.functionCount}');
|
|
print('Memory pages: ${result.memoryPages}');
|
|
|
|
if (result.errors != null && result.errors!.isNotEmpty) {
|
|
print('\nValidation errors:');
|
|
for (final error in result.errors!) {
|
|
print(' [${error.code}] ${error.message}');
|
|
if (error.location != null) {
|
|
print(' at ${error.location}');
|
|
}
|
|
}
|
|
}
|
|
|
|
if (result.warnings != null && result.warnings!.isNotEmpty) {
|
|
print('\nWarnings:');
|
|
for (final warning in result.warnings!) {
|
|
print(' $warning');
|
|
}
|
|
}
|
|
|
|
// Quick validation
|
|
final isValid = await compiler.validation.isValid(wasm);
|
|
print('\nQuick validation: $isValid');
|
|
|
|
// Get validation errors only
|
|
final errors = await compiler.validation.getErrors(wasm);
|
|
print('Error count: ${errors.length}');
|
|
|
|
// Validate required exports
|
|
final hasRequired = await compiler.validation.validateExports(
|
|
wasm,
|
|
['init', 'execute', 'query'],
|
|
);
|
|
print('Has required exports: $hasRequired');
|
|
|
|
// Validate memory constraints
|
|
final memoryValid = await compiler.validation.validateMemory(wasm, 16);
|
|
print('Memory within 16 pages: $memoryValid');
|
|
|
|
print('');
|
|
}
|
|
|
|
Future<void> securityExample(SynorCompiler compiler) async {
|
|
print('=== Security Scanning ===');
|
|
|
|
final wasm = createMinimalWasm();
|
|
|
|
final security = await compiler.analysis.securityScan(wasm);
|
|
|
|
print('Security score: ${security.score}/100');
|
|
|
|
if (security.issues != null && security.issues!.isNotEmpty) {
|
|
print('\nSecurity issues:');
|
|
final severityIcons = {
|
|
'critical': '[CRIT]',
|
|
'high': '[HIGH]',
|
|
'medium': '[MED]',
|
|
'low': '[LOW]',
|
|
};
|
|
for (final issue in security.issues!) {
|
|
final icon = severityIcons[issue.severity] ?? '[???]';
|
|
print('$icon [${issue.severity.toUpperCase()}] ${issue.type}');
|
|
print(' ${issue.description}');
|
|
if (issue.location != null) {
|
|
print(' at ${issue.location}');
|
|
}
|
|
}
|
|
} else {
|
|
print('No security issues found!');
|
|
}
|
|
|
|
if (security.recommendations != null && security.recommendations!.isNotEmpty) {
|
|
print('\nRecommendations:');
|
|
for (final rec in security.recommendations!) {
|
|
print(' • $rec');
|
|
}
|
|
}
|
|
|
|
print('');
|
|
}
|