package compiler import ( "bytes" "context" "encoding/base64" "encoding/json" "fmt" "io" "net/http" "sync/atomic" "time" ) // SynorCompiler is the main compiler client. type SynorCompiler struct { config CompilerConfig httpClient *http.Client closed atomic.Bool // Sub-clients Contracts *ContractsClient Abi *AbiClient Analysis *AnalysisClient Validation *ValidationClient } // NewSynorCompiler creates a new compiler client. func NewSynorCompiler(config CompilerConfig) *SynorCompiler { if config.Endpoint == "" { config.Endpoint = "https://compiler.synor.io/v1" } if config.Timeout == 0 { config.Timeout = 60000 } if config.OptimizationLevel == "" { config.OptimizationLevel = OptimizationSize } c := &SynorCompiler{ config: config, httpClient: &http.Client{ Timeout: time.Duration(config.Timeout) * time.Millisecond, }, } c.Contracts = &ContractsClient{compiler: c} c.Abi = &AbiClient{compiler: c} c.Analysis = &AnalysisClient{compiler: c} c.Validation = &ValidationClient{compiler: c} return c } // DefaultOptimizationLevel returns the default optimization level. func (c *SynorCompiler) DefaultOptimizationLevel() OptimizationLevel { return c.config.OptimizationLevel } // HealthCheck checks service health. func (c *SynorCompiler) HealthCheck(ctx context.Context) (bool, error) { var result map[string]interface{} if err := c.get(ctx, "/health", &result); err != nil { return false, nil } return result["status"] == "healthy", nil } // GetInfo returns service info. func (c *SynorCompiler) GetInfo(ctx context.Context) (map[string]interface{}, error) { var result map[string]interface{} if err := c.get(ctx, "/info", &result); err != nil { return nil, err } return result, nil } // Close closes the client. func (c *SynorCompiler) Close() { c.closed.Store(true) } // IsClosed returns whether the client is closed. func (c *SynorCompiler) IsClosed() bool { return c.closed.Load() } // Compile compiles WASM bytecode. func (c *SynorCompiler) Compile(ctx context.Context, wasm []byte, opts *CompilationRequest) (*CompilationResult, error) { wasmBase64 := base64.StdEncoding.EncodeToString(wasm) body := map[string]interface{}{ "wasm": wasmBase64, } if opts != nil { if opts.OptimizationLevel != nil { body["optimization_level"] = *opts.OptimizationLevel } else { body["optimization_level"] = c.config.OptimizationLevel } if opts.StripOptions != nil { body["strip_options"] = opts.StripOptions } if opts.UseWasmOpt != nil { body["use_wasm_opt"] = *opts.UseWasmOpt } else { body["use_wasm_opt"] = c.config.UseWasmOpt } if opts.Validate != nil { body["validate"] = *opts.Validate } else { body["validate"] = c.config.Validate } if opts.ExtractMetadata != nil { body["extract_metadata"] = *opts.ExtractMetadata } else { body["extract_metadata"] = c.config.ExtractMetadata } if opts.GenerateAbi != nil { body["generate_abi"] = *opts.GenerateAbi } else { body["generate_abi"] = c.config.GenerateAbi } } else { body["optimization_level"] = c.config.OptimizationLevel body["use_wasm_opt"] = c.config.UseWasmOpt body["validate"] = c.config.Validate body["extract_metadata"] = c.config.ExtractMetadata body["generate_abi"] = c.config.GenerateAbi } var result CompilationResult if err := c.post(ctx, "/compile", body, &result); err != nil { return nil, err } return &result, nil } func (c *SynorCompiler) get(ctx context.Context, path string, result interface{}) error { if c.closed.Load() { return &CompilerError{Message: "Client has been closed", Code: "CLIENT_CLOSED"} } req, err := http.NewRequestWithContext(ctx, "GET", c.config.Endpoint+path, nil) if err != nil { return err } c.setHeaders(req) return c.doRequest(req, result) } func (c *SynorCompiler) post(ctx context.Context, path string, body interface{}, result interface{}) error { if c.closed.Load() { return &CompilerError{Message: "Client has been closed", Code: "CLIENT_CLOSED"} } jsonBody, err := json.Marshal(body) if err != nil { return err } req, err := http.NewRequestWithContext(ctx, "POST", c.config.Endpoint+path, bytes.NewReader(jsonBody)) if err != nil { return err } c.setHeaders(req) return c.doRequest(req, result) } func (c *SynorCompiler) setHeaders(req *http.Request) { req.Header.Set("Authorization", "Bearer "+c.config.APIKey) req.Header.Set("Content-Type", "application/json") req.Header.Set("X-SDK-Version", "go/0.1.0") } func (c *SynorCompiler) doRequest(req *http.Request, result interface{}) error { resp, err := c.httpClient.Do(req) if err != nil { return err } defer resp.Body.Close() respBody, err := io.ReadAll(resp.Body) if err != nil { return err } if resp.StatusCode >= 400 { var errResp map[string]interface{} if json.Unmarshal(respBody, &errResp) == nil { msg, _ := errResp["message"].(string) code, _ := errResp["code"].(string) if msg == "" { msg = fmt.Sprintf("HTTP %d", resp.StatusCode) } return &CompilerError{Message: msg, Code: code, HTTPStatus: resp.StatusCode} } return &CompilerError{ Message: fmt.Sprintf("HTTP %d: %s", resp.StatusCode, string(respBody)), HTTPStatus: resp.StatusCode, } } if result != nil && len(respBody) > 0 { return json.Unmarshal(respBody, result) } return nil } // ContractsClient is the contracts sub-client. type ContractsClient struct { compiler *SynorCompiler } // Compile compiles WASM bytecode with default settings. func (c *ContractsClient) Compile(ctx context.Context, wasm []byte, opts *CompilationRequest) (*CompilationResult, error) { return c.compiler.Compile(ctx, wasm, opts) } // CompileDev compiles with development settings. func (c *ContractsClient) CompileDev(ctx context.Context, wasm []byte) (*CompilationResult, error) { level := OptimizationNone useWasmOpt := false validate := true return c.compiler.Compile(ctx, wasm, &CompilationRequest{ OptimizationLevel: &level, UseWasmOpt: &useWasmOpt, Validate: &validate, }) } // CompileProduction compiles with production settings. func (c *ContractsClient) CompileProduction(ctx context.Context, wasm []byte) (*CompilationResult, error) { level := OptimizationAggressive useWasmOpt := true validate := true extractMetadata := true generateAbi := true return c.compiler.Compile(ctx, wasm, &CompilationRequest{ OptimizationLevel: &level, UseWasmOpt: &useWasmOpt, Validate: &validate, ExtractMetadata: &extractMetadata, GenerateAbi: &generateAbi, }) } // Get gets a compiled contract by ID. func (c *ContractsClient) Get(ctx context.Context, contractID string) (*CompilationResult, error) { var result CompilationResult if err := c.compiler.get(ctx, "/contracts/"+contractID, &result); err != nil { return nil, err } return &result, nil } // List lists compiled contracts. func (c *ContractsClient) List(ctx context.Context, limit, offset *int) ([]CompilationResult, error) { path := "/contracts" if limit != nil || offset != nil { path += "?" if limit != nil { path += fmt.Sprintf("limit=%d", *limit) if offset != nil { path += "&" } } if offset != nil { path += fmt.Sprintf("offset=%d", *offset) } } var result struct { Contracts []CompilationResult `json:"contracts"` } if err := c.compiler.get(ctx, path, &result); err != nil { return nil, err } return result.Contracts, nil } // GetCode gets optimized bytecode for a contract. func (c *ContractsClient) GetCode(ctx context.Context, contractID string) ([]byte, error) { var result struct { Code string `json:"code"` } if err := c.compiler.get(ctx, "/contracts/"+contractID+"/code", &result); err != nil { return nil, err } return base64.StdEncoding.DecodeString(result.Code) } // AbiClient is the ABI sub-client. type AbiClient struct { compiler *SynorCompiler } // Extract extracts ABI from WASM bytecode. func (c *AbiClient) Extract(ctx context.Context, wasm []byte) (*ContractAbi, error) { wasmBase64 := base64.StdEncoding.EncodeToString(wasm) var result ContractAbi if err := c.compiler.post(ctx, "/abi/extract", map[string]string{"wasm": wasmBase64}, &result); err != nil { return nil, err } return &result, nil } // Get gets ABI for a compiled contract. func (c *AbiClient) Get(ctx context.Context, contractID string) (*ContractAbi, error) { var result ContractAbi if err := c.compiler.get(ctx, "/contracts/"+contractID+"/abi", &result); err != nil { return nil, err } return &result, nil } // EncodeCall encodes a function call. func (c *AbiClient) EncodeCall(ctx context.Context, functionAbi *FunctionAbi, args []interface{}) (string, error) { var result struct { Data string `json:"data"` } if err := c.compiler.post(ctx, "/abi/encode", map[string]interface{}{ "function": functionAbi, "args": args, }, &result); err != nil { return "", err } return result.Data, nil } // DecodeResult decodes a function result. func (c *AbiClient) DecodeResult(ctx context.Context, functionAbi *FunctionAbi, data string) ([]interface{}, error) { var result struct { Values []interface{} `json:"values"` } if err := c.compiler.post(ctx, "/abi/decode", map[string]interface{}{ "function": functionAbi, "data": data, }, &result); err != nil { return nil, err } return result.Values, nil } // AnalysisClient is the analysis sub-client. type AnalysisClient struct { compiler *SynorCompiler } // Analyze analyzes WASM bytecode. func (c *AnalysisClient) Analyze(ctx context.Context, wasm []byte) (*ContractAnalysis, error) { wasmBase64 := base64.StdEncoding.EncodeToString(wasm) var result ContractAnalysis if err := c.compiler.post(ctx, "/analysis", map[string]string{"wasm": wasmBase64}, &result); err != nil { return nil, err } return &result, nil } // Get gets analysis for a compiled contract. func (c *AnalysisClient) Get(ctx context.Context, contractID string) (*ContractAnalysis, error) { var result ContractAnalysis if err := c.compiler.get(ctx, "/contracts/"+contractID+"/analysis", &result); err != nil { return nil, err } return &result, nil } // ExtractMetadata extracts metadata from WASM bytecode. func (c *AnalysisClient) ExtractMetadata(ctx context.Context, wasm []byte) (*ContractMetadata, error) { wasmBase64 := base64.StdEncoding.EncodeToString(wasm) var result ContractMetadata if err := c.compiler.post(ctx, "/analysis/metadata", map[string]string{"wasm": wasmBase64}, &result); err != nil { return nil, err } return &result, nil } // ExtractSourceMap extracts source map from WASM bytecode. func (c *AnalysisClient) ExtractSourceMap(ctx context.Context, wasm []byte) (*SourceMap, error) { wasmBase64 := base64.StdEncoding.EncodeToString(wasm) var result struct { SourceMap *SourceMap `json:"source_map"` } if err := c.compiler.post(ctx, "/analysis/source-map", map[string]string{"wasm": wasmBase64}, &result); err != nil { return nil, err } return result.SourceMap, nil } // EstimateDeployGas estimates gas for contract deployment. func (c *AnalysisClient) EstimateDeployGas(ctx context.Context, wasm []byte) (int64, error) { wasmBase64 := base64.StdEncoding.EncodeToString(wasm) var result struct { Gas int64 `json:"gas"` } if err := c.compiler.post(ctx, "/analysis/estimate-gas", map[string]string{"wasm": wasmBase64}, &result); err != nil { return 0, err } return result.Gas, nil } // SecurityScan performs security analysis. func (c *AnalysisClient) SecurityScan(ctx context.Context, wasm []byte) (*SecurityAnalysis, error) { wasmBase64 := base64.StdEncoding.EncodeToString(wasm) var result struct { Security SecurityAnalysis `json:"security"` } if err := c.compiler.post(ctx, "/analysis/security", map[string]string{"wasm": wasmBase64}, &result); err != nil { return nil, err } return &result.Security, nil } // ValidationClient is the validation sub-client. type ValidationClient struct { compiler *SynorCompiler } // Validate validates WASM bytecode against VM requirements. func (c *ValidationClient) Validate(ctx context.Context, wasm []byte) (*ValidationResult, error) { wasmBase64 := base64.StdEncoding.EncodeToString(wasm) var result ValidationResult if err := c.compiler.post(ctx, "/validate", map[string]string{"wasm": wasmBase64}, &result); err != nil { return nil, err } return &result, nil } // IsValid checks if WASM is valid. func (c *ValidationClient) IsValid(ctx context.Context, wasm []byte) (bool, error) { result, err := c.Validate(ctx, wasm) if err != nil { return false, err } return result.Valid, nil } // GetErrors gets validation errors. func (c *ValidationClient) GetErrors(ctx context.Context, wasm []byte) ([]string, error) { result, err := c.Validate(ctx, wasm) if err != nil { return nil, err } errors := make([]string, len(result.Errors)) for i, e := range result.Errors { errors[i] = e.Message } return errors, nil } // ValidateExports validates contract exports. func (c *ValidationClient) ValidateExports(ctx context.Context, wasm []byte, requiredExports []string) (bool, error) { wasmBase64 := base64.StdEncoding.EncodeToString(wasm) var result struct { Valid bool `json:"valid"` } if err := c.compiler.post(ctx, "/validate/exports", map[string]interface{}{ "wasm": wasmBase64, "required_exports": requiredExports, }, &result); err != nil { return false, err } return result.Valid, nil } // ValidateMemory validates memory limits. func (c *ValidationClient) ValidateMemory(ctx context.Context, wasm []byte, maxPages int) (bool, error) { wasmBase64 := base64.StdEncoding.EncodeToString(wasm) var result struct { Valid bool `json:"valid"` } if err := c.compiler.post(ctx, "/validate/memory", map[string]interface{}{ "wasm": wasmBase64, "max_pages": maxPages, }, &result); err != nil { return false, err } return result.Valid, nil }