feat(sdk): Add comprehensive examples for C, C++, C#, and Ruby SDKs
Add example code demonstrating all SDK services (Crypto, DEX, ZK, IBC, Compiler) for the remaining languages: - C SDK (5 examples): Using synor_* C API with explicit memory management - C++ SDK (5 examples): Modern C++17 with RAII and designated initializers - C# SDK (5 examples): Async/await patterns with .NET conventions - Ruby SDK (5 examples): Ruby idioms with blocks and symbols Each example covers: - Crypto: Hybrid signatures, mnemonics, Falcon, SPHINCS+, KDF, hashing - DEX: Markets, spot trading, perpetuals, liquidity, portfolio - ZK: Circuits, Groth16, PLONK, STARK, recursive proofs, ceremonies - IBC: Chains, channels, transfers, packets, relayer, monitoring - Compiler: Compilation, optimization, ABI, analysis, validation, security
This commit is contained in:
parent
e169c492aa
commit
cf5130d9e4
19 changed files with 7091 additions and 0 deletions
553
sdk/c/examples/compiler_example.c
Normal file
553
sdk/c/examples/compiler_example.c
Normal file
|
|
@ -0,0 +1,553 @@
|
||||||
|
/**
|
||||||
|
* Synor Compiler SDK Examples for C
|
||||||
|
*
|
||||||
|
* Demonstrates smart contract compilation and analysis:
|
||||||
|
* - WASM contract compilation and optimization
|
||||||
|
* - ABI extraction and encoding
|
||||||
|
* - Contract analysis and security scanning
|
||||||
|
* - Validation and verification
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <synor/compiler.h>
|
||||||
|
|
||||||
|
// Helper function to create a minimal valid WASM module for testing
|
||||||
|
void create_minimal_wasm(uint8_t** wasm, size_t* wasm_len) {
|
||||||
|
static const uint8_t minimal_wasm[] = {
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
*wasm_len = sizeof(minimal_wasm);
|
||||||
|
*wasm = (uint8_t*)malloc(*wasm_len);
|
||||||
|
memcpy(*wasm, minimal_wasm, *wasm_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void compile_contract_example(synor_compiler_t* compiler) {
|
||||||
|
printf("=== Contract Compilation ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
uint8_t* wasm;
|
||||||
|
size_t wasm_len;
|
||||||
|
create_minimal_wasm(&wasm, &wasm_len);
|
||||||
|
|
||||||
|
synor_compile_options_t options = {
|
||||||
|
.optimization_level = SYNOR_OPTIMIZATION_SIZE,
|
||||||
|
.use_wasm_opt = true,
|
||||||
|
.validate = true,
|
||||||
|
.extract_metadata = true,
|
||||||
|
.generate_abi = true,
|
||||||
|
.strip_options = {
|
||||||
|
.strip_debug = true,
|
||||||
|
.strip_producers = true,
|
||||||
|
.strip_names = true,
|
||||||
|
.strip_custom = true,
|
||||||
|
.strip_unused = true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_compile_result_t* result = NULL;
|
||||||
|
err = synor_compile(compiler, wasm, wasm_len, &options, &result);
|
||||||
|
free(wasm);
|
||||||
|
|
||||||
|
if (err != SYNOR_OK) {
|
||||||
|
fprintf(stderr, "Failed to compile contract\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Compilation result:\n");
|
||||||
|
printf(" Contract ID: %s\n", synor_compile_result_get_contract_id(result));
|
||||||
|
printf(" Code hash: %s\n", synor_compile_result_get_code_hash(result));
|
||||||
|
printf(" Original size: %zu bytes\n", synor_compile_result_get_original_size(result));
|
||||||
|
printf(" Optimized size: %zu bytes\n", synor_compile_result_get_optimized_size(result));
|
||||||
|
printf(" Size reduction: %.1f%%\n", synor_compile_result_get_size_reduction(result));
|
||||||
|
printf(" Estimated deploy gas: %lu\n", synor_compile_result_get_estimated_deploy_gas(result));
|
||||||
|
|
||||||
|
// Get metadata if available
|
||||||
|
synor_contract_metadata_t* metadata = synor_compile_result_get_metadata(result);
|
||||||
|
if (metadata) {
|
||||||
|
printf("\nMetadata:\n");
|
||||||
|
printf(" Name: %s\n", synor_metadata_get_name(metadata));
|
||||||
|
printf(" Version: %s\n", synor_metadata_get_version(metadata));
|
||||||
|
printf(" SDK Version: %s\n", synor_metadata_get_sdk_version(metadata));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get ABI if available
|
||||||
|
synor_contract_abi_t* abi = synor_compile_result_get_abi(result);
|
||||||
|
if (abi) {
|
||||||
|
printf("\nABI:\n");
|
||||||
|
printf(" Functions: %zu\n", synor_abi_get_function_count(abi));
|
||||||
|
printf(" Events: %zu\n", synor_abi_get_event_count(abi));
|
||||||
|
printf(" Errors: %zu\n", synor_abi_get_error_count(abi));
|
||||||
|
}
|
||||||
|
|
||||||
|
synor_compile_result_free(result);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void compilation_modes_example(synor_compiler_t* compiler) {
|
||||||
|
printf("=== Compilation Modes ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
uint8_t* wasm;
|
||||||
|
size_t wasm_len;
|
||||||
|
create_minimal_wasm(&wasm, &wasm_len);
|
||||||
|
|
||||||
|
// Development mode: fast compilation, debugging support
|
||||||
|
printf("Development mode:\n");
|
||||||
|
synor_compile_result_t* dev_result = NULL;
|
||||||
|
err = synor_contracts_compile_dev(compiler, wasm, wasm_len, &dev_result);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf(" Size: %zu bytes\n", synor_compile_result_get_optimized_size(dev_result));
|
||||||
|
printf(" Optimization: none\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Production mode: maximum optimization
|
||||||
|
printf("\nProduction mode:\n");
|
||||||
|
synor_compile_result_t* prod_result = NULL;
|
||||||
|
err = synor_contracts_compile_production(compiler, wasm, wasm_len, &prod_result);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf(" Size: %zu bytes\n", synor_compile_result_get_optimized_size(prod_result));
|
||||||
|
printf(" Optimization: aggressive\n");
|
||||||
|
if (dev_result) {
|
||||||
|
printf(" Size savings: %zu bytes\n",
|
||||||
|
synor_compile_result_get_optimized_size(dev_result) -
|
||||||
|
synor_compile_result_get_optimized_size(prod_result));
|
||||||
|
}
|
||||||
|
synor_compile_result_free(prod_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev_result) synor_compile_result_free(dev_result);
|
||||||
|
|
||||||
|
// Custom optimization levels
|
||||||
|
printf("\nOptimization levels:\n");
|
||||||
|
synor_optimization_level_t levels[] = {
|
||||||
|
SYNOR_OPTIMIZATION_NONE,
|
||||||
|
SYNOR_OPTIMIZATION_BASIC,
|
||||||
|
SYNOR_OPTIMIZATION_SIZE,
|
||||||
|
SYNOR_OPTIMIZATION_AGGRESSIVE
|
||||||
|
};
|
||||||
|
const char* level_names[] = {"NONE", "BASIC", "SIZE", "AGGRESSIVE"};
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
synor_compile_options_t options = {
|
||||||
|
.optimization_level = levels[i]
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_compile_result_t* result = NULL;
|
||||||
|
err = synor_compile(compiler, wasm, wasm_len, &options, &result);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf(" %s: %zu bytes\n", level_names[i],
|
||||||
|
synor_compile_result_get_optimized_size(result));
|
||||||
|
synor_compile_result_free(result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free(wasm);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void abi_example(synor_compiler_t* compiler) {
|
||||||
|
printf("=== ABI Operations ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
uint8_t* wasm;
|
||||||
|
size_t wasm_len;
|
||||||
|
create_minimal_wasm(&wasm, &wasm_len);
|
||||||
|
|
||||||
|
// Extract ABI from WASM
|
||||||
|
synor_contract_abi_t* abi = NULL;
|
||||||
|
err = synor_abi_extract(compiler, wasm, wasm_len, &abi);
|
||||||
|
free(wasm);
|
||||||
|
|
||||||
|
if (err != SYNOR_OK) {
|
||||||
|
fprintf(stderr, "Failed to extract ABI\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Contract: %s\n", synor_abi_get_name(abi));
|
||||||
|
printf("Version: %s\n", synor_abi_get_version(abi));
|
||||||
|
|
||||||
|
// List functions
|
||||||
|
size_t func_count = synor_abi_get_function_count(abi);
|
||||||
|
if (func_count > 0) {
|
||||||
|
printf("\nFunctions:\n");
|
||||||
|
for (size_t i = 0; i < func_count; i++) {
|
||||||
|
synor_abi_function_t* func = synor_abi_get_function(abi, i);
|
||||||
|
|
||||||
|
char inputs[256] = "";
|
||||||
|
size_t input_count = synor_abi_function_get_input_count(func);
|
||||||
|
for (size_t j = 0; j < input_count; j++) {
|
||||||
|
synor_abi_param_t* param = synor_abi_function_get_input(func, j);
|
||||||
|
char temp[64];
|
||||||
|
snprintf(temp, sizeof(temp), "%s: %s%s",
|
||||||
|
synor_abi_param_get_name(param),
|
||||||
|
synor_abi_param_get_type_name(param),
|
||||||
|
j < input_count - 1 ? ", " : "");
|
||||||
|
strncat(inputs, temp, sizeof(inputs) - strlen(inputs) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
char outputs[128] = "void";
|
||||||
|
size_t output_count = synor_abi_function_get_output_count(func);
|
||||||
|
if (output_count > 0) {
|
||||||
|
outputs[0] = '\0';
|
||||||
|
for (size_t j = 0; j < output_count; j++) {
|
||||||
|
synor_abi_param_t* param = synor_abi_function_get_output(func, j);
|
||||||
|
char temp[64];
|
||||||
|
snprintf(temp, sizeof(temp), "%s%s",
|
||||||
|
synor_abi_param_get_type_name(param),
|
||||||
|
j < output_count - 1 ? ", " : "");
|
||||||
|
strncat(outputs, temp, sizeof(outputs) - strlen(outputs) - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char modifiers[32] = "";
|
||||||
|
if (synor_abi_function_is_view(func)) strcat(modifiers, "view ");
|
||||||
|
if (synor_abi_function_is_payable(func)) strcat(modifiers, "payable");
|
||||||
|
|
||||||
|
printf(" %s(%s) -> %s %s\n",
|
||||||
|
synor_abi_function_get_name(func), inputs, outputs, modifiers);
|
||||||
|
printf(" Selector: %s\n", synor_abi_function_get_selector(func));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// List events
|
||||||
|
size_t event_count = synor_abi_get_event_count(abi);
|
||||||
|
if (event_count > 0) {
|
||||||
|
printf("\nEvents:\n");
|
||||||
|
for (size_t i = 0; i < event_count; i++) {
|
||||||
|
synor_abi_event_t* event = synor_abi_get_event(abi, i);
|
||||||
|
|
||||||
|
char params[256] = "";
|
||||||
|
size_t param_count = synor_abi_event_get_param_count(event);
|
||||||
|
for (size_t j = 0; j < param_count; j++) {
|
||||||
|
synor_abi_event_param_t* param = synor_abi_event_get_param(event, j);
|
||||||
|
char temp[64];
|
||||||
|
snprintf(temp, sizeof(temp), "%s%s: %s%s",
|
||||||
|
synor_abi_event_param_is_indexed(param) ? "indexed " : "",
|
||||||
|
synor_abi_event_param_get_name(param),
|
||||||
|
synor_abi_event_param_get_type_name(param),
|
||||||
|
j < param_count - 1 ? ", " : "");
|
||||||
|
strncat(params, temp, sizeof(params) - strlen(params) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(" %s(%s)\n", synor_abi_event_get_name(event), params);
|
||||||
|
printf(" Topic: %s\n", synor_abi_event_get_topic(event));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode a function call
|
||||||
|
if (func_count > 0) {
|
||||||
|
synor_abi_function_t* func = synor_abi_get_function(abi, 0);
|
||||||
|
const char* args[] = {"arg1", "arg2"};
|
||||||
|
|
||||||
|
uint8_t* encoded;
|
||||||
|
size_t encoded_len;
|
||||||
|
err = synor_abi_encode_call(compiler, func, args, 2, &encoded, &encoded_len);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nEncoded call to %s: ", synor_abi_function_get_name(func));
|
||||||
|
for (size_t i = 0; i < encoded_len && i < 20; i++) {
|
||||||
|
printf("%02x", encoded[i]);
|
||||||
|
}
|
||||||
|
printf("...\n");
|
||||||
|
|
||||||
|
// Decode a result
|
||||||
|
char** decoded;
|
||||||
|
size_t decoded_count;
|
||||||
|
err = synor_abi_decode_result(compiler, func, encoded, encoded_len,
|
||||||
|
&decoded, &decoded_count);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Decoded result: ");
|
||||||
|
for (size_t i = 0; i < decoded_count; i++) {
|
||||||
|
printf("%s%s", decoded[i], i < decoded_count - 1 ? ", " : "");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
synor_string_array_free(decoded, decoded_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(encoded);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
synor_abi_free(abi);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void analysis_example(synor_compiler_t* compiler) {
|
||||||
|
printf("=== Contract Analysis ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
uint8_t* wasm;
|
||||||
|
size_t wasm_len;
|
||||||
|
create_minimal_wasm(&wasm, &wasm_len);
|
||||||
|
|
||||||
|
// Full analysis
|
||||||
|
synor_contract_analysis_t* analysis = NULL;
|
||||||
|
err = synor_analysis_analyze(compiler, wasm, wasm_len, &analysis);
|
||||||
|
if (err != SYNOR_OK) {
|
||||||
|
fprintf(stderr, "Failed to analyze contract\n");
|
||||||
|
free(wasm);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size breakdown
|
||||||
|
synor_size_breakdown_t* size = synor_analysis_get_size_breakdown(analysis);
|
||||||
|
if (size) {
|
||||||
|
printf("Size breakdown:\n");
|
||||||
|
printf(" Code: %zu bytes\n", synor_size_breakdown_get_code(size));
|
||||||
|
printf(" Data: %zu bytes\n", synor_size_breakdown_get_data(size));
|
||||||
|
printf(" Functions: %zu bytes\n", synor_size_breakdown_get_functions(size));
|
||||||
|
printf(" Memory: %zu bytes\n", synor_size_breakdown_get_memory(size));
|
||||||
|
printf(" Exports: %zu bytes\n", synor_size_breakdown_get_exports(size));
|
||||||
|
printf(" Imports: %zu bytes\n", synor_size_breakdown_get_imports(size));
|
||||||
|
printf(" Total: %zu bytes\n", synor_size_breakdown_get_total(size));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function analysis
|
||||||
|
size_t func_count = synor_analysis_get_function_count(analysis);
|
||||||
|
if (func_count > 0) {
|
||||||
|
printf("\nFunction analysis:\n");
|
||||||
|
for (size_t i = 0; i < 5 && i < func_count; i++) {
|
||||||
|
synor_function_analysis_t* func = synor_analysis_get_function(analysis, i);
|
||||||
|
printf(" %s:\n", synor_function_analysis_get_name(func));
|
||||||
|
printf(" Size: %zu bytes\n", synor_function_analysis_get_size(func));
|
||||||
|
printf(" Instructions: %zu\n", synor_function_analysis_get_instruction_count(func));
|
||||||
|
printf(" Locals: %zu\n", synor_function_analysis_get_local_count(func));
|
||||||
|
printf(" Exported: %s\n", synor_function_analysis_is_exported(func) ? "true" : "false");
|
||||||
|
printf(" Estimated gas: %lu\n", synor_function_analysis_get_estimated_gas(func));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import analysis
|
||||||
|
size_t import_count = synor_analysis_get_import_count(analysis);
|
||||||
|
if (import_count > 0) {
|
||||||
|
printf("\nImports:\n");
|
||||||
|
for (size_t i = 0; i < import_count; i++) {
|
||||||
|
synor_import_analysis_t* imp = synor_analysis_get_import(analysis, i);
|
||||||
|
printf(" %s.%s (%s)\n",
|
||||||
|
synor_import_analysis_get_module(imp),
|
||||||
|
synor_import_analysis_get_name(imp),
|
||||||
|
synor_import_analysis_get_kind(imp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gas analysis
|
||||||
|
synor_gas_analysis_t* gas = synor_analysis_get_gas_analysis(analysis);
|
||||||
|
if (gas) {
|
||||||
|
printf("\nGas analysis:\n");
|
||||||
|
printf(" Deployment: %lu\n", synor_gas_analysis_get_deployment_gas(gas));
|
||||||
|
printf(" Memory init: %lu\n", synor_gas_analysis_get_memory_init_gas(gas));
|
||||||
|
printf(" Data section: %lu\n", synor_gas_analysis_get_data_section_gas(gas));
|
||||||
|
}
|
||||||
|
|
||||||
|
synor_analysis_free(analysis);
|
||||||
|
|
||||||
|
// Extract metadata
|
||||||
|
synor_contract_metadata_t* metadata = NULL;
|
||||||
|
err = synor_analysis_extract_metadata(compiler, wasm, wasm_len, &metadata);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nContract metadata:\n");
|
||||||
|
printf(" Name: %s\n", synor_metadata_get_name(metadata));
|
||||||
|
printf(" Version: %s\n", synor_metadata_get_version(metadata));
|
||||||
|
printf(" Build timestamp: %s\n", synor_metadata_get_build_timestamp(metadata));
|
||||||
|
synor_metadata_free(metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Estimate deployment gas
|
||||||
|
uint64_t gas_estimate;
|
||||||
|
err = synor_analysis_estimate_deploy_gas(compiler, wasm, wasm_len, &gas_estimate);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nEstimated deployment gas: %lu\n", gas_estimate);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(wasm);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void validation_example(synor_compiler_t* compiler) {
|
||||||
|
printf("=== Contract Validation ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
uint8_t* wasm;
|
||||||
|
size_t wasm_len;
|
||||||
|
create_minimal_wasm(&wasm, &wasm_len);
|
||||||
|
|
||||||
|
// Full validation
|
||||||
|
synor_validation_result_t* result = NULL;
|
||||||
|
err = synor_validation_validate(compiler, wasm, wasm_len, &result);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Valid: %s\n", synor_validation_result_is_valid(result) ? "true" : "false");
|
||||||
|
printf("Exports: %zu\n", synor_validation_result_get_export_count(result));
|
||||||
|
printf("Imports: %zu\n", synor_validation_result_get_import_count(result));
|
||||||
|
printf("Functions: %zu\n", synor_validation_result_get_function_count(result));
|
||||||
|
printf("Memory pages: %zu\n", synor_validation_result_get_memory_pages(result));
|
||||||
|
|
||||||
|
// Print errors
|
||||||
|
size_t error_count = synor_validation_result_get_error_count(result);
|
||||||
|
if (error_count > 0) {
|
||||||
|
printf("\nValidation errors:\n");
|
||||||
|
for (size_t i = 0; i < error_count; i++) {
|
||||||
|
synor_validation_error_t* error = synor_validation_result_get_error(result, i);
|
||||||
|
printf(" [%s] %s\n",
|
||||||
|
synor_validation_error_get_code(error),
|
||||||
|
synor_validation_error_get_message(error));
|
||||||
|
const char* location = synor_validation_error_get_location(error);
|
||||||
|
if (location) {
|
||||||
|
printf(" at %s\n", location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print warnings
|
||||||
|
size_t warning_count = synor_validation_result_get_warning_count(result);
|
||||||
|
if (warning_count > 0) {
|
||||||
|
printf("\nWarnings:\n");
|
||||||
|
for (size_t i = 0; i < warning_count; i++) {
|
||||||
|
printf(" %s\n", synor_validation_result_get_warning(result, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
synor_validation_result_free(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quick validation
|
||||||
|
bool is_valid;
|
||||||
|
err = synor_validation_is_valid(compiler, wasm, wasm_len, &is_valid);
|
||||||
|
printf("\nQuick validation: %s\n", is_valid ? "true" : "false");
|
||||||
|
|
||||||
|
// Get validation errors only
|
||||||
|
synor_validation_error_list_t* errors = NULL;
|
||||||
|
err = synor_validation_get_errors(compiler, wasm, wasm_len, &errors);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Error count: %zu\n", synor_validation_error_list_count(errors));
|
||||||
|
synor_validation_error_list_free(errors);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate required exports
|
||||||
|
const char* required[] = {"init", "execute", "query"};
|
||||||
|
bool has_required;
|
||||||
|
err = synor_validation_validate_exports(compiler, wasm, wasm_len,
|
||||||
|
required, 3, &has_required);
|
||||||
|
printf("Has required exports: %s\n", has_required ? "true" : "false");
|
||||||
|
|
||||||
|
// Validate memory constraints
|
||||||
|
bool memory_valid;
|
||||||
|
err = synor_validation_validate_memory(compiler, wasm, wasm_len, 16, &memory_valid);
|
||||||
|
printf("Memory within 16 pages: %s\n", memory_valid ? "true" : "false");
|
||||||
|
|
||||||
|
free(wasm);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void security_example(synor_compiler_t* compiler) {
|
||||||
|
printf("=== Security Scanning ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
uint8_t* wasm;
|
||||||
|
size_t wasm_len;
|
||||||
|
create_minimal_wasm(&wasm, &wasm_len);
|
||||||
|
|
||||||
|
synor_security_scan_result_t* security = NULL;
|
||||||
|
err = synor_analysis_security_scan(compiler, wasm, wasm_len, &security);
|
||||||
|
free(wasm);
|
||||||
|
|
||||||
|
if (err != SYNOR_OK) {
|
||||||
|
fprintf(stderr, "Failed to scan contract\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Security score: %d/100\n", synor_security_scan_get_score(security));
|
||||||
|
|
||||||
|
size_t issue_count = synor_security_scan_get_issue_count(security);
|
||||||
|
if (issue_count > 0) {
|
||||||
|
printf("\nSecurity issues:\n");
|
||||||
|
for (size_t i = 0; i < issue_count; i++) {
|
||||||
|
synor_security_issue_t* issue = synor_security_scan_get_issue(security, i);
|
||||||
|
const char* severity = synor_security_issue_get_severity(issue);
|
||||||
|
const char* icon;
|
||||||
|
|
||||||
|
if (strcmp(severity, "critical") == 0) icon = "[CRIT]";
|
||||||
|
else if (strcmp(severity, "high") == 0) icon = "[HIGH]";
|
||||||
|
else if (strcmp(severity, "medium") == 0) icon = "[MED]";
|
||||||
|
else if (strcmp(severity, "low") == 0) icon = "[LOW]";
|
||||||
|
else icon = "[???]";
|
||||||
|
|
||||||
|
printf("%s [%s] %s\n", icon,
|
||||||
|
synor_security_issue_get_severity(issue),
|
||||||
|
synor_security_issue_get_type(issue));
|
||||||
|
printf(" %s\n", synor_security_issue_get_description(issue));
|
||||||
|
|
||||||
|
const char* location = synor_security_issue_get_location(issue);
|
||||||
|
if (location) {
|
||||||
|
printf(" at %s\n", location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("No security issues found!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t rec_count = synor_security_scan_get_recommendation_count(security);
|
||||||
|
if (rec_count > 0) {
|
||||||
|
printf("\nRecommendations:\n");
|
||||||
|
for (size_t i = 0; i < rec_count; i++) {
|
||||||
|
printf(" • %s\n", synor_security_scan_get_recommendation(security, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
synor_security_scan_result_free(security);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
synor_error_t err;
|
||||||
|
|
||||||
|
// Initialize client
|
||||||
|
synor_compiler_config_t config = {
|
||||||
|
.api_key = getenv("SYNOR_API_KEY") ? getenv("SYNOR_API_KEY") : "your-api-key",
|
||||||
|
.endpoint = "https://compiler.synor.io/v1",
|
||||||
|
.timeout_ms = 60000,
|
||||||
|
.retries = 3,
|
||||||
|
.debug = false,
|
||||||
|
.default_optimization_level = SYNOR_OPTIMIZATION_SIZE,
|
||||||
|
.max_contract_size = 256 * 1024,
|
||||||
|
.use_wasm_opt = true,
|
||||||
|
.validate = true,
|
||||||
|
.extract_metadata = true,
|
||||||
|
.generate_abi = true
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_compiler_t* compiler = NULL;
|
||||||
|
err = synor_compiler_init(&config, &compiler);
|
||||||
|
if (err != SYNOR_OK) {
|
||||||
|
fprintf(stderr, "Failed to initialize compiler client: %s\n", synor_error_string(err));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check service health
|
||||||
|
bool healthy;
|
||||||
|
err = synor_compiler_health_check(compiler, &healthy);
|
||||||
|
printf("Service healthy: %s\n\n", healthy ? "true" : "false");
|
||||||
|
|
||||||
|
// Run examples
|
||||||
|
compile_contract_example(compiler);
|
||||||
|
compilation_modes_example(compiler);
|
||||||
|
abi_example(compiler);
|
||||||
|
analysis_example(compiler);
|
||||||
|
validation_example(compiler);
|
||||||
|
security_example(compiler);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
synor_compiler_free(compiler);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
489
sdk/c/examples/dex_example.c
Normal file
489
sdk/c/examples/dex_example.c
Normal file
|
|
@ -0,0 +1,489 @@
|
||||||
|
/**
|
||||||
|
* Synor DEX SDK Examples for C
|
||||||
|
*
|
||||||
|
* Demonstrates decentralized exchange operations:
|
||||||
|
* - Spot trading (limit/market orders)
|
||||||
|
* - Perpetual futures trading
|
||||||
|
* - Liquidity provision (AMM pools)
|
||||||
|
* - Order book management
|
||||||
|
* - Portfolio tracking
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <synor/dex.h>
|
||||||
|
|
||||||
|
void markets_example(synor_dex_t* dex) {
|
||||||
|
printf("=== Markets ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
synor_market_list_t* markets = NULL;
|
||||||
|
|
||||||
|
// Get all markets
|
||||||
|
err = synor_markets_list(dex, &markets);
|
||||||
|
if (err != SYNOR_OK) {
|
||||||
|
fprintf(stderr, "Failed to get markets\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Available markets: %zu\n", synor_market_list_count(markets));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 5 && i < synor_market_list_count(markets); i++) {
|
||||||
|
synor_market_t* market = synor_market_list_get(markets, i);
|
||||||
|
printf("\n %s:\n", synor_market_get_symbol(market));
|
||||||
|
printf(" Base: %s, Quote: %s\n",
|
||||||
|
synor_market_get_base_asset(market),
|
||||||
|
synor_market_get_quote_asset(market));
|
||||||
|
printf(" Price: %s\n", synor_market_get_last_price(market));
|
||||||
|
printf(" 24h Volume: %s\n", synor_market_get_volume_24h(market));
|
||||||
|
printf(" 24h Change: %s%%\n", synor_market_get_change_24h(market));
|
||||||
|
printf(" Status: %s\n", synor_market_get_status(market));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get specific market
|
||||||
|
synor_market_t* market = NULL;
|
||||||
|
err = synor_markets_get(dex, "SYN-USDC", &market);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nSYN-USDC details:\n");
|
||||||
|
printf(" Min order size: %s\n", synor_market_get_min_order_size(market));
|
||||||
|
printf(" Tick size: %s\n", synor_market_get_tick_size(market));
|
||||||
|
printf(" Maker fee: %s%%\n", synor_market_get_maker_fee(market));
|
||||||
|
printf(" Taker fee: %s%%\n", synor_market_get_taker_fee(market));
|
||||||
|
synor_market_free(market);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get market statistics
|
||||||
|
synor_market_stats_t* stats = NULL;
|
||||||
|
err = synor_markets_get_stats(dex, "SYN-USDC", &stats);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nMarket statistics:\n");
|
||||||
|
printf(" High 24h: %s\n", synor_stats_get_high_24h(stats));
|
||||||
|
printf(" Low 24h: %s\n", synor_stats_get_low_24h(stats));
|
||||||
|
printf(" Open interest: %s\n", synor_stats_get_open_interest(stats));
|
||||||
|
printf(" Funding rate: %s%%\n", synor_stats_get_funding_rate(stats));
|
||||||
|
synor_market_stats_free(stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
synor_market_list_free(markets);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void spot_trading_example(synor_dex_t* dex) {
|
||||||
|
printf("=== Spot Trading ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
|
||||||
|
// Place a limit order
|
||||||
|
printf("Placing limit buy order...\n");
|
||||||
|
synor_order_request_t limit_req = {
|
||||||
|
.market = "SYN-USDC",
|
||||||
|
.side = SYNOR_ORDER_SIDE_BUY,
|
||||||
|
.order_type = SYNOR_ORDER_TYPE_LIMIT,
|
||||||
|
.price = "1.50",
|
||||||
|
.quantity = "100",
|
||||||
|
.time_in_force = SYNOR_TIME_IN_FORCE_GTC
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_order_result_t* limit_order = NULL;
|
||||||
|
err = synor_spot_place_order(dex, &limit_req, &limit_order);
|
||||||
|
if (err != SYNOR_OK) {
|
||||||
|
fprintf(stderr, "Failed to place limit order\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Limit order placed:\n");
|
||||||
|
printf(" Order ID: %s\n", synor_order_get_id(limit_order));
|
||||||
|
printf(" Status: %s\n", synor_order_get_status(limit_order));
|
||||||
|
printf(" Price: %s\n", synor_order_get_price(limit_order));
|
||||||
|
printf(" Quantity: %s\n", synor_order_get_quantity(limit_order));
|
||||||
|
|
||||||
|
// Place a market order
|
||||||
|
printf("\nPlacing market sell order...\n");
|
||||||
|
synor_order_request_t market_req = {
|
||||||
|
.market = "SYN-USDC",
|
||||||
|
.side = SYNOR_ORDER_SIDE_SELL,
|
||||||
|
.order_type = SYNOR_ORDER_TYPE_MARKET,
|
||||||
|
.quantity = "50"
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_order_result_t* market_order = NULL;
|
||||||
|
err = synor_spot_place_order(dex, &market_req, &market_order);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Market order executed:\n");
|
||||||
|
printf(" Order ID: %s\n", synor_order_get_id(market_order));
|
||||||
|
printf(" Status: %s\n", synor_order_get_status(market_order));
|
||||||
|
printf(" Filled: %s\n", synor_order_get_filled_quantity(market_order));
|
||||||
|
printf(" Avg price: %s\n", synor_order_get_avg_price(market_order));
|
||||||
|
synor_order_result_free(market_order);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get order status
|
||||||
|
synor_order_status_t* status = NULL;
|
||||||
|
err = synor_spot_get_order(dex, synor_order_get_id(limit_order), &status);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nOrder status:\n");
|
||||||
|
printf(" Status: %s\n", synor_order_status_get_status(status));
|
||||||
|
printf(" Filled: %s / %s\n",
|
||||||
|
synor_order_status_get_filled(status),
|
||||||
|
synor_order_status_get_quantity(status));
|
||||||
|
printf(" Remaining: %s\n", synor_order_status_get_remaining(status));
|
||||||
|
synor_order_status_free(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancel order
|
||||||
|
printf("\nCancelling order...\n");
|
||||||
|
err = synor_spot_cancel_order(dex, synor_order_get_id(limit_order));
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Order cancelled successfully\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get open orders
|
||||||
|
synor_order_list_t* open_orders = NULL;
|
||||||
|
err = synor_spot_get_open_orders(dex, "SYN-USDC", &open_orders);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nOpen orders: %zu\n", synor_order_list_count(open_orders));
|
||||||
|
synor_order_list_free(open_orders);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get trade history
|
||||||
|
synor_trade_list_t* trades = NULL;
|
||||||
|
err = synor_spot_get_trade_history(dex, "SYN-USDC", 10, &trades);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nRecent trades: %zu\n", synor_trade_list_count(trades));
|
||||||
|
for (size_t i = 0; i < 3 && i < synor_trade_list_count(trades); i++) {
|
||||||
|
synor_trade_t* trade = synor_trade_list_get(trades, i);
|
||||||
|
printf(" %s %s @ %s (%s)\n",
|
||||||
|
synor_trade_get_side(trade),
|
||||||
|
synor_trade_get_quantity(trade),
|
||||||
|
synor_trade_get_price(trade),
|
||||||
|
synor_trade_get_timestamp(trade));
|
||||||
|
}
|
||||||
|
synor_trade_list_free(trades);
|
||||||
|
}
|
||||||
|
|
||||||
|
synor_order_result_free(limit_order);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void perps_trading_example(synor_dex_t* dex) {
|
||||||
|
printf("=== Perpetual Futures Trading ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
|
||||||
|
// Get available perps markets
|
||||||
|
synor_perps_market_list_t* perps_markets = NULL;
|
||||||
|
err = synor_perps_list_markets(dex, &perps_markets);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Available perps markets: %zu\n", synor_perps_market_list_count(perps_markets));
|
||||||
|
for (size_t i = 0; i < 3 && i < synor_perps_market_list_count(perps_markets); i++) {
|
||||||
|
synor_perps_market_t* market = synor_perps_market_list_get(perps_markets, i);
|
||||||
|
printf(" %s: %s (funding: %s%%)\n",
|
||||||
|
synor_perps_market_get_symbol(market),
|
||||||
|
synor_perps_market_get_mark_price(market),
|
||||||
|
synor_perps_market_get_funding_rate(market));
|
||||||
|
}
|
||||||
|
synor_perps_market_list_free(perps_markets);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open a long position
|
||||||
|
printf("\nOpening long position...\n");
|
||||||
|
synor_perps_order_request_t perps_req = {
|
||||||
|
.market = "SYN-USDC-PERP",
|
||||||
|
.side = SYNOR_ORDER_SIDE_BUY,
|
||||||
|
.order_type = SYNOR_ORDER_TYPE_LIMIT,
|
||||||
|
.price = "1.50",
|
||||||
|
.size = "1000",
|
||||||
|
.leverage = 10,
|
||||||
|
.reduce_only = false
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_position_t* position = NULL;
|
||||||
|
err = synor_perps_open_position(dex, &perps_req, &position);
|
||||||
|
if (err != SYNOR_OK) {
|
||||||
|
fprintf(stderr, "Failed to open position\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Position opened:\n");
|
||||||
|
printf(" Position ID: %s\n", synor_position_get_id(position));
|
||||||
|
printf(" Size: %s\n", synor_position_get_size(position));
|
||||||
|
printf(" Entry price: %s\n", synor_position_get_entry_price(position));
|
||||||
|
printf(" Leverage: %dx\n", synor_position_get_leverage(position));
|
||||||
|
printf(" Liquidation price: %s\n", synor_position_get_liquidation_price(position));
|
||||||
|
|
||||||
|
// Get position details
|
||||||
|
synor_position_details_t* details = NULL;
|
||||||
|
err = synor_perps_get_position(dex, synor_position_get_id(position), &details);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nPosition details:\n");
|
||||||
|
printf(" Unrealized PnL: %s\n", synor_position_details_get_unrealized_pnl(details));
|
||||||
|
printf(" Margin: %s\n", synor_position_details_get_margin(details));
|
||||||
|
printf(" Margin ratio: %s%%\n", synor_position_details_get_margin_ratio(details));
|
||||||
|
synor_position_details_free(details);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set stop loss and take profit
|
||||||
|
printf("\nSetting stop loss and take profit...\n");
|
||||||
|
err = synor_perps_set_stop_loss(dex, synor_position_get_id(position), "1.40");
|
||||||
|
if (err == SYNOR_OK) printf("Stop loss set at 1.40\n");
|
||||||
|
|
||||||
|
err = synor_perps_set_take_profit(dex, synor_position_get_id(position), "1.80");
|
||||||
|
if (err == SYNOR_OK) printf("Take profit set at 1.80\n");
|
||||||
|
|
||||||
|
// Close position
|
||||||
|
printf("\nClosing position...\n");
|
||||||
|
synor_close_result_t* close_result = NULL;
|
||||||
|
err = synor_perps_close_position(dex, synor_position_get_id(position), &close_result);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Position closed:\n");
|
||||||
|
printf(" Realized PnL: %s\n", synor_close_result_get_realized_pnl(close_result));
|
||||||
|
printf(" Close price: %s\n", synor_close_result_get_close_price(close_result));
|
||||||
|
synor_close_result_free(close_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all positions
|
||||||
|
synor_position_list_t* positions = NULL;
|
||||||
|
err = synor_perps_get_positions(dex, &positions);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nOpen positions: %zu\n", synor_position_list_count(positions));
|
||||||
|
synor_position_list_free(positions);
|
||||||
|
}
|
||||||
|
|
||||||
|
synor_position_free(position);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void liquidity_example(synor_dex_t* dex) {
|
||||||
|
printf("=== Liquidity Provision ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
|
||||||
|
// Get available pools
|
||||||
|
synor_pool_list_t* pools = NULL;
|
||||||
|
err = synor_liquidity_list_pools(dex, &pools);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Available pools: %zu\n", synor_pool_list_count(pools));
|
||||||
|
for (size_t i = 0; i < 3 && i < synor_pool_list_count(pools); i++) {
|
||||||
|
synor_pool_t* pool = synor_pool_list_get(pools, i);
|
||||||
|
printf("\n %s:\n", synor_pool_get_name(pool));
|
||||||
|
printf(" TVL: $%s\n", synor_pool_get_tvl(pool));
|
||||||
|
printf(" APR: %s%%\n", synor_pool_get_apr(pool));
|
||||||
|
printf(" Volume 24h: $%s\n", synor_pool_get_volume_24h(pool));
|
||||||
|
printf(" Fee tier: %s%%\n", synor_pool_get_fee_tier(pool));
|
||||||
|
}
|
||||||
|
synor_pool_list_free(pools);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get pool details
|
||||||
|
synor_pool_details_t* pool = NULL;
|
||||||
|
err = synor_liquidity_get_pool(dex, "SYN-USDC", &pool);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nSYN-USDC pool details:\n");
|
||||||
|
printf(" Token0: %s (%s)\n",
|
||||||
|
synor_pool_details_get_token0_symbol(pool),
|
||||||
|
synor_pool_details_get_token0_reserve(pool));
|
||||||
|
printf(" Token1: %s (%s)\n",
|
||||||
|
synor_pool_details_get_token1_symbol(pool),
|
||||||
|
synor_pool_details_get_token1_reserve(pool));
|
||||||
|
printf(" Price: %s\n", synor_pool_details_get_price(pool));
|
||||||
|
printf(" Total LP tokens: %s\n", synor_pool_details_get_total_lp_tokens(pool));
|
||||||
|
synor_pool_details_free(pool);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add liquidity
|
||||||
|
printf("\nAdding liquidity...\n");
|
||||||
|
synor_add_liquidity_request_t add_req = {
|
||||||
|
.pool = "SYN-USDC",
|
||||||
|
.amount0 = "100",
|
||||||
|
.amount1 = "150",
|
||||||
|
.slippage_bps = 50 // 0.5%
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_add_liquidity_result_t* add_result = NULL;
|
||||||
|
err = synor_liquidity_add(dex, &add_req, &add_result);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Liquidity added:\n");
|
||||||
|
printf(" LP tokens received: %s\n", synor_add_result_get_lp_tokens(add_result));
|
||||||
|
printf(" Position ID: %s\n", synor_add_result_get_position_id(add_result));
|
||||||
|
printf(" Share of pool: %s%%\n", synor_add_result_get_share_of_pool(add_result));
|
||||||
|
|
||||||
|
// Claim fees
|
||||||
|
printf("\nClaiming fees...\n");
|
||||||
|
synor_claim_fees_result_t* fees = NULL;
|
||||||
|
err = synor_liquidity_claim_fees(dex, synor_add_result_get_position_id(add_result), &fees);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Fees claimed:\n");
|
||||||
|
printf(" Token0: %s\n", synor_claim_fees_get_amount0(fees));
|
||||||
|
printf(" Token1: %s\n", synor_claim_fees_get_amount1(fees));
|
||||||
|
synor_claim_fees_result_free(fees);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove liquidity
|
||||||
|
printf("\nRemoving liquidity...\n");
|
||||||
|
synor_remove_liquidity_request_t remove_req = {
|
||||||
|
.position_id = synor_add_result_get_position_id(add_result),
|
||||||
|
.lp_tokens = synor_add_result_get_lp_tokens(add_result),
|
||||||
|
.slippage_bps = 50
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_remove_liquidity_result_t* remove_result = NULL;
|
||||||
|
err = synor_liquidity_remove(dex, &remove_req, &remove_result);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Liquidity removed:\n");
|
||||||
|
printf(" Token0 received: %s\n", synor_remove_result_get_amount0(remove_result));
|
||||||
|
printf(" Token1 received: %s\n", synor_remove_result_get_amount1(remove_result));
|
||||||
|
synor_remove_liquidity_result_free(remove_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
synor_add_liquidity_result_free(add_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void orderbook_example(synor_dex_t* dex) {
|
||||||
|
printf("=== Order Book ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
|
||||||
|
// Get order book snapshot
|
||||||
|
synor_orderbook_t* orderbook = NULL;
|
||||||
|
err = synor_orderbook_get_snapshot(dex, "SYN-USDC", 10, &orderbook);
|
||||||
|
if (err != SYNOR_OK) {
|
||||||
|
fprintf(stderr, "Failed to get orderbook\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Order book for SYN-USDC:\n");
|
||||||
|
|
||||||
|
printf("\nAsks (sells):\n");
|
||||||
|
for (size_t i = 0; i < 5 && i < synor_orderbook_get_ask_count(orderbook); i++) {
|
||||||
|
synor_orderbook_entry_t* ask = synor_orderbook_get_ask(orderbook, i);
|
||||||
|
printf(" %s @ %s\n",
|
||||||
|
synor_orderbook_entry_get_quantity(ask),
|
||||||
|
synor_orderbook_entry_get_price(ask));
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\nBids (buys):\n");
|
||||||
|
for (size_t i = 0; i < 5 && i < synor_orderbook_get_bid_count(orderbook); i++) {
|
||||||
|
synor_orderbook_entry_t* bid = synor_orderbook_get_bid(orderbook, i);
|
||||||
|
printf(" %s @ %s\n",
|
||||||
|
synor_orderbook_entry_get_quantity(bid),
|
||||||
|
synor_orderbook_entry_get_price(bid));
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\nSpread: %s (%s%%)\n",
|
||||||
|
synor_orderbook_get_spread(orderbook),
|
||||||
|
synor_orderbook_get_spread_percent(orderbook));
|
||||||
|
printf("Mid price: %s\n", synor_orderbook_get_mid_price(orderbook));
|
||||||
|
|
||||||
|
synor_orderbook_free(orderbook);
|
||||||
|
|
||||||
|
// Get recent trades
|
||||||
|
synor_trade_list_t* recent_trades = NULL;
|
||||||
|
err = synor_orderbook_get_recent_trades(dex, "SYN-USDC", 10, &recent_trades);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nRecent trades:\n");
|
||||||
|
for (size_t i = 0; i < 5 && i < synor_trade_list_count(recent_trades); i++) {
|
||||||
|
synor_trade_t* trade = synor_trade_list_get(recent_trades, i);
|
||||||
|
printf(" %s %s @ %s\n",
|
||||||
|
synor_trade_get_side(trade),
|
||||||
|
synor_trade_get_quantity(trade),
|
||||||
|
synor_trade_get_price(trade));
|
||||||
|
}
|
||||||
|
synor_trade_list_free(recent_trades);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void portfolio_example(synor_dex_t* dex) {
|
||||||
|
printf("=== Portfolio ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
|
||||||
|
// Get portfolio overview
|
||||||
|
synor_portfolio_t* portfolio = NULL;
|
||||||
|
err = synor_portfolio_get_overview(dex, &portfolio);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Portfolio overview:\n");
|
||||||
|
printf(" Total value: $%s\n", synor_portfolio_get_total_value(portfolio));
|
||||||
|
printf(" Available balance: $%s\n", synor_portfolio_get_available_balance(portfolio));
|
||||||
|
printf(" In orders: $%s\n", synor_portfolio_get_in_orders(portfolio));
|
||||||
|
printf(" In positions: $%s\n", synor_portfolio_get_in_positions(portfolio));
|
||||||
|
printf(" Unrealized PnL: $%s\n", synor_portfolio_get_unrealized_pnl(portfolio));
|
||||||
|
synor_portfolio_free(portfolio);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get balances
|
||||||
|
synor_balance_list_t* balances = NULL;
|
||||||
|
err = synor_portfolio_get_balances(dex, &balances);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nBalances:\n");
|
||||||
|
for (size_t i = 0; i < synor_balance_list_count(balances); i++) {
|
||||||
|
synor_balance_t* balance = synor_balance_list_get(balances, i);
|
||||||
|
printf(" %s: %s (available: %s, in orders: %s)\n",
|
||||||
|
synor_balance_get_asset(balance),
|
||||||
|
synor_balance_get_total(balance),
|
||||||
|
synor_balance_get_available(balance),
|
||||||
|
synor_balance_get_in_orders(balance));
|
||||||
|
}
|
||||||
|
synor_balance_list_free(balances);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get trade statistics
|
||||||
|
synor_trade_stats_t* stats = NULL;
|
||||||
|
err = synor_portfolio_get_stats(dex, &stats);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nTrade statistics:\n");
|
||||||
|
printf(" Total trades: %d\n", synor_trade_stats_get_total_trades(stats));
|
||||||
|
printf(" Win rate: %s%%\n", synor_trade_stats_get_win_rate(stats));
|
||||||
|
printf(" Avg profit: $%s\n", synor_trade_stats_get_avg_profit(stats));
|
||||||
|
printf(" Avg loss: $%s\n", synor_trade_stats_get_avg_loss(stats));
|
||||||
|
printf(" Best trade: $%s\n", synor_trade_stats_get_best_trade(stats));
|
||||||
|
printf(" Worst trade: $%s\n", synor_trade_stats_get_worst_trade(stats));
|
||||||
|
synor_trade_stats_free(stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
synor_error_t err;
|
||||||
|
|
||||||
|
// Initialize client
|
||||||
|
synor_dex_config_t config = {
|
||||||
|
.api_key = getenv("SYNOR_API_KEY") ? getenv("SYNOR_API_KEY") : "your-api-key",
|
||||||
|
.endpoint = "https://dex.synor.io/v1",
|
||||||
|
.timeout_ms = 30000,
|
||||||
|
.retries = 3,
|
||||||
|
.debug = false,
|
||||||
|
.default_market = "SYN-USDC"
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_dex_t* dex = NULL;
|
||||||
|
err = synor_dex_init(&config, &dex);
|
||||||
|
if (err != SYNOR_OK) {
|
||||||
|
fprintf(stderr, "Failed to initialize DEX client: %s\n", synor_error_string(err));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check service health
|
||||||
|
bool healthy;
|
||||||
|
err = synor_dex_health_check(dex, &healthy);
|
||||||
|
printf("Service healthy: %s\n\n", healthy ? "true" : "false");
|
||||||
|
|
||||||
|
// Run examples
|
||||||
|
markets_example(dex);
|
||||||
|
spot_trading_example(dex);
|
||||||
|
perps_trading_example(dex);
|
||||||
|
liquidity_example(dex);
|
||||||
|
orderbook_example(dex);
|
||||||
|
portfolio_example(dex);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
synor_dex_free(dex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
545
sdk/c/examples/ibc_example.c
Normal file
545
sdk/c/examples/ibc_example.c
Normal file
|
|
@ -0,0 +1,545 @@
|
||||||
|
/**
|
||||||
|
* Synor IBC SDK Examples for C
|
||||||
|
*
|
||||||
|
* Demonstrates Inter-Blockchain Communication operations:
|
||||||
|
* - Cross-chain transfers and messages
|
||||||
|
* - Channel lifecycle management
|
||||||
|
* - Packet handling and acknowledgments
|
||||||
|
* - Relayer operations
|
||||||
|
* - Connection monitoring
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <synor/ibc.h>
|
||||||
|
|
||||||
|
void chains_example(synor_ibc_t* ibc) {
|
||||||
|
printf("=== Chain Discovery ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
|
||||||
|
// Get all connected chains
|
||||||
|
synor_chain_list_t* chains = NULL;
|
||||||
|
err = synor_chains_list(ibc, &chains);
|
||||||
|
if (err != SYNOR_OK) {
|
||||||
|
fprintf(stderr, "Failed to get chains\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Connected chains: %zu\n", synor_chain_list_count(chains));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 5 && i < synor_chain_list_count(chains); i++) {
|
||||||
|
synor_chain_t* chain = synor_chain_list_get(chains, i);
|
||||||
|
printf("\n %s:\n", synor_chain_get_id(chain));
|
||||||
|
printf(" Name: %s\n", synor_chain_get_name(chain));
|
||||||
|
printf(" Type: %s\n", synor_chain_get_type(chain));
|
||||||
|
printf(" Status: %s\n", synor_chain_get_status(chain));
|
||||||
|
printf(" Block height: %lu\n", synor_chain_get_latest_height(chain));
|
||||||
|
printf(" Light client: %s\n", synor_chain_get_light_client(chain));
|
||||||
|
}
|
||||||
|
synor_chain_list_free(chains);
|
||||||
|
|
||||||
|
// Get specific chain info
|
||||||
|
synor_chain_t* synor_chain = NULL;
|
||||||
|
err = synor_chains_get(ibc, "synor-mainnet-1", &synor_chain);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nSynor chain details:\n");
|
||||||
|
printf(" Bech32 prefix: %s\n", synor_chain_get_bech32_prefix(synor_chain));
|
||||||
|
printf(" Gas price: %s\n", synor_chain_get_gas_price(synor_chain));
|
||||||
|
|
||||||
|
char** features;
|
||||||
|
size_t feature_count;
|
||||||
|
synor_chain_get_features(synor_chain, &features, &feature_count);
|
||||||
|
printf(" Supported features: ");
|
||||||
|
for (size_t i = 0; i < feature_count; i++) {
|
||||||
|
printf("%s%s", features[i], i < feature_count - 1 ? ", " : "");
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
synor_string_array_free(features, feature_count);
|
||||||
|
|
||||||
|
synor_chain_free(synor_chain);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get chain connections
|
||||||
|
synor_connection_list_t* connections = NULL;
|
||||||
|
err = synor_chains_get_connections(ibc, "synor-mainnet-1", &connections);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nChain connections: %zu\n", synor_connection_list_count(connections));
|
||||||
|
for (size_t i = 0; i < 3 && i < synor_connection_list_count(connections); i++) {
|
||||||
|
synor_connection_t* conn = synor_connection_list_get(connections, i);
|
||||||
|
printf(" %s -> %s\n",
|
||||||
|
synor_connection_get_id(conn),
|
||||||
|
synor_connection_get_counterparty_chain_id(conn));
|
||||||
|
}
|
||||||
|
synor_connection_list_free(connections);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void channels_example(synor_ibc_t* ibc) {
|
||||||
|
printf("=== Channel Management ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
|
||||||
|
// List existing channels
|
||||||
|
synor_channel_list_t* channels = NULL;
|
||||||
|
err = synor_channels_list(ibc, &channels);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Active channels: %zu\n", synor_channel_list_count(channels));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 3 && i < synor_channel_list_count(channels); i++) {
|
||||||
|
synor_channel_t* channel = synor_channel_list_get(channels, i);
|
||||||
|
printf("\n Channel %s:\n", synor_channel_get_id(channel));
|
||||||
|
printf(" Port: %s\n", synor_channel_get_port_id(channel));
|
||||||
|
printf(" State: %s\n", synor_channel_get_state(channel));
|
||||||
|
printf(" Order: %s\n", synor_channel_get_ordering(channel));
|
||||||
|
printf(" Counterparty: %s on %s\n",
|
||||||
|
synor_channel_get_counterparty_channel_id(channel),
|
||||||
|
synor_channel_get_counterparty_chain_id(channel));
|
||||||
|
printf(" Version: %s\n", synor_channel_get_version(channel));
|
||||||
|
}
|
||||||
|
synor_channel_list_free(channels);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new channel (4-step handshake)
|
||||||
|
printf("\nInitiating channel creation...\n");
|
||||||
|
|
||||||
|
// Step 1: ChanOpenInit
|
||||||
|
synor_channel_init_request_t init_req = {
|
||||||
|
.port_id = "transfer",
|
||||||
|
.counterparty_chain_id = "cosmos-hub-4",
|
||||||
|
.counterparty_port_id = "transfer",
|
||||||
|
.version = "ics20-1",
|
||||||
|
.ordering = SYNOR_CHANNEL_ORDERING_UNORDERED
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_channel_init_result_t* init_result = NULL;
|
||||||
|
err = synor_channels_open_init(ibc, &init_req, &init_result);
|
||||||
|
if (err != SYNOR_OK) {
|
||||||
|
fprintf(stderr, "Failed to init channel\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Channel init:\n");
|
||||||
|
printf(" Channel ID: %s\n", synor_channel_init_result_get_id(init_result));
|
||||||
|
printf(" State: %s\n", synor_channel_init_result_get_state(init_result));
|
||||||
|
printf(" TX hash: %s\n", synor_channel_init_result_get_tx_hash(init_result));
|
||||||
|
|
||||||
|
// Step 2: Wait for ChanOpenTry (counterparty)
|
||||||
|
printf("\nWaiting for counterparty ChanOpenTry...\n");
|
||||||
|
synor_channel_state_t try_state;
|
||||||
|
err = synor_channels_wait_for_state(ibc, synor_channel_init_result_get_id(init_result),
|
||||||
|
SYNOR_CHANNEL_STATE_TRYOPEN, 300, &try_state);
|
||||||
|
printf("Channel state: %d\n", try_state);
|
||||||
|
|
||||||
|
// Step 3: ChanOpenAck
|
||||||
|
printf("\nSending ChanOpenAck...\n");
|
||||||
|
synor_channel_ack_request_t ack_req = {
|
||||||
|
.channel_id = synor_channel_init_result_get_id(init_result),
|
||||||
|
.counterparty_channel_id = "channel-0",
|
||||||
|
.counterparty_version = "ics20-1"
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_channel_ack_result_t* ack_result = NULL;
|
||||||
|
err = synor_channels_open_ack(ibc, &ack_req, &ack_result);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Ack TX: %s\n", synor_channel_ack_result_get_tx_hash(ack_result));
|
||||||
|
synor_channel_ack_result_free(ack_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 4: Wait for ChanOpenConfirm (counterparty)
|
||||||
|
printf("\nWaiting for channel to open...\n");
|
||||||
|
synor_channel_state_t open_state;
|
||||||
|
err = synor_channels_wait_for_state(ibc, synor_channel_init_result_get_id(init_result),
|
||||||
|
SYNOR_CHANNEL_STATE_OPEN, 300, &open_state);
|
||||||
|
printf("Channel is now: %d\n", open_state);
|
||||||
|
|
||||||
|
// Get channel details
|
||||||
|
synor_channel_t* channel = NULL;
|
||||||
|
err = synor_channels_get(ibc, synor_channel_init_result_get_id(init_result), &channel);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nChannel details:\n");
|
||||||
|
printf(" Sequences - Send: %lu, Recv: %lu, Ack: %lu\n",
|
||||||
|
synor_channel_get_next_sequence_send(channel),
|
||||||
|
synor_channel_get_next_sequence_recv(channel),
|
||||||
|
synor_channel_get_next_sequence_ack(channel));
|
||||||
|
synor_channel_free(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
synor_channel_init_result_free(init_result);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void transfer_example(synor_ibc_t* ibc) {
|
||||||
|
printf("=== Cross-Chain Transfers ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
|
||||||
|
// Get supported tokens for transfer
|
||||||
|
synor_transferable_token_list_t* tokens = NULL;
|
||||||
|
err = synor_transfers_get_supported_tokens(ibc, "cosmos-hub-4", &tokens);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Transferable tokens to Cosmos Hub:\n");
|
||||||
|
for (size_t i = 0; i < 5 && i < synor_transferable_token_list_count(tokens); i++) {
|
||||||
|
synor_transferable_token_t* token = synor_transferable_token_list_get(tokens, i);
|
||||||
|
printf(" %s (%s)\n",
|
||||||
|
synor_transferable_token_get_symbol(token),
|
||||||
|
synor_transferable_token_get_denom(token));
|
||||||
|
}
|
||||||
|
synor_transferable_token_list_free(tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initiate a cross-chain transfer
|
||||||
|
printf("\nInitiating transfer...\n");
|
||||||
|
synor_transfer_request_t transfer_req = {
|
||||||
|
.source_channel = "channel-0",
|
||||||
|
.denom = "usynor",
|
||||||
|
.amount = "1000000",
|
||||||
|
.receiver = "cosmos1...",
|
||||||
|
.timeout_height = 0, // Use timestamp instead
|
||||||
|
.timeout_timestamp = (uint64_t)(time(NULL) + 600) * 1000000000ULL,
|
||||||
|
.memo = "IBC transfer from Synor"
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_transfer_result_t* transfer = NULL;
|
||||||
|
err = synor_transfers_send(ibc, &transfer_req, &transfer);
|
||||||
|
if (err != SYNOR_OK) {
|
||||||
|
fprintf(stderr, "Failed to send transfer\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Transfer initiated:\n");
|
||||||
|
printf(" TX hash: %s\n", synor_transfer_result_get_tx_hash(transfer));
|
||||||
|
printf(" Sequence: %lu\n", synor_transfer_result_get_sequence(transfer));
|
||||||
|
printf(" Packet ID: %s\n", synor_transfer_result_get_packet_id(transfer));
|
||||||
|
printf(" Status: %s\n", synor_transfer_result_get_status(transfer));
|
||||||
|
|
||||||
|
// Track transfer progress
|
||||||
|
printf("\nTracking transfer...\n");
|
||||||
|
synor_transfer_status_t* status = NULL;
|
||||||
|
err = synor_transfers_track(ibc, synor_transfer_result_get_packet_id(transfer), &status);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Current status: %s\n", synor_transfer_status_get_state(status));
|
||||||
|
printf("Source TX: %s\n", synor_transfer_status_get_source_tx_hash(status));
|
||||||
|
const char* dest_tx = synor_transfer_status_get_dest_tx_hash(status);
|
||||||
|
if (dest_tx) {
|
||||||
|
printf("Dest TX: %s\n", dest_tx);
|
||||||
|
}
|
||||||
|
synor_transfer_status_free(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for completion
|
||||||
|
printf("\nWaiting for transfer completion...\n");
|
||||||
|
synor_transfer_status_t* final_status = NULL;
|
||||||
|
err = synor_transfers_wait_for_completion(ibc, synor_transfer_result_get_packet_id(transfer),
|
||||||
|
600, &final_status);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Transfer completed:\n");
|
||||||
|
printf(" Final status: %s\n", synor_transfer_status_get_state(final_status));
|
||||||
|
printf(" Acknowledgment: %s\n", synor_transfer_status_get_acknowledgment(final_status));
|
||||||
|
synor_transfer_status_free(final_status);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get transfer history
|
||||||
|
synor_transfer_list_t* history = NULL;
|
||||||
|
err = synor_transfers_get_history(ibc, 10, &history);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nRecent transfers: %zu\n", synor_transfer_list_count(history));
|
||||||
|
for (size_t i = 0; i < 3 && i < synor_transfer_list_count(history); i++) {
|
||||||
|
synor_transfer_t* t = synor_transfer_list_get(history, i);
|
||||||
|
printf(" %s %s -> %s (%s)\n",
|
||||||
|
synor_transfer_get_amount(t),
|
||||||
|
synor_transfer_get_denom(t),
|
||||||
|
synor_transfer_get_dest_chain(t),
|
||||||
|
synor_transfer_get_status(t));
|
||||||
|
}
|
||||||
|
synor_transfer_list_free(history);
|
||||||
|
}
|
||||||
|
|
||||||
|
synor_transfer_result_free(transfer);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void packet_example(synor_ibc_t* ibc) {
|
||||||
|
printf("=== Packet Operations ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
|
||||||
|
// List pending packets
|
||||||
|
synor_packet_list_t* pending = NULL;
|
||||||
|
err = synor_packets_list_pending(ibc, "channel-0", &pending);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Pending packets on channel-0: %zu\n", synor_packet_list_count(pending));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 3 && i < synor_packet_list_count(pending); i++) {
|
||||||
|
synor_packet_t* packet = synor_packet_list_get(pending, i);
|
||||||
|
printf("\n Packet #%lu:\n", synor_packet_get_sequence(packet));
|
||||||
|
printf(" Source: %s/%s\n",
|
||||||
|
synor_packet_get_source_port(packet),
|
||||||
|
synor_packet_get_source_channel(packet));
|
||||||
|
printf(" Dest: %s/%s\n",
|
||||||
|
synor_packet_get_dest_port(packet),
|
||||||
|
synor_packet_get_dest_channel(packet));
|
||||||
|
printf(" State: %s\n", synor_packet_get_state(packet));
|
||||||
|
printf(" Timeout: %lu\n", synor_packet_get_timeout_timestamp(packet));
|
||||||
|
}
|
||||||
|
synor_packet_list_free(pending);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get specific packet
|
||||||
|
synor_packet_t* packet = NULL;
|
||||||
|
err = synor_packets_get(ibc, "channel-0", 1, &packet);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nPacket details:\n");
|
||||||
|
const char* data_hex = synor_packet_get_data_hex(packet);
|
||||||
|
printf(" Data (hex): %.40s...\n", data_hex);
|
||||||
|
printf(" Created: %s\n", synor_packet_get_created_at(packet));
|
||||||
|
synor_packet_free(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get packet commitment proof
|
||||||
|
synor_packet_proof_t* proof = NULL;
|
||||||
|
err = synor_packets_get_commitment_proof(ibc, "channel-0", 1, &proof);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nCommitment proof:\n");
|
||||||
|
printf(" Height: %lu\n", synor_packet_proof_get_height(proof));
|
||||||
|
printf(" Proof size: %zu bytes\n", synor_packet_proof_get_size(proof));
|
||||||
|
synor_packet_proof_free(proof);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get acknowledgment
|
||||||
|
synor_packet_ack_t* ack = NULL;
|
||||||
|
err = synor_packets_get_acknowledgment(ibc, "channel-0", 1, &ack);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nAcknowledgment:\n");
|
||||||
|
printf(" Result: %s\n", synor_packet_ack_is_success(ack) ? "Success" :
|
||||||
|
synor_packet_ack_get_error(ack));
|
||||||
|
printf(" TX hash: %s\n", synor_packet_ack_get_tx_hash(ack));
|
||||||
|
synor_packet_ack_free(ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
// List timed-out packets
|
||||||
|
synor_packet_list_t* timed_out = NULL;
|
||||||
|
err = synor_packets_list_timed_out(ibc, &timed_out);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nTimed-out packets: %zu\n", synor_packet_list_count(timed_out));
|
||||||
|
|
||||||
|
// Timeout a packet manually
|
||||||
|
if (synor_packet_list_count(timed_out) > 0) {
|
||||||
|
synor_packet_t* to_timeout = synor_packet_list_get(timed_out, 0);
|
||||||
|
printf("\nProcessing timeout for packet #%lu\n", synor_packet_get_sequence(to_timeout));
|
||||||
|
|
||||||
|
synor_timeout_result_t* timeout = NULL;
|
||||||
|
err = synor_packets_timeout(ibc, synor_packet_get_source_channel(to_timeout),
|
||||||
|
synor_packet_get_sequence(to_timeout), &timeout);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Timeout TX: %s\n", synor_timeout_result_get_tx_hash(timeout));
|
||||||
|
synor_timeout_result_free(timeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
synor_packet_list_free(timed_out);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void relayer_example(synor_ibc_t* ibc) {
|
||||||
|
printf("=== Relayer Operations ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
|
||||||
|
// Get relayer status
|
||||||
|
synor_relayer_status_t* status = NULL;
|
||||||
|
err = synor_relayer_get_status(ibc, &status);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Relayer status:\n");
|
||||||
|
printf(" Running: %s\n", synor_relayer_status_is_running(status) ? "true" : "false");
|
||||||
|
printf(" Uptime: %s\n", synor_relayer_status_get_uptime(status));
|
||||||
|
printf(" Packets relayed: %lu\n", synor_relayer_status_get_packets_relayed(status));
|
||||||
|
printf(" Errors: %lu\n", synor_relayer_status_get_error_count(status));
|
||||||
|
synor_relayer_status_free(status);
|
||||||
|
}
|
||||||
|
|
||||||
|
// List active paths
|
||||||
|
synor_relay_path_list_t* paths = NULL;
|
||||||
|
err = synor_relayer_list_paths(ibc, &paths);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nActive relay paths: %zu\n", synor_relay_path_list_count(paths));
|
||||||
|
|
||||||
|
for (size_t i = 0; i < synor_relay_path_list_count(paths); i++) {
|
||||||
|
synor_relay_path_t* path = synor_relay_path_list_get(paths, i);
|
||||||
|
printf("\n %s:\n", synor_relay_path_get_id(path));
|
||||||
|
printf(" %s <-> %s\n",
|
||||||
|
synor_relay_path_get_source_chain(path),
|
||||||
|
synor_relay_path_get_dest_chain(path));
|
||||||
|
printf(" Channel: %s <-> %s\n",
|
||||||
|
synor_relay_path_get_source_channel(path),
|
||||||
|
synor_relay_path_get_dest_channel(path));
|
||||||
|
printf(" Status: %s\n", synor_relay_path_get_status(path));
|
||||||
|
printf(" Pending packets: %zu\n", synor_relay_path_get_pending_packets(path));
|
||||||
|
}
|
||||||
|
synor_relay_path_list_free(paths);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure a new path
|
||||||
|
printf("\nConfiguring new relay path...\n");
|
||||||
|
const char* filter_denoms[] = {"usynor", "uosmo"};
|
||||||
|
synor_path_config_t path_config = {
|
||||||
|
.source_chain = "synor-mainnet-1",
|
||||||
|
.dest_chain = "osmosis-1",
|
||||||
|
.source_channel = "channel-1",
|
||||||
|
.dest_channel = "channel-100",
|
||||||
|
.filter_denoms = filter_denoms,
|
||||||
|
.filter_denoms_count = 2,
|
||||||
|
.min_relay_amount = "1000",
|
||||||
|
.max_relay_amount = "1000000000"
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_relay_path_t* new_path = NULL;
|
||||||
|
err = synor_relayer_add_path(ibc, &path_config, &new_path);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Path created: %s\n", synor_relay_path_get_id(new_path));
|
||||||
|
|
||||||
|
// Start relaying on path
|
||||||
|
printf("\nStarting relayer on path...\n");
|
||||||
|
err = synor_relayer_start_path(ibc, synor_relay_path_get_id(new_path));
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Relayer started\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manually relay pending packets
|
||||||
|
printf("\nRelaying pending packets...\n");
|
||||||
|
synor_relay_result_t* relay_result = NULL;
|
||||||
|
err = synor_relayer_relay_pending(ibc, synor_relay_path_get_id(new_path), &relay_result);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Relayed %zu packets\n", synor_relay_result_get_packet_count(relay_result));
|
||||||
|
printf("TX hashes: %zu\n", synor_relay_result_get_tx_hash_count(relay_result));
|
||||||
|
synor_relay_result_free(relay_result);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get relay history
|
||||||
|
synor_relay_event_list_t* history = NULL;
|
||||||
|
err = synor_relayer_get_history(ibc, synor_relay_path_get_id(new_path), 10, &history);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nRelay history:\n");
|
||||||
|
for (size_t i = 0; i < 3 && i < synor_relay_event_list_count(history); i++) {
|
||||||
|
synor_relay_event_t* event = synor_relay_event_list_get(history, i);
|
||||||
|
printf(" %s: %s - %zu packets\n",
|
||||||
|
synor_relay_event_get_timestamp(event),
|
||||||
|
synor_relay_event_get_type(event),
|
||||||
|
synor_relay_event_get_packet_count(event));
|
||||||
|
}
|
||||||
|
synor_relay_event_list_free(history);
|
||||||
|
}
|
||||||
|
|
||||||
|
synor_relay_path_free(new_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void monitoring_example(synor_ibc_t* ibc) {
|
||||||
|
printf("=== IBC Monitoring ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
|
||||||
|
// Get IBC metrics
|
||||||
|
synor_ibc_metrics_t* metrics = NULL;
|
||||||
|
err = synor_monitoring_get_metrics(ibc, &metrics);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("IBC metrics:\n");
|
||||||
|
printf(" Total channels: %lu\n", synor_ibc_metrics_get_total_channels(metrics));
|
||||||
|
printf(" Active channels: %lu\n", synor_ibc_metrics_get_active_channels(metrics));
|
||||||
|
printf(" Total packets: %lu\n", synor_ibc_metrics_get_total_packets(metrics));
|
||||||
|
printf(" Pending packets: %lu\n", synor_ibc_metrics_get_pending_packets(metrics));
|
||||||
|
printf(" Failed packets: %lu\n", synor_ibc_metrics_get_failed_packets(metrics));
|
||||||
|
printf(" Avg relay time: %lums\n", synor_ibc_metrics_get_avg_relay_time(metrics));
|
||||||
|
synor_ibc_metrics_free(metrics);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get chain health
|
||||||
|
synor_chain_health_list_t* chain_health = NULL;
|
||||||
|
err = synor_monitoring_get_chain_health(ibc, &chain_health);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nChain health:\n");
|
||||||
|
for (size_t i = 0; i < 3 && i < synor_chain_health_list_count(chain_health); i++) {
|
||||||
|
synor_chain_health_t* health = synor_chain_health_list_get(chain_health, i);
|
||||||
|
printf(" %s:\n", synor_chain_health_get_chain_id(health));
|
||||||
|
printf(" Status: %s\n", synor_chain_health_get_status(health));
|
||||||
|
printf(" Block lag: %lu\n", synor_chain_health_get_block_lag(health));
|
||||||
|
printf(" Last update: %s\n", synor_chain_health_get_last_update(health));
|
||||||
|
}
|
||||||
|
synor_chain_health_list_free(chain_health);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get channel statistics
|
||||||
|
synor_channel_stats_t* stats = NULL;
|
||||||
|
err = synor_monitoring_get_channel_stats(ibc, "channel-0", &stats);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nChannel-0 statistics:\n");
|
||||||
|
printf(" Packets sent: %lu\n", synor_channel_stats_get_packets_sent(stats));
|
||||||
|
printf(" Packets received: %lu\n", synor_channel_stats_get_packets_received(stats));
|
||||||
|
printf(" Success rate: %s%%\n", synor_channel_stats_get_success_rate(stats));
|
||||||
|
printf(" Avg confirmation time: %lums\n", synor_channel_stats_get_avg_confirmation_time(stats));
|
||||||
|
synor_channel_stats_free(stats);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get alerts
|
||||||
|
synor_ibc_alert_list_t* alerts = NULL;
|
||||||
|
err = synor_monitoring_get_alerts(ibc, &alerts);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nActive alerts: %zu\n", synor_ibc_alert_list_count(alerts));
|
||||||
|
for (size_t i = 0; i < synor_ibc_alert_list_count(alerts); i++) {
|
||||||
|
synor_ibc_alert_t* alert = synor_ibc_alert_list_get(alerts, i);
|
||||||
|
printf(" [%s] %s\n",
|
||||||
|
synor_ibc_alert_get_severity(alert),
|
||||||
|
synor_ibc_alert_get_message(alert));
|
||||||
|
}
|
||||||
|
synor_ibc_alert_list_free(alerts);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
synor_error_t err;
|
||||||
|
|
||||||
|
// Initialize client
|
||||||
|
synor_ibc_config_t config = {
|
||||||
|
.api_key = getenv("SYNOR_API_KEY") ? getenv("SYNOR_API_KEY") : "your-api-key",
|
||||||
|
.endpoint = "https://ibc.synor.io/v1",
|
||||||
|
.timeout_ms = 30000,
|
||||||
|
.retries = 3,
|
||||||
|
.debug = false,
|
||||||
|
.default_chain = "synor-mainnet-1",
|
||||||
|
.confirmations = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_ibc_t* ibc = NULL;
|
||||||
|
err = synor_ibc_init(&config, &ibc);
|
||||||
|
if (err != SYNOR_OK) {
|
||||||
|
fprintf(stderr, "Failed to initialize IBC client: %s\n", synor_error_string(err));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check service health
|
||||||
|
bool healthy;
|
||||||
|
err = synor_ibc_health_check(ibc, &healthy);
|
||||||
|
printf("Service healthy: %s\n\n", healthy ? "true" : "false");
|
||||||
|
|
||||||
|
// Run examples
|
||||||
|
chains_example(ibc);
|
||||||
|
channels_example(ibc);
|
||||||
|
transfer_example(ibc);
|
||||||
|
packet_example(ibc);
|
||||||
|
relayer_example(ibc);
|
||||||
|
monitoring_example(ibc);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
synor_ibc_free(ibc);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
495
sdk/c/examples/zk_example.c
Normal file
495
sdk/c/examples/zk_example.c
Normal file
|
|
@ -0,0 +1,495 @@
|
||||||
|
/**
|
||||||
|
* Synor ZK SDK Examples for C
|
||||||
|
*
|
||||||
|
* Demonstrates zero-knowledge proof operations:
|
||||||
|
* - Circuit compilation (Circom)
|
||||||
|
* - Proof generation and verification
|
||||||
|
* - Multiple proving systems (Groth16, PLONK, STARK)
|
||||||
|
* - Recursive proof composition
|
||||||
|
* - Trusted setup ceremonies
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <synor/zk.h>
|
||||||
|
|
||||||
|
void circuit_example(synor_zk_t* zk) {
|
||||||
|
printf("=== Circuit Compilation ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
|
||||||
|
// Simple Circom circuit: prove knowledge of factors
|
||||||
|
const char* circom_code =
|
||||||
|
"pragma circom 2.1.0;\n"
|
||||||
|
"\n"
|
||||||
|
"template Multiplier() {\n"
|
||||||
|
" signal input a;\n"
|
||||||
|
" signal input b;\n"
|
||||||
|
" signal output c;\n"
|
||||||
|
"\n"
|
||||||
|
" c <== a * b;\n"
|
||||||
|
"}\n"
|
||||||
|
"\n"
|
||||||
|
"component main = Multiplier();\n";
|
||||||
|
|
||||||
|
// Compile the circuit
|
||||||
|
printf("Compiling circuit...\n");
|
||||||
|
synor_circuit_source_t source = {
|
||||||
|
.code = circom_code,
|
||||||
|
.language = SYNOR_CIRCUIT_LANGUAGE_CIRCOM
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_circuit_t* circuit = NULL;
|
||||||
|
err = synor_circuits_compile(zk, &source, &circuit);
|
||||||
|
if (err != SYNOR_OK) {
|
||||||
|
fprintf(stderr, "Failed to compile circuit\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Circuit compiled:\n");
|
||||||
|
printf(" Circuit ID: %s\n", synor_circuit_get_id(circuit));
|
||||||
|
printf(" Constraints: %zu\n", synor_circuit_get_constraints(circuit));
|
||||||
|
printf(" Public inputs: %zu\n", synor_circuit_get_public_inputs(circuit));
|
||||||
|
printf(" Private inputs: %zu\n", synor_circuit_get_private_inputs(circuit));
|
||||||
|
printf(" Outputs: %zu\n", synor_circuit_get_outputs(circuit));
|
||||||
|
|
||||||
|
// Get circuit info
|
||||||
|
synor_circuit_info_t* info = NULL;
|
||||||
|
err = synor_circuits_get(zk, synor_circuit_get_id(circuit), &info);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nCircuit info:\n");
|
||||||
|
printf(" Name: %s\n", synor_circuit_info_get_name(info));
|
||||||
|
printf(" Version: %s\n", synor_circuit_info_get_version(info));
|
||||||
|
printf(" Wires: %zu\n", synor_circuit_info_get_wire_count(info));
|
||||||
|
printf(" Labels: %zu\n", synor_circuit_info_get_label_count(info));
|
||||||
|
synor_circuit_info_free(info);
|
||||||
|
}
|
||||||
|
|
||||||
|
// List available circuits
|
||||||
|
synor_circuit_list_t* circuits = NULL;
|
||||||
|
err = synor_circuits_list(zk, &circuits);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nAvailable circuits: %zu\n", synor_circuit_list_count(circuits));
|
||||||
|
for (size_t i = 0; i < 3 && i < synor_circuit_list_count(circuits); i++) {
|
||||||
|
synor_circuit_t* c = synor_circuit_list_get(circuits, i);
|
||||||
|
printf(" %s: %s (%zu constraints)\n",
|
||||||
|
synor_circuit_get_id(c),
|
||||||
|
synor_circuit_get_name(c),
|
||||||
|
synor_circuit_get_constraints(c));
|
||||||
|
}
|
||||||
|
synor_circuit_list_free(circuits);
|
||||||
|
}
|
||||||
|
|
||||||
|
synor_circuit_free(circuit);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void groth16_example(synor_zk_t* zk) {
|
||||||
|
printf("=== Groth16 Proving System ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
const char* circuit_id = "multiplier-v1";
|
||||||
|
|
||||||
|
// Generate proving/verification keys (trusted setup)
|
||||||
|
printf("Generating keys...\n");
|
||||||
|
synor_groth16_keys_t* keys = NULL;
|
||||||
|
err = synor_groth16_setup(zk, circuit_id, &keys);
|
||||||
|
if (err != SYNOR_OK) {
|
||||||
|
fprintf(stderr, "Failed to generate keys\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Keys generated:\n");
|
||||||
|
printf(" Proving key size: %zu bytes\n", synor_groth16_keys_get_pk_size(keys));
|
||||||
|
printf(" Verification key size: %zu bytes\n", synor_groth16_keys_get_vk_size(keys));
|
||||||
|
|
||||||
|
// Prepare witness (private inputs)
|
||||||
|
synor_witness_t* witness = synor_witness_create();
|
||||||
|
synor_witness_set(witness, "a", "3");
|
||||||
|
synor_witness_set(witness, "b", "7");
|
||||||
|
|
||||||
|
// Generate proof
|
||||||
|
printf("\nGenerating proof...\n");
|
||||||
|
synor_prove_request_t prove_req = {
|
||||||
|
.circuit_id = circuit_id,
|
||||||
|
.witness = witness,
|
||||||
|
.proving_key = synor_groth16_keys_get_pk(keys),
|
||||||
|
.proving_key_len = synor_groth16_keys_get_pk_size(keys)
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_proof_t* proof = NULL;
|
||||||
|
err = synor_groth16_prove(zk, &prove_req, &proof);
|
||||||
|
if (err != SYNOR_OK) {
|
||||||
|
fprintf(stderr, "Failed to generate proof\n");
|
||||||
|
synor_witness_free(witness);
|
||||||
|
synor_groth16_keys_free(keys);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("Proof generated:\n");
|
||||||
|
printf(" Proof size: %zu bytes\n", synor_proof_get_size(proof));
|
||||||
|
printf(" Public signals: %zu\n", synor_proof_get_public_signal_count(proof));
|
||||||
|
printf(" Proving time: %lums\n", synor_proof_get_proving_time_ms(proof));
|
||||||
|
|
||||||
|
// Verify proof
|
||||||
|
printf("\nVerifying proof...\n");
|
||||||
|
synor_verify_request_t verify_req = {
|
||||||
|
.proof = synor_proof_get_bytes(proof),
|
||||||
|
.proof_len = synor_proof_get_size(proof),
|
||||||
|
.public_signals = synor_proof_get_public_signals(proof),
|
||||||
|
.public_signal_count = synor_proof_get_public_signal_count(proof),
|
||||||
|
.verification_key = synor_groth16_keys_get_vk(keys),
|
||||||
|
.verification_key_len = synor_groth16_keys_get_vk_size(keys)
|
||||||
|
};
|
||||||
|
|
||||||
|
bool verified;
|
||||||
|
err = synor_groth16_verify(zk, &verify_req, &verified);
|
||||||
|
printf("Verification result: %s\n", verified ? "true" : "false");
|
||||||
|
|
||||||
|
// Export proof for on-chain verification
|
||||||
|
char* solidity_calldata = NULL;
|
||||||
|
err = synor_groth16_export_calldata(zk, proof, &solidity_calldata);
|
||||||
|
if (err == SYNOR_OK && solidity_calldata) {
|
||||||
|
printf("\nSolidity calldata: %.100s...\n", solidity_calldata);
|
||||||
|
free(solidity_calldata);
|
||||||
|
}
|
||||||
|
|
||||||
|
synor_proof_free(proof);
|
||||||
|
synor_witness_free(witness);
|
||||||
|
synor_groth16_keys_free(keys);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void plonk_example(synor_zk_t* zk) {
|
||||||
|
printf("=== PLONK Proving System ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
const char* circuit_id = "multiplier-v1";
|
||||||
|
|
||||||
|
// PLONK uses universal trusted setup
|
||||||
|
printf("Getting universal setup...\n");
|
||||||
|
synor_srs_t* srs = NULL;
|
||||||
|
err = synor_plonk_get_universal_setup(zk, 14, &srs); // 2^14 constraints
|
||||||
|
if (err != SYNOR_OK) {
|
||||||
|
fprintf(stderr, "Failed to get SRS\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("SRS loaded: %zu bytes\n", synor_srs_get_size(srs));
|
||||||
|
|
||||||
|
// Generate circuit-specific keys
|
||||||
|
printf("\nGenerating circuit keys...\n");
|
||||||
|
synor_plonk_keys_t* keys = NULL;
|
||||||
|
err = synor_plonk_setup(zk, circuit_id, srs, &keys);
|
||||||
|
if (err != SYNOR_OK) {
|
||||||
|
fprintf(stderr, "Failed to generate keys\n");
|
||||||
|
synor_srs_free(srs);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("Keys generated\n");
|
||||||
|
|
||||||
|
// Generate proof
|
||||||
|
synor_witness_t* witness = synor_witness_create();
|
||||||
|
synor_witness_set(witness, "a", "5");
|
||||||
|
synor_witness_set(witness, "b", "9");
|
||||||
|
|
||||||
|
printf("\nGenerating PLONK proof...\n");
|
||||||
|
synor_plonk_prove_request_t prove_req = {
|
||||||
|
.circuit_id = circuit_id,
|
||||||
|
.witness = witness,
|
||||||
|
.proving_key = synor_plonk_keys_get_pk(keys),
|
||||||
|
.proving_key_len = synor_plonk_keys_get_pk_size(keys)
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_proof_t* proof = NULL;
|
||||||
|
err = synor_plonk_prove(zk, &prove_req, &proof);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Proof generated:\n");
|
||||||
|
printf(" Proof size: %zu bytes\n", synor_proof_get_size(proof));
|
||||||
|
printf(" Proving time: %lums\n", synor_proof_get_proving_time_ms(proof));
|
||||||
|
|
||||||
|
// Verify proof
|
||||||
|
synor_plonk_verify_request_t verify_req = {
|
||||||
|
.proof = synor_proof_get_bytes(proof),
|
||||||
|
.proof_len = synor_proof_get_size(proof),
|
||||||
|
.public_signals = synor_proof_get_public_signals(proof),
|
||||||
|
.public_signal_count = synor_proof_get_public_signal_count(proof),
|
||||||
|
.verification_key = synor_plonk_keys_get_vk(keys),
|
||||||
|
.verification_key_len = synor_plonk_keys_get_vk_size(keys)
|
||||||
|
};
|
||||||
|
|
||||||
|
bool verified;
|
||||||
|
synor_plonk_verify(zk, &verify_req, &verified);
|
||||||
|
printf("Verification result: %s\n", verified ? "true" : "false");
|
||||||
|
|
||||||
|
synor_proof_free(proof);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare with Groth16
|
||||||
|
printf("\nPLONK advantages:\n");
|
||||||
|
printf(" - Universal trusted setup\n");
|
||||||
|
printf(" - Larger proofs (~2.5 KB vs ~200 bytes)\n");
|
||||||
|
printf(" - Faster proving for some circuits\n");
|
||||||
|
|
||||||
|
synor_witness_free(witness);
|
||||||
|
synor_plonk_keys_free(keys);
|
||||||
|
synor_srs_free(srs);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void stark_example(synor_zk_t* zk) {
|
||||||
|
printf("=== STARK Proving System ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
const char* circuit_id = "multiplier-v1";
|
||||||
|
|
||||||
|
// STARKs don't need trusted setup
|
||||||
|
printf("Configuring STARK parameters...\n");
|
||||||
|
synor_stark_config_t config = {
|
||||||
|
.field_size = 256,
|
||||||
|
.hash_function = SYNOR_HASH_FUNCTION_POSEIDON,
|
||||||
|
.blowup_factor = 8,
|
||||||
|
.num_queries = 30,
|
||||||
|
.folding_factor = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate proof
|
||||||
|
synor_witness_t* witness = synor_witness_create();
|
||||||
|
synor_witness_set(witness, "a", "11");
|
||||||
|
synor_witness_set(witness, "b", "13");
|
||||||
|
|
||||||
|
printf("\nGenerating STARK proof...\n");
|
||||||
|
synor_stark_prove_request_t prove_req = {
|
||||||
|
.circuit_id = circuit_id,
|
||||||
|
.witness = witness,
|
||||||
|
.config = &config
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_stark_proof_t* proof = NULL;
|
||||||
|
err = synor_stark_prove(zk, &prove_req, &proof);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Proof generated:\n");
|
||||||
|
printf(" Proof size: %zu bytes\n", synor_stark_proof_get_size(proof));
|
||||||
|
printf(" Proving time: %lums\n", synor_stark_proof_get_proving_time_ms(proof));
|
||||||
|
printf(" FRI layers: %zu\n", synor_stark_proof_get_fri_layers(proof));
|
||||||
|
|
||||||
|
// Verify proof
|
||||||
|
printf("\nVerifying STARK proof...\n");
|
||||||
|
synor_stark_verify_request_t verify_req = {
|
||||||
|
.proof = synor_stark_proof_get_bytes(proof),
|
||||||
|
.proof_len = synor_stark_proof_get_size(proof),
|
||||||
|
.public_signals = synor_stark_proof_get_public_signals(proof),
|
||||||
|
.public_signal_count = synor_stark_proof_get_public_signal_count(proof),
|
||||||
|
.config = &config
|
||||||
|
};
|
||||||
|
|
||||||
|
bool verified;
|
||||||
|
synor_stark_verify(zk, &verify_req, &verified);
|
||||||
|
printf("Verification result: %s\n", verified ? "true" : "false");
|
||||||
|
|
||||||
|
synor_stark_proof_free(proof);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare with SNARKs
|
||||||
|
printf("\nSTARK advantages:\n");
|
||||||
|
printf(" - No trusted setup needed\n");
|
||||||
|
printf(" - Post-quantum secure\n");
|
||||||
|
printf(" - Larger proofs (~100 KB)\n");
|
||||||
|
printf(" - Faster proving for complex computations\n");
|
||||||
|
|
||||||
|
synor_witness_free(witness);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_example(synor_zk_t* zk) {
|
||||||
|
printf("=== Recursive Proof Composition ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
|
||||||
|
// Create inner proofs
|
||||||
|
printf("Generating inner proofs...\n");
|
||||||
|
synor_recursive_proof_list_t* inner_proofs = synor_recursive_proof_list_create();
|
||||||
|
|
||||||
|
for (int i = 1; i <= 3; i++) {
|
||||||
|
synor_witness_t* witness = synor_witness_create();
|
||||||
|
char a_str[16], b_str[16];
|
||||||
|
snprintf(a_str, sizeof(a_str), "%d", i);
|
||||||
|
snprintf(b_str, sizeof(b_str), "%d", i + 1);
|
||||||
|
synor_witness_set(witness, "a", a_str);
|
||||||
|
synor_witness_set(witness, "b", b_str);
|
||||||
|
|
||||||
|
synor_recursive_prove_request_t prove_req = {
|
||||||
|
.circuit_id = "multiplier-v1",
|
||||||
|
.witness = witness,
|
||||||
|
.level = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_recursive_proof_t* proof = NULL;
|
||||||
|
err = synor_recursive_prove_inner(zk, &prove_req, &proof);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
synor_recursive_proof_list_add(inner_proofs, proof);
|
||||||
|
printf(" Inner proof %d generated\n", i);
|
||||||
|
}
|
||||||
|
|
||||||
|
synor_witness_free(witness);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aggregate proofs recursively
|
||||||
|
printf("\nAggregating proofs...\n");
|
||||||
|
synor_aggregate_request_t aggregate_req = {
|
||||||
|
.proofs = inner_proofs,
|
||||||
|
.aggregation_circuit = "recursive-aggregator-v1"
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_aggregated_proof_t* aggregated = NULL;
|
||||||
|
err = synor_recursive_aggregate(zk, &aggregate_req, &aggregated);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Aggregated proof:\n");
|
||||||
|
printf(" Proof size: %zu bytes\n", synor_aggregated_proof_get_size(aggregated));
|
||||||
|
printf(" Proofs aggregated: %zu\n", synor_aggregated_proof_get_count(aggregated));
|
||||||
|
printf(" Recursion depth: %zu\n", synor_aggregated_proof_get_depth(aggregated));
|
||||||
|
|
||||||
|
// Verify aggregated proof
|
||||||
|
printf("\nVerifying aggregated proof...\n");
|
||||||
|
bool verified;
|
||||||
|
err = synor_recursive_verify_aggregated(zk, aggregated, &verified);
|
||||||
|
printf("Verification result: %s\n", verified ? "true" : "false");
|
||||||
|
|
||||||
|
synor_aggregated_proof_free(aggregated);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use cases
|
||||||
|
printf("\nRecursive proof use cases:\n");
|
||||||
|
printf(" - Rollup batch verification\n");
|
||||||
|
printf(" - Incremental computation proofs\n");
|
||||||
|
printf(" - Cross-chain state proofs\n");
|
||||||
|
|
||||||
|
synor_recursive_proof_list_free(inner_proofs);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void ceremony_example(synor_zk_t* zk) {
|
||||||
|
printf("=== Trusted Setup Ceremony ===\n");
|
||||||
|
|
||||||
|
synor_error_t err;
|
||||||
|
|
||||||
|
// List active ceremonies
|
||||||
|
synor_ceremony_list_t* ceremonies = NULL;
|
||||||
|
err = synor_ceremony_list(zk, SYNOR_CEREMONY_STATUS_ACTIVE, &ceremonies);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Active ceremonies: %zu\n", synor_ceremony_list_count(ceremonies));
|
||||||
|
for (size_t i = 0; i < 3 && i < synor_ceremony_list_count(ceremonies); i++) {
|
||||||
|
synor_ceremony_t* ceremony = synor_ceremony_list_get(ceremonies, i);
|
||||||
|
printf("\n %s:\n", synor_ceremony_get_id(ceremony));
|
||||||
|
printf(" Circuit: %s\n", synor_ceremony_get_circuit_id(ceremony));
|
||||||
|
printf(" Participants: %zu\n", synor_ceremony_get_participant_count(ceremony));
|
||||||
|
printf(" Current round: %zu\n", synor_ceremony_get_current_round(ceremony));
|
||||||
|
printf(" Status: %s\n", synor_ceremony_get_status(ceremony));
|
||||||
|
}
|
||||||
|
synor_ceremony_list_free(ceremonies);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new ceremony
|
||||||
|
printf("\nCreating new ceremony...\n");
|
||||||
|
synor_ceremony_config_t config = {
|
||||||
|
.circuit_id = "new-circuit-v1",
|
||||||
|
.min_participants = 10,
|
||||||
|
.max_participants = 100,
|
||||||
|
.round_duration = 3600, // 1 hour per round
|
||||||
|
.verify_contributions = true
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_ceremony_t* new_ceremony = NULL;
|
||||||
|
err = synor_ceremony_create(zk, &config, &new_ceremony);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Ceremony created:\n");
|
||||||
|
printf(" Ceremony ID: %s\n", synor_ceremony_get_id(new_ceremony));
|
||||||
|
printf(" Join URL: %s\n", synor_ceremony_get_join_url(new_ceremony));
|
||||||
|
|
||||||
|
// Participate in ceremony
|
||||||
|
printf("\nParticipating in ceremony...\n");
|
||||||
|
uint8_t entropy[32];
|
||||||
|
// In real code, use secure random: arc4random_buf(entropy, sizeof(entropy));
|
||||||
|
memset(entropy, 0x42, sizeof(entropy)); // Example only
|
||||||
|
|
||||||
|
synor_contribution_request_t contrib_req = {
|
||||||
|
.ceremony_id = synor_ceremony_get_id(new_ceremony),
|
||||||
|
.entropy = entropy,
|
||||||
|
.entropy_len = sizeof(entropy)
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_contribution_t* contribution = NULL;
|
||||||
|
err = synor_ceremony_contribute(zk, &contrib_req, &contribution);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("Contribution made:\n");
|
||||||
|
printf(" Contribution ID: %s\n", synor_contribution_get_id(contribution));
|
||||||
|
printf(" Position: %zu\n", synor_contribution_get_position(contribution));
|
||||||
|
printf(" Hash: %s\n", synor_contribution_get_hash(contribution));
|
||||||
|
|
||||||
|
// Verify contribution
|
||||||
|
printf("\nVerifying contribution...\n");
|
||||||
|
bool valid;
|
||||||
|
synor_ceremony_verify_contribution(zk, synor_contribution_get_id(contribution), &valid);
|
||||||
|
printf("Contribution valid: %s\n", valid ? "true" : "false");
|
||||||
|
|
||||||
|
synor_contribution_free(contribution);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get ceremony transcript
|
||||||
|
synor_transcript_t* transcript = NULL;
|
||||||
|
err = synor_ceremony_get_transcript(zk, synor_ceremony_get_id(new_ceremony), &transcript);
|
||||||
|
if (err == SYNOR_OK) {
|
||||||
|
printf("\nCeremony transcript:\n");
|
||||||
|
printf(" Total contributions: %zu\n", synor_transcript_get_contribution_count(transcript));
|
||||||
|
printf(" Start time: %s\n", synor_transcript_get_start_time(transcript));
|
||||||
|
const char* final_hash = synor_transcript_get_final_hash(transcript);
|
||||||
|
printf(" Final hash: %s\n", final_hash ? final_hash : "pending");
|
||||||
|
synor_transcript_free(transcript);
|
||||||
|
}
|
||||||
|
|
||||||
|
synor_ceremony_free(new_ceremony);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
synor_error_t err;
|
||||||
|
|
||||||
|
// Initialize client
|
||||||
|
synor_zk_config_t config = {
|
||||||
|
.api_key = getenv("SYNOR_API_KEY") ? getenv("SYNOR_API_KEY") : "your-api-key",
|
||||||
|
.endpoint = "https://zk.synor.io/v1",
|
||||||
|
.timeout_ms = 120000, // ZK operations can be slow
|
||||||
|
.retries = 3,
|
||||||
|
.debug = false,
|
||||||
|
.default_proving_system = SYNOR_PROVING_SYSTEM_GROTH16,
|
||||||
|
.prove_timeout_ms = 300000,
|
||||||
|
.verify_timeout_ms = 30000
|
||||||
|
};
|
||||||
|
|
||||||
|
synor_zk_t* zk = NULL;
|
||||||
|
err = synor_zk_init(&config, &zk);
|
||||||
|
if (err != SYNOR_OK) {
|
||||||
|
fprintf(stderr, "Failed to initialize ZK client: %s\n", synor_error_string(err));
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check service health
|
||||||
|
bool healthy;
|
||||||
|
err = synor_zk_health_check(zk, &healthy);
|
||||||
|
printf("Service healthy: %s\n\n", healthy ? "true" : "false");
|
||||||
|
|
||||||
|
// Run examples
|
||||||
|
circuit_example(zk);
|
||||||
|
groth16_example(zk);
|
||||||
|
plonk_example(zk);
|
||||||
|
stark_example(zk);
|
||||||
|
recursive_example(zk);
|
||||||
|
ceremony_example(zk);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
synor_zk_free(zk);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
377
sdk/cpp/examples/compiler_example.cpp
Normal file
377
sdk/cpp/examples/compiler_example.cpp
Normal file
|
|
@ -0,0 +1,377 @@
|
||||||
|
/**
|
||||||
|
* Synor Compiler SDK Examples for C++
|
||||||
|
*
|
||||||
|
* Demonstrates smart contract compilation and analysis:
|
||||||
|
* - WASM contract compilation and optimization
|
||||||
|
* - ABI extraction and encoding
|
||||||
|
* - Contract analysis and security scanning
|
||||||
|
* - Validation and verification
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <synor/compiler.hpp>
|
||||||
|
|
||||||
|
using namespace synor::compiler;
|
||||||
|
|
||||||
|
// Helper function to create a minimal valid WASM module for testing
|
||||||
|
std::vector<uint8_t> create_minimal_wasm() {
|
||||||
|
return {
|
||||||
|
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
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void compile_contract_example(SynorCompiler& compiler) {
|
||||||
|
std::cout << "=== Contract Compilation ===" << std::endl;
|
||||||
|
|
||||||
|
auto wasm = create_minimal_wasm();
|
||||||
|
|
||||||
|
auto result = compiler.compile(wasm, {
|
||||||
|
.optimization_level = OptimizationLevel::Size,
|
||||||
|
.use_wasm_opt = true,
|
||||||
|
.validate = true,
|
||||||
|
.extract_metadata = true,
|
||||||
|
.generate_abi = true,
|
||||||
|
.strip_options = {
|
||||||
|
.strip_debug = true,
|
||||||
|
.strip_producers = true,
|
||||||
|
.strip_names = true,
|
||||||
|
.strip_custom = true,
|
||||||
|
.strip_unused = true,
|
||||||
|
.preserve_sections = {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
std::cout << "Compilation result:" << std::endl;
|
||||||
|
std::cout << " Contract ID: " << result.contract_id() << std::endl;
|
||||||
|
std::cout << " Code hash: " << result.code_hash() << std::endl;
|
||||||
|
std::cout << " Original size: " << result.original_size() << " bytes" << std::endl;
|
||||||
|
std::cout << " Optimized size: " << result.optimized_size() << " bytes" << std::endl;
|
||||||
|
std::cout << " Size reduction: " << std::fixed << std::setprecision(1) << result.size_reduction() << "%" << std::endl;
|
||||||
|
std::cout << " Estimated deploy gas: " << result.estimated_deploy_gas() << std::endl;
|
||||||
|
|
||||||
|
if (result.metadata()) {
|
||||||
|
std::cout << "\nMetadata:" << std::endl;
|
||||||
|
std::cout << " Name: " << result.metadata()->name() << std::endl;
|
||||||
|
std::cout << " Version: " << result.metadata()->version() << std::endl;
|
||||||
|
std::cout << " SDK Version: " << result.metadata()->sdk_version() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.abi()) {
|
||||||
|
std::cout << "\nABI:" << std::endl;
|
||||||
|
std::cout << " Functions: " << result.abi()->functions().size() << std::endl;
|
||||||
|
std::cout << " Events: " << result.abi()->events().size() << std::endl;
|
||||||
|
std::cout << " Errors: " << result.abi()->errors().size() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void compilation_modes_example(SynorCompiler& compiler) {
|
||||||
|
std::cout << "=== Compilation Modes ===" << std::endl;
|
||||||
|
|
||||||
|
auto wasm = create_minimal_wasm();
|
||||||
|
|
||||||
|
// Development mode: fast compilation, debugging support
|
||||||
|
std::cout << "Development mode:" << std::endl;
|
||||||
|
auto dev_result = compiler.contracts().compile_dev(wasm);
|
||||||
|
std::cout << " Size: " << dev_result.optimized_size() << " bytes" << std::endl;
|
||||||
|
std::cout << " Optimization: none" << std::endl;
|
||||||
|
|
||||||
|
// Production mode: maximum optimization
|
||||||
|
std::cout << "\nProduction mode:" << std::endl;
|
||||||
|
auto prod_result = compiler.contracts().compile_production(wasm);
|
||||||
|
std::cout << " Size: " << prod_result.optimized_size() << " bytes" << std::endl;
|
||||||
|
std::cout << " Optimization: aggressive" << std::endl;
|
||||||
|
std::cout << " Size savings: " << (dev_result.optimized_size() - prod_result.optimized_size()) << " bytes" << std::endl;
|
||||||
|
|
||||||
|
// Custom optimization levels
|
||||||
|
std::cout << "\nOptimization levels:" << std::endl;
|
||||||
|
std::vector<std::pair<OptimizationLevel, std::string>> levels = {
|
||||||
|
{OptimizationLevel::None, "NONE"},
|
||||||
|
{OptimizationLevel::Basic, "BASIC"},
|
||||||
|
{OptimizationLevel::Size, "SIZE"},
|
||||||
|
{OptimizationLevel::Aggressive, "AGGRESSIVE"}
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const auto& [level, name] : levels) {
|
||||||
|
auto result = compiler.compile(wasm, {.optimization_level = level});
|
||||||
|
std::cout << " " << name << ": " << result.optimized_size() << " bytes" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void abi_example(SynorCompiler& compiler) {
|
||||||
|
std::cout << "=== ABI Operations ===" << std::endl;
|
||||||
|
|
||||||
|
auto wasm = create_minimal_wasm();
|
||||||
|
|
||||||
|
// Extract ABI from WASM
|
||||||
|
auto abi = compiler.abi().extract(wasm);
|
||||||
|
std::cout << "Contract: " << abi.name() << std::endl;
|
||||||
|
std::cout << "Version: " << abi.version() << std::endl;
|
||||||
|
|
||||||
|
// List functions
|
||||||
|
if (!abi.functions().empty()) {
|
||||||
|
std::cout << "\nFunctions:" << std::endl;
|
||||||
|
for (const auto& func : abi.functions()) {
|
||||||
|
std::string inputs;
|
||||||
|
for (size_t i = 0; i < func.inputs().size(); ++i) {
|
||||||
|
const auto& param = func.inputs()[i];
|
||||||
|
if (i > 0) inputs += ", ";
|
||||||
|
inputs += param.name() + ": " + param.type().type_name();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string outputs;
|
||||||
|
if (func.outputs().empty()) {
|
||||||
|
outputs = "void";
|
||||||
|
} else {
|
||||||
|
for (size_t i = 0; i < func.outputs().size(); ++i) {
|
||||||
|
if (i > 0) outputs += ", ";
|
||||||
|
outputs += func.outputs()[i].type().type_name();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string modifiers;
|
||||||
|
if (func.view()) modifiers += "view ";
|
||||||
|
if (func.payable()) modifiers += "payable";
|
||||||
|
|
||||||
|
std::cout << " " << func.name() << "(" << inputs << ") -> " << outputs << " " << modifiers << std::endl;
|
||||||
|
std::cout << " Selector: " << func.selector() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// List events
|
||||||
|
if (!abi.events().empty()) {
|
||||||
|
std::cout << "\nEvents:" << std::endl;
|
||||||
|
for (const auto& event : abi.events()) {
|
||||||
|
std::string params;
|
||||||
|
for (size_t i = 0; i < event.params().size(); ++i) {
|
||||||
|
const auto& param = event.params()[i];
|
||||||
|
if (i > 0) params += ", ";
|
||||||
|
if (param.indexed()) params += "indexed ";
|
||||||
|
params += param.name() + ": " + param.type().type_name();
|
||||||
|
}
|
||||||
|
std::cout << " " << event.name() << "(" << params << ")" << std::endl;
|
||||||
|
std::cout << " Topic: " << event.topic() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode a function call
|
||||||
|
if (!abi.functions().empty()) {
|
||||||
|
const auto& func = abi.functions().front();
|
||||||
|
auto encoded = compiler.abi().encode_call(func, {"arg1", "arg2"});
|
||||||
|
std::cout << "\nEncoded call to " << func.name() << ": " << encoded << std::endl;
|
||||||
|
|
||||||
|
// Decode a result
|
||||||
|
auto decoded = compiler.abi().decode_result(func, encoded);
|
||||||
|
std::cout << "Decoded result: " << decoded << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void analysis_example(SynorCompiler& compiler) {
|
||||||
|
std::cout << "=== Contract Analysis ===" << std::endl;
|
||||||
|
|
||||||
|
auto wasm = create_minimal_wasm();
|
||||||
|
|
||||||
|
// Full analysis
|
||||||
|
auto analysis = compiler.analysis().analyze(wasm);
|
||||||
|
|
||||||
|
// Size breakdown
|
||||||
|
if (analysis.size_breakdown()) {
|
||||||
|
const auto& size = *analysis.size_breakdown();
|
||||||
|
std::cout << "Size breakdown:" << std::endl;
|
||||||
|
std::cout << " Code: " << size.code() << " bytes" << std::endl;
|
||||||
|
std::cout << " Data: " << size.data() << " bytes" << std::endl;
|
||||||
|
std::cout << " Functions: " << size.functions() << " bytes" << std::endl;
|
||||||
|
std::cout << " Memory: " << size.memory() << " bytes" << std::endl;
|
||||||
|
std::cout << " Exports: " << size.exports() << " bytes" << std::endl;
|
||||||
|
std::cout << " Imports: " << size.imports() << " bytes" << std::endl;
|
||||||
|
std::cout << " Total: " << size.total() << " bytes" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function analysis
|
||||||
|
if (!analysis.functions().empty()) {
|
||||||
|
std::cout << "\nFunction analysis:" << std::endl;
|
||||||
|
for (size_t i = 0; i < std::min(analysis.functions().size(), size_t(5)); ++i) {
|
||||||
|
const auto& func = analysis.functions()[i];
|
||||||
|
std::cout << " " << func.name() << ":" << std::endl;
|
||||||
|
std::cout << " Size: " << func.size() << " bytes" << std::endl;
|
||||||
|
std::cout << " Instructions: " << func.instruction_count() << std::endl;
|
||||||
|
std::cout << " Locals: " << func.local_count() << std::endl;
|
||||||
|
std::cout << " Exported: " << (func.exported() ? "true" : "false") << std::endl;
|
||||||
|
std::cout << " Estimated gas: " << func.estimated_gas() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import analysis
|
||||||
|
if (!analysis.imports().empty()) {
|
||||||
|
std::cout << "\nImports:" << std::endl;
|
||||||
|
for (const auto& imp : analysis.imports()) {
|
||||||
|
std::cout << " " << imp.module() << "." << imp.name() << " (" << imp.kind() << ")" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gas analysis
|
||||||
|
if (analysis.gas_analysis()) {
|
||||||
|
const auto& gas = *analysis.gas_analysis();
|
||||||
|
std::cout << "\nGas analysis:" << std::endl;
|
||||||
|
std::cout << " Deployment: " << gas.deployment_gas() << std::endl;
|
||||||
|
std::cout << " Memory init: " << gas.memory_init_gas() << std::endl;
|
||||||
|
std::cout << " Data section: " << gas.data_section_gas() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract metadata
|
||||||
|
auto metadata = compiler.analysis().extract_metadata(wasm);
|
||||||
|
std::cout << "\nContract metadata:" << std::endl;
|
||||||
|
std::cout << " Name: " << metadata.name() << std::endl;
|
||||||
|
std::cout << " Version: " << metadata.version() << std::endl;
|
||||||
|
std::cout << " Build timestamp: " << metadata.build_timestamp() << std::endl;
|
||||||
|
|
||||||
|
// Estimate deployment gas
|
||||||
|
auto gas_estimate = compiler.analysis().estimate_deploy_gas(wasm);
|
||||||
|
std::cout << "\nEstimated deployment gas: " << gas_estimate << std::endl;
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void validation_example(SynorCompiler& compiler) {
|
||||||
|
std::cout << "=== Contract Validation ===" << std::endl;
|
||||||
|
|
||||||
|
auto wasm = create_minimal_wasm();
|
||||||
|
|
||||||
|
// Full validation
|
||||||
|
auto result = compiler.validation().validate(wasm);
|
||||||
|
std::cout << "Valid: " << (result.valid() ? "true" : "false") << std::endl;
|
||||||
|
std::cout << "Exports: " << result.export_count() << std::endl;
|
||||||
|
std::cout << "Imports: " << result.import_count() << std::endl;
|
||||||
|
std::cout << "Functions: " << result.function_count() << std::endl;
|
||||||
|
std::cout << "Memory pages: " << result.memory_pages() << std::endl;
|
||||||
|
|
||||||
|
if (!result.errors().empty()) {
|
||||||
|
std::cout << "\nValidation errors:" << std::endl;
|
||||||
|
for (const auto& error : result.errors()) {
|
||||||
|
std::cout << " [" << error.code() << "] " << error.message() << std::endl;
|
||||||
|
if (!error.location().empty()) {
|
||||||
|
std::cout << " at " << error.location() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!result.warnings().empty()) {
|
||||||
|
std::cout << "\nWarnings:" << std::endl;
|
||||||
|
for (const auto& warning : result.warnings()) {
|
||||||
|
std::cout << " " << warning << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quick validation
|
||||||
|
bool is_valid = compiler.validation().is_valid(wasm);
|
||||||
|
std::cout << "\nQuick validation: " << (is_valid ? "true" : "false") << std::endl;
|
||||||
|
|
||||||
|
// Get validation errors only
|
||||||
|
auto errors = compiler.validation().get_errors(wasm);
|
||||||
|
std::cout << "Error count: " << errors.size() << std::endl;
|
||||||
|
|
||||||
|
// Validate required exports
|
||||||
|
bool has_required = compiler.validation().validate_exports(wasm, {"init", "execute", "query"});
|
||||||
|
std::cout << "Has required exports: " << (has_required ? "true" : "false") << std::endl;
|
||||||
|
|
||||||
|
// Validate memory constraints
|
||||||
|
bool memory_valid = compiler.validation().validate_memory(wasm, 16);
|
||||||
|
std::cout << "Memory within 16 pages: " << (memory_valid ? "true" : "false") << std::endl;
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void security_example(SynorCompiler& compiler) {
|
||||||
|
std::cout << "=== Security Scanning ===" << std::endl;
|
||||||
|
|
||||||
|
auto wasm = create_minimal_wasm();
|
||||||
|
|
||||||
|
auto security = compiler.analysis().security_scan(wasm);
|
||||||
|
|
||||||
|
std::cout << "Security score: " << security.score() << "/100" << std::endl;
|
||||||
|
|
||||||
|
if (!security.issues().empty()) {
|
||||||
|
std::cout << "\nSecurity issues:" << std::endl;
|
||||||
|
for (const auto& issue : security.issues()) {
|
||||||
|
std::string icon;
|
||||||
|
std::string severity = issue.severity();
|
||||||
|
if (severity == "critical") icon = "[CRIT]";
|
||||||
|
else if (severity == "high") icon = "[HIGH]";
|
||||||
|
else if (severity == "medium") icon = "[MED]";
|
||||||
|
else if (severity == "low") icon = "[LOW]";
|
||||||
|
else icon = "[???]";
|
||||||
|
|
||||||
|
std::cout << icon << " [" << issue.severity() << "] " << issue.type() << std::endl;
|
||||||
|
std::cout << " " << issue.description() << std::endl;
|
||||||
|
if (!issue.location().empty()) {
|
||||||
|
std::cout << " at " << issue.location() << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
std::cout << "No security issues found!" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!security.recommendations().empty()) {
|
||||||
|
std::cout << "\nRecommendations:" << std::endl;
|
||||||
|
for (const auto& rec : security.recommendations()) {
|
||||||
|
std::cout << " • " << rec << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
// Initialize client
|
||||||
|
const char* api_key = std::getenv("SYNOR_API_KEY");
|
||||||
|
CompilerConfig config{
|
||||||
|
.api_key = api_key ? api_key : "your-api-key",
|
||||||
|
.endpoint = "https://compiler.synor.io/v1",
|
||||||
|
.timeout = std::chrono::seconds(60),
|
||||||
|
.retries = 3,
|
||||||
|
.debug = false,
|
||||||
|
.default_optimization_level = OptimizationLevel::Size,
|
||||||
|
.max_contract_size = 256 * 1024,
|
||||||
|
.use_wasm_opt = true,
|
||||||
|
.validate = true,
|
||||||
|
.extract_metadata = true,
|
||||||
|
.generate_abi = true
|
||||||
|
};
|
||||||
|
|
||||||
|
SynorCompiler compiler(config);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check service health
|
||||||
|
bool healthy = compiler.health_check();
|
||||||
|
std::cout << "Service healthy: " << (healthy ? "true" : "false") << std::endl << std::endl;
|
||||||
|
|
||||||
|
// Run examples
|
||||||
|
compile_contract_example(compiler);
|
||||||
|
compilation_modes_example(compiler);
|
||||||
|
abi_example(compiler);
|
||||||
|
analysis_example(compiler);
|
||||||
|
validation_example(compiler);
|
||||||
|
security_example(compiler);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
std::cerr << "Error: " << e.what() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
273
sdk/cpp/examples/crypto_example.cpp
Normal file
273
sdk/cpp/examples/crypto_example.cpp
Normal file
|
|
@ -0,0 +1,273 @@
|
||||||
|
/**
|
||||||
|
* Synor Crypto SDK Examples for C++
|
||||||
|
*
|
||||||
|
* Demonstrates quantum-resistant cryptographic operations:
|
||||||
|
* - Hybrid Ed25519 + Dilithium3 signatures
|
||||||
|
* - BIP-39 mnemonic generation and validation
|
||||||
|
* - Post-quantum algorithms (Falcon, SPHINCS+)
|
||||||
|
* - Key derivation functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <synor/crypto.hpp>
|
||||||
|
|
||||||
|
using namespace synor::crypto;
|
||||||
|
|
||||||
|
// Helper function to convert bytes to hex string
|
||||||
|
std::string bytes_to_hex(const std::vector<uint8_t>& data, size_t max_len = 0) {
|
||||||
|
std::stringstream ss;
|
||||||
|
size_t len = max_len > 0 && max_len < data.size() ? max_len : data.size();
|
||||||
|
for (size_t i = 0; i < len; ++i) {
|
||||||
|
ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(data[i]);
|
||||||
|
}
|
||||||
|
if (max_len > 0 && max_len < data.size()) {
|
||||||
|
ss << "...";
|
||||||
|
}
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mnemonic_example(SynorCrypto& crypto) {
|
||||||
|
std::cout << "=== Mnemonic Operations ===" << std::endl;
|
||||||
|
|
||||||
|
// Generate a 24-word mnemonic (256-bit entropy)
|
||||||
|
auto mnemonic = crypto.mnemonic().generate(24);
|
||||||
|
std::cout << "Generated mnemonic: " << mnemonic.phrase() << std::endl;
|
||||||
|
std::cout << "Word count: " << mnemonic.word_count() << std::endl;
|
||||||
|
|
||||||
|
// Validate a mnemonic
|
||||||
|
auto validation = crypto.mnemonic().validate(mnemonic.phrase());
|
||||||
|
std::cout << "Valid: " << (validation.is_valid() ? "true" : "false") << std::endl;
|
||||||
|
if (!validation.is_valid()) {
|
||||||
|
std::cout << "Error: " << validation.error() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert mnemonic to seed
|
||||||
|
auto seed = crypto.mnemonic().to_seed(mnemonic.phrase(), "optional-passphrase");
|
||||||
|
std::cout << "Seed (hex): " << bytes_to_hex(seed, 16) << std::endl;
|
||||||
|
|
||||||
|
// Word suggestions for autocomplete
|
||||||
|
auto suggestions = crypto.mnemonic().suggest_words("aban", 5);
|
||||||
|
std::cout << "Suggestions for 'aban': ";
|
||||||
|
for (size_t i = 0; i < suggestions.size(); ++i) {
|
||||||
|
std::cout << suggestions[i] << (i < suggestions.size() - 1 ? ", " : "");
|
||||||
|
}
|
||||||
|
std::cout << std::endl << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void keypair_example(SynorCrypto& crypto) {
|
||||||
|
std::cout << "=== Keypair Operations ===" << std::endl;
|
||||||
|
|
||||||
|
// Generate a random keypair
|
||||||
|
auto keypair = crypto.keypairs().generate();
|
||||||
|
std::cout << "Generated hybrid keypair:" << std::endl;
|
||||||
|
std::cout << " Ed25519 public key size: " << keypair.public_key().ed25519_bytes().size() << " bytes" << std::endl;
|
||||||
|
std::cout << " Dilithium public key size: " << keypair.public_key().dilithium_bytes().size() << " bytes" << std::endl;
|
||||||
|
std::cout << " Total public key size: " << keypair.public_key().size() << " bytes" << std::endl;
|
||||||
|
|
||||||
|
// Get addresses for different networks
|
||||||
|
std::cout << "\nAddresses:" << std::endl;
|
||||||
|
std::cout << " Mainnet: " << keypair.get_address(Network::Mainnet) << std::endl;
|
||||||
|
std::cout << " Testnet: " << keypair.get_address(Network::Testnet) << std::endl;
|
||||||
|
std::cout << " Devnet: " << keypair.get_address(Network::Devnet) << std::endl;
|
||||||
|
|
||||||
|
// Create keypair from mnemonic (deterministic)
|
||||||
|
auto mnemonic = crypto.mnemonic().generate(24);
|
||||||
|
auto keypair2 = crypto.keypairs().from_mnemonic(mnemonic.phrase(), "");
|
||||||
|
auto addr = keypair2.get_address(Network::Mainnet);
|
||||||
|
std::cout << "\nKeypair from mnemonic: " << addr.substr(0, 20) << "..." << std::endl;
|
||||||
|
|
||||||
|
// Derive child keypair using BIP-44 path
|
||||||
|
auto path = DerivationPath::external(0, 0); // m/44'/21337'/0'/0/0
|
||||||
|
std::cout << "Derivation path: " << path.to_string() << std::endl;
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void signing_example(SynorCrypto& crypto) {
|
||||||
|
std::cout << "=== Hybrid Signing ===" << std::endl;
|
||||||
|
|
||||||
|
// Generate keypair
|
||||||
|
auto keypair = crypto.keypairs().generate();
|
||||||
|
|
||||||
|
// Sign a message
|
||||||
|
std::string message_str = "Hello, quantum-resistant world!";
|
||||||
|
std::vector<uint8_t> message(message_str.begin(), message_str.end());
|
||||||
|
auto signature = crypto.signing().sign(keypair, message);
|
||||||
|
|
||||||
|
std::cout << "Signature created:" << std::endl;
|
||||||
|
std::cout << " Ed25519 component: " << signature.ed25519_bytes().size() << " bytes" << std::endl;
|
||||||
|
std::cout << " Dilithium component: " << signature.dilithium_bytes().size() << " bytes" << std::endl;
|
||||||
|
std::cout << " Total signature size: " << signature.size() << " bytes" << std::endl;
|
||||||
|
|
||||||
|
// Verify the signature
|
||||||
|
bool valid = crypto.signing().verify(keypair.public_key(), message, signature);
|
||||||
|
std::cout << "\nVerification result: " << (valid ? "true" : "false") << std::endl;
|
||||||
|
|
||||||
|
// Verify with tampered message fails
|
||||||
|
std::string tampered_str = "Hello, tampered message!";
|
||||||
|
std::vector<uint8_t> tampered_message(tampered_str.begin(), tampered_str.end());
|
||||||
|
bool invalid_result = crypto.signing().verify(keypair.public_key(), tampered_message, signature);
|
||||||
|
std::cout << "Tampered message verification: " << (invalid_result ? "true" : "false") << std::endl;
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void falcon_example(SynorCrypto& crypto) {
|
||||||
|
std::cout << "=== Falcon Post-Quantum Signatures ===" << std::endl;
|
||||||
|
|
||||||
|
// Generate Falcon-512 keypair (128-bit security)
|
||||||
|
auto falcon512 = crypto.falcon().generate(FalconVariant::Falcon512);
|
||||||
|
std::cout << "Falcon-512 keypair:" << std::endl;
|
||||||
|
std::cout << " Public key: " << falcon512.public_key().key_bytes().size() << " bytes" << std::endl;
|
||||||
|
std::cout << " Security level: 128-bit" << std::endl;
|
||||||
|
|
||||||
|
// Generate Falcon-1024 keypair (256-bit security)
|
||||||
|
auto falcon1024 = crypto.falcon().generate(FalconVariant::Falcon1024);
|
||||||
|
std::cout << "\nFalcon-1024 keypair:" << std::endl;
|
||||||
|
std::cout << " Public key: " << falcon1024.public_key().key_bytes().size() << " bytes" << std::endl;
|
||||||
|
std::cout << " Security level: 256-bit" << std::endl;
|
||||||
|
|
||||||
|
// Sign with Falcon-512
|
||||||
|
std::string message_str = "Post-quantum secure message";
|
||||||
|
std::vector<uint8_t> message(message_str.begin(), message_str.end());
|
||||||
|
auto signature = crypto.falcon().sign(falcon512, message);
|
||||||
|
std::cout << "\nFalcon-512 signature: " << signature.signature_bytes().size() << " bytes" << std::endl;
|
||||||
|
|
||||||
|
// Verify
|
||||||
|
bool valid = crypto.falcon().verify(falcon512.public_key().key_bytes(), message, signature);
|
||||||
|
std::cout << "Verification: " << (valid ? "true" : "false") << std::endl;
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sphincs_example(SynorCrypto& crypto) {
|
||||||
|
std::cout << "=== SPHINCS+ Hash-Based Signatures ===" << std::endl;
|
||||||
|
|
||||||
|
// SPHINCS+ variants with different security levels
|
||||||
|
struct VariantInfo {
|
||||||
|
SphincsVariant variant;
|
||||||
|
int security;
|
||||||
|
int sig_size;
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<VariantInfo> variants = {
|
||||||
|
{SphincsVariant::Shake128s, 128, 7856, "SHAKE128S"},
|
||||||
|
{SphincsVariant::Shake192s, 192, 16224, "SHAKE192S"},
|
||||||
|
{SphincsVariant::Shake256s, 256, 29792, "SHAKE256S"},
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string message_str = "Hash-based quantum security";
|
||||||
|
std::vector<uint8_t> message(message_str.begin(), message_str.end());
|
||||||
|
|
||||||
|
for (const auto& v : variants) {
|
||||||
|
auto keypair = crypto.sphincs().generate(v.variant);
|
||||||
|
std::cout << "SPHINCS+ " << v.name << ":" << std::endl;
|
||||||
|
std::cout << " Security level: " << v.security << "-bit" << std::endl;
|
||||||
|
std::cout << " Expected signature size: " << v.sig_size << " bytes" << std::endl;
|
||||||
|
|
||||||
|
// Sign a message
|
||||||
|
auto signature = crypto.sphincs().sign(keypair, message);
|
||||||
|
std::cout << " Actual signature size: " << signature.signature_bytes().size() << " bytes" << std::endl;
|
||||||
|
|
||||||
|
// Verify
|
||||||
|
bool valid = crypto.sphincs().verify(keypair.public_key().key_bytes(), message, signature);
|
||||||
|
std::cout << " Verification: " << (valid ? "true" : "false") << std::endl << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void kdf_example(SynorCrypto& crypto) {
|
||||||
|
std::cout << "=== Key Derivation Functions ===" << std::endl;
|
||||||
|
|
||||||
|
// HKDF (HMAC-based Key Derivation Function)
|
||||||
|
std::string seed_str = "master-secret-key-material-here";
|
||||||
|
std::vector<uint8_t> seed(seed_str.begin(), seed_str.end());
|
||||||
|
|
||||||
|
std::string salt_str = "application-salt";
|
||||||
|
std::string info_str = "encryption-key";
|
||||||
|
|
||||||
|
DerivationConfig hkdf_config{
|
||||||
|
.salt = std::vector<uint8_t>(salt_str.begin(), salt_str.end()),
|
||||||
|
.info = std::vector<uint8_t>(info_str.begin(), info_str.end()),
|
||||||
|
.output_length = 32
|
||||||
|
};
|
||||||
|
|
||||||
|
auto derived_key = crypto.kdf().derive_key(seed, hkdf_config);
|
||||||
|
std::cout << "HKDF derived key: " << bytes_to_hex(derived_key) << std::endl;
|
||||||
|
|
||||||
|
// PBKDF2 (Password-Based Key Derivation Function)
|
||||||
|
std::string password_str = "user-password";
|
||||||
|
std::vector<uint8_t> password(password_str.begin(), password_str.end());
|
||||||
|
|
||||||
|
std::string pbkdf2_salt_str = "random-salt-value";
|
||||||
|
|
||||||
|
PasswordDerivationConfig pbkdf2_config{
|
||||||
|
.salt = std::vector<uint8_t>(pbkdf2_salt_str.begin(), pbkdf2_salt_str.end()),
|
||||||
|
.iterations = 100000,
|
||||||
|
.output_length = 32
|
||||||
|
};
|
||||||
|
|
||||||
|
auto password_key = crypto.kdf().derive_from_password(password, pbkdf2_config);
|
||||||
|
std::cout << "PBKDF2 derived key: " << bytes_to_hex(password_key) << std::endl;
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hash_example(SynorCrypto& crypto) {
|
||||||
|
std::cout << "=== Hash Functions ===" << std::endl;
|
||||||
|
|
||||||
|
std::string data_str = "Data to hash";
|
||||||
|
std::vector<uint8_t> data(data_str.begin(), data_str.end());
|
||||||
|
|
||||||
|
// SHA3-256 (FIPS 202)
|
||||||
|
auto sha3 = crypto.hash().sha3_256(data);
|
||||||
|
std::cout << "SHA3-256: " << sha3.hex() << std::endl;
|
||||||
|
|
||||||
|
// BLAKE3 (fast, parallel)
|
||||||
|
auto blake3 = crypto.hash().blake3(data);
|
||||||
|
std::cout << "BLAKE3: " << blake3.hex() << std::endl;
|
||||||
|
|
||||||
|
// Keccak-256 (Ethereum compatible)
|
||||||
|
auto keccak = crypto.hash().keccak256(data);
|
||||||
|
std::cout << "Keccak: " << keccak.hex() << std::endl;
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
// Initialize client
|
||||||
|
const char* api_key = std::getenv("SYNOR_API_KEY");
|
||||||
|
CryptoConfig config{
|
||||||
|
.api_key = api_key ? api_key : "your-api-key",
|
||||||
|
.endpoint = "https://crypto.synor.io/v1",
|
||||||
|
.timeout = std::chrono::seconds(30),
|
||||||
|
.retries = 3,
|
||||||
|
.debug = false,
|
||||||
|
.default_network = Network::Mainnet
|
||||||
|
};
|
||||||
|
|
||||||
|
SynorCrypto crypto(config);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check service health
|
||||||
|
bool healthy = crypto.health_check();
|
||||||
|
std::cout << "Service healthy: " << (healthy ? "true" : "false") << std::endl << std::endl;
|
||||||
|
|
||||||
|
// Run examples
|
||||||
|
mnemonic_example(crypto);
|
||||||
|
keypair_example(crypto);
|
||||||
|
signing_example(crypto);
|
||||||
|
falcon_example(crypto);
|
||||||
|
sphincs_example(crypto);
|
||||||
|
kdf_example(crypto);
|
||||||
|
hash_example(crypto);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
std::cerr << "Error: " << e.what() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
358
sdk/cpp/examples/dex_example.cpp
Normal file
358
sdk/cpp/examples/dex_example.cpp
Normal file
|
|
@ -0,0 +1,358 @@
|
||||||
|
/**
|
||||||
|
* Synor DEX SDK Examples for C++
|
||||||
|
*
|
||||||
|
* Demonstrates decentralized exchange operations:
|
||||||
|
* - Spot trading (limit/market orders)
|
||||||
|
* - Perpetual futures trading
|
||||||
|
* - Liquidity provision (AMM pools)
|
||||||
|
* - Order book management
|
||||||
|
* - Portfolio tracking
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <synor/dex.hpp>
|
||||||
|
|
||||||
|
using namespace synor::dex;
|
||||||
|
|
||||||
|
void markets_example(SynorDex& dex) {
|
||||||
|
std::cout << "=== Markets ===" << std::endl;
|
||||||
|
|
||||||
|
// Get all markets
|
||||||
|
auto markets = dex.markets().list();
|
||||||
|
std::cout << "Available markets: " << markets.size() << std::endl;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < std::min(markets.size(), size_t(5)); ++i) {
|
||||||
|
const auto& market = markets[i];
|
||||||
|
std::cout << "\n " << market.symbol() << ":" << std::endl;
|
||||||
|
std::cout << " Base: " << market.base_asset() << ", Quote: " << market.quote_asset() << std::endl;
|
||||||
|
std::cout << " Price: " << market.last_price() << std::endl;
|
||||||
|
std::cout << " 24h Volume: " << market.volume_24h() << std::endl;
|
||||||
|
std::cout << " 24h Change: " << market.change_24h() << "%" << std::endl;
|
||||||
|
std::cout << " Status: " << market.status() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get specific market
|
||||||
|
auto market = dex.markets().get("SYN-USDC");
|
||||||
|
std::cout << "\nSYN-USDC details:" << std::endl;
|
||||||
|
std::cout << " Min order size: " << market.min_order_size() << std::endl;
|
||||||
|
std::cout << " Tick size: " << market.tick_size() << std::endl;
|
||||||
|
std::cout << " Maker fee: " << market.maker_fee() << "%" << std::endl;
|
||||||
|
std::cout << " Taker fee: " << market.taker_fee() << "%" << std::endl;
|
||||||
|
|
||||||
|
// Get market statistics
|
||||||
|
auto stats = dex.markets().get_stats("SYN-USDC");
|
||||||
|
std::cout << "\nMarket statistics:" << std::endl;
|
||||||
|
std::cout << " High 24h: " << stats.high_24h() << std::endl;
|
||||||
|
std::cout << " Low 24h: " << stats.low_24h() << std::endl;
|
||||||
|
std::cout << " Open interest: " << stats.open_interest() << std::endl;
|
||||||
|
std::cout << " Funding rate: " << stats.funding_rate() << "%" << std::endl;
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void spot_trading_example(SynorDex& dex) {
|
||||||
|
std::cout << "=== Spot Trading ===" << std::endl;
|
||||||
|
|
||||||
|
// Place a limit order
|
||||||
|
std::cout << "Placing limit buy order..." << std::endl;
|
||||||
|
auto limit_order = dex.spot().place_order({
|
||||||
|
.market = "SYN-USDC",
|
||||||
|
.side = OrderSide::Buy,
|
||||||
|
.order_type = OrderType::Limit,
|
||||||
|
.price = "1.50",
|
||||||
|
.quantity = "100",
|
||||||
|
.time_in_force = TimeInForce::GTC
|
||||||
|
});
|
||||||
|
|
||||||
|
std::cout << "Limit order placed:" << std::endl;
|
||||||
|
std::cout << " Order ID: " << limit_order.order_id() << std::endl;
|
||||||
|
std::cout << " Status: " << limit_order.status() << std::endl;
|
||||||
|
std::cout << " Price: " << limit_order.price() << std::endl;
|
||||||
|
std::cout << " Quantity: " << limit_order.quantity() << std::endl;
|
||||||
|
|
||||||
|
// Place a market order
|
||||||
|
std::cout << "\nPlacing market sell order..." << std::endl;
|
||||||
|
auto market_order = dex.spot().place_order({
|
||||||
|
.market = "SYN-USDC",
|
||||||
|
.side = OrderSide::Sell,
|
||||||
|
.order_type = OrderType::Market,
|
||||||
|
.quantity = "50"
|
||||||
|
});
|
||||||
|
|
||||||
|
std::cout << "Market order executed:" << std::endl;
|
||||||
|
std::cout << " Order ID: " << market_order.order_id() << std::endl;
|
||||||
|
std::cout << " Status: " << market_order.status() << std::endl;
|
||||||
|
std::cout << " Filled: " << market_order.filled_quantity() << std::endl;
|
||||||
|
std::cout << " Avg price: " << market_order.average_price() << std::endl;
|
||||||
|
|
||||||
|
// Get order status
|
||||||
|
auto status = dex.spot().get_order(limit_order.order_id());
|
||||||
|
std::cout << "\nOrder status:" << std::endl;
|
||||||
|
std::cout << " Status: " << status.status() << std::endl;
|
||||||
|
std::cout << " Filled: " << status.filled_quantity() << " / " << status.quantity() << std::endl;
|
||||||
|
std::cout << " Remaining: " << status.remaining_quantity() << std::endl;
|
||||||
|
|
||||||
|
// Cancel order
|
||||||
|
std::cout << "\nCancelling order..." << std::endl;
|
||||||
|
dex.spot().cancel_order(limit_order.order_id());
|
||||||
|
std::cout << "Order cancelled successfully" << std::endl;
|
||||||
|
|
||||||
|
// Get open orders
|
||||||
|
auto open_orders = dex.spot().get_open_orders("SYN-USDC");
|
||||||
|
std::cout << "\nOpen orders: " << open_orders.size() << std::endl;
|
||||||
|
|
||||||
|
// Get trade history
|
||||||
|
auto trades = dex.spot().get_trade_history("SYN-USDC", 10);
|
||||||
|
std::cout << "\nRecent trades: " << trades.size() << std::endl;
|
||||||
|
for (size_t i = 0; i < std::min(trades.size(), size_t(3)); ++i) {
|
||||||
|
const auto& trade = trades[i];
|
||||||
|
std::cout << " " << trade.side() << " " << trade.quantity()
|
||||||
|
<< " @ " << trade.price() << " (" << trade.timestamp() << ")" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void perps_trading_example(SynorDex& dex) {
|
||||||
|
std::cout << "=== Perpetual Futures Trading ===" << std::endl;
|
||||||
|
|
||||||
|
// Get available perps markets
|
||||||
|
auto perps_markets = dex.perps().list_markets();
|
||||||
|
std::cout << "Available perps markets: " << perps_markets.size() << std::endl;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < std::min(perps_markets.size(), size_t(3)); ++i) {
|
||||||
|
const auto& market = perps_markets[i];
|
||||||
|
std::cout << " " << market.symbol() << ": " << market.mark_price()
|
||||||
|
<< " (funding: " << market.funding_rate() << "%)" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open a long position
|
||||||
|
std::cout << "\nOpening long position..." << std::endl;
|
||||||
|
auto position = dex.perps().open_position({
|
||||||
|
.market = "SYN-USDC-PERP",
|
||||||
|
.side = OrderSide::Buy,
|
||||||
|
.order_type = OrderType::Limit,
|
||||||
|
.price = "1.50",
|
||||||
|
.size = "1000",
|
||||||
|
.leverage = 10,
|
||||||
|
.reduce_only = false
|
||||||
|
});
|
||||||
|
|
||||||
|
std::cout << "Position opened:" << std::endl;
|
||||||
|
std::cout << " Position ID: " << position.position_id() << std::endl;
|
||||||
|
std::cout << " Size: " << position.size() << std::endl;
|
||||||
|
std::cout << " Entry price: " << position.entry_price() << std::endl;
|
||||||
|
std::cout << " Leverage: " << position.leverage() << "x" << std::endl;
|
||||||
|
std::cout << " Liquidation price: " << position.liquidation_price() << std::endl;
|
||||||
|
|
||||||
|
// Get position details
|
||||||
|
auto details = dex.perps().get_position(position.position_id());
|
||||||
|
std::cout << "\nPosition details:" << std::endl;
|
||||||
|
std::cout << " Unrealized PnL: " << details.unrealized_pnl() << std::endl;
|
||||||
|
std::cout << " Margin: " << details.margin() << std::endl;
|
||||||
|
std::cout << " Margin ratio: " << details.margin_ratio() << "%" << std::endl;
|
||||||
|
|
||||||
|
// Set stop loss and take profit
|
||||||
|
std::cout << "\nSetting stop loss and take profit..." << std::endl;
|
||||||
|
dex.perps().set_stop_loss(position.position_id(), "1.40");
|
||||||
|
std::cout << "Stop loss set at 1.40" << std::endl;
|
||||||
|
|
||||||
|
dex.perps().set_take_profit(position.position_id(), "1.80");
|
||||||
|
std::cout << "Take profit set at 1.80" << std::endl;
|
||||||
|
|
||||||
|
// Close position
|
||||||
|
std::cout << "\nClosing position..." << std::endl;
|
||||||
|
auto close_result = dex.perps().close_position(position.position_id());
|
||||||
|
std::cout << "Position closed:" << std::endl;
|
||||||
|
std::cout << " Realized PnL: " << close_result.realized_pnl() << std::endl;
|
||||||
|
std::cout << " Close price: " << close_result.close_price() << std::endl;
|
||||||
|
|
||||||
|
// Get all positions
|
||||||
|
auto positions = dex.perps().get_positions();
|
||||||
|
std::cout << "\nOpen positions: " << positions.size() << std::endl;
|
||||||
|
|
||||||
|
// Get funding history
|
||||||
|
auto funding = dex.perps().get_funding_history("SYN-USDC-PERP", 10);
|
||||||
|
std::cout << "Funding payments: " << funding.size() << std::endl;
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void liquidity_example(SynorDex& dex) {
|
||||||
|
std::cout << "=== Liquidity Provision ===" << std::endl;
|
||||||
|
|
||||||
|
// Get available pools
|
||||||
|
auto pools = dex.liquidity().list_pools();
|
||||||
|
std::cout << "Available pools: " << pools.size() << std::endl;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < std::min(pools.size(), size_t(3)); ++i) {
|
||||||
|
const auto& pool = pools[i];
|
||||||
|
std::cout << "\n " << pool.name() << ":" << std::endl;
|
||||||
|
std::cout << " TVL: $" << pool.tvl() << std::endl;
|
||||||
|
std::cout << " APR: " << pool.apr() << "%" << std::endl;
|
||||||
|
std::cout << " Volume 24h: $" << pool.volume_24h() << std::endl;
|
||||||
|
std::cout << " Fee tier: " << pool.fee_tier() << "%" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get pool details
|
||||||
|
auto pool = dex.liquidity().get_pool("SYN-USDC");
|
||||||
|
std::cout << "\nSYN-USDC pool details:" << std::endl;
|
||||||
|
std::cout << " Token0: " << pool.token0().symbol() << " (" << pool.token0_reserve() << ")" << std::endl;
|
||||||
|
std::cout << " Token1: " << pool.token1().symbol() << " (" << pool.token1_reserve() << ")" << std::endl;
|
||||||
|
std::cout << " Price: " << pool.price() << std::endl;
|
||||||
|
std::cout << " Total LP tokens: " << pool.total_lp_tokens() << std::endl;
|
||||||
|
|
||||||
|
// Add liquidity
|
||||||
|
std::cout << "\nAdding liquidity..." << std::endl;
|
||||||
|
auto add_result = dex.liquidity().add_liquidity({
|
||||||
|
.pool = "SYN-USDC",
|
||||||
|
.amount0 = "100",
|
||||||
|
.amount1 = "150",
|
||||||
|
.slippage_bps = 50 // 0.5%
|
||||||
|
});
|
||||||
|
|
||||||
|
std::cout << "Liquidity added:" << std::endl;
|
||||||
|
std::cout << " LP tokens received: " << add_result.lp_tokens() << std::endl;
|
||||||
|
std::cout << " Position ID: " << add_result.position_id() << std::endl;
|
||||||
|
std::cout << " Share of pool: " << add_result.share_of_pool() << "%" << std::endl;
|
||||||
|
|
||||||
|
// Get LP positions
|
||||||
|
auto lp_positions = dex.liquidity().get_positions();
|
||||||
|
std::cout << "\nLP positions: " << lp_positions.size() << std::endl;
|
||||||
|
for (const auto& pos : lp_positions) {
|
||||||
|
std::cout << " " << pos.pool() << ": " << pos.lp_tokens()
|
||||||
|
<< " LP tokens (value: $" << pos.value() << ")" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Claim fees
|
||||||
|
std::cout << "\nClaiming fees..." << std::endl;
|
||||||
|
auto fees = dex.liquidity().claim_fees(add_result.position_id());
|
||||||
|
std::cout << "Fees claimed:" << std::endl;
|
||||||
|
std::cout << " Token0: " << fees.amount0() << std::endl;
|
||||||
|
std::cout << " Token1: " << fees.amount1() << std::endl;
|
||||||
|
|
||||||
|
// Remove liquidity
|
||||||
|
std::cout << "\nRemoving liquidity..." << std::endl;
|
||||||
|
auto remove_result = dex.liquidity().remove_liquidity({
|
||||||
|
.position_id = add_result.position_id(),
|
||||||
|
.lp_tokens = add_result.lp_tokens(),
|
||||||
|
.slippage_bps = 50
|
||||||
|
});
|
||||||
|
|
||||||
|
std::cout << "Liquidity removed:" << std::endl;
|
||||||
|
std::cout << " Token0 received: " << remove_result.amount0() << std::endl;
|
||||||
|
std::cout << " Token1 received: " << remove_result.amount1() << std::endl;
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void orderbook_example(SynorDex& dex) {
|
||||||
|
std::cout << "=== Order Book ===" << std::endl;
|
||||||
|
|
||||||
|
// Get order book snapshot
|
||||||
|
auto orderbook = dex.orderbook().get_snapshot("SYN-USDC", 10);
|
||||||
|
|
||||||
|
std::cout << "Order book for SYN-USDC:" << std::endl;
|
||||||
|
std::cout << "\nAsks (sells):" << std::endl;
|
||||||
|
for (size_t i = 0; i < std::min(orderbook.asks().size(), size_t(5)); ++i) {
|
||||||
|
const auto& ask = orderbook.asks()[i];
|
||||||
|
std::cout << " " << ask.quantity() << " @ " << ask.price() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "\nBids (buys):" << std::endl;
|
||||||
|
for (size_t i = 0; i < std::min(orderbook.bids().size(), size_t(5)); ++i) {
|
||||||
|
const auto& bid = orderbook.bids()[i];
|
||||||
|
std::cout << " " << bid.quantity() << " @ " << bid.price() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << "\nSpread: " << orderbook.spread() << " (" << orderbook.spread_percent() << "%)" << std::endl;
|
||||||
|
std::cout << "Mid price: " << orderbook.mid_price() << std::endl;
|
||||||
|
|
||||||
|
// Get recent trades
|
||||||
|
auto recent_trades = dex.orderbook().get_recent_trades("SYN-USDC", 10);
|
||||||
|
std::cout << "\nRecent trades:" << std::endl;
|
||||||
|
for (size_t i = 0; i < std::min(recent_trades.size(), size_t(5)); ++i) {
|
||||||
|
const auto& trade = recent_trades[i];
|
||||||
|
std::cout << " " << trade.side() << " " << trade.quantity() << " @ " << trade.price() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void portfolio_example(SynorDex& dex) {
|
||||||
|
std::cout << "=== Portfolio ===" << std::endl;
|
||||||
|
|
||||||
|
// Get portfolio overview
|
||||||
|
auto portfolio = dex.portfolio().get_overview();
|
||||||
|
|
||||||
|
std::cout << "Portfolio overview:" << std::endl;
|
||||||
|
std::cout << " Total value: $" << portfolio.total_value() << std::endl;
|
||||||
|
std::cout << " Available balance: $" << portfolio.available_balance() << std::endl;
|
||||||
|
std::cout << " In orders: $" << portfolio.in_orders() << std::endl;
|
||||||
|
std::cout << " In positions: $" << portfolio.in_positions() << std::endl;
|
||||||
|
std::cout << " Unrealized PnL: $" << portfolio.unrealized_pnl() << std::endl;
|
||||||
|
|
||||||
|
// Get balances
|
||||||
|
auto balances = dex.portfolio().get_balances();
|
||||||
|
std::cout << "\nBalances:" << std::endl;
|
||||||
|
for (const auto& balance : balances) {
|
||||||
|
std::cout << " " << balance.asset() << ": " << balance.total()
|
||||||
|
<< " (available: " << balance.available()
|
||||||
|
<< ", in orders: " << balance.in_orders() << ")" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get PnL history
|
||||||
|
auto pnl_history = dex.portfolio().get_pnl_history(30);
|
||||||
|
std::cout << "\nPnL history (last " << pnl_history.size() << " days):" << std::endl;
|
||||||
|
if (!pnl_history.empty()) {
|
||||||
|
std::cout << " Total PnL: $" << pnl_history.back().cumulative_pnl() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get trade statistics
|
||||||
|
auto stats = dex.portfolio().get_stats();
|
||||||
|
std::cout << "\nTrade statistics:" << std::endl;
|
||||||
|
std::cout << " Total trades: " << stats.total_trades() << std::endl;
|
||||||
|
std::cout << " Win rate: " << stats.win_rate() << "%" << std::endl;
|
||||||
|
std::cout << " Avg profit: $" << stats.avg_profit() << std::endl;
|
||||||
|
std::cout << " Avg loss: $" << stats.avg_loss() << std::endl;
|
||||||
|
std::cout << " Best trade: $" << stats.best_trade() << std::endl;
|
||||||
|
std::cout << " Worst trade: $" << stats.worst_trade() << std::endl;
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
// Initialize client
|
||||||
|
const char* api_key = std::getenv("SYNOR_API_KEY");
|
||||||
|
DexConfig config{
|
||||||
|
.api_key = api_key ? api_key : "your-api-key",
|
||||||
|
.endpoint = "https://dex.synor.io/v1",
|
||||||
|
.timeout = std::chrono::seconds(30),
|
||||||
|
.retries = 3,
|
||||||
|
.debug = false,
|
||||||
|
.default_market = "SYN-USDC"
|
||||||
|
};
|
||||||
|
|
||||||
|
SynorDex dex(config);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check service health
|
||||||
|
bool healthy = dex.health_check();
|
||||||
|
std::cout << "Service healthy: " << (healthy ? "true" : "false") << std::endl << std::endl;
|
||||||
|
|
||||||
|
// Run examples
|
||||||
|
markets_example(dex);
|
||||||
|
spot_trading_example(dex);
|
||||||
|
perps_trading_example(dex);
|
||||||
|
liquidity_example(dex);
|
||||||
|
orderbook_example(dex);
|
||||||
|
portfolio_example(dex);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
std::cerr << "Error: " << e.what() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
389
sdk/cpp/examples/ibc_example.cpp
Normal file
389
sdk/cpp/examples/ibc_example.cpp
Normal file
|
|
@ -0,0 +1,389 @@
|
||||||
|
/**
|
||||||
|
* Synor IBC SDK Examples for C++
|
||||||
|
*
|
||||||
|
* Demonstrates Inter-Blockchain Communication operations:
|
||||||
|
* - Cross-chain transfers and messages
|
||||||
|
* - Channel lifecycle management
|
||||||
|
* - Packet handling and acknowledgments
|
||||||
|
* - Relayer operations
|
||||||
|
* - Connection monitoring
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <chrono>
|
||||||
|
#include <synor/ibc.hpp>
|
||||||
|
|
||||||
|
using namespace synor::ibc;
|
||||||
|
|
||||||
|
void chains_example(SynorIbc& ibc) {
|
||||||
|
std::cout << "=== Chain Discovery ===" << std::endl;
|
||||||
|
|
||||||
|
// Get all connected chains
|
||||||
|
auto chains = ibc.chains().list();
|
||||||
|
std::cout << "Connected chains: " << chains.size() << std::endl;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < std::min(chains.size(), size_t(5)); ++i) {
|
||||||
|
const auto& chain = chains[i];
|
||||||
|
std::cout << "\n " << chain.chain_id() << ":" << std::endl;
|
||||||
|
std::cout << " Name: " << chain.name() << std::endl;
|
||||||
|
std::cout << " Type: " << chain.chain_type() << std::endl;
|
||||||
|
std::cout << " Status: " << chain.status() << std::endl;
|
||||||
|
std::cout << " Block height: " << chain.latest_height() << std::endl;
|
||||||
|
std::cout << " Light client: " << chain.light_client() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get specific chain info
|
||||||
|
auto synor_chain = ibc.chains().get("synor-mainnet-1");
|
||||||
|
std::cout << "\nSynor chain details:" << std::endl;
|
||||||
|
std::cout << " Bech32 prefix: " << synor_chain.bech32_prefix() << std::endl;
|
||||||
|
std::cout << " Gas price: " << synor_chain.gas_price() << std::endl;
|
||||||
|
|
||||||
|
auto features = synor_chain.features();
|
||||||
|
std::cout << " Supported features: ";
|
||||||
|
for (size_t i = 0; i < features.size(); ++i) {
|
||||||
|
std::cout << features[i] << (i < features.size() - 1 ? ", " : "");
|
||||||
|
}
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
// Get chain connections
|
||||||
|
auto connections = ibc.chains().get_connections("synor-mainnet-1");
|
||||||
|
std::cout << "\nChain connections: " << connections.size() << std::endl;
|
||||||
|
for (size_t i = 0; i < std::min(connections.size(), size_t(3)); ++i) {
|
||||||
|
const auto& conn = connections[i];
|
||||||
|
std::cout << " " << conn.connection_id() << " -> " << conn.counterparty_chain_id() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void channels_example(SynorIbc& ibc) {
|
||||||
|
std::cout << "=== Channel Management ===" << std::endl;
|
||||||
|
|
||||||
|
// List existing channels
|
||||||
|
auto channels = ibc.channels().list();
|
||||||
|
std::cout << "Active channels: " << channels.size() << std::endl;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < std::min(channels.size(), size_t(3)); ++i) {
|
||||||
|
const auto& channel = channels[i];
|
||||||
|
std::cout << "\n Channel " << channel.channel_id() << ":" << std::endl;
|
||||||
|
std::cout << " Port: " << channel.port_id() << std::endl;
|
||||||
|
std::cout << " State: " << channel.state() << std::endl;
|
||||||
|
std::cout << " Order: " << channel.ordering() << std::endl;
|
||||||
|
std::cout << " Counterparty: " << channel.counterparty_channel_id()
|
||||||
|
<< " on " << channel.counterparty_chain_id() << std::endl;
|
||||||
|
std::cout << " Version: " << channel.version() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new channel (4-step handshake)
|
||||||
|
std::cout << "\nInitiating channel creation..." << std::endl;
|
||||||
|
|
||||||
|
// Step 1: ChanOpenInit
|
||||||
|
auto init_result = ibc.channels().open_init({
|
||||||
|
.port_id = "transfer",
|
||||||
|
.counterparty_chain_id = "cosmos-hub-4",
|
||||||
|
.counterparty_port_id = "transfer",
|
||||||
|
.version = "ics20-1",
|
||||||
|
.ordering = ChannelOrdering::Unordered
|
||||||
|
});
|
||||||
|
|
||||||
|
std::cout << "Channel init:" << std::endl;
|
||||||
|
std::cout << " Channel ID: " << init_result.channel_id() << std::endl;
|
||||||
|
std::cout << " State: " << init_result.state() << std::endl;
|
||||||
|
std::cout << " TX hash: " << init_result.tx_hash() << std::endl;
|
||||||
|
|
||||||
|
// Step 2: Wait for ChanOpenTry (counterparty)
|
||||||
|
std::cout << "\nWaiting for counterparty ChanOpenTry..." << std::endl;
|
||||||
|
auto try_state = ibc.channels().wait_for_state(
|
||||||
|
init_result.channel_id(),
|
||||||
|
ChannelState::TryOpen,
|
||||||
|
std::chrono::minutes(5)
|
||||||
|
);
|
||||||
|
std::cout << "Channel state: " << try_state << std::endl;
|
||||||
|
|
||||||
|
// Step 3: ChanOpenAck
|
||||||
|
std::cout << "\nSending ChanOpenAck..." << std::endl;
|
||||||
|
auto ack_result = ibc.channels().open_ack({
|
||||||
|
.channel_id = init_result.channel_id(),
|
||||||
|
.counterparty_channel_id = "channel-0",
|
||||||
|
.counterparty_version = "ics20-1"
|
||||||
|
});
|
||||||
|
std::cout << "Ack TX: " << ack_result.tx_hash() << std::endl;
|
||||||
|
|
||||||
|
// Step 4: Wait for ChanOpenConfirm (counterparty)
|
||||||
|
std::cout << "\nWaiting for channel to open..." << std::endl;
|
||||||
|
auto open_state = ibc.channels().wait_for_state(
|
||||||
|
init_result.channel_id(),
|
||||||
|
ChannelState::Open,
|
||||||
|
std::chrono::minutes(5)
|
||||||
|
);
|
||||||
|
std::cout << "Channel is now: " << open_state << std::endl;
|
||||||
|
|
||||||
|
// Get channel details
|
||||||
|
auto channel = ibc.channels().get(init_result.channel_id());
|
||||||
|
std::cout << "\nChannel details:" << std::endl;
|
||||||
|
std::cout << " Sequences - Send: " << channel.next_sequence_send()
|
||||||
|
<< ", Recv: " << channel.next_sequence_recv()
|
||||||
|
<< ", Ack: " << channel.next_sequence_ack() << std::endl;
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void transfer_example(SynorIbc& ibc) {
|
||||||
|
std::cout << "=== Cross-Chain Transfers ===" << std::endl;
|
||||||
|
|
||||||
|
// Get supported tokens for transfer
|
||||||
|
auto tokens = ibc.transfers().get_supported_tokens("cosmos-hub-4");
|
||||||
|
std::cout << "Transferable tokens to Cosmos Hub:" << std::endl;
|
||||||
|
for (size_t i = 0; i < std::min(tokens.size(), size_t(5)); ++i) {
|
||||||
|
const auto& token = tokens[i];
|
||||||
|
std::cout << " " << token.symbol() << " (" << token.denom() << ")" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initiate a cross-chain transfer
|
||||||
|
std::cout << "\nInitiating transfer..." << std::endl;
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
auto timeout = std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||||
|
(now + std::chrono::seconds(600)).time_since_epoch()
|
||||||
|
).count();
|
||||||
|
|
||||||
|
auto transfer = ibc.transfers().send({
|
||||||
|
.source_channel = "channel-0",
|
||||||
|
.denom = "usynor",
|
||||||
|
.amount = "1000000",
|
||||||
|
.receiver = "cosmos1...",
|
||||||
|
.timeout_height = 0, // Use timestamp instead
|
||||||
|
.timeout_timestamp = static_cast<uint64_t>(timeout),
|
||||||
|
.memo = "IBC transfer from Synor"
|
||||||
|
});
|
||||||
|
|
||||||
|
std::cout << "Transfer initiated:" << std::endl;
|
||||||
|
std::cout << " TX hash: " << transfer.tx_hash() << std::endl;
|
||||||
|
std::cout << " Sequence: " << transfer.sequence() << std::endl;
|
||||||
|
std::cout << " Packet ID: " << transfer.packet_id() << std::endl;
|
||||||
|
std::cout << " Status: " << transfer.status() << std::endl;
|
||||||
|
|
||||||
|
// Track transfer progress
|
||||||
|
std::cout << "\nTracking transfer..." << std::endl;
|
||||||
|
auto status = ibc.transfers().track(transfer.packet_id());
|
||||||
|
std::cout << "Current status: " << status.state() << std::endl;
|
||||||
|
std::cout << "Source TX: " << status.source_tx_hash() << std::endl;
|
||||||
|
if (!status.dest_tx_hash().empty()) {
|
||||||
|
std::cout << "Dest TX: " << status.dest_tx_hash() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for completion
|
||||||
|
std::cout << "\nWaiting for transfer completion..." << std::endl;
|
||||||
|
auto final_status = ibc.transfers().wait_for_completion(
|
||||||
|
transfer.packet_id(),
|
||||||
|
std::chrono::minutes(10)
|
||||||
|
);
|
||||||
|
|
||||||
|
std::cout << "Transfer completed:" << std::endl;
|
||||||
|
std::cout << " Final status: " << final_status.state() << std::endl;
|
||||||
|
std::cout << " Acknowledgment: " << final_status.acknowledgment() << std::endl;
|
||||||
|
|
||||||
|
// Get transfer history
|
||||||
|
auto history = ibc.transfers().get_history(10);
|
||||||
|
std::cout << "\nRecent transfers: " << history.size() << std::endl;
|
||||||
|
for (size_t i = 0; i < std::min(history.size(), size_t(3)); ++i) {
|
||||||
|
const auto& t = history[i];
|
||||||
|
std::cout << " " << t.amount() << " " << t.denom()
|
||||||
|
<< " -> " << t.dest_chain() << " (" << t.status() << ")" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void packet_example(SynorIbc& ibc) {
|
||||||
|
std::cout << "=== Packet Operations ===" << std::endl;
|
||||||
|
|
||||||
|
// List pending packets
|
||||||
|
auto pending = ibc.packets().list_pending("channel-0");
|
||||||
|
std::cout << "Pending packets on channel-0: " << pending.size() << std::endl;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < std::min(pending.size(), size_t(3)); ++i) {
|
||||||
|
const auto& packet = pending[i];
|
||||||
|
std::cout << "\n Packet #" << packet.sequence() << ":" << std::endl;
|
||||||
|
std::cout << " Source: " << packet.source_port() << "/" << packet.source_channel() << std::endl;
|
||||||
|
std::cout << " Dest: " << packet.dest_port() << "/" << packet.dest_channel() << std::endl;
|
||||||
|
std::cout << " State: " << packet.state() << std::endl;
|
||||||
|
std::cout << " Timeout: " << packet.timeout_timestamp() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get specific packet
|
||||||
|
auto packet = ibc.packets().get("channel-0", 1);
|
||||||
|
std::cout << "\nPacket details:" << std::endl;
|
||||||
|
std::cout << " Data (hex): " << packet.data_hex().substr(0, 40) << "..." << std::endl;
|
||||||
|
std::cout << " Created: " << packet.created_at() << std::endl;
|
||||||
|
|
||||||
|
// Get packet commitment proof
|
||||||
|
auto proof = ibc.packets().get_commitment_proof("channel-0", 1);
|
||||||
|
std::cout << "\nCommitment proof:" << std::endl;
|
||||||
|
std::cout << " Height: " << proof.proof_height() << std::endl;
|
||||||
|
std::cout << " Proof size: " << proof.proof().size() << " bytes" << std::endl;
|
||||||
|
|
||||||
|
// Get acknowledgment
|
||||||
|
auto ack = ibc.packets().get_acknowledgment("channel-0", 1);
|
||||||
|
std::cout << "\nAcknowledgment:" << std::endl;
|
||||||
|
std::cout << " Result: " << (ack.success() ? "Success" : std::string("Error: ") + ack.error()) << std::endl;
|
||||||
|
std::cout << " TX hash: " << ack.tx_hash() << std::endl;
|
||||||
|
|
||||||
|
// List timed-out packets
|
||||||
|
auto timed_out = ibc.packets().list_timed_out();
|
||||||
|
std::cout << "\nTimed-out packets: " << timed_out.size() << std::endl;
|
||||||
|
|
||||||
|
// Timeout a packet manually
|
||||||
|
if (!timed_out.empty()) {
|
||||||
|
const auto& to_timeout = timed_out.front();
|
||||||
|
std::cout << "\nProcessing timeout for packet #" << to_timeout.sequence() << std::endl;
|
||||||
|
auto timeout = ibc.packets().timeout(to_timeout.source_channel(), to_timeout.sequence());
|
||||||
|
std::cout << "Timeout TX: " << timeout.tx_hash() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void relayer_example(SynorIbc& ibc) {
|
||||||
|
std::cout << "=== Relayer Operations ===" << std::endl;
|
||||||
|
|
||||||
|
// Get relayer status
|
||||||
|
auto status = ibc.relayer().get_status();
|
||||||
|
std::cout << "Relayer status:" << std::endl;
|
||||||
|
std::cout << " Running: " << (status.running() ? "true" : "false") << std::endl;
|
||||||
|
std::cout << " Uptime: " << status.uptime() << std::endl;
|
||||||
|
std::cout << " Packets relayed: " << status.packets_relayed() << std::endl;
|
||||||
|
std::cout << " Errors: " << status.error_count() << std::endl;
|
||||||
|
|
||||||
|
// List active paths
|
||||||
|
auto paths = ibc.relayer().list_paths();
|
||||||
|
std::cout << "\nActive relay paths: " << paths.size() << std::endl;
|
||||||
|
|
||||||
|
for (const auto& path : paths) {
|
||||||
|
std::cout << "\n " << path.path_id() << ":" << std::endl;
|
||||||
|
std::cout << " " << path.source_chain() << " <-> " << path.dest_chain() << std::endl;
|
||||||
|
std::cout << " Channel: " << path.source_channel() << " <-> " << path.dest_channel() << std::endl;
|
||||||
|
std::cout << " Status: " << path.status() << std::endl;
|
||||||
|
std::cout << " Pending packets: " << path.pending_packets() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure a new path
|
||||||
|
std::cout << "\nConfiguring new relay path..." << std::endl;
|
||||||
|
auto new_path = ibc.relayer().add_path({
|
||||||
|
.source_chain = "synor-mainnet-1",
|
||||||
|
.dest_chain = "osmosis-1",
|
||||||
|
.source_channel = "channel-1",
|
||||||
|
.dest_channel = "channel-100",
|
||||||
|
.filter_denoms = {"usynor", "uosmo"},
|
||||||
|
.min_relay_amount = "1000",
|
||||||
|
.max_relay_amount = "1000000000"
|
||||||
|
});
|
||||||
|
|
||||||
|
std::cout << "Path created: " << new_path.path_id() << std::endl;
|
||||||
|
|
||||||
|
// Start relaying on path
|
||||||
|
std::cout << "\nStarting relayer on path..." << std::endl;
|
||||||
|
ibc.relayer().start_path(new_path.path_id());
|
||||||
|
std::cout << "Relayer started" << std::endl;
|
||||||
|
|
||||||
|
// Manually relay pending packets
|
||||||
|
std::cout << "\nRelaying pending packets..." << std::endl;
|
||||||
|
auto relay_result = ibc.relayer().relay_pending(new_path.path_id());
|
||||||
|
std::cout << "Relayed " << relay_result.packet_count() << " packets" << std::endl;
|
||||||
|
std::cout << "TX hashes: " << relay_result.tx_hashes().size() << std::endl;
|
||||||
|
|
||||||
|
// Get relay history
|
||||||
|
auto history = ibc.relayer().get_history(new_path.path_id(), 10);
|
||||||
|
std::cout << "\nRelay history:" << std::endl;
|
||||||
|
for (size_t i = 0; i < std::min(history.size(), size_t(3)); ++i) {
|
||||||
|
const auto& event = history[i];
|
||||||
|
std::cout << " " << event.timestamp() << ": " << event.event_type()
|
||||||
|
<< " - " << event.packet_count() << " packets" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void monitoring_example(SynorIbc& ibc) {
|
||||||
|
std::cout << "=== IBC Monitoring ===" << std::endl;
|
||||||
|
|
||||||
|
// Get IBC metrics
|
||||||
|
auto metrics = ibc.monitoring().get_metrics();
|
||||||
|
std::cout << "IBC metrics:" << std::endl;
|
||||||
|
std::cout << " Total channels: " << metrics.total_channels() << std::endl;
|
||||||
|
std::cout << " Active channels: " << metrics.active_channels() << std::endl;
|
||||||
|
std::cout << " Total packets: " << metrics.total_packets() << std::endl;
|
||||||
|
std::cout << " Pending packets: " << metrics.pending_packets() << std::endl;
|
||||||
|
std::cout << " Failed packets: " << metrics.failed_packets() << std::endl;
|
||||||
|
std::cout << " Avg relay time: " << metrics.avg_relay_time() << "ms" << std::endl;
|
||||||
|
|
||||||
|
// Get chain health
|
||||||
|
auto chain_health = ibc.monitoring().get_chain_health();
|
||||||
|
std::cout << "\nChain health:" << std::endl;
|
||||||
|
for (size_t i = 0; i < std::min(chain_health.size(), size_t(3)); ++i) {
|
||||||
|
const auto& health = chain_health[i];
|
||||||
|
std::cout << " " << health.chain_id() << ":" << std::endl;
|
||||||
|
std::cout << " Status: " << health.status() << std::endl;
|
||||||
|
std::cout << " Block lag: " << health.block_lag() << std::endl;
|
||||||
|
std::cout << " Last update: " << health.last_update() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get channel statistics
|
||||||
|
auto stats = ibc.monitoring().get_channel_stats("channel-0");
|
||||||
|
std::cout << "\nChannel-0 statistics:" << std::endl;
|
||||||
|
std::cout << " Packets sent: " << stats.packets_sent() << std::endl;
|
||||||
|
std::cout << " Packets received: " << stats.packets_received() << std::endl;
|
||||||
|
std::cout << " Success rate: " << stats.success_rate() << "%" << std::endl;
|
||||||
|
std::cout << " Avg confirmation time: " << stats.avg_confirmation_time() << "ms" << std::endl;
|
||||||
|
|
||||||
|
// Subscribe to IBC events
|
||||||
|
std::cout << "\nSubscribing to IBC events..." << std::endl;
|
||||||
|
ibc.monitoring().subscribe([](const IbcEvent& event) {
|
||||||
|
std::cout << "Event: " << event.type() << " on " << event.channel_id() << std::endl;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Get alerts
|
||||||
|
auto alerts = ibc.monitoring().get_alerts();
|
||||||
|
std::cout << "\nActive alerts: " << alerts.size() << std::endl;
|
||||||
|
for (const auto& alert : alerts) {
|
||||||
|
std::cout << " [" << alert.severity() << "] " << alert.message() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
// Initialize client
|
||||||
|
const char* api_key = std::getenv("SYNOR_API_KEY");
|
||||||
|
IbcConfig config{
|
||||||
|
.api_key = api_key ? api_key : "your-api-key",
|
||||||
|
.endpoint = "https://ibc.synor.io/v1",
|
||||||
|
.timeout = std::chrono::seconds(30),
|
||||||
|
.retries = 3,
|
||||||
|
.debug = false,
|
||||||
|
.default_chain = "synor-mainnet-1",
|
||||||
|
.confirmations = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
SynorIbc ibc(config);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check service health
|
||||||
|
bool healthy = ibc.health_check();
|
||||||
|
std::cout << "Service healthy: " << (healthy ? "true" : "false") << std::endl << std::endl;
|
||||||
|
|
||||||
|
// Run examples
|
||||||
|
chains_example(ibc);
|
||||||
|
channels_example(ibc);
|
||||||
|
transfer_example(ibc);
|
||||||
|
packet_example(ibc);
|
||||||
|
relayer_example(ibc);
|
||||||
|
monitoring_example(ibc);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
std::cerr << "Error: " << e.what() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
359
sdk/cpp/examples/zk_example.cpp
Normal file
359
sdk/cpp/examples/zk_example.cpp
Normal file
|
|
@ -0,0 +1,359 @@
|
||||||
|
/**
|
||||||
|
* Synor ZK SDK Examples for C++
|
||||||
|
*
|
||||||
|
* Demonstrates zero-knowledge proof operations:
|
||||||
|
* - Circuit compilation (Circom)
|
||||||
|
* - Proof generation and verification
|
||||||
|
* - Multiple proving systems (Groth16, PLONK, STARK)
|
||||||
|
* - Recursive proof composition
|
||||||
|
* - Trusted setup ceremonies
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <random>
|
||||||
|
#include <synor/zk.hpp>
|
||||||
|
|
||||||
|
using namespace synor::zk;
|
||||||
|
|
||||||
|
void circuit_example(SynorZk& zk) {
|
||||||
|
std::cout << "=== Circuit Compilation ===" << std::endl;
|
||||||
|
|
||||||
|
// Simple Circom circuit: prove knowledge of factors
|
||||||
|
std::string circom_code = R"(
|
||||||
|
pragma circom 2.1.0;
|
||||||
|
|
||||||
|
template Multiplier() {
|
||||||
|
signal input a;
|
||||||
|
signal input b;
|
||||||
|
signal output c;
|
||||||
|
|
||||||
|
c <== a * b;
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Multiplier();
|
||||||
|
)";
|
||||||
|
|
||||||
|
// Compile the circuit
|
||||||
|
std::cout << "Compiling circuit..." << std::endl;
|
||||||
|
auto circuit = zk.circuits().compile({
|
||||||
|
.code = circom_code,
|
||||||
|
.language = CircuitLanguage::Circom
|
||||||
|
});
|
||||||
|
|
||||||
|
std::cout << "Circuit compiled:" << std::endl;
|
||||||
|
std::cout << " Circuit ID: " << circuit.circuit_id() << std::endl;
|
||||||
|
std::cout << " Constraints: " << circuit.constraints() << std::endl;
|
||||||
|
std::cout << " Public inputs: " << circuit.public_inputs() << std::endl;
|
||||||
|
std::cout << " Private inputs: " << circuit.private_inputs() << std::endl;
|
||||||
|
std::cout << " Outputs: " << circuit.outputs() << std::endl;
|
||||||
|
|
||||||
|
// Get circuit info
|
||||||
|
auto info = zk.circuits().get(circuit.circuit_id());
|
||||||
|
std::cout << "\nCircuit info:" << std::endl;
|
||||||
|
std::cout << " Name: " << info.name() << std::endl;
|
||||||
|
std::cout << " Version: " << info.version() << std::endl;
|
||||||
|
std::cout << " Wires: " << info.wire_count() << std::endl;
|
||||||
|
std::cout << " Labels: " << info.label_count() << std::endl;
|
||||||
|
|
||||||
|
// List available circuits
|
||||||
|
auto circuits = zk.circuits().list();
|
||||||
|
std::cout << "\nAvailable circuits: " << circuits.size() << std::endl;
|
||||||
|
for (size_t i = 0; i < std::min(circuits.size(), size_t(3)); ++i) {
|
||||||
|
const auto& c = circuits[i];
|
||||||
|
std::cout << " " << c.circuit_id() << ": " << c.name()
|
||||||
|
<< " (" << c.constraints() << " constraints)" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void groth16_example(SynorZk& zk) {
|
||||||
|
std::cout << "=== Groth16 Proving System ===" << std::endl;
|
||||||
|
|
||||||
|
std::string circuit_id = "multiplier-v1";
|
||||||
|
|
||||||
|
// Generate proving/verification keys (trusted setup)
|
||||||
|
std::cout << "Generating keys..." << std::endl;
|
||||||
|
auto keys = zk.groth16().setup(circuit_id);
|
||||||
|
std::cout << "Keys generated:" << std::endl;
|
||||||
|
std::cout << " Proving key size: " << keys.proving_key().size() << " bytes" << std::endl;
|
||||||
|
std::cout << " Verification key size: " << keys.verification_key().size() << " bytes" << std::endl;
|
||||||
|
|
||||||
|
// Prepare witness (private inputs)
|
||||||
|
std::map<std::string, std::string> witness = {
|
||||||
|
{"a", "3"},
|
||||||
|
{"b", "7"}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate proof
|
||||||
|
std::cout << "\nGenerating proof..." << std::endl;
|
||||||
|
auto proof = zk.groth16().prove({
|
||||||
|
.circuit_id = circuit_id,
|
||||||
|
.witness = witness,
|
||||||
|
.proving_key = keys.proving_key()
|
||||||
|
});
|
||||||
|
|
||||||
|
std::cout << "Proof generated:" << std::endl;
|
||||||
|
std::cout << " Proof size: " << proof.proof_bytes().size() << " bytes" << std::endl;
|
||||||
|
std::cout << " Public signals: " << proof.public_signals().size() << std::endl;
|
||||||
|
std::cout << " Proving time: " << proof.proving_time_ms() << "ms" << std::endl;
|
||||||
|
|
||||||
|
// Verify proof
|
||||||
|
std::cout << "\nVerifying proof..." << std::endl;
|
||||||
|
bool verified = zk.groth16().verify({
|
||||||
|
.proof = proof.proof_bytes(),
|
||||||
|
.public_signals = proof.public_signals(),
|
||||||
|
.verification_key = keys.verification_key()
|
||||||
|
});
|
||||||
|
|
||||||
|
std::cout << "Verification result: " << (verified ? "true" : "false") << std::endl;
|
||||||
|
|
||||||
|
// Export proof for on-chain verification
|
||||||
|
auto solidity_calldata = zk.groth16().export_calldata(proof);
|
||||||
|
std::cout << "\nSolidity calldata: " << solidity_calldata.substr(0, 100) << "..." << std::endl;
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void plonk_example(SynorZk& zk) {
|
||||||
|
std::cout << "=== PLONK Proving System ===" << std::endl;
|
||||||
|
|
||||||
|
std::string circuit_id = "multiplier-v1";
|
||||||
|
|
||||||
|
// PLONK uses universal trusted setup
|
||||||
|
std::cout << "Getting universal setup..." << std::endl;
|
||||||
|
auto srs = zk.plonk().get_universal_setup(14); // 2^14 constraints
|
||||||
|
std::cout << "SRS loaded: " << srs.size() << " bytes" << std::endl;
|
||||||
|
|
||||||
|
// Generate circuit-specific keys
|
||||||
|
std::cout << "\nGenerating circuit keys..." << std::endl;
|
||||||
|
auto keys = zk.plonk().setup(circuit_id, srs);
|
||||||
|
std::cout << "Keys generated" << std::endl;
|
||||||
|
|
||||||
|
// Generate proof
|
||||||
|
std::map<std::string, std::string> witness = {{"a", "5"}, {"b", "9"}};
|
||||||
|
std::cout << "\nGenerating PLONK proof..." << std::endl;
|
||||||
|
auto proof = zk.plonk().prove({
|
||||||
|
.circuit_id = circuit_id,
|
||||||
|
.witness = witness,
|
||||||
|
.proving_key = keys.proving_key()
|
||||||
|
});
|
||||||
|
|
||||||
|
std::cout << "Proof generated:" << std::endl;
|
||||||
|
std::cout << " Proof size: " << proof.proof_bytes().size() << " bytes" << std::endl;
|
||||||
|
std::cout << " Proving time: " << proof.proving_time_ms() << "ms" << std::endl;
|
||||||
|
|
||||||
|
// Verify proof
|
||||||
|
bool verified = zk.plonk().verify({
|
||||||
|
.proof = proof.proof_bytes(),
|
||||||
|
.public_signals = proof.public_signals(),
|
||||||
|
.verification_key = keys.verification_key()
|
||||||
|
});
|
||||||
|
std::cout << "Verification result: " << (verified ? "true" : "false") << std::endl;
|
||||||
|
|
||||||
|
// Compare with Groth16
|
||||||
|
std::cout << "\nPLONK advantages:" << std::endl;
|
||||||
|
std::cout << " - Universal trusted setup" << std::endl;
|
||||||
|
std::cout << " - Larger proofs (~2.5 KB vs ~200 bytes)" << std::endl;
|
||||||
|
std::cout << " - Faster proving for some circuits" << std::endl;
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stark_example(SynorZk& zk) {
|
||||||
|
std::cout << "=== STARK Proving System ===" << std::endl;
|
||||||
|
|
||||||
|
std::string circuit_id = "multiplier-v1";
|
||||||
|
|
||||||
|
// STARKs don't need trusted setup
|
||||||
|
std::cout << "Configuring STARK parameters..." << std::endl;
|
||||||
|
StarkConfig config{
|
||||||
|
.field_size = 256,
|
||||||
|
.hash_function = HashFunction::Poseidon,
|
||||||
|
.blowup_factor = 8,
|
||||||
|
.num_queries = 30,
|
||||||
|
.folding_factor = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate proof
|
||||||
|
std::map<std::string, std::string> witness = {{"a", "11"}, {"b", "13"}};
|
||||||
|
std::cout << "\nGenerating STARK proof..." << std::endl;
|
||||||
|
auto proof = zk.stark().prove({
|
||||||
|
.circuit_id = circuit_id,
|
||||||
|
.witness = witness,
|
||||||
|
.config = config
|
||||||
|
});
|
||||||
|
|
||||||
|
std::cout << "Proof generated:" << std::endl;
|
||||||
|
std::cout << " Proof size: " << proof.proof_bytes().size() << " bytes" << std::endl;
|
||||||
|
std::cout << " Proving time: " << proof.proving_time_ms() << "ms" << std::endl;
|
||||||
|
std::cout << " FRI layers: " << proof.fri_layers() << std::endl;
|
||||||
|
|
||||||
|
// Verify proof
|
||||||
|
std::cout << "\nVerifying STARK proof..." << std::endl;
|
||||||
|
bool verified = zk.stark().verify({
|
||||||
|
.proof = proof.proof_bytes(),
|
||||||
|
.public_signals = proof.public_signals(),
|
||||||
|
.config = config
|
||||||
|
});
|
||||||
|
|
||||||
|
std::cout << "Verification result: " << (verified ? "true" : "false") << std::endl;
|
||||||
|
|
||||||
|
// Compare with SNARKs
|
||||||
|
std::cout << "\nSTARK advantages:" << std::endl;
|
||||||
|
std::cout << " - No trusted setup needed" << std::endl;
|
||||||
|
std::cout << " - Post-quantum secure" << std::endl;
|
||||||
|
std::cout << " - Larger proofs (~100 KB)" << std::endl;
|
||||||
|
std::cout << " - Faster proving for complex computations" << std::endl;
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void recursive_example(SynorZk& zk) {
|
||||||
|
std::cout << "=== Recursive Proof Composition ===" << std::endl;
|
||||||
|
|
||||||
|
// Create inner proofs
|
||||||
|
std::cout << "Generating inner proofs..." << std::endl;
|
||||||
|
std::vector<RecursiveProof> inner_proofs;
|
||||||
|
|
||||||
|
for (int i = 1; i <= 3; ++i) {
|
||||||
|
std::map<std::string, std::string> witness = {
|
||||||
|
{"a", std::to_string(i)},
|
||||||
|
{"b", std::to_string(i + 1)}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto proof = zk.recursive().prove_inner({
|
||||||
|
.circuit_id = "multiplier-v1",
|
||||||
|
.witness = witness,
|
||||||
|
.level = 0
|
||||||
|
});
|
||||||
|
inner_proofs.push_back(proof);
|
||||||
|
std::cout << " Inner proof " << i << " generated" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aggregate proofs recursively
|
||||||
|
std::cout << "\nAggregating proofs..." << std::endl;
|
||||||
|
auto aggregated_proof = zk.recursive().aggregate({
|
||||||
|
.proofs = inner_proofs,
|
||||||
|
.aggregation_circuit = "recursive-aggregator-v1"
|
||||||
|
});
|
||||||
|
|
||||||
|
std::cout << "Aggregated proof:" << std::endl;
|
||||||
|
std::cout << " Proof size: " << aggregated_proof.proof_bytes().size() << " bytes" << std::endl;
|
||||||
|
std::cout << " Proofs aggregated: " << aggregated_proof.proofs_aggregated() << std::endl;
|
||||||
|
std::cout << " Recursion depth: " << aggregated_proof.recursion_depth() << std::endl;
|
||||||
|
|
||||||
|
// Verify aggregated proof (verifies all inner proofs at once)
|
||||||
|
std::cout << "\nVerifying aggregated proof..." << std::endl;
|
||||||
|
bool verified = zk.recursive().verify_aggregated(aggregated_proof);
|
||||||
|
std::cout << "Verification result: " << (verified ? "true" : "false") << std::endl;
|
||||||
|
|
||||||
|
// Use cases
|
||||||
|
std::cout << "\nRecursive proof use cases:" << std::endl;
|
||||||
|
std::cout << " - Rollup batch verification" << std::endl;
|
||||||
|
std::cout << " - Incremental computation proofs" << std::endl;
|
||||||
|
std::cout << " - Cross-chain state proofs" << std::endl;
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ceremony_example(SynorZk& zk) {
|
||||||
|
std::cout << "=== Trusted Setup Ceremony ===" << std::endl;
|
||||||
|
|
||||||
|
// List active ceremonies
|
||||||
|
auto ceremonies = zk.ceremony().list(CeremonyStatus::Active);
|
||||||
|
std::cout << "Active ceremonies: " << ceremonies.size() << std::endl;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < std::min(ceremonies.size(), size_t(3)); ++i) {
|
||||||
|
const auto& ceremony = ceremonies[i];
|
||||||
|
std::cout << "\n " << ceremony.ceremony_id() << ":" << std::endl;
|
||||||
|
std::cout << " Circuit: " << ceremony.circuit_id() << std::endl;
|
||||||
|
std::cout << " Participants: " << ceremony.participant_count() << std::endl;
|
||||||
|
std::cout << " Current round: " << ceremony.current_round() << std::endl;
|
||||||
|
std::cout << " Status: " << ceremony.status() << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new ceremony
|
||||||
|
std::cout << "\nCreating new ceremony..." << std::endl;
|
||||||
|
auto new_ceremony = zk.ceremony().create({
|
||||||
|
.circuit_id = "new-circuit-v1",
|
||||||
|
.min_participants = 10,
|
||||||
|
.max_participants = 100,
|
||||||
|
.round_duration = 3600, // 1 hour per round
|
||||||
|
.verify_contributions = true
|
||||||
|
});
|
||||||
|
|
||||||
|
std::cout << "Ceremony created:" << std::endl;
|
||||||
|
std::cout << " Ceremony ID: " << new_ceremony.ceremony_id() << std::endl;
|
||||||
|
std::cout << " Join URL: " << new_ceremony.join_url() << std::endl;
|
||||||
|
|
||||||
|
// Participate in a ceremony
|
||||||
|
std::cout << "\nParticipating in ceremony..." << std::endl;
|
||||||
|
|
||||||
|
// Generate entropy
|
||||||
|
std::vector<uint8_t> entropy(32);
|
||||||
|
std::random_device rd;
|
||||||
|
std::generate(entropy.begin(), entropy.end(), std::ref(rd));
|
||||||
|
|
||||||
|
auto contribution = zk.ceremony().contribute({
|
||||||
|
.ceremony_id = new_ceremony.ceremony_id(),
|
||||||
|
.entropy = entropy
|
||||||
|
});
|
||||||
|
|
||||||
|
std::cout << "Contribution made:" << std::endl;
|
||||||
|
std::cout << " Contribution ID: " << contribution.contribution_id() << std::endl;
|
||||||
|
std::cout << " Position: " << contribution.position() << std::endl;
|
||||||
|
std::cout << " Hash: " << contribution.hash() << std::endl;
|
||||||
|
|
||||||
|
// Verify a contribution
|
||||||
|
std::cout << "\nVerifying contribution..." << std::endl;
|
||||||
|
bool valid = zk.ceremony().verify_contribution(contribution.contribution_id());
|
||||||
|
std::cout << "Contribution valid: " << (valid ? "true" : "false") << std::endl;
|
||||||
|
|
||||||
|
// Get ceremony transcript (for auditability)
|
||||||
|
auto transcript = zk.ceremony().get_transcript(new_ceremony.ceremony_id());
|
||||||
|
std::cout << "\nCeremony transcript:" << std::endl;
|
||||||
|
std::cout << " Total contributions: " << transcript.contributions().size() << std::endl;
|
||||||
|
std::cout << " Start time: " << transcript.start_time() << std::endl;
|
||||||
|
std::cout << " Final hash: " << (transcript.final_hash().empty() ? "pending" : transcript.final_hash()) << std::endl;
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
// Initialize client
|
||||||
|
const char* api_key = std::getenv("SYNOR_API_KEY");
|
||||||
|
ZkConfig config{
|
||||||
|
.api_key = api_key ? api_key : "your-api-key",
|
||||||
|
.endpoint = "https://zk.synor.io/v1",
|
||||||
|
.timeout = std::chrono::seconds(120), // ZK operations can be slow
|
||||||
|
.retries = 3,
|
||||||
|
.debug = false,
|
||||||
|
.default_proving_system = ProvingSystem::Groth16,
|
||||||
|
.prove_timeout = std::chrono::seconds(300),
|
||||||
|
.verify_timeout = std::chrono::seconds(30)
|
||||||
|
};
|
||||||
|
|
||||||
|
SynorZk zk(config);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check service health
|
||||||
|
bool healthy = zk.health_check();
|
||||||
|
std::cout << "Service healthy: " << (healthy ? "true" : "false") << std::endl << std::endl;
|
||||||
|
|
||||||
|
// Run examples
|
||||||
|
circuit_example(zk);
|
||||||
|
groth16_example(zk);
|
||||||
|
plonk_example(zk);
|
||||||
|
stark_example(zk);
|
||||||
|
recursive_example(zk);
|
||||||
|
ceremony_example(zk);
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
std::cerr << "Error: " << e.what() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
415
sdk/csharp/examples/CompilerExample.cs
Normal file
415
sdk/csharp/examples/CompilerExample.cs
Normal file
|
|
@ -0,0 +1,415 @@
|
||||||
|
/**
|
||||||
|
* Synor Compiler SDK Examples for C#
|
||||||
|
*
|
||||||
|
* Demonstrates smart contract compilation and analysis:
|
||||||
|
* - WASM contract compilation and optimization
|
||||||
|
* - ABI extraction and encoding
|
||||||
|
* - Contract analysis and security scanning
|
||||||
|
* - Validation and verification
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Synor.Compiler;
|
||||||
|
|
||||||
|
namespace Synor.Examples;
|
||||||
|
|
||||||
|
public class CompilerExample
|
||||||
|
{
|
||||||
|
private readonly SynorCompiler _compiler;
|
||||||
|
|
||||||
|
public CompilerExample(SynorCompiler compiler)
|
||||||
|
{
|
||||||
|
_compiler = compiler;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a minimal valid WASM module for testing
|
||||||
|
/// </summary>
|
||||||
|
private static byte[] CreateMinimalWasm()
|
||||||
|
{
|
||||||
|
return new 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, (byte)'a', (byte)'d', (byte)'d', 0x00, 0x00,
|
||||||
|
// Code section
|
||||||
|
0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunCompileContractExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Contract Compilation ===");
|
||||||
|
|
||||||
|
var wasm = CreateMinimalWasm();
|
||||||
|
|
||||||
|
var result = await _compiler.CompileAsync(wasm, new CompileOptions
|
||||||
|
{
|
||||||
|
OptimizationLevel = OptimizationLevel.Size,
|
||||||
|
UseWasmOpt = true,
|
||||||
|
Validate = true,
|
||||||
|
ExtractMetadata = true,
|
||||||
|
GenerateAbi = true,
|
||||||
|
StripOptions = new StripOptions
|
||||||
|
{
|
||||||
|
StripDebug = true,
|
||||||
|
StripProducers = true,
|
||||||
|
StripNames = true,
|
||||||
|
StripCustom = true,
|
||||||
|
StripUnused = true,
|
||||||
|
PreserveSections = new List<string>()
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Console.WriteLine("Compilation result:");
|
||||||
|
Console.WriteLine($" Contract ID: {result.ContractId}");
|
||||||
|
Console.WriteLine($" Code hash: {result.CodeHash}");
|
||||||
|
Console.WriteLine($" Original size: {result.OriginalSize} bytes");
|
||||||
|
Console.WriteLine($" Optimized size: {result.OptimizedSize} bytes");
|
||||||
|
Console.WriteLine($" Size reduction: {result.SizeReduction:F1}%");
|
||||||
|
Console.WriteLine($" Estimated deploy gas: {result.EstimatedDeployGas}");
|
||||||
|
|
||||||
|
if (result.Metadata != null)
|
||||||
|
{
|
||||||
|
Console.WriteLine("\nMetadata:");
|
||||||
|
Console.WriteLine($" Name: {result.Metadata.Name}");
|
||||||
|
Console.WriteLine($" Version: {result.Metadata.Version}");
|
||||||
|
Console.WriteLine($" SDK Version: {result.Metadata.SdkVersion}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.Abi != null)
|
||||||
|
{
|
||||||
|
Console.WriteLine("\nABI:");
|
||||||
|
Console.WriteLine($" Functions: {result.Abi.Functions.Count}");
|
||||||
|
Console.WriteLine($" Events: {result.Abi.Events.Count}");
|
||||||
|
Console.WriteLine($" Errors: {result.Abi.Errors.Count}");
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunCompilationModesExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Compilation Modes ===");
|
||||||
|
|
||||||
|
var wasm = CreateMinimalWasm();
|
||||||
|
|
||||||
|
// Development mode: fast compilation, debugging support
|
||||||
|
Console.WriteLine("Development mode:");
|
||||||
|
var devResult = await _compiler.Contracts.CompileDevAsync(wasm);
|
||||||
|
Console.WriteLine($" Size: {devResult.OptimizedSize} bytes");
|
||||||
|
Console.WriteLine(" Optimization: none");
|
||||||
|
|
||||||
|
// Production mode: maximum optimization
|
||||||
|
Console.WriteLine("\nProduction mode:");
|
||||||
|
var prodResult = await _compiler.Contracts.CompileProductionAsync(wasm);
|
||||||
|
Console.WriteLine($" Size: {prodResult.OptimizedSize} bytes");
|
||||||
|
Console.WriteLine(" Optimization: aggressive");
|
||||||
|
Console.WriteLine($" Size savings: {devResult.OptimizedSize - prodResult.OptimizedSize} bytes");
|
||||||
|
|
||||||
|
// Custom optimization levels
|
||||||
|
Console.WriteLine("\nOptimization levels:");
|
||||||
|
var levels = new (OptimizationLevel Level, string Name)[]
|
||||||
|
{
|
||||||
|
(OptimizationLevel.None, "NONE"),
|
||||||
|
(OptimizationLevel.Basic, "BASIC"),
|
||||||
|
(OptimizationLevel.Size, "SIZE"),
|
||||||
|
(OptimizationLevel.Aggressive, "AGGRESSIVE")
|
||||||
|
};
|
||||||
|
|
||||||
|
foreach (var (level, name) in levels)
|
||||||
|
{
|
||||||
|
var result = await _compiler.CompileAsync(wasm, new CompileOptions
|
||||||
|
{
|
||||||
|
OptimizationLevel = level
|
||||||
|
});
|
||||||
|
Console.WriteLine($" {name}: {result.OptimizedSize} bytes");
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunAbiExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== ABI Operations ===");
|
||||||
|
|
||||||
|
var wasm = CreateMinimalWasm();
|
||||||
|
|
||||||
|
// Extract ABI from WASM
|
||||||
|
var abi = await _compiler.Abi.ExtractAsync(wasm);
|
||||||
|
Console.WriteLine($"Contract: {abi.Name}");
|
||||||
|
Console.WriteLine($"Version: {abi.Version}");
|
||||||
|
|
||||||
|
// List functions
|
||||||
|
if (abi.Functions.Count > 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("\nFunctions:");
|
||||||
|
foreach (var func in abi.Functions)
|
||||||
|
{
|
||||||
|
var inputs = string.Join(", ", func.Inputs.ConvertAll(p => $"{p.Name}: {p.Type.TypeName}"));
|
||||||
|
var outputs = func.Outputs.Count == 0
|
||||||
|
? "void"
|
||||||
|
: string.Join(", ", func.Outputs.ConvertAll(o => o.Type.TypeName));
|
||||||
|
|
||||||
|
var modifiers = new List<string>();
|
||||||
|
if (func.View) modifiers.Add("view");
|
||||||
|
if (func.Payable) modifiers.Add("payable");
|
||||||
|
var modifierStr = modifiers.Count > 0 ? string.Join(" ", modifiers) : "";
|
||||||
|
|
||||||
|
Console.WriteLine($" {func.Name}({inputs}) -> {outputs} {modifierStr}");
|
||||||
|
Console.WriteLine($" Selector: {func.Selector}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// List events
|
||||||
|
if (abi.Events.Count > 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("\nEvents:");
|
||||||
|
foreach (var evt in abi.Events)
|
||||||
|
{
|
||||||
|
var paramParts = new List<string>();
|
||||||
|
foreach (var param in evt.Params)
|
||||||
|
{
|
||||||
|
var prefix = param.Indexed ? "indexed " : "";
|
||||||
|
paramParts.Add($"{prefix}{param.Name}: {param.Type.TypeName}");
|
||||||
|
}
|
||||||
|
Console.WriteLine($" {evt.Name}({string.Join(", ", paramParts)})");
|
||||||
|
Console.WriteLine($" Topic: {evt.Topic}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode a function call
|
||||||
|
if (abi.Functions.Count > 0)
|
||||||
|
{
|
||||||
|
var func = abi.Functions[0];
|
||||||
|
var encoded = await _compiler.Abi.EncodeCallAsync(func, new[] { "arg1", "arg2" });
|
||||||
|
Console.WriteLine($"\nEncoded call to {func.Name}: {encoded}");
|
||||||
|
|
||||||
|
// Decode a result
|
||||||
|
var decoded = await _compiler.Abi.DecodeResultAsync(func, encoded);
|
||||||
|
Console.WriteLine($"Decoded result: {decoded}");
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunAnalysisExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Contract Analysis ===");
|
||||||
|
|
||||||
|
var wasm = CreateMinimalWasm();
|
||||||
|
|
||||||
|
// Full analysis
|
||||||
|
var analysis = await _compiler.Analysis.AnalyzeAsync(wasm);
|
||||||
|
|
||||||
|
// Size breakdown
|
||||||
|
if (analysis.SizeBreakdown != null)
|
||||||
|
{
|
||||||
|
var size = analysis.SizeBreakdown;
|
||||||
|
Console.WriteLine("Size breakdown:");
|
||||||
|
Console.WriteLine($" Code: {size.Code} bytes");
|
||||||
|
Console.WriteLine($" Data: {size.Data} bytes");
|
||||||
|
Console.WriteLine($" Functions: {size.Functions} bytes");
|
||||||
|
Console.WriteLine($" Memory: {size.Memory} bytes");
|
||||||
|
Console.WriteLine($" Exports: {size.Exports} bytes");
|
||||||
|
Console.WriteLine($" Imports: {size.Imports} bytes");
|
||||||
|
Console.WriteLine($" Total: {size.Total} bytes");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Function analysis
|
||||||
|
if (analysis.Functions.Count > 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("\nFunction analysis:");
|
||||||
|
foreach (var func in analysis.Functions.GetRange(0, Math.Min(analysis.Functions.Count, 5)))
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {func.Name}:");
|
||||||
|
Console.WriteLine($" Size: {func.Size} bytes");
|
||||||
|
Console.WriteLine($" Instructions: {func.InstructionCount}");
|
||||||
|
Console.WriteLine($" Locals: {func.LocalCount}");
|
||||||
|
Console.WriteLine($" Exported: {func.Exported}");
|
||||||
|
Console.WriteLine($" Estimated gas: {func.EstimatedGas}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Import analysis
|
||||||
|
if (analysis.Imports.Count > 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("\nImports:");
|
||||||
|
foreach (var imp in analysis.Imports)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {imp.Module}.{imp.Name} ({imp.Kind})");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gas analysis
|
||||||
|
if (analysis.GasAnalysis != null)
|
||||||
|
{
|
||||||
|
var gas = analysis.GasAnalysis;
|
||||||
|
Console.WriteLine("\nGas analysis:");
|
||||||
|
Console.WriteLine($" Deployment: {gas.DeploymentGas}");
|
||||||
|
Console.WriteLine($" Memory init: {gas.MemoryInitGas}");
|
||||||
|
Console.WriteLine($" Data section: {gas.DataSectionGas}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract metadata
|
||||||
|
var metadata = await _compiler.Analysis.ExtractMetadataAsync(wasm);
|
||||||
|
Console.WriteLine("\nContract metadata:");
|
||||||
|
Console.WriteLine($" Name: {metadata.Name}");
|
||||||
|
Console.WriteLine($" Version: {metadata.Version}");
|
||||||
|
Console.WriteLine($" Build timestamp: {metadata.BuildTimestamp}");
|
||||||
|
|
||||||
|
// Estimate deployment gas
|
||||||
|
var gasEstimate = await _compiler.Analysis.EstimateDeployGasAsync(wasm);
|
||||||
|
Console.WriteLine($"\nEstimated deployment gas: {gasEstimate}");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunValidationExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Contract Validation ===");
|
||||||
|
|
||||||
|
var wasm = CreateMinimalWasm();
|
||||||
|
|
||||||
|
// Full validation
|
||||||
|
var result = await _compiler.Validation.ValidateAsync(wasm);
|
||||||
|
Console.WriteLine($"Valid: {result.Valid}");
|
||||||
|
Console.WriteLine($"Exports: {result.ExportCount}");
|
||||||
|
Console.WriteLine($"Imports: {result.ImportCount}");
|
||||||
|
Console.WriteLine($"Functions: {result.FunctionCount}");
|
||||||
|
Console.WriteLine($"Memory pages: {result.MemoryPages}");
|
||||||
|
|
||||||
|
if (result.Errors.Count > 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("\nValidation errors:");
|
||||||
|
foreach (var error in result.Errors)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" [{error.Code}] {error.Message}");
|
||||||
|
if (!string.IsNullOrEmpty(error.Location))
|
||||||
|
{
|
||||||
|
Console.WriteLine($" at {error.Location}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result.Warnings.Count > 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("\nWarnings:");
|
||||||
|
foreach (var warning in result.Warnings)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {warning}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Quick validation
|
||||||
|
var isValid = await _compiler.Validation.IsValidAsync(wasm);
|
||||||
|
Console.WriteLine($"\nQuick validation: {isValid}");
|
||||||
|
|
||||||
|
// Get validation errors only
|
||||||
|
var errors = await _compiler.Validation.GetErrorsAsync(wasm);
|
||||||
|
Console.WriteLine($"Error count: {errors.Count}");
|
||||||
|
|
||||||
|
// Validate required exports
|
||||||
|
var hasRequired = await _compiler.Validation.ValidateExportsAsync(wasm, new[] { "init", "execute", "query" });
|
||||||
|
Console.WriteLine($"Has required exports: {hasRequired}");
|
||||||
|
|
||||||
|
// Validate memory constraints
|
||||||
|
var memoryValid = await _compiler.Validation.ValidateMemoryAsync(wasm, 16);
|
||||||
|
Console.WriteLine($"Memory within 16 pages: {memoryValid}");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunSecurityExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Security Scanning ===");
|
||||||
|
|
||||||
|
var wasm = CreateMinimalWasm();
|
||||||
|
|
||||||
|
var security = await _compiler.Analysis.SecurityScanAsync(wasm);
|
||||||
|
|
||||||
|
Console.WriteLine($"Security score: {security.Score}/100");
|
||||||
|
|
||||||
|
if (security.Issues.Count > 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("\nSecurity issues:");
|
||||||
|
foreach (var issue in security.Issues)
|
||||||
|
{
|
||||||
|
var icon = issue.Severity switch
|
||||||
|
{
|
||||||
|
"critical" => "[CRIT]",
|
||||||
|
"high" => "[HIGH]",
|
||||||
|
"medium" => "[MED]",
|
||||||
|
"low" => "[LOW]",
|
||||||
|
_ => "[???]"
|
||||||
|
};
|
||||||
|
|
||||||
|
Console.WriteLine($"{icon} [{issue.Severity}] {issue.Type}");
|
||||||
|
Console.WriteLine($" {issue.Description}");
|
||||||
|
if (!string.IsNullOrEmpty(issue.Location))
|
||||||
|
{
|
||||||
|
Console.WriteLine($" at {issue.Location}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.WriteLine("No security issues found!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (security.Recommendations.Count > 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("\nRecommendations:");
|
||||||
|
foreach (var rec in security.Recommendations)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" • {rec}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task Main(string[] args)
|
||||||
|
{
|
||||||
|
// Initialize client
|
||||||
|
var apiKey = Environment.GetEnvironmentVariable("SYNOR_API_KEY") ?? "your-api-key";
|
||||||
|
var config = new CompilerConfig
|
||||||
|
{
|
||||||
|
ApiKey = apiKey,
|
||||||
|
Endpoint = "https://compiler.synor.io/v1",
|
||||||
|
Timeout = TimeSpan.FromSeconds(60),
|
||||||
|
Retries = 3,
|
||||||
|
Debug = false,
|
||||||
|
DefaultOptimizationLevel = OptimizationLevel.Size,
|
||||||
|
MaxContractSize = 256 * 1024,
|
||||||
|
UseWasmOpt = true,
|
||||||
|
Validate = true,
|
||||||
|
ExtractMetadata = true,
|
||||||
|
GenerateAbi = true
|
||||||
|
};
|
||||||
|
|
||||||
|
var compiler = new SynorCompiler(config);
|
||||||
|
var example = new CompilerExample(compiler);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Check service health
|
||||||
|
var healthy = await compiler.HealthCheckAsync();
|
||||||
|
Console.WriteLine($"Service healthy: {healthy}\n");
|
||||||
|
|
||||||
|
// Run examples
|
||||||
|
await example.RunCompileContractExample();
|
||||||
|
await example.RunCompilationModesExample();
|
||||||
|
await example.RunAbiExample();
|
||||||
|
await example.RunAnalysisExample();
|
||||||
|
await example.RunValidationExample();
|
||||||
|
await example.RunSecurityExample();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"Error: {ex.Message}");
|
||||||
|
Environment.Exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
272
sdk/csharp/examples/CryptoExample.cs
Normal file
272
sdk/csharp/examples/CryptoExample.cs
Normal file
|
|
@ -0,0 +1,272 @@
|
||||||
|
/**
|
||||||
|
* Synor Crypto SDK Examples for C#
|
||||||
|
*
|
||||||
|
* Demonstrates quantum-resistant cryptographic operations:
|
||||||
|
* - Hybrid Ed25519 + Dilithium3 signatures
|
||||||
|
* - BIP-39 mnemonic generation and validation
|
||||||
|
* - Post-quantum algorithms (Falcon, SPHINCS+)
|
||||||
|
* - Key derivation functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Synor.Crypto;
|
||||||
|
|
||||||
|
namespace Synor.Examples;
|
||||||
|
|
||||||
|
public class CryptoExample
|
||||||
|
{
|
||||||
|
private readonly SynorCrypto _crypto;
|
||||||
|
|
||||||
|
public CryptoExample(SynorCrypto crypto)
|
||||||
|
{
|
||||||
|
_crypto = crypto;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunMnemonicExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Mnemonic Operations ===");
|
||||||
|
|
||||||
|
// Generate a 24-word mnemonic (256-bit entropy)
|
||||||
|
var mnemonic = await _crypto.Mnemonic.GenerateAsync(24);
|
||||||
|
Console.WriteLine($"Generated mnemonic: {mnemonic.Phrase}");
|
||||||
|
Console.WriteLine($"Word count: {mnemonic.WordCount}");
|
||||||
|
|
||||||
|
// Validate a mnemonic
|
||||||
|
var validation = await _crypto.Mnemonic.ValidateAsync(mnemonic.Phrase);
|
||||||
|
Console.WriteLine($"Valid: {validation.IsValid}");
|
||||||
|
if (!validation.IsValid)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Error: {validation.Error}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert mnemonic to seed
|
||||||
|
var seed = await _crypto.Mnemonic.ToSeedAsync(mnemonic.Phrase, "optional-passphrase");
|
||||||
|
Console.WriteLine($"Seed (hex): {BytesToHex(seed, 16)}...");
|
||||||
|
|
||||||
|
// Word suggestions for autocomplete
|
||||||
|
var suggestions = await _crypto.Mnemonic.SuggestWordsAsync("aban", 5);
|
||||||
|
Console.WriteLine($"Suggestions for 'aban': {string.Join(", ", suggestions)}");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunKeypairExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Keypair Operations ===");
|
||||||
|
|
||||||
|
// Generate a random keypair
|
||||||
|
var keypair = await _crypto.Keypairs.GenerateAsync();
|
||||||
|
Console.WriteLine("Generated hybrid keypair:");
|
||||||
|
Console.WriteLine($" Ed25519 public key size: {keypair.PublicKey.Ed25519Bytes.Length} bytes");
|
||||||
|
Console.WriteLine($" Dilithium public key size: {keypair.PublicKey.DilithiumBytes.Length} bytes");
|
||||||
|
Console.WriteLine($" Total public key size: {keypair.PublicKey.Size} bytes");
|
||||||
|
|
||||||
|
// Get addresses for different networks
|
||||||
|
Console.WriteLine("\nAddresses:");
|
||||||
|
Console.WriteLine($" Mainnet: {keypair.GetAddress(Network.Mainnet)}");
|
||||||
|
Console.WriteLine($" Testnet: {keypair.GetAddress(Network.Testnet)}");
|
||||||
|
Console.WriteLine($" Devnet: {keypair.GetAddress(Network.Devnet)}");
|
||||||
|
|
||||||
|
// Create keypair from mnemonic (deterministic)
|
||||||
|
var mnemonic = await _crypto.Mnemonic.GenerateAsync(24);
|
||||||
|
var keypair2 = await _crypto.Keypairs.FromMnemonicAsync(mnemonic.Phrase);
|
||||||
|
var addr = keypair2.GetAddress(Network.Mainnet);
|
||||||
|
Console.WriteLine($"\nKeypair from mnemonic: {addr[..20]}...");
|
||||||
|
|
||||||
|
// Derive child keypair using BIP-44 path
|
||||||
|
var path = DerivationPath.External(0, 0); // m/44'/21337'/0'/0/0
|
||||||
|
Console.WriteLine($"Derivation path: {path}");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunSigningExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Hybrid Signing ===");
|
||||||
|
|
||||||
|
// Generate keypair
|
||||||
|
var keypair = await _crypto.Keypairs.GenerateAsync();
|
||||||
|
|
||||||
|
// Sign a message
|
||||||
|
var message = Encoding.UTF8.GetBytes("Hello, quantum-resistant world!");
|
||||||
|
var signature = await _crypto.Signing.SignAsync(keypair, message);
|
||||||
|
|
||||||
|
Console.WriteLine("Signature created:");
|
||||||
|
Console.WriteLine($" Ed25519 component: {signature.Ed25519Bytes.Length} bytes");
|
||||||
|
Console.WriteLine($" Dilithium component: {signature.DilithiumBytes.Length} bytes");
|
||||||
|
Console.WriteLine($" Total signature size: {signature.Size} bytes");
|
||||||
|
|
||||||
|
// Verify the signature
|
||||||
|
var valid = await _crypto.Signing.VerifyAsync(keypair.PublicKey, message, signature);
|
||||||
|
Console.WriteLine($"\nVerification result: {valid}");
|
||||||
|
|
||||||
|
// Verify with tampered message fails
|
||||||
|
var tamperedMessage = Encoding.UTF8.GetBytes("Hello, tampered message!");
|
||||||
|
var invalidResult = await _crypto.Signing.VerifyAsync(keypair.PublicKey, tamperedMessage, signature);
|
||||||
|
Console.WriteLine($"Tampered message verification: {invalidResult}");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunFalconExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Falcon Post-Quantum Signatures ===");
|
||||||
|
|
||||||
|
// Generate Falcon-512 keypair (128-bit security)
|
||||||
|
var falcon512 = await _crypto.Falcon.GenerateAsync(FalconVariant.Falcon512);
|
||||||
|
Console.WriteLine("Falcon-512 keypair:");
|
||||||
|
Console.WriteLine($" Public key: {falcon512.PublicKey.KeyBytes.Length} bytes");
|
||||||
|
Console.WriteLine(" Security level: 128-bit");
|
||||||
|
|
||||||
|
// Generate Falcon-1024 keypair (256-bit security)
|
||||||
|
var falcon1024 = await _crypto.Falcon.GenerateAsync(FalconVariant.Falcon1024);
|
||||||
|
Console.WriteLine("\nFalcon-1024 keypair:");
|
||||||
|
Console.WriteLine($" Public key: {falcon1024.PublicKey.KeyBytes.Length} bytes");
|
||||||
|
Console.WriteLine(" Security level: 256-bit");
|
||||||
|
|
||||||
|
// Sign with Falcon-512
|
||||||
|
var message = Encoding.UTF8.GetBytes("Post-quantum secure message");
|
||||||
|
var signature = await _crypto.Falcon.SignAsync(falcon512, message);
|
||||||
|
Console.WriteLine($"\nFalcon-512 signature: {signature.SignatureBytes.Length} bytes");
|
||||||
|
|
||||||
|
// Verify
|
||||||
|
var valid = await _crypto.Falcon.VerifyAsync(falcon512.PublicKey.KeyBytes, message, signature);
|
||||||
|
Console.WriteLine($"Verification: {valid}");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunSphincsExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== SPHINCS+ Hash-Based Signatures ===");
|
||||||
|
|
||||||
|
// SPHINCS+ variants with different security levels
|
||||||
|
var variants = new (SphincsVariant Variant, int Security, int SigSize, string Name)[]
|
||||||
|
{
|
||||||
|
(SphincsVariant.Shake128s, 128, 7856, "SHAKE128S"),
|
||||||
|
(SphincsVariant.Shake192s, 192, 16224, "SHAKE192S"),
|
||||||
|
(SphincsVariant.Shake256s, 256, 29792, "SHAKE256S"),
|
||||||
|
};
|
||||||
|
|
||||||
|
var message = Encoding.UTF8.GetBytes("Hash-based quantum security");
|
||||||
|
|
||||||
|
foreach (var (variant, security, sigSize, name) in variants)
|
||||||
|
{
|
||||||
|
var keypair = await _crypto.Sphincs.GenerateAsync(variant);
|
||||||
|
Console.WriteLine($"SPHINCS+ {name}:");
|
||||||
|
Console.WriteLine($" Security level: {security}-bit");
|
||||||
|
Console.WriteLine($" Expected signature size: {sigSize} bytes");
|
||||||
|
|
||||||
|
// Sign a message
|
||||||
|
var signature = await _crypto.Sphincs.SignAsync(keypair, message);
|
||||||
|
Console.WriteLine($" Actual signature size: {signature.SignatureBytes.Length} bytes");
|
||||||
|
|
||||||
|
// Verify
|
||||||
|
var valid = await _crypto.Sphincs.VerifyAsync(keypair.PublicKey.KeyBytes, message, signature);
|
||||||
|
Console.WriteLine($" Verification: {valid}");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunKdfExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Key Derivation Functions ===");
|
||||||
|
|
||||||
|
// HKDF (HMAC-based Key Derivation Function)
|
||||||
|
var seed = Encoding.UTF8.GetBytes("master-secret-key-material-here");
|
||||||
|
var hkdfConfig = new DerivationConfig
|
||||||
|
{
|
||||||
|
Salt = Encoding.UTF8.GetBytes("application-salt"),
|
||||||
|
Info = Encoding.UTF8.GetBytes("encryption-key"),
|
||||||
|
OutputLength = 32
|
||||||
|
};
|
||||||
|
|
||||||
|
var derivedKey = await _crypto.Kdf.DeriveKeyAsync(seed, hkdfConfig);
|
||||||
|
Console.WriteLine($"HKDF derived key: {BytesToHex(derivedKey)}");
|
||||||
|
|
||||||
|
// PBKDF2 (Password-Based Key Derivation Function)
|
||||||
|
var password = Encoding.UTF8.GetBytes("user-password");
|
||||||
|
var pbkdf2Config = new PasswordDerivationConfig
|
||||||
|
{
|
||||||
|
Salt = Encoding.UTF8.GetBytes("random-salt-value"),
|
||||||
|
Iterations = 100000,
|
||||||
|
OutputLength = 32
|
||||||
|
};
|
||||||
|
|
||||||
|
var passwordKey = await _crypto.Kdf.DeriveFromPasswordAsync(password, pbkdf2Config);
|
||||||
|
Console.WriteLine($"PBKDF2 derived key: {BytesToHex(passwordKey)}");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunHashExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Hash Functions ===");
|
||||||
|
|
||||||
|
var data = Encoding.UTF8.GetBytes("Data to hash");
|
||||||
|
|
||||||
|
// SHA3-256 (FIPS 202)
|
||||||
|
var sha3 = await _crypto.Hash.Sha3_256Async(data);
|
||||||
|
Console.WriteLine($"SHA3-256: {sha3.Hex}");
|
||||||
|
|
||||||
|
// BLAKE3 (fast, parallel)
|
||||||
|
var blake3 = await _crypto.Hash.Blake3Async(data);
|
||||||
|
Console.WriteLine($"BLAKE3: {blake3.Hex}");
|
||||||
|
|
||||||
|
// Keccak-256 (Ethereum compatible)
|
||||||
|
var keccak = await _crypto.Hash.Keccak256Async(data);
|
||||||
|
Console.WriteLine($"Keccak: {keccak.Hex}");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string BytesToHex(byte[] data, int? maxLen = null)
|
||||||
|
{
|
||||||
|
var len = maxLen ?? data.Length;
|
||||||
|
var sb = new StringBuilder(len * 2);
|
||||||
|
for (var i = 0; i < Math.Min(len, data.Length); i++)
|
||||||
|
{
|
||||||
|
sb.AppendFormat("{0:x2}", data[i]);
|
||||||
|
}
|
||||||
|
if (maxLen.HasValue && maxLen.Value < data.Length)
|
||||||
|
{
|
||||||
|
sb.Append("...");
|
||||||
|
}
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task Main(string[] args)
|
||||||
|
{
|
||||||
|
// Initialize client
|
||||||
|
var apiKey = Environment.GetEnvironmentVariable("SYNOR_API_KEY") ?? "your-api-key";
|
||||||
|
var config = new CryptoConfig
|
||||||
|
{
|
||||||
|
ApiKey = apiKey,
|
||||||
|
Endpoint = "https://crypto.synor.io/v1",
|
||||||
|
Timeout = TimeSpan.FromSeconds(30),
|
||||||
|
Retries = 3,
|
||||||
|
Debug = false,
|
||||||
|
DefaultNetwork = Network.Mainnet
|
||||||
|
};
|
||||||
|
|
||||||
|
var crypto = new SynorCrypto(config);
|
||||||
|
var example = new CryptoExample(crypto);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Check service health
|
||||||
|
var healthy = await crypto.HealthCheckAsync();
|
||||||
|
Console.WriteLine($"Service healthy: {healthy}\n");
|
||||||
|
|
||||||
|
// Run examples
|
||||||
|
await example.RunMnemonicExample();
|
||||||
|
await example.RunKeypairExample();
|
||||||
|
await example.RunSigningExample();
|
||||||
|
await example.RunFalconExample();
|
||||||
|
await example.RunSphincsExample();
|
||||||
|
await example.RunKdfExample();
|
||||||
|
await example.RunHashExample();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"Error: {ex.Message}");
|
||||||
|
Environment.Exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
324
sdk/csharp/examples/DexExample.cs
Normal file
324
sdk/csharp/examples/DexExample.cs
Normal file
|
|
@ -0,0 +1,324 @@
|
||||||
|
/**
|
||||||
|
* Synor DEX SDK Examples for C#
|
||||||
|
*
|
||||||
|
* Demonstrates decentralized exchange operations:
|
||||||
|
* - Market data and orderbook queries
|
||||||
|
* - Spot trading (limit and market orders)
|
||||||
|
* - Perpetual futures trading
|
||||||
|
* - Liquidity provision (AMM)
|
||||||
|
* - Portfolio management
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Synor.Dex;
|
||||||
|
|
||||||
|
namespace Synor.Examples;
|
||||||
|
|
||||||
|
public class DexExample
|
||||||
|
{
|
||||||
|
private readonly SynorDex _dex;
|
||||||
|
|
||||||
|
public DexExample(SynorDex dex)
|
||||||
|
{
|
||||||
|
_dex = dex;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunMarketsExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Market Information ===");
|
||||||
|
|
||||||
|
// List all available markets
|
||||||
|
var markets = await _dex.Markets.ListAsync();
|
||||||
|
Console.WriteLine($"Available markets: {markets.Count}");
|
||||||
|
foreach (var market in markets.GetRange(0, Math.Min(markets.Count, 5)))
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {market.Symbol}: {market.BaseAsset}/{market.QuoteAsset} ({market.Status})");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get specific market details
|
||||||
|
var ethUsdc = await _dex.Markets.GetAsync("ETH-USDC");
|
||||||
|
Console.WriteLine($"\n{ethUsdc.Symbol} market:");
|
||||||
|
Console.WriteLine($" Price: ${ethUsdc.LastPrice:F2}");
|
||||||
|
Console.WriteLine($" 24h Change: {ethUsdc.Change24h:F2}%");
|
||||||
|
Console.WriteLine($" 24h Volume: ${ethUsdc.Volume24h:N0}");
|
||||||
|
Console.WriteLine($" 24h High: ${ethUsdc.High24h:F2}");
|
||||||
|
Console.WriteLine($" 24h Low: ${ethUsdc.Low24h:F2}");
|
||||||
|
|
||||||
|
// Get orderbook
|
||||||
|
var orderbook = await _dex.Markets.GetOrderbookAsync("ETH-USDC", 10);
|
||||||
|
Console.WriteLine($"\nOrderbook ({orderbook.Bids.Count} bids, {orderbook.Asks.Count} asks):");
|
||||||
|
Console.WriteLine(" Best bid: ${0:F2} ({1:F4} ETH)", orderbook.Bids[0].Price, orderbook.Bids[0].Quantity);
|
||||||
|
Console.WriteLine(" Best ask: ${0:F2} ({1:F4} ETH)", orderbook.Asks[0].Price, orderbook.Asks[0].Quantity);
|
||||||
|
Console.WriteLine($" Spread: ${orderbook.Spread:F2} ({orderbook.SpreadPercent:F3}%)");
|
||||||
|
|
||||||
|
// Get recent trades
|
||||||
|
var trades = await _dex.Markets.GetTradesAsync("ETH-USDC", 5);
|
||||||
|
Console.WriteLine("\nRecent trades:");
|
||||||
|
foreach (var trade in trades)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {trade.Side}: {trade.Quantity:F4} @ ${trade.Price:F2}");
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunSpotTradingExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Spot Trading ===");
|
||||||
|
|
||||||
|
// Get account balance
|
||||||
|
var balances = await _dex.Account.GetBalancesAsync();
|
||||||
|
Console.WriteLine("Account balances:");
|
||||||
|
foreach (var balance in balances)
|
||||||
|
{
|
||||||
|
if (balance.Total > 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {balance.Asset}: {balance.Available:F4} available, {balance.Locked:F4} locked");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Place a limit buy order
|
||||||
|
Console.WriteLine("\nPlacing limit buy order...");
|
||||||
|
var limitOrder = await _dex.Spot.PlaceOrderAsync(new SpotOrderRequest
|
||||||
|
{
|
||||||
|
Symbol = "ETH-USDC",
|
||||||
|
Side = OrderSide.Buy,
|
||||||
|
Type = OrderType.Limit,
|
||||||
|
Quantity = 0.1m,
|
||||||
|
Price = 3000.00m,
|
||||||
|
TimeInForce = TimeInForce.GoodTillCancel
|
||||||
|
});
|
||||||
|
|
||||||
|
Console.WriteLine($"Limit order placed:");
|
||||||
|
Console.WriteLine($" Order ID: {limitOrder.OrderId}");
|
||||||
|
Console.WriteLine($" Status: {limitOrder.Status}");
|
||||||
|
Console.WriteLine($" Price: ${limitOrder.Price:F2}");
|
||||||
|
Console.WriteLine($" Quantity: {limitOrder.Quantity:F4}");
|
||||||
|
|
||||||
|
// Place a market sell order
|
||||||
|
Console.WriteLine("\nPlacing market sell order...");
|
||||||
|
var marketOrder = await _dex.Spot.PlaceOrderAsync(new SpotOrderRequest
|
||||||
|
{
|
||||||
|
Symbol = "ETH-USDC",
|
||||||
|
Side = OrderSide.Sell,
|
||||||
|
Type = OrderType.Market,
|
||||||
|
Quantity = 0.05m
|
||||||
|
});
|
||||||
|
|
||||||
|
Console.WriteLine($"Market order executed:");
|
||||||
|
Console.WriteLine($" Order ID: {marketOrder.OrderId}");
|
||||||
|
Console.WriteLine($" Status: {marketOrder.Status}");
|
||||||
|
Console.WriteLine($" Filled: {marketOrder.FilledQuantity:F4}");
|
||||||
|
Console.WriteLine($" Avg price: ${marketOrder.AveragePrice:F2}");
|
||||||
|
|
||||||
|
// Get open orders
|
||||||
|
var openOrders = await _dex.Spot.GetOpenOrdersAsync("ETH-USDC");
|
||||||
|
Console.WriteLine($"\nOpen orders: {openOrders.Count}");
|
||||||
|
foreach (var order in openOrders)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {order.OrderId}: {order.Side} {order.Quantity:F4} @ ${order.Price:F2}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancel an order
|
||||||
|
if (openOrders.Count > 0)
|
||||||
|
{
|
||||||
|
var cancelled = await _dex.Spot.CancelOrderAsync(openOrders[0].OrderId);
|
||||||
|
Console.WriteLine($"\nCancelled order: {cancelled.OrderId}");
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunPerpsExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Perpetual Futures ===");
|
||||||
|
|
||||||
|
// Get perpetual markets
|
||||||
|
var perpMarkets = await _dex.Perps.GetMarketsAsync();
|
||||||
|
Console.WriteLine($"Perpetual markets: {perpMarkets.Count}");
|
||||||
|
foreach (var market in perpMarkets.GetRange(0, Math.Min(perpMarkets.Count, 3)))
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {market.Symbol}: Mark ${market.MarkPrice:F2}, Funding {market.FundingRate:F4}%");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get account position
|
||||||
|
var positions = await _dex.Perps.GetPositionsAsync();
|
||||||
|
Console.WriteLine($"\nOpen positions: {positions.Count}");
|
||||||
|
foreach (var position in positions)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {position.Symbol}: {position.Side} {position.Size:F4}");
|
||||||
|
Console.WriteLine($" Entry: ${position.EntryPrice:F2}, PnL: ${position.UnrealizedPnl:F2}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Open a long position
|
||||||
|
Console.WriteLine("\nOpening long position...");
|
||||||
|
var longOrder = await _dex.Perps.PlaceOrderAsync(new PerpOrderRequest
|
||||||
|
{
|
||||||
|
Symbol = "BTC-USDC-PERP",
|
||||||
|
Side = OrderSide.Buy,
|
||||||
|
Type = OrderType.Limit,
|
||||||
|
Quantity = 0.01m,
|
||||||
|
Price = 95000.00m,
|
||||||
|
Leverage = 10,
|
||||||
|
ReduceOnly = false
|
||||||
|
});
|
||||||
|
|
||||||
|
Console.WriteLine($"Position order placed:");
|
||||||
|
Console.WriteLine($" Order ID: {longOrder.OrderId}");
|
||||||
|
Console.WriteLine($" Leverage: {longOrder.Leverage}x");
|
||||||
|
Console.WriteLine($" Margin: ${longOrder.RequiredMargin:F2}");
|
||||||
|
|
||||||
|
// Set stop-loss and take-profit
|
||||||
|
Console.WriteLine("\nSetting SL/TP...");
|
||||||
|
await _dex.Perps.SetStopLossAsync("BTC-USDC-PERP", 90000.00m);
|
||||||
|
await _dex.Perps.SetTakeProfitAsync("BTC-USDC-PERP", 100000.00m);
|
||||||
|
Console.WriteLine(" Stop loss: $90,000");
|
||||||
|
Console.WriteLine(" Take profit: $100,000");
|
||||||
|
|
||||||
|
// Get funding rate history
|
||||||
|
var fundingHistory = await _dex.Perps.GetFundingHistoryAsync("BTC-USDC-PERP", 5);
|
||||||
|
Console.WriteLine("\nFunding rate history:");
|
||||||
|
foreach (var funding in fundingHistory)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {funding.Timestamp}: {funding.Rate:F4}%");
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunLiquidityExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Liquidity Provision ===");
|
||||||
|
|
||||||
|
// Get available pools
|
||||||
|
var pools = await _dex.Liquidity.GetPoolsAsync();
|
||||||
|
Console.WriteLine($"Liquidity pools: {pools.Count}");
|
||||||
|
foreach (var pool in pools.GetRange(0, Math.Min(pools.Count, 5)))
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {pool.Name}: TVL ${pool.TotalValueLocked:N0}, APR {pool.Apr:F2}%");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get pool details
|
||||||
|
var ethUsdcPool = await _dex.Liquidity.GetPoolAsync("ETH-USDC");
|
||||||
|
Console.WriteLine($"\n{ethUsdcPool.Name} pool:");
|
||||||
|
Console.WriteLine($" TVL: ${ethUsdcPool.TotalValueLocked:N0}");
|
||||||
|
Console.WriteLine($" Volume 24h: ${ethUsdcPool.Volume24h:N0}");
|
||||||
|
Console.WriteLine($" Fee tier: {ethUsdcPool.FeeTier:F2}%");
|
||||||
|
Console.WriteLine($" APR: {ethUsdcPool.Apr:F2}%");
|
||||||
|
Console.WriteLine($" Reserve A: {ethUsdcPool.ReserveA:F4} ETH");
|
||||||
|
Console.WriteLine($" Reserve B: {ethUsdcPool.ReserveB:F2} USDC");
|
||||||
|
|
||||||
|
// Add liquidity
|
||||||
|
Console.WriteLine("\nAdding liquidity...");
|
||||||
|
var addResult = await _dex.Liquidity.AddLiquidityAsync(new AddLiquidityRequest
|
||||||
|
{
|
||||||
|
PoolId = "ETH-USDC",
|
||||||
|
AmountA = 0.1m,
|
||||||
|
AmountB = 300.0m,
|
||||||
|
SlippageTolerance = 0.5m
|
||||||
|
});
|
||||||
|
|
||||||
|
Console.WriteLine($"Liquidity added:");
|
||||||
|
Console.WriteLine($" LP tokens received: {addResult.LpTokensReceived:F8}");
|
||||||
|
Console.WriteLine($" Share of pool: {addResult.ShareOfPool:F4}%");
|
||||||
|
|
||||||
|
// Get LP positions
|
||||||
|
var lpPositions = await _dex.Liquidity.GetPositionsAsync();
|
||||||
|
Console.WriteLine($"\nLP positions: {lpPositions.Count}");
|
||||||
|
foreach (var position in lpPositions)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {position.PoolId}: {position.LpTokens:F8} tokens, ${position.Value:F2}");
|
||||||
|
Console.WriteLine($" Earned fees: ${position.EarnedFees:F2}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove liquidity
|
||||||
|
Console.WriteLine("\nRemoving liquidity...");
|
||||||
|
var removeResult = await _dex.Liquidity.RemoveLiquidityAsync(new RemoveLiquidityRequest
|
||||||
|
{
|
||||||
|
PoolId = "ETH-USDC",
|
||||||
|
LpTokens = addResult.LpTokensReceived,
|
||||||
|
SlippageTolerance = 0.5m
|
||||||
|
});
|
||||||
|
|
||||||
|
Console.WriteLine($"Liquidity removed:");
|
||||||
|
Console.WriteLine($" Amount A: {removeResult.AmountA:F4} ETH");
|
||||||
|
Console.WriteLine($" Amount B: {removeResult.AmountB:F2} USDC");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunPortfolioExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Portfolio Management ===");
|
||||||
|
|
||||||
|
// Get portfolio summary
|
||||||
|
var portfolio = await _dex.Portfolio.GetSummaryAsync();
|
||||||
|
Console.WriteLine("Portfolio summary:");
|
||||||
|
Console.WriteLine($" Total value: ${portfolio.TotalValue:N2}");
|
||||||
|
Console.WriteLine($" Available: ${portfolio.AvailableBalance:N2}");
|
||||||
|
Console.WriteLine($" In orders: ${portfolio.InOrders:N2}");
|
||||||
|
Console.WriteLine($" In positions: ${portfolio.InPositions:N2}");
|
||||||
|
Console.WriteLine($" Unrealized PnL: ${portfolio.UnrealizedPnl:N2}");
|
||||||
|
|
||||||
|
// Get asset allocation
|
||||||
|
Console.WriteLine("\nAsset allocation:");
|
||||||
|
foreach (var allocation in portfolio.Allocations)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {allocation.Asset}: {allocation.Percentage:F1}% (${allocation.Value:N2})");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get trade history
|
||||||
|
var tradeHistory = await _dex.Portfolio.GetTradeHistoryAsync(new TradeHistoryFilter
|
||||||
|
{
|
||||||
|
Limit = 10
|
||||||
|
});
|
||||||
|
Console.WriteLine($"\nRecent trades: {tradeHistory.Count}");
|
||||||
|
foreach (var trade in tradeHistory)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {trade.Timestamp}: {trade.Side} {trade.Quantity:F4} {trade.Symbol} @ ${trade.Price:F2}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get PnL report
|
||||||
|
var pnlReport = await _dex.Portfolio.GetPnlReportAsync(Period.Month);
|
||||||
|
Console.WriteLine($"\nMonthly PnL report:");
|
||||||
|
Console.WriteLine($" Realized PnL: ${pnlReport.RealizedPnl:N2}");
|
||||||
|
Console.WriteLine($" Unrealized PnL: ${pnlReport.UnrealizedPnl:N2}");
|
||||||
|
Console.WriteLine($" Total fees: ${pnlReport.TotalFees:N2}");
|
||||||
|
Console.WriteLine($" Net profit: ${pnlReport.NetProfit:N2}");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task Main(string[] args)
|
||||||
|
{
|
||||||
|
// Initialize client
|
||||||
|
var apiKey = Environment.GetEnvironmentVariable("SYNOR_API_KEY") ?? "your-api-key";
|
||||||
|
var config = new DexConfig
|
||||||
|
{
|
||||||
|
ApiKey = apiKey,
|
||||||
|
Endpoint = "https://dex.synor.io/v1",
|
||||||
|
Timeout = TimeSpan.FromSeconds(30),
|
||||||
|
Retries = 3,
|
||||||
|
Debug = false
|
||||||
|
};
|
||||||
|
|
||||||
|
var dex = new SynorDex(config);
|
||||||
|
var example = new DexExample(dex);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Check service health
|
||||||
|
var healthy = await dex.HealthCheckAsync();
|
||||||
|
Console.WriteLine($"Service healthy: {healthy}\n");
|
||||||
|
|
||||||
|
// Run examples
|
||||||
|
await example.RunMarketsExample();
|
||||||
|
await example.RunSpotTradingExample();
|
||||||
|
await example.RunPerpsExample();
|
||||||
|
await example.RunLiquidityExample();
|
||||||
|
await example.RunPortfolioExample();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"Error: {ex.Message}");
|
||||||
|
Environment.Exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
326
sdk/csharp/examples/IbcExample.cs
Normal file
326
sdk/csharp/examples/IbcExample.cs
Normal file
|
|
@ -0,0 +1,326 @@
|
||||||
|
/**
|
||||||
|
* Synor IBC SDK Examples for C#
|
||||||
|
*
|
||||||
|
* Demonstrates Inter-Blockchain Communication operations:
|
||||||
|
* - Chain and channel management
|
||||||
|
* - Cross-chain token transfers
|
||||||
|
* - Packet lifecycle handling
|
||||||
|
* - Relayer operations
|
||||||
|
* - Connection monitoring
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Synor.Ibc;
|
||||||
|
|
||||||
|
namespace Synor.Examples;
|
||||||
|
|
||||||
|
public class IbcExample
|
||||||
|
{
|
||||||
|
private readonly SynorIbc _ibc;
|
||||||
|
|
||||||
|
public IbcExample(SynorIbc ibc)
|
||||||
|
{
|
||||||
|
_ibc = ibc;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunChainsExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Chain Information ===");
|
||||||
|
|
||||||
|
// List connected chains
|
||||||
|
var chains = await _ibc.Chains.ListAsync();
|
||||||
|
Console.WriteLine($"Connected chains: {chains.Count}");
|
||||||
|
foreach (var chain in chains.GetRange(0, Math.Min(chains.Count, 5)))
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {chain.ChainId}: {chain.Name} ({chain.Status})");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get specific chain info
|
||||||
|
var cosmosHub = await _ibc.Chains.GetAsync("cosmoshub-4");
|
||||||
|
Console.WriteLine($"\n{cosmosHub.Name}:");
|
||||||
|
Console.WriteLine($" Chain ID: {cosmosHub.ChainId}");
|
||||||
|
Console.WriteLine($" RPC endpoint: {cosmosHub.RpcEndpoint}");
|
||||||
|
Console.WriteLine($" Block height: {cosmosHub.LatestHeight}");
|
||||||
|
Console.WriteLine($" Active channels: {cosmosHub.ActiveChannels}");
|
||||||
|
|
||||||
|
// Get chain clients
|
||||||
|
var clients = await _ibc.Chains.GetClientsAsync("cosmoshub-4");
|
||||||
|
Console.WriteLine($"\nIBC clients: {clients.Count}");
|
||||||
|
foreach (var client in clients.GetRange(0, Math.Min(clients.Count, 3)))
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {client.ClientId}: {client.ChainId} ({client.ClientType})");
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunChannelsExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Channel Management ===");
|
||||||
|
|
||||||
|
// List channels
|
||||||
|
var channels = await _ibc.Channels.ListAsync();
|
||||||
|
Console.WriteLine($"IBC channels: {channels.Count}");
|
||||||
|
foreach (var channel in channels.GetRange(0, Math.Min(channels.Count, 5)))
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {channel.ChannelId}: {channel.SourceChain} <-> {channel.DestChain} ({channel.State})");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get channel details
|
||||||
|
var channelId = "channel-0";
|
||||||
|
var channel = await _ibc.Channels.GetAsync(channelId);
|
||||||
|
Console.WriteLine($"\nChannel {channelId}:");
|
||||||
|
Console.WriteLine($" State: {channel.State}");
|
||||||
|
Console.WriteLine($" Port: {channel.PortId}");
|
||||||
|
Console.WriteLine($" Counterparty: {channel.CounterpartyChannelId}");
|
||||||
|
Console.WriteLine($" Connection: {channel.ConnectionId}");
|
||||||
|
Console.WriteLine($" Ordering: {channel.Ordering}");
|
||||||
|
Console.WriteLine($" Version: {channel.Version}");
|
||||||
|
|
||||||
|
// Create a new channel (4-step handshake)
|
||||||
|
Console.WriteLine("\nInitiating channel creation...");
|
||||||
|
var initResult = await _ibc.Channels.InitAsync(new ChannelInitRequest
|
||||||
|
{
|
||||||
|
SourceChain = "synor-mainnet",
|
||||||
|
DestChain = "osmosis-1",
|
||||||
|
PortId = "transfer",
|
||||||
|
Version = "ics20-1"
|
||||||
|
});
|
||||||
|
Console.WriteLine($" ChanOpenInit sent: {initResult.ChannelId}");
|
||||||
|
|
||||||
|
// In production, the following steps happen through relayers:
|
||||||
|
// ChanOpenTry -> ChanOpenAck -> ChanOpenConfirm
|
||||||
|
|
||||||
|
// Get channel statistics
|
||||||
|
var stats = await _ibc.Channels.GetStatsAsync(channelId);
|
||||||
|
Console.WriteLine($"\nChannel statistics:");
|
||||||
|
Console.WriteLine($" Packets sent: {stats.PacketsSent}");
|
||||||
|
Console.WriteLine($" Packets received: {stats.PacketsReceived}");
|
||||||
|
Console.WriteLine($" Packets acknowledged: {stats.PacketsAcknowledged}");
|
||||||
|
Console.WriteLine($" Packets timed out: {stats.PacketsTimedOut}");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunTransferExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Cross-Chain Transfers ===");
|
||||||
|
|
||||||
|
// Get transfer routes
|
||||||
|
Console.WriteLine("Available transfer routes:");
|
||||||
|
var routes = await _ibc.Transfers.GetRoutesAsync("ATOM", "synor-mainnet");
|
||||||
|
foreach (var route in routes)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {route.SourceChain} -> {route.DestChain}: {route.ChannelId}");
|
||||||
|
Console.WriteLine($" Estimated time: {route.EstimatedTime}");
|
||||||
|
Console.WriteLine($" Fee: {route.Fee} {route.FeeAsset}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initiate a transfer
|
||||||
|
Console.WriteLine("\nInitiating transfer...");
|
||||||
|
var transfer = await _ibc.Transfers.SendAsync(new TransferRequest
|
||||||
|
{
|
||||||
|
SourceChain = "cosmoshub-4",
|
||||||
|
DestChain = "synor-mainnet",
|
||||||
|
ChannelId = "channel-0",
|
||||||
|
Asset = "uatom",
|
||||||
|
Amount = "1000000", // 1 ATOM
|
||||||
|
Sender = "cosmos1abc...",
|
||||||
|
Receiver = "synor1xyz...",
|
||||||
|
Timeout = TimeSpan.FromMinutes(30),
|
||||||
|
Memo = "IBC transfer test"
|
||||||
|
});
|
||||||
|
|
||||||
|
Console.WriteLine($"Transfer initiated:");
|
||||||
|
Console.WriteLine($" Transfer ID: {transfer.TransferId}");
|
||||||
|
Console.WriteLine($" Sequence: {transfer.Sequence}");
|
||||||
|
Console.WriteLine($" Status: {transfer.Status}");
|
||||||
|
|
||||||
|
// Track transfer status
|
||||||
|
Console.WriteLine("\nTracking transfer...");
|
||||||
|
var status = await _ibc.Transfers.GetStatusAsync(transfer.TransferId);
|
||||||
|
Console.WriteLine($" Current status: {status.Status}");
|
||||||
|
Console.WriteLine($" Source tx: {status.SourceTxHash}");
|
||||||
|
if (!string.IsNullOrEmpty(status.DestTxHash))
|
||||||
|
{
|
||||||
|
Console.WriteLine($" Dest tx: {status.DestTxHash}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get transfer history
|
||||||
|
var history = await _ibc.Transfers.GetHistoryAsync(new TransferHistoryFilter
|
||||||
|
{
|
||||||
|
Limit = 5
|
||||||
|
});
|
||||||
|
Console.WriteLine($"\nRecent transfers: {history.Count}");
|
||||||
|
foreach (var tx in history)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {tx.TransferId}: {tx.Amount} {tx.Asset} ({tx.Status})");
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunPacketExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Packet Handling ===");
|
||||||
|
|
||||||
|
// Get pending packets
|
||||||
|
var pendingPackets = await _ibc.Packets.GetPendingAsync("channel-0");
|
||||||
|
Console.WriteLine($"Pending packets: {pendingPackets.Count}");
|
||||||
|
foreach (var packet in pendingPackets.GetRange(0, Math.Min(pendingPackets.Count, 5)))
|
||||||
|
{
|
||||||
|
Console.WriteLine($" Seq {packet.Sequence}: {packet.SourcePort} -> {packet.DestPort}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get packet details
|
||||||
|
if (pendingPackets.Count > 0)
|
||||||
|
{
|
||||||
|
var packet = await _ibc.Packets.GetAsync("channel-0", pendingPackets[0].Sequence);
|
||||||
|
Console.WriteLine($"\nPacket {packet.Sequence}:");
|
||||||
|
Console.WriteLine($" Source: {packet.SourcePort}/{packet.SourceChannel}");
|
||||||
|
Console.WriteLine($" Dest: {packet.DestPort}/{packet.DestChannel}");
|
||||||
|
Console.WriteLine($" Timeout height: {packet.TimeoutHeight}");
|
||||||
|
Console.WriteLine($" Timeout timestamp: {packet.TimeoutTimestamp}");
|
||||||
|
Console.WriteLine($" Data: {Convert.ToHexString(packet.Data)[..Math.Min(packet.Data.Length * 2, 64)]}...");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query packet commitments
|
||||||
|
var commitments = await _ibc.Packets.GetCommitmentsAsync("channel-0");
|
||||||
|
Console.WriteLine($"\nPacket commitments: {commitments.Count}");
|
||||||
|
|
||||||
|
// Query unreceived packets
|
||||||
|
var unreceived = await _ibc.Packets.GetUnreceivedAsync("channel-0", new ulong[] { 1, 2, 3, 4, 5 });
|
||||||
|
Console.WriteLine($"Unreceived packets: {string.Join(", ", unreceived)}");
|
||||||
|
|
||||||
|
// Query acknowledgements
|
||||||
|
var acks = await _ibc.Packets.GetAcknowledgementsAsync("channel-0");
|
||||||
|
Console.WriteLine($"Packet acknowledgements: {acks.Count}");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunRelayerExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Relayer Operations ===");
|
||||||
|
|
||||||
|
// Get relayer status
|
||||||
|
var relayers = await _ibc.Relayer.ListAsync();
|
||||||
|
Console.WriteLine($"Active relayers: {relayers.Count}");
|
||||||
|
foreach (var relayer in relayers.GetRange(0, Math.Min(relayers.Count, 3)))
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {relayer.Address}: {relayer.PacketsRelayed} packets ({relayer.Status})");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Register as a relayer
|
||||||
|
Console.WriteLine("\nRegistering as relayer...");
|
||||||
|
var registration = await _ibc.Relayer.RegisterAsync(new RelayerRegistration
|
||||||
|
{
|
||||||
|
Address = "synor1relayer...",
|
||||||
|
Chains = new List<string> { "synor-mainnet", "cosmoshub-4", "osmosis-1" },
|
||||||
|
Commission = 0.1m // 0.1%
|
||||||
|
});
|
||||||
|
Console.WriteLine($" Registered: {registration.RelayerId}");
|
||||||
|
|
||||||
|
// Start relaying
|
||||||
|
Console.WriteLine("\nStarting packet relay...");
|
||||||
|
var relayConfig = new RelayConfig
|
||||||
|
{
|
||||||
|
Channels = new List<string> { "channel-0", "channel-1" },
|
||||||
|
BatchSize = 10,
|
||||||
|
PollInterval = TimeSpan.FromSeconds(5)
|
||||||
|
};
|
||||||
|
|
||||||
|
// In production, this would run continuously
|
||||||
|
var pendingCount = await _ibc.Relayer.GetPendingCountAsync(relayConfig.Channels);
|
||||||
|
Console.WriteLine($" Pending packets to relay: {pendingCount}");
|
||||||
|
|
||||||
|
// Relay a batch
|
||||||
|
var relayResult = await _ibc.Relayer.RelayBatchAsync("channel-0", 5);
|
||||||
|
Console.WriteLine($" Relayed: {relayResult.PacketsRelayed}");
|
||||||
|
Console.WriteLine($" Fees earned: {relayResult.FeesEarned}");
|
||||||
|
|
||||||
|
// Get relayer earnings
|
||||||
|
var earnings = await _ibc.Relayer.GetEarningsAsync("synor1relayer...");
|
||||||
|
Console.WriteLine($"\nRelayer earnings:");
|
||||||
|
Console.WriteLine($" Total earned: {earnings.TotalEarned}");
|
||||||
|
Console.WriteLine($" Packets relayed: {earnings.PacketsRelayed}");
|
||||||
|
Console.WriteLine($" Success rate: {earnings.SuccessRate:F1}%");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunMonitoringExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Connection Monitoring ===");
|
||||||
|
|
||||||
|
// Get connection health
|
||||||
|
var connections = await _ibc.Monitoring.GetConnectionsAsync();
|
||||||
|
Console.WriteLine("Connection health:");
|
||||||
|
foreach (var conn in connections)
|
||||||
|
{
|
||||||
|
var healthIcon = conn.Healthy ? "✓" : "✗";
|
||||||
|
Console.WriteLine($" [{healthIcon}] {conn.ConnectionId}: {conn.ChainA} <-> {conn.ChainB}");
|
||||||
|
Console.WriteLine($" Latency: {conn.Latency}ms, Uptime: {conn.Uptime:F1}%");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get channel metrics
|
||||||
|
var metrics = await _ibc.Monitoring.GetChannelMetricsAsync("channel-0");
|
||||||
|
Console.WriteLine($"\nChannel metrics:");
|
||||||
|
Console.WriteLine($" Throughput: {metrics.PacketsPerHour}/hour");
|
||||||
|
Console.WriteLine($" Avg latency: {metrics.AvgLatencyMs}ms");
|
||||||
|
Console.WriteLine($" Success rate: {metrics.SuccessRate:F1}%");
|
||||||
|
Console.WriteLine($" Volume 24h: {metrics.Volume24h}");
|
||||||
|
|
||||||
|
// Subscribe to events (in production)
|
||||||
|
Console.WriteLine("\nEvent subscription example:");
|
||||||
|
Console.WriteLine(" Subscribing to packet events...");
|
||||||
|
// await _ibc.Monitoring.SubscribeAsync("channel-0", (evt) => {
|
||||||
|
// Console.WriteLine($" Event: {evt.Type} - {evt.Data}");
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Get alerts
|
||||||
|
var alerts = await _ibc.Monitoring.GetAlertsAsync();
|
||||||
|
Console.WriteLine($"\nActive alerts: {alerts.Count}");
|
||||||
|
foreach (var alert in alerts)
|
||||||
|
{
|
||||||
|
Console.WriteLine($" [{alert.Severity}] {alert.Message}");
|
||||||
|
Console.WriteLine($" Channel: {alert.ChannelId}, Time: {alert.Timestamp}");
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task Main(string[] args)
|
||||||
|
{
|
||||||
|
// Initialize client
|
||||||
|
var apiKey = Environment.GetEnvironmentVariable("SYNOR_API_KEY") ?? "your-api-key";
|
||||||
|
var config = new IbcConfig
|
||||||
|
{
|
||||||
|
ApiKey = apiKey,
|
||||||
|
Endpoint = "https://ibc.synor.io/v1",
|
||||||
|
Timeout = TimeSpan.FromSeconds(60),
|
||||||
|
Retries = 3,
|
||||||
|
Debug = false,
|
||||||
|
DefaultTimeout = TimeSpan.FromMinutes(30)
|
||||||
|
};
|
||||||
|
|
||||||
|
var ibc = new SynorIbc(config);
|
||||||
|
var example = new IbcExample(ibc);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Check service health
|
||||||
|
var healthy = await ibc.HealthCheckAsync();
|
||||||
|
Console.WriteLine($"Service healthy: {healthy}\n");
|
||||||
|
|
||||||
|
// Run examples
|
||||||
|
await example.RunChainsExample();
|
||||||
|
await example.RunChannelsExample();
|
||||||
|
await example.RunTransferExample();
|
||||||
|
await example.RunPacketExample();
|
||||||
|
await example.RunRelayerExample();
|
||||||
|
await example.RunMonitoringExample();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"Error: {ex.Message}");
|
||||||
|
Environment.Exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
399
sdk/csharp/examples/ZkExample.cs
Normal file
399
sdk/csharp/examples/ZkExample.cs
Normal file
|
|
@ -0,0 +1,399 @@
|
||||||
|
/**
|
||||||
|
* Synor ZK SDK Examples for C#
|
||||||
|
*
|
||||||
|
* Demonstrates zero-knowledge proof operations:
|
||||||
|
* - Circuit compilation (Circom)
|
||||||
|
* - Proof generation and verification
|
||||||
|
* - Multiple proving systems (Groth16, PLONK, STARK)
|
||||||
|
* - Recursive proof composition
|
||||||
|
* - Trusted setup ceremonies
|
||||||
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Synor.Zk;
|
||||||
|
|
||||||
|
namespace Synor.Examples;
|
||||||
|
|
||||||
|
public class ZkExample
|
||||||
|
{
|
||||||
|
private readonly SynorZk _zk;
|
||||||
|
|
||||||
|
public ZkExample(SynorZk zk)
|
||||||
|
{
|
||||||
|
_zk = zk;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunCircuitExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Circuit Compilation ===");
|
||||||
|
|
||||||
|
// Simple Circom circuit: prove knowledge of factors
|
||||||
|
var circomCode = @"
|
||||||
|
pragma circom 2.1.0;
|
||||||
|
|
||||||
|
template Multiplier() {
|
||||||
|
signal input a;
|
||||||
|
signal input b;
|
||||||
|
signal output c;
|
||||||
|
|
||||||
|
c <== a * b;
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Multiplier();
|
||||||
|
";
|
||||||
|
|
||||||
|
// Compile the circuit
|
||||||
|
Console.WriteLine("Compiling circuit...");
|
||||||
|
var circuit = await _zk.Circuits.CompileAsync(new CompileRequest
|
||||||
|
{
|
||||||
|
Code = circomCode,
|
||||||
|
Language = CircuitLanguage.Circom
|
||||||
|
});
|
||||||
|
|
||||||
|
Console.WriteLine("Circuit compiled:");
|
||||||
|
Console.WriteLine($" Circuit ID: {circuit.CircuitId}");
|
||||||
|
Console.WriteLine($" Constraints: {circuit.Constraints}");
|
||||||
|
Console.WriteLine($" Public inputs: {circuit.PublicInputs}");
|
||||||
|
Console.WriteLine($" Private inputs: {circuit.PrivateInputs}");
|
||||||
|
Console.WriteLine($" Outputs: {circuit.Outputs}");
|
||||||
|
|
||||||
|
// Get circuit info
|
||||||
|
var info = await _zk.Circuits.GetAsync(circuit.CircuitId);
|
||||||
|
Console.WriteLine("\nCircuit info:");
|
||||||
|
Console.WriteLine($" Name: {info.Name}");
|
||||||
|
Console.WriteLine($" Version: {info.Version}");
|
||||||
|
Console.WriteLine($" Wires: {info.WireCount}");
|
||||||
|
Console.WriteLine($" Labels: {info.LabelCount}");
|
||||||
|
|
||||||
|
// List available circuits
|
||||||
|
var circuits = await _zk.Circuits.ListAsync();
|
||||||
|
Console.WriteLine($"\nAvailable circuits: {circuits.Count}");
|
||||||
|
foreach (var c in circuits.GetRange(0, Math.Min(circuits.Count, 3)))
|
||||||
|
{
|
||||||
|
Console.WriteLine($" {c.CircuitId}: {c.Name} ({c.Constraints} constraints)");
|
||||||
|
}
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunGroth16Example()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Groth16 Proving System ===");
|
||||||
|
|
||||||
|
var circuitId = "multiplier-v1";
|
||||||
|
|
||||||
|
// Generate proving/verification keys (trusted setup)
|
||||||
|
Console.WriteLine("Generating keys...");
|
||||||
|
var keys = await _zk.Groth16.SetupAsync(circuitId);
|
||||||
|
Console.WriteLine("Keys generated:");
|
||||||
|
Console.WriteLine($" Proving key size: {keys.ProvingKey.Length} bytes");
|
||||||
|
Console.WriteLine($" Verification key size: {keys.VerificationKey.Length} bytes");
|
||||||
|
|
||||||
|
// Prepare witness (private inputs)
|
||||||
|
var witness = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
["a"] = "3",
|
||||||
|
["b"] = "7"
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate proof
|
||||||
|
Console.WriteLine("\nGenerating proof...");
|
||||||
|
var proof = await _zk.Groth16.ProveAsync(new ProveRequest
|
||||||
|
{
|
||||||
|
CircuitId = circuitId,
|
||||||
|
Witness = witness,
|
||||||
|
ProvingKey = keys.ProvingKey
|
||||||
|
});
|
||||||
|
|
||||||
|
Console.WriteLine("Proof generated:");
|
||||||
|
Console.WriteLine($" Proof size: {proof.ProofBytes.Length} bytes");
|
||||||
|
Console.WriteLine($" Public signals: {proof.PublicSignals.Count}");
|
||||||
|
Console.WriteLine($" Proving time: {proof.ProvingTimeMs}ms");
|
||||||
|
|
||||||
|
// Verify proof
|
||||||
|
Console.WriteLine("\nVerifying proof...");
|
||||||
|
var verified = await _zk.Groth16.VerifyAsync(new VerifyRequest
|
||||||
|
{
|
||||||
|
Proof = proof.ProofBytes,
|
||||||
|
PublicSignals = proof.PublicSignals,
|
||||||
|
VerificationKey = keys.VerificationKey
|
||||||
|
});
|
||||||
|
|
||||||
|
Console.WriteLine($"Verification result: {verified}");
|
||||||
|
|
||||||
|
// Export proof for on-chain verification
|
||||||
|
var solidityCalldata = await _zk.Groth16.ExportCalldataAsync(proof);
|
||||||
|
Console.WriteLine($"\nSolidity calldata: {solidityCalldata[..Math.Min(solidityCalldata.Length, 100)]}...");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunPlonkExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== PLONK Proving System ===");
|
||||||
|
|
||||||
|
var circuitId = "multiplier-v1";
|
||||||
|
|
||||||
|
// PLONK uses universal trusted setup
|
||||||
|
Console.WriteLine("Getting universal setup...");
|
||||||
|
var srs = await _zk.Plonk.GetUniversalSetupAsync(14); // 2^14 constraints
|
||||||
|
Console.WriteLine($"SRS loaded: {srs.Length} bytes");
|
||||||
|
|
||||||
|
// Generate circuit-specific keys
|
||||||
|
Console.WriteLine("\nGenerating circuit keys...");
|
||||||
|
var keys = await _zk.Plonk.SetupAsync(circuitId, srs);
|
||||||
|
Console.WriteLine("Keys generated");
|
||||||
|
|
||||||
|
// Generate proof
|
||||||
|
var witness = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
["a"] = "5",
|
||||||
|
["b"] = "9"
|
||||||
|
};
|
||||||
|
|
||||||
|
Console.WriteLine("\nGenerating PLONK proof...");
|
||||||
|
var proof = await _zk.Plonk.ProveAsync(new ProveRequest
|
||||||
|
{
|
||||||
|
CircuitId = circuitId,
|
||||||
|
Witness = witness,
|
||||||
|
ProvingKey = keys.ProvingKey
|
||||||
|
});
|
||||||
|
|
||||||
|
Console.WriteLine("Proof generated:");
|
||||||
|
Console.WriteLine($" Proof size: {proof.ProofBytes.Length} bytes");
|
||||||
|
Console.WriteLine($" Proving time: {proof.ProvingTimeMs}ms");
|
||||||
|
|
||||||
|
// Verify proof
|
||||||
|
var verified = await _zk.Plonk.VerifyAsync(new VerifyRequest
|
||||||
|
{
|
||||||
|
Proof = proof.ProofBytes,
|
||||||
|
PublicSignals = proof.PublicSignals,
|
||||||
|
VerificationKey = keys.VerificationKey
|
||||||
|
});
|
||||||
|
Console.WriteLine($"Verification result: {verified}");
|
||||||
|
|
||||||
|
// Compare with Groth16
|
||||||
|
Console.WriteLine("\nPLONK advantages:");
|
||||||
|
Console.WriteLine(" - Universal trusted setup");
|
||||||
|
Console.WriteLine(" - Larger proofs (~2.5 KB vs ~200 bytes)");
|
||||||
|
Console.WriteLine(" - Faster proving for some circuits");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunStarkExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== STARK Proving System ===");
|
||||||
|
|
||||||
|
var circuitId = "multiplier-v1";
|
||||||
|
|
||||||
|
// STARKs don't need trusted setup
|
||||||
|
Console.WriteLine("Configuring STARK parameters...");
|
||||||
|
var config = new StarkConfig
|
||||||
|
{
|
||||||
|
FieldSize = 256,
|
||||||
|
HashFunction = HashFunction.Poseidon,
|
||||||
|
BlowupFactor = 8,
|
||||||
|
NumQueries = 30,
|
||||||
|
FoldingFactor = 8
|
||||||
|
};
|
||||||
|
|
||||||
|
// Generate proof
|
||||||
|
var witness = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
["a"] = "11",
|
||||||
|
["b"] = "13"
|
||||||
|
};
|
||||||
|
|
||||||
|
Console.WriteLine("\nGenerating STARK proof...");
|
||||||
|
var proof = await _zk.Stark.ProveAsync(new StarkProveRequest
|
||||||
|
{
|
||||||
|
CircuitId = circuitId,
|
||||||
|
Witness = witness,
|
||||||
|
Config = config
|
||||||
|
});
|
||||||
|
|
||||||
|
Console.WriteLine("Proof generated:");
|
||||||
|
Console.WriteLine($" Proof size: {proof.ProofBytes.Length} bytes");
|
||||||
|
Console.WriteLine($" Proving time: {proof.ProvingTimeMs}ms");
|
||||||
|
Console.WriteLine($" FRI layers: {proof.FriLayers}");
|
||||||
|
|
||||||
|
// Verify proof
|
||||||
|
Console.WriteLine("\nVerifying STARK proof...");
|
||||||
|
var verified = await _zk.Stark.VerifyAsync(new StarkVerifyRequest
|
||||||
|
{
|
||||||
|
Proof = proof.ProofBytes,
|
||||||
|
PublicSignals = proof.PublicSignals,
|
||||||
|
Config = config
|
||||||
|
});
|
||||||
|
|
||||||
|
Console.WriteLine($"Verification result: {verified}");
|
||||||
|
|
||||||
|
// Compare with SNARKs
|
||||||
|
Console.WriteLine("\nSTARK advantages:");
|
||||||
|
Console.WriteLine(" - No trusted setup needed");
|
||||||
|
Console.WriteLine(" - Post-quantum secure");
|
||||||
|
Console.WriteLine(" - Larger proofs (~100 KB)");
|
||||||
|
Console.WriteLine(" - Faster proving for complex computations");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunRecursiveExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Recursive Proof Composition ===");
|
||||||
|
|
||||||
|
// Create inner proofs
|
||||||
|
Console.WriteLine("Generating inner proofs...");
|
||||||
|
var innerProofs = new List<RecursiveProof>();
|
||||||
|
|
||||||
|
for (var i = 1; i <= 3; i++)
|
||||||
|
{
|
||||||
|
var witness = new Dictionary<string, string>
|
||||||
|
{
|
||||||
|
["a"] = i.ToString(),
|
||||||
|
["b"] = (i + 1).ToString()
|
||||||
|
};
|
||||||
|
|
||||||
|
var proof = await _zk.Recursive.ProveInnerAsync(new RecursiveProveRequest
|
||||||
|
{
|
||||||
|
CircuitId = "multiplier-v1",
|
||||||
|
Witness = witness,
|
||||||
|
Level = 0
|
||||||
|
});
|
||||||
|
innerProofs.Add(proof);
|
||||||
|
Console.WriteLine($" Inner proof {i} generated");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Aggregate proofs recursively
|
||||||
|
Console.WriteLine("\nAggregating proofs...");
|
||||||
|
var aggregatedProof = await _zk.Recursive.AggregateAsync(new AggregateRequest
|
||||||
|
{
|
||||||
|
Proofs = innerProofs,
|
||||||
|
AggregationCircuit = "recursive-aggregator-v1"
|
||||||
|
});
|
||||||
|
|
||||||
|
Console.WriteLine("Aggregated proof:");
|
||||||
|
Console.WriteLine($" Proof size: {aggregatedProof.ProofBytes.Length} bytes");
|
||||||
|
Console.WriteLine($" Proofs aggregated: {aggregatedProof.ProofsAggregated}");
|
||||||
|
Console.WriteLine($" Recursion depth: {aggregatedProof.RecursionDepth}");
|
||||||
|
|
||||||
|
// Verify aggregated proof (verifies all inner proofs at once)
|
||||||
|
Console.WriteLine("\nVerifying aggregated proof...");
|
||||||
|
var verified = await _zk.Recursive.VerifyAggregatedAsync(aggregatedProof);
|
||||||
|
Console.WriteLine($"Verification result: {verified}");
|
||||||
|
|
||||||
|
// Use cases
|
||||||
|
Console.WriteLine("\nRecursive proof use cases:");
|
||||||
|
Console.WriteLine(" - Rollup batch verification");
|
||||||
|
Console.WriteLine(" - Incremental computation proofs");
|
||||||
|
Console.WriteLine(" - Cross-chain state proofs");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task RunCeremonyExample()
|
||||||
|
{
|
||||||
|
Console.WriteLine("=== Trusted Setup Ceremony ===");
|
||||||
|
|
||||||
|
// List active ceremonies
|
||||||
|
var ceremonies = await _zk.Ceremony.ListAsync(CeremonyStatus.Active);
|
||||||
|
Console.WriteLine($"Active ceremonies: {ceremonies.Count}");
|
||||||
|
|
||||||
|
foreach (var ceremony in ceremonies.GetRange(0, Math.Min(ceremonies.Count, 3)))
|
||||||
|
{
|
||||||
|
Console.WriteLine($"\n {ceremony.CeremonyId}:");
|
||||||
|
Console.WriteLine($" Circuit: {ceremony.CircuitId}");
|
||||||
|
Console.WriteLine($" Participants: {ceremony.ParticipantCount}");
|
||||||
|
Console.WriteLine($" Current round: {ceremony.CurrentRound}");
|
||||||
|
Console.WriteLine($" Status: {ceremony.Status}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new ceremony
|
||||||
|
Console.WriteLine("\nCreating new ceremony...");
|
||||||
|
var newCeremony = await _zk.Ceremony.CreateAsync(new CreateCeremonyRequest
|
||||||
|
{
|
||||||
|
CircuitId = "new-circuit-v1",
|
||||||
|
MinParticipants = 10,
|
||||||
|
MaxParticipants = 100,
|
||||||
|
RoundDuration = 3600, // 1 hour per round
|
||||||
|
VerifyContributions = true
|
||||||
|
});
|
||||||
|
|
||||||
|
Console.WriteLine("Ceremony created:");
|
||||||
|
Console.WriteLine($" Ceremony ID: {newCeremony.CeremonyId}");
|
||||||
|
Console.WriteLine($" Join URL: {newCeremony.JoinUrl}");
|
||||||
|
|
||||||
|
// Participate in a ceremony
|
||||||
|
Console.WriteLine("\nParticipating in ceremony...");
|
||||||
|
|
||||||
|
// Generate entropy
|
||||||
|
var entropy = new byte[32];
|
||||||
|
using (var rng = RandomNumberGenerator.Create())
|
||||||
|
{
|
||||||
|
rng.GetBytes(entropy);
|
||||||
|
}
|
||||||
|
|
||||||
|
var contribution = await _zk.Ceremony.ContributeAsync(new ContributeRequest
|
||||||
|
{
|
||||||
|
CeremonyId = newCeremony.CeremonyId,
|
||||||
|
Entropy = entropy
|
||||||
|
});
|
||||||
|
|
||||||
|
Console.WriteLine("Contribution made:");
|
||||||
|
Console.WriteLine($" Contribution ID: {contribution.ContributionId}");
|
||||||
|
Console.WriteLine($" Position: {contribution.Position}");
|
||||||
|
Console.WriteLine($" Hash: {contribution.Hash}");
|
||||||
|
|
||||||
|
// Verify a contribution
|
||||||
|
Console.WriteLine("\nVerifying contribution...");
|
||||||
|
var valid = await _zk.Ceremony.VerifyContributionAsync(contribution.ContributionId);
|
||||||
|
Console.WriteLine($"Contribution valid: {valid}");
|
||||||
|
|
||||||
|
// Get ceremony transcript (for auditability)
|
||||||
|
var transcript = await _zk.Ceremony.GetTranscriptAsync(newCeremony.CeremonyId);
|
||||||
|
Console.WriteLine("\nCeremony transcript:");
|
||||||
|
Console.WriteLine($" Total contributions: {transcript.Contributions.Count}");
|
||||||
|
Console.WriteLine($" Start time: {transcript.StartTime}");
|
||||||
|
Console.WriteLine($" Final hash: {(string.IsNullOrEmpty(transcript.FinalHash) ? "pending" : transcript.FinalHash)}");
|
||||||
|
Console.WriteLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task Main(string[] args)
|
||||||
|
{
|
||||||
|
// Initialize client
|
||||||
|
var apiKey = Environment.GetEnvironmentVariable("SYNOR_API_KEY") ?? "your-api-key";
|
||||||
|
var config = new ZkConfig
|
||||||
|
{
|
||||||
|
ApiKey = apiKey,
|
||||||
|
Endpoint = "https://zk.synor.io/v1",
|
||||||
|
Timeout = TimeSpan.FromSeconds(120), // ZK operations can be slow
|
||||||
|
Retries = 3,
|
||||||
|
Debug = false,
|
||||||
|
DefaultProvingSystem = ProvingSystem.Groth16,
|
||||||
|
ProveTimeout = TimeSpan.FromSeconds(300),
|
||||||
|
VerifyTimeout = TimeSpan.FromSeconds(30)
|
||||||
|
};
|
||||||
|
|
||||||
|
var zk = new SynorZk(config);
|
||||||
|
var example = new ZkExample(zk);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Check service health
|
||||||
|
var healthy = await zk.HealthCheckAsync();
|
||||||
|
Console.WriteLine($"Service healthy: {healthy}\n");
|
||||||
|
|
||||||
|
// Run examples
|
||||||
|
await example.RunCircuitExample();
|
||||||
|
await example.RunGroth16Example();
|
||||||
|
await example.RunPlonkExample();
|
||||||
|
await example.RunStarkExample();
|
||||||
|
await example.RunRecursiveExample();
|
||||||
|
await example.RunCeremonyExample();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"Error: {ex.Message}");
|
||||||
|
Environment.Exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
353
sdk/ruby/examples/compiler_example.rb
Normal file
353
sdk/ruby/examples/compiler_example.rb
Normal file
|
|
@ -0,0 +1,353 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
#
|
||||||
|
# Synor Compiler SDK Examples for Ruby
|
||||||
|
#
|
||||||
|
# Demonstrates smart contract compilation and analysis:
|
||||||
|
# - WASM contract compilation and optimization
|
||||||
|
# - ABI extraction and encoding
|
||||||
|
# - Contract analysis and security scanning
|
||||||
|
# - Validation and verification
|
||||||
|
#
|
||||||
|
|
||||||
|
require 'synor/compiler'
|
||||||
|
|
||||||
|
class CompilerExample
|
||||||
|
def initialize(compiler)
|
||||||
|
@compiler = compiler
|
||||||
|
end
|
||||||
|
|
||||||
|
# Creates a minimal valid WASM module for testing
|
||||||
|
def create_minimal_wasm
|
||||||
|
[
|
||||||
|
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, # "add"
|
||||||
|
# Code section
|
||||||
|
0x0a, 0x09, 0x01, 0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b
|
||||||
|
].pack('C*')
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_compile_contract_example
|
||||||
|
puts '=== Contract Compilation ==='
|
||||||
|
|
||||||
|
wasm = create_minimal_wasm
|
||||||
|
|
||||||
|
result = @compiler.compile(wasm,
|
||||||
|
optimization_level: :size,
|
||||||
|
use_wasm_opt: true,
|
||||||
|
validate: true,
|
||||||
|
extract_metadata: true,
|
||||||
|
generate_abi: true,
|
||||||
|
strip_options: {
|
||||||
|
strip_debug: true,
|
||||||
|
strip_producers: true,
|
||||||
|
strip_names: true,
|
||||||
|
strip_custom: true,
|
||||||
|
strip_unused: true,
|
||||||
|
preserve_sections: []
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
puts 'Compilation result:'
|
||||||
|
puts " Contract ID: #{result.contract_id}"
|
||||||
|
puts " Code hash: #{result.code_hash}"
|
||||||
|
puts " Original size: #{result.original_size} bytes"
|
||||||
|
puts " Optimized size: #{result.optimized_size} bytes"
|
||||||
|
puts " Size reduction: #{format('%.1f', result.size_reduction)}%"
|
||||||
|
puts " Estimated deploy gas: #{result.estimated_deploy_gas}"
|
||||||
|
|
||||||
|
if result.metadata
|
||||||
|
puts "\nMetadata:"
|
||||||
|
puts " Name: #{result.metadata.name}"
|
||||||
|
puts " Version: #{result.metadata.version}"
|
||||||
|
puts " SDK Version: #{result.metadata.sdk_version}"
|
||||||
|
end
|
||||||
|
|
||||||
|
if result.abi
|
||||||
|
puts "\nABI:"
|
||||||
|
puts " Functions: #{result.abi.functions.length}"
|
||||||
|
puts " Events: #{result.abi.events.length}"
|
||||||
|
puts " Errors: #{result.abi.errors.length}"
|
||||||
|
end
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_compilation_modes_example
|
||||||
|
puts '=== Compilation Modes ==='
|
||||||
|
|
||||||
|
wasm = create_minimal_wasm
|
||||||
|
|
||||||
|
# Development mode: fast compilation, debugging support
|
||||||
|
puts 'Development mode:'
|
||||||
|
dev_result = @compiler.contracts.compile_dev(wasm)
|
||||||
|
puts " Size: #{dev_result.optimized_size} bytes"
|
||||||
|
puts ' Optimization: none'
|
||||||
|
|
||||||
|
# Production mode: maximum optimization
|
||||||
|
puts "\nProduction mode:"
|
||||||
|
prod_result = @compiler.contracts.compile_production(wasm)
|
||||||
|
puts " Size: #{prod_result.optimized_size} bytes"
|
||||||
|
puts ' Optimization: aggressive'
|
||||||
|
puts " Size savings: #{dev_result.optimized_size - prod_result.optimized_size} bytes"
|
||||||
|
|
||||||
|
# Custom optimization levels
|
||||||
|
puts "\nOptimization levels:"
|
||||||
|
levels = [
|
||||||
|
{ level: :none, name: 'NONE' },
|
||||||
|
{ level: :basic, name: 'BASIC' },
|
||||||
|
{ level: :size, name: 'SIZE' },
|
||||||
|
{ level: :aggressive, name: 'AGGRESSIVE' }
|
||||||
|
]
|
||||||
|
|
||||||
|
levels.each do |l|
|
||||||
|
result = @compiler.compile(wasm, optimization_level: l[:level])
|
||||||
|
puts " #{l[:name]}: #{result.optimized_size} bytes"
|
||||||
|
end
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_abi_example
|
||||||
|
puts '=== ABI Operations ==='
|
||||||
|
|
||||||
|
wasm = create_minimal_wasm
|
||||||
|
|
||||||
|
# Extract ABI from WASM
|
||||||
|
abi = @compiler.abi.extract(wasm)
|
||||||
|
puts "Contract: #{abi.name}"
|
||||||
|
puts "Version: #{abi.version}"
|
||||||
|
|
||||||
|
# List functions
|
||||||
|
if abi.functions.any?
|
||||||
|
puts "\nFunctions:"
|
||||||
|
abi.functions.each do |func|
|
||||||
|
inputs = func.inputs.map { |p| "#{p.name}: #{p.type.type_name}" }.join(', ')
|
||||||
|
outputs = func.outputs.empty? ? 'void' : func.outputs.map { |o| o.type.type_name }.join(', ')
|
||||||
|
|
||||||
|
modifiers = []
|
||||||
|
modifiers << 'view' if func.view?
|
||||||
|
modifiers << 'payable' if func.payable?
|
||||||
|
modifier_str = modifiers.join(' ')
|
||||||
|
|
||||||
|
puts " #{func.name}(#{inputs}) -> #{outputs} #{modifier_str}"
|
||||||
|
puts " Selector: #{func.selector}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# List events
|
||||||
|
if abi.events.any?
|
||||||
|
puts "\nEvents:"
|
||||||
|
abi.events.each do |event|
|
||||||
|
params = event.params.map do |param|
|
||||||
|
prefix = param.indexed? ? 'indexed ' : ''
|
||||||
|
"#{prefix}#{param.name}: #{param.type.type_name}"
|
||||||
|
end.join(', ')
|
||||||
|
puts " #{event.name}(#{params})"
|
||||||
|
puts " Topic: #{event.topic}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Encode a function call
|
||||||
|
if abi.functions.any?
|
||||||
|
func = abi.functions.first
|
||||||
|
encoded = @compiler.abi.encode_call(func, %w[arg1 arg2])
|
||||||
|
puts "\nEncoded call to #{func.name}: #{encoded}"
|
||||||
|
|
||||||
|
# Decode a result
|
||||||
|
decoded = @compiler.abi.decode_result(func, encoded)
|
||||||
|
puts "Decoded result: #{decoded}"
|
||||||
|
end
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_analysis_example
|
||||||
|
puts '=== Contract Analysis ==='
|
||||||
|
|
||||||
|
wasm = create_minimal_wasm
|
||||||
|
|
||||||
|
# Full analysis
|
||||||
|
analysis = @compiler.analysis.analyze(wasm)
|
||||||
|
|
||||||
|
# Size breakdown
|
||||||
|
if analysis.size_breakdown
|
||||||
|
size = analysis.size_breakdown
|
||||||
|
puts 'Size breakdown:'
|
||||||
|
puts " Code: #{size.code} bytes"
|
||||||
|
puts " Data: #{size.data} bytes"
|
||||||
|
puts " Functions: #{size.functions} bytes"
|
||||||
|
puts " Memory: #{size.memory} bytes"
|
||||||
|
puts " Exports: #{size.exports} bytes"
|
||||||
|
puts " Imports: #{size.imports} bytes"
|
||||||
|
puts " Total: #{size.total} bytes"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Function analysis
|
||||||
|
if analysis.functions.any?
|
||||||
|
puts "\nFunction analysis:"
|
||||||
|
analysis.functions.first(5).each do |func|
|
||||||
|
puts " #{func.name}:"
|
||||||
|
puts " Size: #{func.size} bytes"
|
||||||
|
puts " Instructions: #{func.instruction_count}"
|
||||||
|
puts " Locals: #{func.local_count}"
|
||||||
|
puts " Exported: #{func.exported?}"
|
||||||
|
puts " Estimated gas: #{func.estimated_gas}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Import analysis
|
||||||
|
if analysis.imports.any?
|
||||||
|
puts "\nImports:"
|
||||||
|
analysis.imports.each do |imp|
|
||||||
|
puts " #{imp.module}.#{imp.name} (#{imp.kind})"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Gas analysis
|
||||||
|
if analysis.gas_analysis
|
||||||
|
gas = analysis.gas_analysis
|
||||||
|
puts "\nGas analysis:"
|
||||||
|
puts " Deployment: #{gas.deployment_gas}"
|
||||||
|
puts " Memory init: #{gas.memory_init_gas}"
|
||||||
|
puts " Data section: #{gas.data_section_gas}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Extract metadata
|
||||||
|
metadata = @compiler.analysis.extract_metadata(wasm)
|
||||||
|
puts "\nContract metadata:"
|
||||||
|
puts " Name: #{metadata.name}"
|
||||||
|
puts " Version: #{metadata.version}"
|
||||||
|
puts " Build timestamp: #{metadata.build_timestamp}"
|
||||||
|
|
||||||
|
# Estimate deployment gas
|
||||||
|
gas_estimate = @compiler.analysis.estimate_deploy_gas(wasm)
|
||||||
|
puts "\nEstimated deployment gas: #{gas_estimate}"
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_validation_example
|
||||||
|
puts '=== Contract Validation ==='
|
||||||
|
|
||||||
|
wasm = create_minimal_wasm
|
||||||
|
|
||||||
|
# Full validation
|
||||||
|
result = @compiler.validation.validate(wasm)
|
||||||
|
puts "Valid: #{result.valid?}"
|
||||||
|
puts "Exports: #{result.export_count}"
|
||||||
|
puts "Imports: #{result.import_count}"
|
||||||
|
puts "Functions: #{result.function_count}"
|
||||||
|
puts "Memory pages: #{result.memory_pages}"
|
||||||
|
|
||||||
|
if result.errors.any?
|
||||||
|
puts "\nValidation errors:"
|
||||||
|
result.errors.each do |error|
|
||||||
|
puts " [#{error.code}] #{error.message}"
|
||||||
|
puts " at #{error.location}" if error.location
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if result.warnings.any?
|
||||||
|
puts "\nWarnings:"
|
||||||
|
result.warnings.each do |warning|
|
||||||
|
puts " #{warning}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Quick validation
|
||||||
|
is_valid = @compiler.validation.valid?(wasm)
|
||||||
|
puts "\nQuick validation: #{is_valid}"
|
||||||
|
|
||||||
|
# Get validation errors only
|
||||||
|
errors = @compiler.validation.get_errors(wasm)
|
||||||
|
puts "Error count: #{errors.length}"
|
||||||
|
|
||||||
|
# Validate required exports
|
||||||
|
has_required = @compiler.validation.validate_exports(wasm, %w[init execute query])
|
||||||
|
puts "Has required exports: #{has_required}"
|
||||||
|
|
||||||
|
# Validate memory constraints
|
||||||
|
memory_valid = @compiler.validation.validate_memory(wasm, 16)
|
||||||
|
puts "Memory within 16 pages: #{memory_valid}"
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_security_example
|
||||||
|
puts '=== Security Scanning ==='
|
||||||
|
|
||||||
|
wasm = create_minimal_wasm
|
||||||
|
|
||||||
|
security = @compiler.analysis.security_scan(wasm)
|
||||||
|
|
||||||
|
puts "Security score: #{security.score}/100"
|
||||||
|
|
||||||
|
if security.issues.any?
|
||||||
|
puts "\nSecurity issues:"
|
||||||
|
security.issues.each do |issue|
|
||||||
|
icon = case issue.severity
|
||||||
|
when 'critical' then '[CRIT]'
|
||||||
|
when 'high' then '[HIGH]'
|
||||||
|
when 'medium' then '[MED]'
|
||||||
|
when 'low' then '[LOW]'
|
||||||
|
else '[???]'
|
||||||
|
end
|
||||||
|
|
||||||
|
puts "#{icon} [#{issue.severity}] #{issue.type}"
|
||||||
|
puts " #{issue.description}"
|
||||||
|
puts " at #{issue.location}" if issue.location
|
||||||
|
end
|
||||||
|
else
|
||||||
|
puts 'No security issues found!'
|
||||||
|
end
|
||||||
|
|
||||||
|
if security.recommendations.any?
|
||||||
|
puts "\nRecommendations:"
|
||||||
|
security.recommendations.each do |rec|
|
||||||
|
puts " • #{rec}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Main execution
|
||||||
|
if __FILE__ == $PROGRAM_NAME
|
||||||
|
# Initialize client
|
||||||
|
api_key = ENV.fetch('SYNOR_API_KEY', 'your-api-key')
|
||||||
|
config = Synor::Compiler::Config.new(
|
||||||
|
api_key: api_key,
|
||||||
|
endpoint: 'https://compiler.synor.io/v1',
|
||||||
|
timeout: 60,
|
||||||
|
retries: 3,
|
||||||
|
debug: false,
|
||||||
|
default_optimization_level: :size,
|
||||||
|
max_contract_size: 256 * 1024,
|
||||||
|
use_wasm_opt: true,
|
||||||
|
validate: true,
|
||||||
|
extract_metadata: true,
|
||||||
|
generate_abi: true
|
||||||
|
)
|
||||||
|
|
||||||
|
compiler = Synor::Compiler::Client.new(config)
|
||||||
|
example = CompilerExample.new(compiler)
|
||||||
|
|
||||||
|
begin
|
||||||
|
# Check service health
|
||||||
|
healthy = compiler.health_check
|
||||||
|
puts "Service healthy: #{healthy}\n\n"
|
||||||
|
|
||||||
|
# Run examples
|
||||||
|
example.run_compile_contract_example
|
||||||
|
example.run_compilation_modes_example
|
||||||
|
example.run_abi_example
|
||||||
|
example.run_analysis_example
|
||||||
|
example.run_validation_example
|
||||||
|
example.run_security_example
|
||||||
|
rescue StandardError => e
|
||||||
|
warn "Error: #{e.message}"
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
end
|
||||||
241
sdk/ruby/examples/crypto_example.rb
Normal file
241
sdk/ruby/examples/crypto_example.rb
Normal file
|
|
@ -0,0 +1,241 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
#
|
||||||
|
# Synor Crypto SDK Examples for Ruby
|
||||||
|
#
|
||||||
|
# Demonstrates quantum-resistant cryptographic operations:
|
||||||
|
# - Hybrid Ed25519 + Dilithium3 signatures
|
||||||
|
# - BIP-39 mnemonic generation and validation
|
||||||
|
# - Post-quantum algorithms (Falcon, SPHINCS+)
|
||||||
|
# - Key derivation functions
|
||||||
|
#
|
||||||
|
|
||||||
|
require 'synor/crypto'
|
||||||
|
|
||||||
|
class CryptoExample
|
||||||
|
def initialize(crypto)
|
||||||
|
@crypto = crypto
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_mnemonic_example
|
||||||
|
puts '=== Mnemonic Operations ==='
|
||||||
|
|
||||||
|
# Generate a 24-word mnemonic (256-bit entropy)
|
||||||
|
mnemonic = @crypto.mnemonic.generate(24)
|
||||||
|
puts "Generated mnemonic: #{mnemonic.phrase}"
|
||||||
|
puts "Word count: #{mnemonic.word_count}"
|
||||||
|
|
||||||
|
# Validate a mnemonic
|
||||||
|
validation = @crypto.mnemonic.validate(mnemonic.phrase)
|
||||||
|
puts "Valid: #{validation.valid?}"
|
||||||
|
puts "Error: #{validation.error}" unless validation.valid?
|
||||||
|
|
||||||
|
# Convert mnemonic to seed
|
||||||
|
seed = @crypto.mnemonic.to_seed(mnemonic.phrase, 'optional-passphrase')
|
||||||
|
puts "Seed (hex): #{bytes_to_hex(seed, 16)}..."
|
||||||
|
|
||||||
|
# Word suggestions for autocomplete
|
||||||
|
suggestions = @crypto.mnemonic.suggest_words('aban', 5)
|
||||||
|
puts "Suggestions for 'aban': #{suggestions.join(', ')}"
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_keypair_example
|
||||||
|
puts '=== Keypair Operations ==='
|
||||||
|
|
||||||
|
# Generate a random keypair
|
||||||
|
keypair = @crypto.keypairs.generate
|
||||||
|
puts 'Generated hybrid keypair:'
|
||||||
|
puts " Ed25519 public key size: #{keypair.public_key.ed25519_bytes.length} bytes"
|
||||||
|
puts " Dilithium public key size: #{keypair.public_key.dilithium_bytes.length} bytes"
|
||||||
|
puts " Total public key size: #{keypair.public_key.size} bytes"
|
||||||
|
|
||||||
|
# Get addresses for different networks
|
||||||
|
puts "\nAddresses:"
|
||||||
|
puts " Mainnet: #{keypair.get_address(:mainnet)}"
|
||||||
|
puts " Testnet: #{keypair.get_address(:testnet)}"
|
||||||
|
puts " Devnet: #{keypair.get_address(:devnet)}"
|
||||||
|
|
||||||
|
# Create keypair from mnemonic (deterministic)
|
||||||
|
mnemonic = @crypto.mnemonic.generate(24)
|
||||||
|
keypair2 = @crypto.keypairs.from_mnemonic(mnemonic.phrase)
|
||||||
|
addr = keypair2.get_address(:mainnet)
|
||||||
|
puts "\nKeypair from mnemonic: #{addr[0, 20]}..."
|
||||||
|
|
||||||
|
# Derive child keypair using BIP-44 path
|
||||||
|
path = Synor::Crypto::DerivationPath.external(0, 0) # m/44'/21337'/0'/0/0
|
||||||
|
puts "Derivation path: #{path}"
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_signing_example
|
||||||
|
puts '=== Hybrid Signing ==='
|
||||||
|
|
||||||
|
# Generate keypair
|
||||||
|
keypair = @crypto.keypairs.generate
|
||||||
|
|
||||||
|
# Sign a message
|
||||||
|
message = 'Hello, quantum-resistant world!'.bytes
|
||||||
|
signature = @crypto.signing.sign(keypair, message)
|
||||||
|
|
||||||
|
puts 'Signature created:'
|
||||||
|
puts " Ed25519 component: #{signature.ed25519_bytes.length} bytes"
|
||||||
|
puts " Dilithium component: #{signature.dilithium_bytes.length} bytes"
|
||||||
|
puts " Total signature size: #{signature.size} bytes"
|
||||||
|
|
||||||
|
# Verify the signature
|
||||||
|
valid = @crypto.signing.verify(keypair.public_key, message, signature)
|
||||||
|
puts "\nVerification result: #{valid}"
|
||||||
|
|
||||||
|
# Verify with tampered message fails
|
||||||
|
tampered_message = 'Hello, tampered message!'.bytes
|
||||||
|
invalid_result = @crypto.signing.verify(keypair.public_key, tampered_message, signature)
|
||||||
|
puts "Tampered message verification: #{invalid_result}"
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_falcon_example
|
||||||
|
puts '=== Falcon Post-Quantum Signatures ==='
|
||||||
|
|
||||||
|
# Generate Falcon-512 keypair (128-bit security)
|
||||||
|
falcon512 = @crypto.falcon.generate(:falcon512)
|
||||||
|
puts 'Falcon-512 keypair:'
|
||||||
|
puts " Public key: #{falcon512.public_key.key_bytes.length} bytes"
|
||||||
|
puts ' Security level: 128-bit'
|
||||||
|
|
||||||
|
# Generate Falcon-1024 keypair (256-bit security)
|
||||||
|
falcon1024 = @crypto.falcon.generate(:falcon1024)
|
||||||
|
puts "\nFalcon-1024 keypair:"
|
||||||
|
puts " Public key: #{falcon1024.public_key.key_bytes.length} bytes"
|
||||||
|
puts ' Security level: 256-bit'
|
||||||
|
|
||||||
|
# Sign with Falcon-512
|
||||||
|
message = 'Post-quantum secure message'.bytes
|
||||||
|
signature = @crypto.falcon.sign(falcon512, message)
|
||||||
|
puts "\nFalcon-512 signature: #{signature.signature_bytes.length} bytes"
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
valid = @crypto.falcon.verify(falcon512.public_key.key_bytes, message, signature)
|
||||||
|
puts "Verification: #{valid}"
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_sphincs_example
|
||||||
|
puts '=== SPHINCS+ Hash-Based Signatures ==='
|
||||||
|
|
||||||
|
# SPHINCS+ variants with different security levels
|
||||||
|
variants = [
|
||||||
|
{ variant: :shake128s, security: 128, sig_size: 7856, name: 'SHAKE128S' },
|
||||||
|
{ variant: :shake192s, security: 192, sig_size: 16_224, name: 'SHAKE192S' },
|
||||||
|
{ variant: :shake256s, security: 256, sig_size: 29_792, name: 'SHAKE256S' }
|
||||||
|
]
|
||||||
|
|
||||||
|
message = 'Hash-based quantum security'.bytes
|
||||||
|
|
||||||
|
variants.each do |v|
|
||||||
|
keypair = @crypto.sphincs.generate(v[:variant])
|
||||||
|
puts "SPHINCS+ #{v[:name]}:"
|
||||||
|
puts " Security level: #{v[:security]}-bit"
|
||||||
|
puts " Expected signature size: #{v[:sig_size]} bytes"
|
||||||
|
|
||||||
|
# Sign a message
|
||||||
|
signature = @crypto.sphincs.sign(keypair, message)
|
||||||
|
puts " Actual signature size: #{signature.signature_bytes.length} bytes"
|
||||||
|
|
||||||
|
# Verify
|
||||||
|
valid = @crypto.sphincs.verify(keypair.public_key.key_bytes, message, signature)
|
||||||
|
puts " Verification: #{valid}"
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_kdf_example
|
||||||
|
puts '=== Key Derivation Functions ==='
|
||||||
|
|
||||||
|
# HKDF (HMAC-based Key Derivation Function)
|
||||||
|
seed = 'master-secret-key-material-here'.bytes
|
||||||
|
hkdf_config = {
|
||||||
|
salt: 'application-salt'.bytes,
|
||||||
|
info: 'encryption-key'.bytes,
|
||||||
|
output_length: 32
|
||||||
|
}
|
||||||
|
|
||||||
|
derived_key = @crypto.kdf.derive_key(seed, hkdf_config)
|
||||||
|
puts "HKDF derived key: #{bytes_to_hex(derived_key)}"
|
||||||
|
|
||||||
|
# PBKDF2 (Password-Based Key Derivation Function)
|
||||||
|
password = 'user-password'.bytes
|
||||||
|
pbkdf2_config = {
|
||||||
|
salt: 'random-salt-value'.bytes,
|
||||||
|
iterations: 100_000,
|
||||||
|
output_length: 32
|
||||||
|
}
|
||||||
|
|
||||||
|
password_key = @crypto.kdf.derive_from_password(password, pbkdf2_config)
|
||||||
|
puts "PBKDF2 derived key: #{bytes_to_hex(password_key)}"
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_hash_example
|
||||||
|
puts '=== Hash Functions ==='
|
||||||
|
|
||||||
|
data = 'Data to hash'.bytes
|
||||||
|
|
||||||
|
# SHA3-256 (FIPS 202)
|
||||||
|
sha3 = @crypto.hash.sha3_256(data)
|
||||||
|
puts "SHA3-256: #{sha3.hex}"
|
||||||
|
|
||||||
|
# BLAKE3 (fast, parallel)
|
||||||
|
blake3 = @crypto.hash.blake3(data)
|
||||||
|
puts "BLAKE3: #{blake3.hex}"
|
||||||
|
|
||||||
|
# Keccak-256 (Ethereum compatible)
|
||||||
|
keccak = @crypto.hash.keccak256(data)
|
||||||
|
puts "Keccak: #{keccak.hex}"
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def bytes_to_hex(data, max_len = nil)
|
||||||
|
len = max_len || data.length
|
||||||
|
hex = data[0, len].map { |b| format('%02x', b) }.join
|
||||||
|
hex += '...' if max_len && max_len < data.length
|
||||||
|
hex
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Main execution
|
||||||
|
if __FILE__ == $PROGRAM_NAME
|
||||||
|
# Initialize client
|
||||||
|
api_key = ENV.fetch('SYNOR_API_KEY', 'your-api-key')
|
||||||
|
config = Synor::Crypto::Config.new(
|
||||||
|
api_key: api_key,
|
||||||
|
endpoint: 'https://crypto.synor.io/v1',
|
||||||
|
timeout: 30,
|
||||||
|
retries: 3,
|
||||||
|
debug: false,
|
||||||
|
default_network: :mainnet
|
||||||
|
)
|
||||||
|
|
||||||
|
crypto = Synor::Crypto::Client.new(config)
|
||||||
|
example = CryptoExample.new(crypto)
|
||||||
|
|
||||||
|
begin
|
||||||
|
# Check service health
|
||||||
|
healthy = crypto.health_check
|
||||||
|
puts "Service healthy: #{healthy}\n\n"
|
||||||
|
|
||||||
|
# Run examples
|
||||||
|
example.run_mnemonic_example
|
||||||
|
example.run_keypair_example
|
||||||
|
example.run_signing_example
|
||||||
|
example.run_falcon_example
|
||||||
|
example.run_sphincs_example
|
||||||
|
example.run_kdf_example
|
||||||
|
example.run_hash_example
|
||||||
|
rescue StandardError => e
|
||||||
|
warn "Error: #{e.message}"
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
end
|
||||||
288
sdk/ruby/examples/dex_example.rb
Normal file
288
sdk/ruby/examples/dex_example.rb
Normal file
|
|
@ -0,0 +1,288 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
#
|
||||||
|
# Synor DEX SDK Examples for Ruby
|
||||||
|
#
|
||||||
|
# Demonstrates decentralized exchange operations:
|
||||||
|
# - Market data and orderbook queries
|
||||||
|
# - Spot trading (limit and market orders)
|
||||||
|
# - Perpetual futures trading
|
||||||
|
# - Liquidity provision (AMM)
|
||||||
|
# - Portfolio management
|
||||||
|
#
|
||||||
|
|
||||||
|
require 'synor/dex'
|
||||||
|
|
||||||
|
class DexExample
|
||||||
|
def initialize(dex)
|
||||||
|
@dex = dex
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_markets_example
|
||||||
|
puts '=== Market Information ==='
|
||||||
|
|
||||||
|
# List all available markets
|
||||||
|
markets = @dex.markets.list
|
||||||
|
puts "Available markets: #{markets.length}"
|
||||||
|
markets.first(5).each do |market|
|
||||||
|
puts " #{market.symbol}: #{market.base_asset}/#{market.quote_asset} (#{market.status})"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get specific market details
|
||||||
|
eth_usdc = @dex.markets.get('ETH-USDC')
|
||||||
|
puts "\n#{eth_usdc.symbol} market:"
|
||||||
|
puts " Price: $#{format('%.2f', eth_usdc.last_price)}"
|
||||||
|
puts " 24h Change: #{format('%.2f', eth_usdc.change_24h)}%"
|
||||||
|
puts " 24h Volume: $#{eth_usdc.volume_24h.to_i.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse}"
|
||||||
|
puts " 24h High: $#{format('%.2f', eth_usdc.high_24h)}"
|
||||||
|
puts " 24h Low: $#{format('%.2f', eth_usdc.low_24h)}"
|
||||||
|
|
||||||
|
# Get orderbook
|
||||||
|
orderbook = @dex.markets.get_orderbook('ETH-USDC', depth: 10)
|
||||||
|
puts "\nOrderbook (#{orderbook.bids.length} bids, #{orderbook.asks.length} asks):"
|
||||||
|
puts " Best bid: $#{format('%.2f', orderbook.bids.first.price)} (#{format('%.4f', orderbook.bids.first.quantity)} ETH)"
|
||||||
|
puts " Best ask: $#{format('%.2f', orderbook.asks.first.price)} (#{format('%.4f', orderbook.asks.first.quantity)} ETH)"
|
||||||
|
puts " Spread: $#{format('%.2f', orderbook.spread)} (#{format('%.3f', orderbook.spread_percent)}%)"
|
||||||
|
|
||||||
|
# Get recent trades
|
||||||
|
trades = @dex.markets.get_trades('ETH-USDC', limit: 5)
|
||||||
|
puts "\nRecent trades:"
|
||||||
|
trades.each do |trade|
|
||||||
|
puts " #{trade.side}: #{format('%.4f', trade.quantity)} @ $#{format('%.2f', trade.price)}"
|
||||||
|
end
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_spot_trading_example
|
||||||
|
puts '=== Spot Trading ==='
|
||||||
|
|
||||||
|
# Get account balance
|
||||||
|
balances = @dex.account.get_balances
|
||||||
|
puts 'Account balances:'
|
||||||
|
balances.select { |b| b.total.positive? }.each do |balance|
|
||||||
|
puts " #{balance.asset}: #{format('%.4f', balance.available)} available, #{format('%.4f', balance.locked)} locked"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Place a limit buy order
|
||||||
|
puts "\nPlacing limit buy order..."
|
||||||
|
limit_order = @dex.spot.place_order(
|
||||||
|
symbol: 'ETH-USDC',
|
||||||
|
side: :buy,
|
||||||
|
type: :limit,
|
||||||
|
quantity: 0.1,
|
||||||
|
price: 3000.00,
|
||||||
|
time_in_force: :gtc
|
||||||
|
)
|
||||||
|
|
||||||
|
puts 'Limit order placed:'
|
||||||
|
puts " Order ID: #{limit_order.order_id}"
|
||||||
|
puts " Status: #{limit_order.status}"
|
||||||
|
puts " Price: $#{format('%.2f', limit_order.price)}"
|
||||||
|
puts " Quantity: #{format('%.4f', limit_order.quantity)}"
|
||||||
|
|
||||||
|
# Place a market sell order
|
||||||
|
puts "\nPlacing market sell order..."
|
||||||
|
market_order = @dex.spot.place_order(
|
||||||
|
symbol: 'ETH-USDC',
|
||||||
|
side: :sell,
|
||||||
|
type: :market,
|
||||||
|
quantity: 0.05
|
||||||
|
)
|
||||||
|
|
||||||
|
puts 'Market order executed:'
|
||||||
|
puts " Order ID: #{market_order.order_id}"
|
||||||
|
puts " Status: #{market_order.status}"
|
||||||
|
puts " Filled: #{format('%.4f', market_order.filled_quantity)}"
|
||||||
|
puts " Avg price: $#{format('%.2f', market_order.average_price)}"
|
||||||
|
|
||||||
|
# Get open orders
|
||||||
|
open_orders = @dex.spot.get_open_orders(symbol: 'ETH-USDC')
|
||||||
|
puts "\nOpen orders: #{open_orders.length}"
|
||||||
|
open_orders.each do |order|
|
||||||
|
puts " #{order.order_id}: #{order.side} #{format('%.4f', order.quantity)} @ $#{format('%.2f', order.price)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Cancel an order
|
||||||
|
if open_orders.any?
|
||||||
|
cancelled = @dex.spot.cancel_order(open_orders.first.order_id)
|
||||||
|
puts "\nCancelled order: #{cancelled.order_id}"
|
||||||
|
end
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_perps_example
|
||||||
|
puts '=== Perpetual Futures ==='
|
||||||
|
|
||||||
|
# Get perpetual markets
|
||||||
|
perp_markets = @dex.perps.get_markets
|
||||||
|
puts "Perpetual markets: #{perp_markets.length}"
|
||||||
|
perp_markets.first(3).each do |market|
|
||||||
|
puts " #{market.symbol}: Mark $#{format('%.2f', market.mark_price)}, Funding #{format('%.4f', market.funding_rate)}%"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get account position
|
||||||
|
positions = @dex.perps.get_positions
|
||||||
|
puts "\nOpen positions: #{positions.length}"
|
||||||
|
positions.each do |position|
|
||||||
|
puts " #{position.symbol}: #{position.side} #{format('%.4f', position.size)}"
|
||||||
|
puts " Entry: $#{format('%.2f', position.entry_price)}, PnL: $#{format('%.2f', position.unrealized_pnl)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Open a long position
|
||||||
|
puts "\nOpening long position..."
|
||||||
|
long_order = @dex.perps.place_order(
|
||||||
|
symbol: 'BTC-USDC-PERP',
|
||||||
|
side: :buy,
|
||||||
|
type: :limit,
|
||||||
|
quantity: 0.01,
|
||||||
|
price: 95_000.00,
|
||||||
|
leverage: 10,
|
||||||
|
reduce_only: false
|
||||||
|
)
|
||||||
|
|
||||||
|
puts 'Position order placed:'
|
||||||
|
puts " Order ID: #{long_order.order_id}"
|
||||||
|
puts " Leverage: #{long_order.leverage}x"
|
||||||
|
puts " Margin: $#{format('%.2f', long_order.required_margin)}"
|
||||||
|
|
||||||
|
# Set stop-loss and take-profit
|
||||||
|
puts "\nSetting SL/TP..."
|
||||||
|
@dex.perps.set_stop_loss('BTC-USDC-PERP', 90_000.00)
|
||||||
|
@dex.perps.set_take_profit('BTC-USDC-PERP', 100_000.00)
|
||||||
|
puts ' Stop loss: $90,000'
|
||||||
|
puts ' Take profit: $100,000'
|
||||||
|
|
||||||
|
# Get funding rate history
|
||||||
|
funding_history = @dex.perps.get_funding_history('BTC-USDC-PERP', limit: 5)
|
||||||
|
puts "\nFunding rate history:"
|
||||||
|
funding_history.each do |funding|
|
||||||
|
puts " #{funding.timestamp}: #{format('%.4f', funding.rate)}%"
|
||||||
|
end
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_liquidity_example
|
||||||
|
puts '=== Liquidity Provision ==='
|
||||||
|
|
||||||
|
# Get available pools
|
||||||
|
pools = @dex.liquidity.get_pools
|
||||||
|
puts "Liquidity pools: #{pools.length}"
|
||||||
|
pools.first(5).each do |pool|
|
||||||
|
tvl = pool.total_value_locked.to_i.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
|
||||||
|
puts " #{pool.name}: TVL $#{tvl}, APR #{format('%.2f', pool.apr)}%"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get pool details
|
||||||
|
eth_usdc_pool = @dex.liquidity.get_pool('ETH-USDC')
|
||||||
|
tvl = eth_usdc_pool.total_value_locked.to_i.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
|
||||||
|
vol = eth_usdc_pool.volume_24h.to_i.to_s.reverse.gsub(/(\d{3})(?=\d)/, '\\1,').reverse
|
||||||
|
puts "\n#{eth_usdc_pool.name} pool:"
|
||||||
|
puts " TVL: $#{tvl}"
|
||||||
|
puts " Volume 24h: $#{vol}"
|
||||||
|
puts " Fee tier: #{format('%.2f', eth_usdc_pool.fee_tier)}%"
|
||||||
|
puts " APR: #{format('%.2f', eth_usdc_pool.apr)}%"
|
||||||
|
puts " Reserve A: #{format('%.4f', eth_usdc_pool.reserve_a)} ETH"
|
||||||
|
puts " Reserve B: #{format('%.2f', eth_usdc_pool.reserve_b)} USDC"
|
||||||
|
|
||||||
|
# Add liquidity
|
||||||
|
puts "\nAdding liquidity..."
|
||||||
|
add_result = @dex.liquidity.add_liquidity(
|
||||||
|
pool_id: 'ETH-USDC',
|
||||||
|
amount_a: 0.1,
|
||||||
|
amount_b: 300.0,
|
||||||
|
slippage_tolerance: 0.5
|
||||||
|
)
|
||||||
|
|
||||||
|
puts 'Liquidity added:'
|
||||||
|
puts " LP tokens received: #{format('%.8f', add_result.lp_tokens_received)}"
|
||||||
|
puts " Share of pool: #{format('%.4f', add_result.share_of_pool)}%"
|
||||||
|
|
||||||
|
# Get LP positions
|
||||||
|
lp_positions = @dex.liquidity.get_positions
|
||||||
|
puts "\nLP positions: #{lp_positions.length}"
|
||||||
|
lp_positions.each do |position|
|
||||||
|
puts " #{position.pool_id}: #{format('%.8f', position.lp_tokens)} tokens, $#{format('%.2f', position.value)}"
|
||||||
|
puts " Earned fees: $#{format('%.2f', position.earned_fees)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Remove liquidity
|
||||||
|
puts "\nRemoving liquidity..."
|
||||||
|
remove_result = @dex.liquidity.remove_liquidity(
|
||||||
|
pool_id: 'ETH-USDC',
|
||||||
|
lp_tokens: add_result.lp_tokens_received,
|
||||||
|
slippage_tolerance: 0.5
|
||||||
|
)
|
||||||
|
|
||||||
|
puts 'Liquidity removed:'
|
||||||
|
puts " Amount A: #{format('%.4f', remove_result.amount_a)} ETH"
|
||||||
|
puts " Amount B: #{format('%.2f', remove_result.amount_b)} USDC"
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_portfolio_example
|
||||||
|
puts '=== Portfolio Management ==='
|
||||||
|
|
||||||
|
# Get portfolio summary
|
||||||
|
portfolio = @dex.portfolio.get_summary
|
||||||
|
puts 'Portfolio summary:'
|
||||||
|
puts " Total value: $#{format('%.2f', portfolio.total_value)}"
|
||||||
|
puts " Available: $#{format('%.2f', portfolio.available_balance)}"
|
||||||
|
puts " In orders: $#{format('%.2f', portfolio.in_orders)}"
|
||||||
|
puts " In positions: $#{format('%.2f', portfolio.in_positions)}"
|
||||||
|
puts " Unrealized PnL: $#{format('%.2f', portfolio.unrealized_pnl)}"
|
||||||
|
|
||||||
|
# Get asset allocation
|
||||||
|
puts "\nAsset allocation:"
|
||||||
|
portfolio.allocations.each do |allocation|
|
||||||
|
puts " #{allocation.asset}: #{format('%.1f', allocation.percentage)}% ($#{format('%.2f', allocation.value)})"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get trade history
|
||||||
|
trade_history = @dex.portfolio.get_trade_history(limit: 10)
|
||||||
|
puts "\nRecent trades: #{trade_history.length}"
|
||||||
|
trade_history.each do |trade|
|
||||||
|
puts " #{trade.timestamp}: #{trade.side} #{format('%.4f', trade.quantity)} #{trade.symbol} @ $#{format('%.2f', trade.price)}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get PnL report
|
||||||
|
pnl_report = @dex.portfolio.get_pnl_report(:month)
|
||||||
|
puts "\nMonthly PnL report:"
|
||||||
|
puts " Realized PnL: $#{format('%.2f', pnl_report.realized_pnl)}"
|
||||||
|
puts " Unrealized PnL: $#{format('%.2f', pnl_report.unrealized_pnl)}"
|
||||||
|
puts " Total fees: $#{format('%.2f', pnl_report.total_fees)}"
|
||||||
|
puts " Net profit: $#{format('%.2f', pnl_report.net_profit)}"
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Main execution
|
||||||
|
if __FILE__ == $PROGRAM_NAME
|
||||||
|
# Initialize client
|
||||||
|
api_key = ENV.fetch('SYNOR_API_KEY', 'your-api-key')
|
||||||
|
config = Synor::Dex::Config.new(
|
||||||
|
api_key: api_key,
|
||||||
|
endpoint: 'https://dex.synor.io/v1',
|
||||||
|
timeout: 30,
|
||||||
|
retries: 3,
|
||||||
|
debug: false
|
||||||
|
)
|
||||||
|
|
||||||
|
dex = Synor::Dex::Client.new(config)
|
||||||
|
example = DexExample.new(dex)
|
||||||
|
|
||||||
|
begin
|
||||||
|
# Check service health
|
||||||
|
healthy = dex.health_check
|
||||||
|
puts "Service healthy: #{healthy}\n\n"
|
||||||
|
|
||||||
|
# Run examples
|
||||||
|
example.run_markets_example
|
||||||
|
example.run_spot_trading_example
|
||||||
|
example.run_perps_example
|
||||||
|
example.run_liquidity_example
|
||||||
|
example.run_portfolio_example
|
||||||
|
rescue StandardError => e
|
||||||
|
warn "Error: #{e.message}"
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
end
|
||||||
290
sdk/ruby/examples/ibc_example.rb
Normal file
290
sdk/ruby/examples/ibc_example.rb
Normal file
|
|
@ -0,0 +1,290 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
#
|
||||||
|
# Synor IBC SDK Examples for Ruby
|
||||||
|
#
|
||||||
|
# Demonstrates Inter-Blockchain Communication operations:
|
||||||
|
# - Chain and channel management
|
||||||
|
# - Cross-chain token transfers
|
||||||
|
# - Packet lifecycle handling
|
||||||
|
# - Relayer operations
|
||||||
|
# - Connection monitoring
|
||||||
|
#
|
||||||
|
|
||||||
|
require 'synor/ibc'
|
||||||
|
|
||||||
|
class IbcExample
|
||||||
|
def initialize(ibc)
|
||||||
|
@ibc = ibc
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_chains_example
|
||||||
|
puts '=== Chain Information ==='
|
||||||
|
|
||||||
|
# List connected chains
|
||||||
|
chains = @ibc.chains.list
|
||||||
|
puts "Connected chains: #{chains.length}"
|
||||||
|
chains.first(5).each do |chain|
|
||||||
|
puts " #{chain.chain_id}: #{chain.name} (#{chain.status})"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get specific chain info
|
||||||
|
cosmos_hub = @ibc.chains.get('cosmoshub-4')
|
||||||
|
puts "\n#{cosmos_hub.name}:"
|
||||||
|
puts " Chain ID: #{cosmos_hub.chain_id}"
|
||||||
|
puts " RPC endpoint: #{cosmos_hub.rpc_endpoint}"
|
||||||
|
puts " Block height: #{cosmos_hub.latest_height}"
|
||||||
|
puts " Active channels: #{cosmos_hub.active_channels}"
|
||||||
|
|
||||||
|
# Get chain clients
|
||||||
|
clients = @ibc.chains.get_clients('cosmoshub-4')
|
||||||
|
puts "\nIBC clients: #{clients.length}"
|
||||||
|
clients.first(3).each do |client|
|
||||||
|
puts " #{client.client_id}: #{client.chain_id} (#{client.client_type})"
|
||||||
|
end
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_channels_example
|
||||||
|
puts '=== Channel Management ==='
|
||||||
|
|
||||||
|
# List channels
|
||||||
|
channels = @ibc.channels.list
|
||||||
|
puts "IBC channels: #{channels.length}"
|
||||||
|
channels.first(5).each do |channel|
|
||||||
|
puts " #{channel.channel_id}: #{channel.source_chain} <-> #{channel.dest_chain} (#{channel.state})"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get channel details
|
||||||
|
channel_id = 'channel-0'
|
||||||
|
channel = @ibc.channels.get(channel_id)
|
||||||
|
puts "\nChannel #{channel_id}:"
|
||||||
|
puts " State: #{channel.state}"
|
||||||
|
puts " Port: #{channel.port_id}"
|
||||||
|
puts " Counterparty: #{channel.counterparty_channel_id}"
|
||||||
|
puts " Connection: #{channel.connection_id}"
|
||||||
|
puts " Ordering: #{channel.ordering}"
|
||||||
|
puts " Version: #{channel.version}"
|
||||||
|
|
||||||
|
# Create a new channel (4-step handshake)
|
||||||
|
puts "\nInitiating channel creation..."
|
||||||
|
init_result = @ibc.channels.init(
|
||||||
|
source_chain: 'synor-mainnet',
|
||||||
|
dest_chain: 'osmosis-1',
|
||||||
|
port_id: 'transfer',
|
||||||
|
version: 'ics20-1'
|
||||||
|
)
|
||||||
|
puts " ChanOpenInit sent: #{init_result.channel_id}"
|
||||||
|
|
||||||
|
# In production, the following steps happen through relayers:
|
||||||
|
# ChanOpenTry -> ChanOpenAck -> ChanOpenConfirm
|
||||||
|
|
||||||
|
# Get channel statistics
|
||||||
|
stats = @ibc.channels.get_stats(channel_id)
|
||||||
|
puts "\nChannel statistics:"
|
||||||
|
puts " Packets sent: #{stats.packets_sent}"
|
||||||
|
puts " Packets received: #{stats.packets_received}"
|
||||||
|
puts " Packets acknowledged: #{stats.packets_acknowledged}"
|
||||||
|
puts " Packets timed out: #{stats.packets_timed_out}"
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_transfer_example
|
||||||
|
puts '=== Cross-Chain Transfers ==='
|
||||||
|
|
||||||
|
# Get transfer routes
|
||||||
|
puts 'Available transfer routes:'
|
||||||
|
routes = @ibc.transfers.get_routes('ATOM', 'synor-mainnet')
|
||||||
|
routes.each do |route|
|
||||||
|
puts " #{route.source_chain} -> #{route.dest_chain}: #{route.channel_id}"
|
||||||
|
puts " Estimated time: #{route.estimated_time}"
|
||||||
|
puts " Fee: #{route.fee} #{route.fee_asset}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Initiate a transfer
|
||||||
|
puts "\nInitiating transfer..."
|
||||||
|
transfer = @ibc.transfers.send(
|
||||||
|
source_chain: 'cosmoshub-4',
|
||||||
|
dest_chain: 'synor-mainnet',
|
||||||
|
channel_id: 'channel-0',
|
||||||
|
asset: 'uatom',
|
||||||
|
amount: '1000000', # 1 ATOM
|
||||||
|
sender: 'cosmos1abc...',
|
||||||
|
receiver: 'synor1xyz...',
|
||||||
|
timeout: 1800, # 30 minutes in seconds
|
||||||
|
memo: 'IBC transfer test'
|
||||||
|
)
|
||||||
|
|
||||||
|
puts 'Transfer initiated:'
|
||||||
|
puts " Transfer ID: #{transfer.transfer_id}"
|
||||||
|
puts " Sequence: #{transfer.sequence}"
|
||||||
|
puts " Status: #{transfer.status}"
|
||||||
|
|
||||||
|
# Track transfer status
|
||||||
|
puts "\nTracking transfer..."
|
||||||
|
status = @ibc.transfers.get_status(transfer.transfer_id)
|
||||||
|
puts " Current status: #{status.status}"
|
||||||
|
puts " Source tx: #{status.source_tx_hash}"
|
||||||
|
puts " Dest tx: #{status.dest_tx_hash}" if status.dest_tx_hash
|
||||||
|
|
||||||
|
# Get transfer history
|
||||||
|
history = @ibc.transfers.get_history(limit: 5)
|
||||||
|
puts "\nRecent transfers: #{history.length}"
|
||||||
|
history.each do |tx|
|
||||||
|
puts " #{tx.transfer_id}: #{tx.amount} #{tx.asset} (#{tx.status})"
|
||||||
|
end
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_packet_example
|
||||||
|
puts '=== Packet Handling ==='
|
||||||
|
|
||||||
|
# Get pending packets
|
||||||
|
pending_packets = @ibc.packets.get_pending('channel-0')
|
||||||
|
puts "Pending packets: #{pending_packets.length}"
|
||||||
|
pending_packets.first(5).each do |packet|
|
||||||
|
puts " Seq #{packet.sequence}: #{packet.source_port} -> #{packet.dest_port}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get packet details
|
||||||
|
if pending_packets.any?
|
||||||
|
packet = @ibc.packets.get('channel-0', pending_packets.first.sequence)
|
||||||
|
puts "\nPacket #{packet.sequence}:"
|
||||||
|
puts " Source: #{packet.source_port}/#{packet.source_channel}"
|
||||||
|
puts " Dest: #{packet.dest_port}/#{packet.dest_channel}"
|
||||||
|
puts " Timeout height: #{packet.timeout_height}"
|
||||||
|
puts " Timeout timestamp: #{packet.timeout_timestamp}"
|
||||||
|
data_hex = packet.data.unpack1('H*')
|
||||||
|
puts " Data: #{data_hex[0, 64]}..."
|
||||||
|
end
|
||||||
|
|
||||||
|
# Query packet commitments
|
||||||
|
commitments = @ibc.packets.get_commitments('channel-0')
|
||||||
|
puts "\nPacket commitments: #{commitments.length}"
|
||||||
|
|
||||||
|
# Query unreceived packets
|
||||||
|
unreceived = @ibc.packets.get_unreceived('channel-0', [1, 2, 3, 4, 5])
|
||||||
|
puts "Unreceived packets: #{unreceived.join(', ')}"
|
||||||
|
|
||||||
|
# Query acknowledgements
|
||||||
|
acks = @ibc.packets.get_acknowledgements('channel-0')
|
||||||
|
puts "Packet acknowledgements: #{acks.length}"
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_relayer_example
|
||||||
|
puts '=== Relayer Operations ==='
|
||||||
|
|
||||||
|
# Get relayer status
|
||||||
|
relayers = @ibc.relayer.list
|
||||||
|
puts "Active relayers: #{relayers.length}"
|
||||||
|
relayers.first(3).each do |relayer|
|
||||||
|
puts " #{relayer.address}: #{relayer.packets_relayed} packets (#{relayer.status})"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Register as a relayer
|
||||||
|
puts "\nRegistering as relayer..."
|
||||||
|
registration = @ibc.relayer.register(
|
||||||
|
address: 'synor1relayer...',
|
||||||
|
chains: %w[synor-mainnet cosmoshub-4 osmosis-1],
|
||||||
|
commission: 0.1 # 0.1%
|
||||||
|
)
|
||||||
|
puts " Registered: #{registration.relayer_id}"
|
||||||
|
|
||||||
|
# Start relaying
|
||||||
|
puts "\nStarting packet relay..."
|
||||||
|
relay_config = {
|
||||||
|
channels: %w[channel-0 channel-1],
|
||||||
|
batch_size: 10,
|
||||||
|
poll_interval: 5
|
||||||
|
}
|
||||||
|
|
||||||
|
# In production, this would run continuously
|
||||||
|
pending_count = @ibc.relayer.get_pending_count(relay_config[:channels])
|
||||||
|
puts " Pending packets to relay: #{pending_count}"
|
||||||
|
|
||||||
|
# Relay a batch
|
||||||
|
relay_result = @ibc.relayer.relay_batch('channel-0', 5)
|
||||||
|
puts " Relayed: #{relay_result.packets_relayed}"
|
||||||
|
puts " Fees earned: #{relay_result.fees_earned}"
|
||||||
|
|
||||||
|
# Get relayer earnings
|
||||||
|
earnings = @ibc.relayer.get_earnings('synor1relayer...')
|
||||||
|
puts "\nRelayer earnings:"
|
||||||
|
puts " Total earned: #{earnings.total_earned}"
|
||||||
|
puts " Packets relayed: #{earnings.packets_relayed}"
|
||||||
|
puts " Success rate: #{format('%.1f', earnings.success_rate)}%"
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_monitoring_example
|
||||||
|
puts '=== Connection Monitoring ==='
|
||||||
|
|
||||||
|
# Get connection health
|
||||||
|
connections = @ibc.monitoring.get_connections
|
||||||
|
puts 'Connection health:'
|
||||||
|
connections.each do |conn|
|
||||||
|
health_icon = conn.healthy? ? '✓' : '✗'
|
||||||
|
puts " [#{health_icon}] #{conn.connection_id}: #{conn.chain_a} <-> #{conn.chain_b}"
|
||||||
|
puts " Latency: #{conn.latency}ms, Uptime: #{format('%.1f', conn.uptime)}%"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Get channel metrics
|
||||||
|
metrics = @ibc.monitoring.get_channel_metrics('channel-0')
|
||||||
|
puts "\nChannel metrics:"
|
||||||
|
puts " Throughput: #{metrics.packets_per_hour}/hour"
|
||||||
|
puts " Avg latency: #{metrics.avg_latency_ms}ms"
|
||||||
|
puts " Success rate: #{format('%.1f', metrics.success_rate)}%"
|
||||||
|
puts " Volume 24h: #{metrics.volume_24h}"
|
||||||
|
|
||||||
|
# Subscribe to events (in production)
|
||||||
|
puts "\nEvent subscription example:"
|
||||||
|
puts ' Subscribing to packet events...'
|
||||||
|
# @ibc.monitoring.subscribe('channel-0') do |event|
|
||||||
|
# puts " Event: #{event.type} - #{event.data}"
|
||||||
|
# end
|
||||||
|
|
||||||
|
# Get alerts
|
||||||
|
alerts = @ibc.monitoring.get_alerts
|
||||||
|
puts "\nActive alerts: #{alerts.length}"
|
||||||
|
alerts.each do |alert|
|
||||||
|
puts " [#{alert.severity}] #{alert.message}"
|
||||||
|
puts " Channel: #{alert.channel_id}, Time: #{alert.timestamp}"
|
||||||
|
end
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Main execution
|
||||||
|
if __FILE__ == $PROGRAM_NAME
|
||||||
|
# Initialize client
|
||||||
|
api_key = ENV.fetch('SYNOR_API_KEY', 'your-api-key')
|
||||||
|
config = Synor::Ibc::Config.new(
|
||||||
|
api_key: api_key,
|
||||||
|
endpoint: 'https://ibc.synor.io/v1',
|
||||||
|
timeout: 60,
|
||||||
|
retries: 3,
|
||||||
|
debug: false,
|
||||||
|
default_timeout: 1800 # 30 minutes
|
||||||
|
)
|
||||||
|
|
||||||
|
ibc = Synor::Ibc::Client.new(config)
|
||||||
|
example = IbcExample.new(ibc)
|
||||||
|
|
||||||
|
begin
|
||||||
|
# Check service health
|
||||||
|
healthy = ibc.health_check
|
||||||
|
puts "Service healthy: #{healthy}\n\n"
|
||||||
|
|
||||||
|
# Run examples
|
||||||
|
example.run_chains_example
|
||||||
|
example.run_channels_example
|
||||||
|
example.run_transfer_example
|
||||||
|
example.run_packet_example
|
||||||
|
example.run_relayer_example
|
||||||
|
example.run_monitoring_example
|
||||||
|
rescue StandardError => e
|
||||||
|
warn "Error: #{e.message}"
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
end
|
||||||
345
sdk/ruby/examples/zk_example.rb
Normal file
345
sdk/ruby/examples/zk_example.rb
Normal file
|
|
@ -0,0 +1,345 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
#
|
||||||
|
# Synor ZK SDK Examples for Ruby
|
||||||
|
#
|
||||||
|
# Demonstrates zero-knowledge proof operations:
|
||||||
|
# - Circuit compilation (Circom)
|
||||||
|
# - Proof generation and verification
|
||||||
|
# - Multiple proving systems (Groth16, PLONK, STARK)
|
||||||
|
# - Recursive proof composition
|
||||||
|
# - Trusted setup ceremonies
|
||||||
|
#
|
||||||
|
|
||||||
|
require 'securerandom'
|
||||||
|
require 'synor/zk'
|
||||||
|
|
||||||
|
class ZkExample
|
||||||
|
def initialize(zk)
|
||||||
|
@zk = zk
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_circuit_example
|
||||||
|
puts '=== Circuit Compilation ==='
|
||||||
|
|
||||||
|
# Simple Circom circuit: prove knowledge of factors
|
||||||
|
circom_code = <<~CIRCOM
|
||||||
|
pragma circom 2.1.0;
|
||||||
|
|
||||||
|
template Multiplier() {
|
||||||
|
signal input a;
|
||||||
|
signal input b;
|
||||||
|
signal output c;
|
||||||
|
|
||||||
|
c <== a * b;
|
||||||
|
}
|
||||||
|
|
||||||
|
component main = Multiplier();
|
||||||
|
CIRCOM
|
||||||
|
|
||||||
|
# Compile the circuit
|
||||||
|
puts 'Compiling circuit...'
|
||||||
|
circuit = @zk.circuits.compile(
|
||||||
|
code: circom_code,
|
||||||
|
language: :circom
|
||||||
|
)
|
||||||
|
|
||||||
|
puts 'Circuit compiled:'
|
||||||
|
puts " Circuit ID: #{circuit.circuit_id}"
|
||||||
|
puts " Constraints: #{circuit.constraints}"
|
||||||
|
puts " Public inputs: #{circuit.public_inputs}"
|
||||||
|
puts " Private inputs: #{circuit.private_inputs}"
|
||||||
|
puts " Outputs: #{circuit.outputs}"
|
||||||
|
|
||||||
|
# Get circuit info
|
||||||
|
info = @zk.circuits.get(circuit.circuit_id)
|
||||||
|
puts "\nCircuit info:"
|
||||||
|
puts " Name: #{info.name}"
|
||||||
|
puts " Version: #{info.version}"
|
||||||
|
puts " Wires: #{info.wire_count}"
|
||||||
|
puts " Labels: #{info.label_count}"
|
||||||
|
|
||||||
|
# List available circuits
|
||||||
|
circuits = @zk.circuits.list
|
||||||
|
puts "\nAvailable circuits: #{circuits.length}"
|
||||||
|
circuits.first(3).each do |c|
|
||||||
|
puts " #{c.circuit_id}: #{c.name} (#{c.constraints} constraints)"
|
||||||
|
end
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_groth16_example
|
||||||
|
puts '=== Groth16 Proving System ==='
|
||||||
|
|
||||||
|
circuit_id = 'multiplier-v1'
|
||||||
|
|
||||||
|
# Generate proving/verification keys (trusted setup)
|
||||||
|
puts 'Generating keys...'
|
||||||
|
keys = @zk.groth16.setup(circuit_id)
|
||||||
|
puts 'Keys generated:'
|
||||||
|
puts " Proving key size: #{keys.proving_key.length} bytes"
|
||||||
|
puts " Verification key size: #{keys.verification_key.length} bytes"
|
||||||
|
|
||||||
|
# Prepare witness (private inputs)
|
||||||
|
witness = { 'a' => '3', 'b' => '7' }
|
||||||
|
|
||||||
|
# Generate proof
|
||||||
|
puts "\nGenerating proof..."
|
||||||
|
proof = @zk.groth16.prove(
|
||||||
|
circuit_id: circuit_id,
|
||||||
|
witness: witness,
|
||||||
|
proving_key: keys.proving_key
|
||||||
|
)
|
||||||
|
|
||||||
|
puts 'Proof generated:'
|
||||||
|
puts " Proof size: #{proof.proof_bytes.length} bytes"
|
||||||
|
puts " Public signals: #{proof.public_signals.length}"
|
||||||
|
puts " Proving time: #{proof.proving_time_ms}ms"
|
||||||
|
|
||||||
|
# Verify proof
|
||||||
|
puts "\nVerifying proof..."
|
||||||
|
verified = @zk.groth16.verify(
|
||||||
|
proof: proof.proof_bytes,
|
||||||
|
public_signals: proof.public_signals,
|
||||||
|
verification_key: keys.verification_key
|
||||||
|
)
|
||||||
|
|
||||||
|
puts "Verification result: #{verified}"
|
||||||
|
|
||||||
|
# Export proof for on-chain verification
|
||||||
|
solidity_calldata = @zk.groth16.export_calldata(proof)
|
||||||
|
puts "\nSolidity calldata: #{solidity_calldata[0, 100]}..."
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_plonk_example
|
||||||
|
puts '=== PLONK Proving System ==='
|
||||||
|
|
||||||
|
circuit_id = 'multiplier-v1'
|
||||||
|
|
||||||
|
# PLONK uses universal trusted setup
|
||||||
|
puts 'Getting universal setup...'
|
||||||
|
srs = @zk.plonk.get_universal_setup(14) # 2^14 constraints
|
||||||
|
puts "SRS loaded: #{srs.length} bytes"
|
||||||
|
|
||||||
|
# Generate circuit-specific keys
|
||||||
|
puts "\nGenerating circuit keys..."
|
||||||
|
keys = @zk.plonk.setup(circuit_id, srs)
|
||||||
|
puts 'Keys generated'
|
||||||
|
|
||||||
|
# Generate proof
|
||||||
|
witness = { 'a' => '5', 'b' => '9' }
|
||||||
|
puts "\nGenerating PLONK proof..."
|
||||||
|
proof = @zk.plonk.prove(
|
||||||
|
circuit_id: circuit_id,
|
||||||
|
witness: witness,
|
||||||
|
proving_key: keys.proving_key
|
||||||
|
)
|
||||||
|
|
||||||
|
puts 'Proof generated:'
|
||||||
|
puts " Proof size: #{proof.proof_bytes.length} bytes"
|
||||||
|
puts " Proving time: #{proof.proving_time_ms}ms"
|
||||||
|
|
||||||
|
# Verify proof
|
||||||
|
verified = @zk.plonk.verify(
|
||||||
|
proof: proof.proof_bytes,
|
||||||
|
public_signals: proof.public_signals,
|
||||||
|
verification_key: keys.verification_key
|
||||||
|
)
|
||||||
|
puts "Verification result: #{verified}"
|
||||||
|
|
||||||
|
# Compare with Groth16
|
||||||
|
puts "\nPLONK advantages:"
|
||||||
|
puts ' - Universal trusted setup'
|
||||||
|
puts ' - Larger proofs (~2.5 KB vs ~200 bytes)'
|
||||||
|
puts ' - Faster proving for some circuits'
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_stark_example
|
||||||
|
puts '=== STARK Proving System ==='
|
||||||
|
|
||||||
|
circuit_id = 'multiplier-v1'
|
||||||
|
|
||||||
|
# STARKs don't need trusted setup
|
||||||
|
puts 'Configuring STARK parameters...'
|
||||||
|
config = {
|
||||||
|
field_size: 256,
|
||||||
|
hash_function: :poseidon,
|
||||||
|
blowup_factor: 8,
|
||||||
|
num_queries: 30,
|
||||||
|
folding_factor: 8
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate proof
|
||||||
|
witness = { 'a' => '11', 'b' => '13' }
|
||||||
|
puts "\nGenerating STARK proof..."
|
||||||
|
proof = @zk.stark.prove(
|
||||||
|
circuit_id: circuit_id,
|
||||||
|
witness: witness,
|
||||||
|
config: config
|
||||||
|
)
|
||||||
|
|
||||||
|
puts 'Proof generated:'
|
||||||
|
puts " Proof size: #{proof.proof_bytes.length} bytes"
|
||||||
|
puts " Proving time: #{proof.proving_time_ms}ms"
|
||||||
|
puts " FRI layers: #{proof.fri_layers}"
|
||||||
|
|
||||||
|
# Verify proof
|
||||||
|
puts "\nVerifying STARK proof..."
|
||||||
|
verified = @zk.stark.verify(
|
||||||
|
proof: proof.proof_bytes,
|
||||||
|
public_signals: proof.public_signals,
|
||||||
|
config: config
|
||||||
|
)
|
||||||
|
|
||||||
|
puts "Verification result: #{verified}"
|
||||||
|
|
||||||
|
# Compare with SNARKs
|
||||||
|
puts "\nSTARK advantages:"
|
||||||
|
puts ' - No trusted setup needed'
|
||||||
|
puts ' - Post-quantum secure'
|
||||||
|
puts ' - Larger proofs (~100 KB)'
|
||||||
|
puts ' - Faster proving for complex computations'
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_recursive_example
|
||||||
|
puts '=== Recursive Proof Composition ==='
|
||||||
|
|
||||||
|
# Create inner proofs
|
||||||
|
puts 'Generating inner proofs...'
|
||||||
|
inner_proofs = []
|
||||||
|
|
||||||
|
(1..3).each do |i|
|
||||||
|
witness = { 'a' => i.to_s, 'b' => (i + 1).to_s }
|
||||||
|
|
||||||
|
proof = @zk.recursive.prove_inner(
|
||||||
|
circuit_id: 'multiplier-v1',
|
||||||
|
witness: witness,
|
||||||
|
level: 0
|
||||||
|
)
|
||||||
|
inner_proofs << proof
|
||||||
|
puts " Inner proof #{i} generated"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Aggregate proofs recursively
|
||||||
|
puts "\nAggregating proofs..."
|
||||||
|
aggregated_proof = @zk.recursive.aggregate(
|
||||||
|
proofs: inner_proofs,
|
||||||
|
aggregation_circuit: 'recursive-aggregator-v1'
|
||||||
|
)
|
||||||
|
|
||||||
|
puts 'Aggregated proof:'
|
||||||
|
puts " Proof size: #{aggregated_proof.proof_bytes.length} bytes"
|
||||||
|
puts " Proofs aggregated: #{aggregated_proof.proofs_aggregated}"
|
||||||
|
puts " Recursion depth: #{aggregated_proof.recursion_depth}"
|
||||||
|
|
||||||
|
# Verify aggregated proof (verifies all inner proofs at once)
|
||||||
|
puts "\nVerifying aggregated proof..."
|
||||||
|
verified = @zk.recursive.verify_aggregated(aggregated_proof)
|
||||||
|
puts "Verification result: #{verified}"
|
||||||
|
|
||||||
|
# Use cases
|
||||||
|
puts "\nRecursive proof use cases:"
|
||||||
|
puts ' - Rollup batch verification'
|
||||||
|
puts ' - Incremental computation proofs'
|
||||||
|
puts ' - Cross-chain state proofs'
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
|
||||||
|
def run_ceremony_example
|
||||||
|
puts '=== Trusted Setup Ceremony ==='
|
||||||
|
|
||||||
|
# List active ceremonies
|
||||||
|
ceremonies = @zk.ceremony.list(:active)
|
||||||
|
puts "Active ceremonies: #{ceremonies.length}"
|
||||||
|
|
||||||
|
ceremonies.first(3).each do |ceremony|
|
||||||
|
puts "\n #{ceremony.ceremony_id}:"
|
||||||
|
puts " Circuit: #{ceremony.circuit_id}"
|
||||||
|
puts " Participants: #{ceremony.participant_count}"
|
||||||
|
puts " Current round: #{ceremony.current_round}"
|
||||||
|
puts " Status: #{ceremony.status}"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Create a new ceremony
|
||||||
|
puts "\nCreating new ceremony..."
|
||||||
|
new_ceremony = @zk.ceremony.create(
|
||||||
|
circuit_id: 'new-circuit-v1',
|
||||||
|
min_participants: 10,
|
||||||
|
max_participants: 100,
|
||||||
|
round_duration: 3600, # 1 hour per round
|
||||||
|
verify_contributions: true
|
||||||
|
)
|
||||||
|
|
||||||
|
puts 'Ceremony created:'
|
||||||
|
puts " Ceremony ID: #{new_ceremony.ceremony_id}"
|
||||||
|
puts " Join URL: #{new_ceremony.join_url}"
|
||||||
|
|
||||||
|
# Participate in a ceremony
|
||||||
|
puts "\nParticipating in ceremony..."
|
||||||
|
|
||||||
|
# Generate entropy
|
||||||
|
entropy = SecureRandom.random_bytes(32)
|
||||||
|
|
||||||
|
contribution = @zk.ceremony.contribute(
|
||||||
|
ceremony_id: new_ceremony.ceremony_id,
|
||||||
|
entropy: entropy
|
||||||
|
)
|
||||||
|
|
||||||
|
puts 'Contribution made:'
|
||||||
|
puts " Contribution ID: #{contribution.contribution_id}"
|
||||||
|
puts " Position: #{contribution.position}"
|
||||||
|
puts " Hash: #{contribution.hash}"
|
||||||
|
|
||||||
|
# Verify a contribution
|
||||||
|
puts "\nVerifying contribution..."
|
||||||
|
valid = @zk.ceremony.verify_contribution(contribution.contribution_id)
|
||||||
|
puts "Contribution valid: #{valid}"
|
||||||
|
|
||||||
|
# Get ceremony transcript (for auditability)
|
||||||
|
transcript = @zk.ceremony.get_transcript(new_ceremony.ceremony_id)
|
||||||
|
puts "\nCeremony transcript:"
|
||||||
|
puts " Total contributions: #{transcript.contributions.length}"
|
||||||
|
puts " Start time: #{transcript.start_time}"
|
||||||
|
puts " Final hash: #{transcript.final_hash.empty? ? 'pending' : transcript.final_hash}"
|
||||||
|
puts
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Main execution
|
||||||
|
if __FILE__ == $PROGRAM_NAME
|
||||||
|
# Initialize client
|
||||||
|
api_key = ENV.fetch('SYNOR_API_KEY', 'your-api-key')
|
||||||
|
config = Synor::Zk::Config.new(
|
||||||
|
api_key: api_key,
|
||||||
|
endpoint: 'https://zk.synor.io/v1',
|
||||||
|
timeout: 120, # ZK operations can be slow
|
||||||
|
retries: 3,
|
||||||
|
debug: false,
|
||||||
|
default_proving_system: :groth16,
|
||||||
|
prove_timeout: 300,
|
||||||
|
verify_timeout: 30
|
||||||
|
)
|
||||||
|
|
||||||
|
zk = Synor::Zk::Client.new(config)
|
||||||
|
example = ZkExample.new(zk)
|
||||||
|
|
||||||
|
begin
|
||||||
|
# Check service health
|
||||||
|
healthy = zk.health_check
|
||||||
|
puts "Service healthy: #{healthy}\n\n"
|
||||||
|
|
||||||
|
# Run examples
|
||||||
|
example.run_circuit_example
|
||||||
|
example.run_groth16_example
|
||||||
|
example.run_plonk_example
|
||||||
|
example.run_stark_example
|
||||||
|
example.run_recursive_example
|
||||||
|
example.run_ceremony_example
|
||||||
|
rescue StandardError => e
|
||||||
|
warn "Error: #{e.message}"
|
||||||
|
exit 1
|
||||||
|
end
|
||||||
|
end
|
||||||
Loading…
Add table
Reference in a new issue