- Introduced `ibc_example.rs` demonstrating Inter-Blockchain Communication operations including cross-chain transfers, channel management, packet handling, and relayer operations. - Introduced `zk_example.rs` showcasing Zero-Knowledge proof operations such as circuit compilation, proof generation and verification, and on-chain verification with multiple proving systems.
465 lines
12 KiB
Go
465 lines
12 KiB
Go
// Package main demonstrates the Synor Compiler SDK for Go
|
|
//
|
|
// This example covers smart contract compilation and analysis:
|
|
// - WASM contract compilation and optimization
|
|
// - ABI extraction and encoding
|
|
// - Contract analysis and security scanning
|
|
// - Validation and verification
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"log"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/synor/sdk-go/compiler"
|
|
)
|
|
|
|
func main() {
|
|
// Initialize client
|
|
config := compiler.Config{
|
|
APIKey: getEnv("SYNOR_API_KEY", "your-api-key"),
|
|
Endpoint: "https://compiler.synor.io/v1",
|
|
Timeout: 60 * time.Second,
|
|
Retries: 3,
|
|
Debug: false,
|
|
DefaultOptimizationLevel: compiler.OptimizationSize,
|
|
MaxContractSize: 256 * 1024,
|
|
UseWasmOpt: true,
|
|
Validate: true,
|
|
ExtractMetadata: true,
|
|
GenerateABI: true,
|
|
}
|
|
|
|
client, err := compiler.NewClient(config)
|
|
if err != nil {
|
|
log.Fatalf("Failed to create client: %v", err)
|
|
}
|
|
defer client.Close()
|
|
|
|
ctx := context.Background()
|
|
|
|
// Check service health
|
|
healthy, err := client.HealthCheck(ctx)
|
|
if err != nil {
|
|
log.Printf("Health check failed: %v", err)
|
|
} else {
|
|
fmt.Printf("Service healthy: %v\n\n", healthy)
|
|
}
|
|
|
|
// Run examples
|
|
compileContractExample(ctx, client)
|
|
compilationModesExample(ctx, client)
|
|
abiExample(ctx, client)
|
|
analysisExample(ctx, client)
|
|
validationExample(ctx, client)
|
|
securityExample(ctx, client)
|
|
}
|
|
|
|
// createMinimalWasm creates a minimal valid WASM module for testing.
|
|
func createMinimalWasm() []byte {
|
|
return []byte{
|
|
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,
|
|
}
|
|
}
|
|
|
|
func compileContractExample(ctx context.Context, client *compiler.Client) {
|
|
fmt.Println("=== Contract Compilation ===")
|
|
|
|
wasm := createMinimalWasm()
|
|
|
|
result, err := client.Compile(ctx, wasm, &compiler.CompileOptions{
|
|
OptimizationLevel: compiler.OptimizationSize,
|
|
UseWasmOpt: true,
|
|
Validate: true,
|
|
ExtractMetadata: true,
|
|
GenerateABI: true,
|
|
StripOptions: &compiler.StripOptions{
|
|
StripDebug: true,
|
|
StripProducers: true,
|
|
StripNames: true,
|
|
StripCustom: true,
|
|
StripUnused: true,
|
|
PreserveSections: []string{},
|
|
},
|
|
})
|
|
if err != nil {
|
|
log.Printf("Failed to compile contract: %v", err)
|
|
return
|
|
}
|
|
|
|
fmt.Println("Compilation result:")
|
|
fmt.Printf(" Contract ID: %s\n", result.ContractID)
|
|
fmt.Printf(" Code hash: %s\n", result.CodeHash)
|
|
fmt.Printf(" Original size: %d bytes\n", result.OriginalSize)
|
|
fmt.Printf(" Optimized size: %d bytes\n", result.OptimizedSize)
|
|
fmt.Printf(" Size reduction: %.1f%%\n", result.SizeReduction)
|
|
fmt.Printf(" Estimated deploy gas: %d\n", result.EstimatedDeployGas)
|
|
|
|
if result.Metadata != nil {
|
|
fmt.Println("\nMetadata:")
|
|
fmt.Printf(" Name: %s\n", result.Metadata.Name)
|
|
fmt.Printf(" Version: %s\n", result.Metadata.Version)
|
|
fmt.Printf(" SDK Version: %s\n", result.Metadata.SDKVersion)
|
|
}
|
|
|
|
if result.ABI != nil {
|
|
fmt.Println("\nABI:")
|
|
fmt.Printf(" Functions: %d\n", len(result.ABI.Functions))
|
|
fmt.Printf(" Events: %d\n", len(result.ABI.Events))
|
|
fmt.Printf(" Errors: %d\n", len(result.ABI.Errors))
|
|
}
|
|
|
|
fmt.Println()
|
|
}
|
|
|
|
func compilationModesExample(ctx context.Context, client *compiler.Client) {
|
|
fmt.Println("=== Compilation Modes ===")
|
|
|
|
wasm := createMinimalWasm()
|
|
|
|
// Development mode: fast compilation, debugging support
|
|
fmt.Println("Development mode:")
|
|
devResult, err := client.Contracts.CompileDev(ctx, wasm)
|
|
if err != nil {
|
|
log.Printf("Failed to compile in dev mode: %v", err)
|
|
return
|
|
}
|
|
fmt.Printf(" Size: %d bytes\n", devResult.OptimizedSize)
|
|
fmt.Println(" Optimization: none")
|
|
|
|
// Production mode: maximum optimization
|
|
fmt.Println("\nProduction mode:")
|
|
prodResult, err := client.Contracts.CompileProduction(ctx, wasm)
|
|
if err != nil {
|
|
log.Printf("Failed to compile in production mode: %v", err)
|
|
return
|
|
}
|
|
fmt.Printf(" Size: %d bytes\n", prodResult.OptimizedSize)
|
|
fmt.Println(" Optimization: aggressive")
|
|
fmt.Printf(" Size savings: %d bytes\n", devResult.OptimizedSize-prodResult.OptimizedSize)
|
|
|
|
// Custom optimization levels
|
|
fmt.Println("\nOptimization levels:")
|
|
levels := []compiler.OptimizationLevel{
|
|
compiler.OptimizationNone,
|
|
compiler.OptimizationBasic,
|
|
compiler.OptimizationSize,
|
|
compiler.OptimizationAggressive,
|
|
}
|
|
|
|
for _, level := range levels {
|
|
result, err := client.Compile(ctx, wasm, &compiler.CompileOptions{
|
|
OptimizationLevel: level,
|
|
})
|
|
if err != nil {
|
|
log.Printf("Failed to compile with %s: %v", level, err)
|
|
continue
|
|
}
|
|
fmt.Printf(" %s: %d bytes\n", level, result.OptimizedSize)
|
|
}
|
|
|
|
fmt.Println()
|
|
}
|
|
|
|
func abiExample(ctx context.Context, client *compiler.Client) {
|
|
fmt.Println("=== ABI Operations ===")
|
|
|
|
wasm := createMinimalWasm()
|
|
|
|
// Extract ABI from WASM
|
|
abi, err := client.ABI.Extract(ctx, wasm)
|
|
if err != nil {
|
|
log.Printf("Failed to extract ABI: %v", err)
|
|
return
|
|
}
|
|
fmt.Printf("Contract: %s\n", abi.Name)
|
|
fmt.Printf("Version: %s\n", abi.Version)
|
|
|
|
// List functions
|
|
if len(abi.Functions) > 0 {
|
|
fmt.Println("\nFunctions:")
|
|
for _, fn := range abi.Functions {
|
|
inputs := ""
|
|
for i, input := range fn.Inputs {
|
|
if i > 0 {
|
|
inputs += ", "
|
|
}
|
|
inputs += fmt.Sprintf("%s: %s", input.Name, input.Type.TypeName)
|
|
}
|
|
|
|
outputs := "void"
|
|
if len(fn.Outputs) > 0 {
|
|
outputTypes := make([]string, len(fn.Outputs))
|
|
for i, output := range fn.Outputs {
|
|
outputTypes[i] = output.Type.TypeName
|
|
}
|
|
outputs = fmt.Sprintf("%v", outputTypes)
|
|
}
|
|
|
|
modifiers := ""
|
|
if fn.View {
|
|
modifiers += "view "
|
|
}
|
|
if fn.Payable {
|
|
modifiers += "payable"
|
|
}
|
|
|
|
fmt.Printf(" %s(%s) -> %s %s\n", fn.Name, inputs, outputs, modifiers)
|
|
fmt.Printf(" Selector: %s\n", fn.Selector)
|
|
}
|
|
}
|
|
|
|
// List events
|
|
if len(abi.Events) > 0 {
|
|
fmt.Println("\nEvents:")
|
|
for _, event := range abi.Events {
|
|
params := ""
|
|
for i, param := range event.Params {
|
|
if i > 0 {
|
|
params += ", "
|
|
}
|
|
indexed := ""
|
|
if param.Indexed {
|
|
indexed = "indexed "
|
|
}
|
|
params += fmt.Sprintf("%s%s: %s", indexed, param.Name, param.Type.TypeName)
|
|
}
|
|
fmt.Printf(" %s(%s)\n", event.Name, params)
|
|
fmt.Printf(" Topic: %s\n", event.Topic)
|
|
}
|
|
}
|
|
|
|
// Encode a function call
|
|
if len(abi.Functions) > 0 {
|
|
fn := abi.Functions[0]
|
|
encoded, err := client.ABI.EncodeCall(ctx, fn, []interface{}{"arg1", "arg2"})
|
|
if err != nil {
|
|
log.Printf("Failed to encode call: %v", err)
|
|
} else {
|
|
fmt.Printf("\nEncoded call to %s: %s\n", fn.Name, encoded)
|
|
}
|
|
|
|
// Decode a result
|
|
decoded, err := client.ABI.DecodeResult(ctx, fn, encoded)
|
|
if err != nil {
|
|
log.Printf("Failed to decode result: %v", err)
|
|
} else {
|
|
fmt.Printf("Decoded result: %v\n", decoded)
|
|
}
|
|
}
|
|
|
|
fmt.Println()
|
|
}
|
|
|
|
func analysisExample(ctx context.Context, client *compiler.Client) {
|
|
fmt.Println("=== Contract Analysis ===")
|
|
|
|
wasm := createMinimalWasm()
|
|
|
|
// Full analysis
|
|
analysis, err := client.Analysis.Analyze(ctx, wasm)
|
|
if err != nil {
|
|
log.Printf("Failed to analyze contract: %v", err)
|
|
return
|
|
}
|
|
|
|
// Size breakdown
|
|
if analysis.SizeBreakdown != nil {
|
|
fmt.Println("Size breakdown:")
|
|
fmt.Printf(" Code: %d bytes\n", analysis.SizeBreakdown.Code)
|
|
fmt.Printf(" Data: %d bytes\n", analysis.SizeBreakdown.Data)
|
|
fmt.Printf(" Functions: %d bytes\n", analysis.SizeBreakdown.Functions)
|
|
fmt.Printf(" Memory: %d bytes\n", analysis.SizeBreakdown.Memory)
|
|
fmt.Printf(" Exports: %d bytes\n", analysis.SizeBreakdown.Exports)
|
|
fmt.Printf(" Imports: %d bytes\n", analysis.SizeBreakdown.Imports)
|
|
fmt.Printf(" Total: %d bytes\n", analysis.SizeBreakdown.Total)
|
|
}
|
|
|
|
// Function analysis
|
|
if len(analysis.Functions) > 0 {
|
|
fmt.Println("\nFunction analysis:")
|
|
limit := 5
|
|
if len(analysis.Functions) < limit {
|
|
limit = len(analysis.Functions)
|
|
}
|
|
for _, fn := range analysis.Functions[:limit] {
|
|
fmt.Printf(" %s:\n", fn.Name)
|
|
fmt.Printf(" Size: %d bytes\n", fn.Size)
|
|
fmt.Printf(" Instructions: %d\n", fn.InstructionCount)
|
|
fmt.Printf(" Locals: %d\n", fn.LocalCount)
|
|
fmt.Printf(" Exported: %v\n", fn.Exported)
|
|
fmt.Printf(" Estimated gas: %d\n", fn.EstimatedGas)
|
|
}
|
|
}
|
|
|
|
// Import analysis
|
|
if len(analysis.Imports) > 0 {
|
|
fmt.Println("\nImports:")
|
|
for _, imp := range analysis.Imports {
|
|
fmt.Printf(" %s.%s (%s)\n", imp.Module, imp.Name, imp.Kind)
|
|
}
|
|
}
|
|
|
|
// Gas analysis
|
|
if analysis.GasAnalysis != nil {
|
|
fmt.Println("\nGas analysis:")
|
|
fmt.Printf(" Deployment: %d\n", analysis.GasAnalysis.DeploymentGas)
|
|
fmt.Printf(" Memory init: %d\n", analysis.GasAnalysis.MemoryInitGas)
|
|
fmt.Printf(" Data section: %d\n", analysis.GasAnalysis.DataSectionGas)
|
|
}
|
|
|
|
// Extract metadata
|
|
metadata, err := client.Analysis.ExtractMetadata(ctx, wasm)
|
|
if err != nil {
|
|
log.Printf("Failed to extract metadata: %v", err)
|
|
} else {
|
|
fmt.Println("\nContract metadata:")
|
|
fmt.Printf(" Name: %s\n", metadata.Name)
|
|
fmt.Printf(" Version: %s\n", metadata.Version)
|
|
fmt.Printf(" Build timestamp: %s\n", metadata.BuildTimestamp)
|
|
}
|
|
|
|
// Estimate deployment gas
|
|
gas, err := client.Analysis.EstimateDeployGas(ctx, wasm)
|
|
if err != nil {
|
|
log.Printf("Failed to estimate deploy gas: %v", err)
|
|
} else {
|
|
fmt.Printf("\nEstimated deployment gas: %d\n", gas)
|
|
}
|
|
|
|
fmt.Println()
|
|
}
|
|
|
|
func validationExample(ctx context.Context, client *compiler.Client) {
|
|
fmt.Println("=== Contract Validation ===")
|
|
|
|
wasm := createMinimalWasm()
|
|
|
|
// Full validation
|
|
result, err := client.Validation.Validate(ctx, wasm)
|
|
if err != nil {
|
|
log.Printf("Failed to validate contract: %v", err)
|
|
return
|
|
}
|
|
fmt.Printf("Valid: %v\n", result.Valid)
|
|
fmt.Printf("Exports: %d\n", result.ExportCount)
|
|
fmt.Printf("Imports: %d\n", result.ImportCount)
|
|
fmt.Printf("Functions: %d\n", result.FunctionCount)
|
|
fmt.Printf("Memory pages: %d\n", result.MemoryPages)
|
|
|
|
if len(result.Errors) > 0 {
|
|
fmt.Println("\nValidation errors:")
|
|
for _, e := range result.Errors {
|
|
fmt.Printf(" [%s] %s\n", e.Code, e.Message)
|
|
if e.Location != "" {
|
|
fmt.Printf(" at %s\n", e.Location)
|
|
}
|
|
}
|
|
}
|
|
|
|
if len(result.Warnings) > 0 {
|
|
fmt.Println("\nWarnings:")
|
|
for _, warning := range result.Warnings {
|
|
fmt.Printf(" %s\n", warning)
|
|
}
|
|
}
|
|
|
|
// Quick validation
|
|
isValid, err := client.Validation.IsValid(ctx, wasm)
|
|
if err != nil {
|
|
log.Printf("Failed quick validation: %v", err)
|
|
} else {
|
|
fmt.Printf("\nQuick validation: %v\n", isValid)
|
|
}
|
|
|
|
// Get validation errors only
|
|
errors, err := client.Validation.GetErrors(ctx, wasm)
|
|
if err != nil {
|
|
log.Printf("Failed to get validation errors: %v", err)
|
|
} else {
|
|
fmt.Printf("Error count: %d\n", len(errors))
|
|
}
|
|
|
|
// Validate required exports
|
|
hasRequired, err := client.Validation.ValidateExports(ctx, wasm, []string{"init", "execute", "query"})
|
|
if err != nil {
|
|
log.Printf("Failed to validate exports: %v", err)
|
|
} else {
|
|
fmt.Printf("Has required exports: %v\n", hasRequired)
|
|
}
|
|
|
|
// Validate memory constraints
|
|
memoryValid, err := client.Validation.ValidateMemory(ctx, wasm, 16)
|
|
if err != nil {
|
|
log.Printf("Failed to validate memory: %v", err)
|
|
} else {
|
|
fmt.Printf("Memory within 16 pages: %v\n", memoryValid)
|
|
}
|
|
|
|
fmt.Println()
|
|
}
|
|
|
|
func securityExample(ctx context.Context, client *compiler.Client) {
|
|
fmt.Println("=== Security Scanning ===")
|
|
|
|
wasm := createMinimalWasm()
|
|
|
|
security, err := client.Analysis.SecurityScan(ctx, wasm)
|
|
if err != nil {
|
|
log.Printf("Failed to perform security scan: %v", err)
|
|
return
|
|
}
|
|
|
|
fmt.Printf("Security score: %d/100\n", security.Score)
|
|
|
|
if len(security.Issues) > 0 {
|
|
fmt.Println("\nSecurity issues:")
|
|
severityIcons := map[string]string{
|
|
"critical": "[CRIT]",
|
|
"high": "[HIGH]",
|
|
"medium": "[MED]",
|
|
"low": "[LOW]",
|
|
}
|
|
for _, issue := range security.Issues {
|
|
icon := severityIcons[issue.Severity]
|
|
if icon == "" {
|
|
icon = "[???]"
|
|
}
|
|
fmt.Printf("%s [%s] %s\n", icon, issue.Severity, issue.Type)
|
|
fmt.Printf(" %s\n", issue.Description)
|
|
if issue.Location != "" {
|
|
fmt.Printf(" at %s\n", issue.Location)
|
|
}
|
|
}
|
|
} else {
|
|
fmt.Println("No security issues found!")
|
|
}
|
|
|
|
if len(security.Recommendations) > 0 {
|
|
fmt.Println("\nRecommendations:")
|
|
for _, rec := range security.Recommendations {
|
|
fmt.Printf(" * %s\n", rec)
|
|
}
|
|
}
|
|
|
|
fmt.Println()
|
|
}
|
|
|
|
func getEnv(key, defaultValue string) string {
|
|
if value := os.Getenv(key); value != "" {
|
|
return value
|
|
}
|
|
return defaultValue
|
|
}
|