From 5e59d3e70f01e54e8196de7c63650783b91f4bc9 Mon Sep 17 00:00:00 2001 From: KevinMB0220 Date: Sat, 17 Jan 2026 14:55:07 -0600 Subject: [PATCH 1/2] fix(contract): redeploy Zylith with Argent wallet compatibility ## Changes ### Contract Updates - Move proof and public_inputs arrays to end of function parameters for Argent wallet compatibility - Change tick_lower/tick_upper from i32 to felt252 for Starknet.js compatibility - Add get_version() function to contract interface - Update Scarb.toml to use starknet 2.13.1 ### Redeployment - New contract address: 0x00c692a0a7b34ffe8c5484e6db9488dc881ceae9c9b05d67de21387ea9f3edd6 - Same verifier contracts maintained ### Frontend/ASP Updates - Update contract address in all configuration files - Update ABIs to match new contract interface - Update tests with new contract address ### New Scripts - Add circuit verification scripts - Add position commitment calculation helpers Co-Authored-By: Claude Opus 4.5 --- .claude/settings.json | 7 + asp/README.md | 4 +- asp/src/abis/zylith-abi.json | 399 ++++++++--------- asp/src/bin/initialize_pool.rs | 2 +- asp/src/main.rs | 2 +- asp/start.sh | 2 +- circuits/proof_script_1766861888677913151.js | 25 ++ circuits/scripts/finalize_verifiers.sh | 42 ++ circuits/scripts/generate_proof_keys.sh | 54 +++ .../test_position_commitment_direct.js | 58 +++ .../test_position_commitment_fixture.js | 52 +++ frontend/README.md | 2 +- .../portfolio/__tests__/NotesList.test.tsx | 4 +- .../__tests__/use-private-deposit.test.ts | 6 +- frontend/src/hooks/use-liquidity.ts | 68 +-- frontend/src/hooks/use-private-swap.ts | 13 +- frontend/src/lib/abis/zylith-abi.json | 403 +++++++++--------- frontend/src/lib/config.ts | 2 +- frontend/src/lib/contracts/zylith-contract.ts | 7 +- scripts/calculate_position_commitment.js | 67 +++ zylith/CONTRACT_ADDRESS.md | 4 +- zylith/Scarb.lock | 4 +- zylith/Scarb.toml | 4 +- zylith/deployment_devnet_20251228_191103.json | 26 ++ .../deployment_sepolia_20260117_134421.json | 26 ++ zylith/src/interfaces/izylith.cairo | 22 +- zylith/src/zylith.cairo | 29 +- zylith/tests/test_e2e_proofs.cairo | 330 -------------- .../test_swap_with_frontend_values.cairo | 150 +++++++ .../test_u256_to_felt252_conversion.cairo | 202 +++++++++ 30 files changed, 1220 insertions(+), 796 deletions(-) create mode 100644 .claude/settings.json create mode 100644 circuits/proof_script_1766861888677913151.js create mode 100755 circuits/scripts/finalize_verifiers.sh create mode 100755 circuits/scripts/generate_proof_keys.sh create mode 100644 circuits/scripts/test_position_commitment_direct.js create mode 100644 circuits/scripts/test_position_commitment_fixture.js create mode 100755 scripts/calculate_position_commitment.js create mode 100644 zylith/deployment_devnet_20251228_191103.json create mode 100644 zylith/deployment_sepolia_20260117_134421.json delete mode 100644 zylith/tests/test_e2e_proofs.cairo create mode 100644 zylith/tests/test_swap_with_frontend_values.cairo create mode 100644 zylith/tests/test_u256_to_felt252_conversion.cairo diff --git a/.claude/settings.json b/.claude/settings.json new file mode 100644 index 0000000..32147ce --- /dev/null +++ b/.claude/settings.json @@ -0,0 +1,7 @@ +{ + "permissions": { + "allow": [ + "Bash(scarb build:*)" + ] + } +} diff --git a/asp/README.md b/asp/README.md index 52866cb..eeef497 100644 --- a/asp/README.md +++ b/asp/README.md @@ -18,7 +18,7 @@ cd asp # Configurar variables de entorno export RPC_URL="https://api.cartridge.gg/x/starknet/sepolia" -export CONTRACT_ADDRESS="0x00cf52fa0d4f080faac7e780ae5b7298047c1626db180ad7bd628fa87860dfba" +export CONTRACT_ADDRESS="0x00c692a0a7b34ffe8c5484e6db9488dc881ceae9c9b05d67de21387ea9f3edd6" export PORT="3000" # Compilar (primera vez) @@ -42,7 +42,7 @@ cargo run --release ```bash export RPC_URL="https://api.cartridge.gg/x/starknet/sepolia" -export CONTRACT_ADDRESS="0x00cf52fa0d4f080faac7e780ae5b7298047c1626db180ad7bd628fa87860dfba" +export CONTRACT_ADDRESS="0x00c692a0a7b34ffe8c5484e6db9488dc881ceae9c9b05d67de21387ea9f3edd6" export PORT="3000" ``` diff --git a/asp/src/abis/zylith-abi.json b/asp/src/abis/zylith-abi.json index 88918c6..c9d236f 100644 --- a/asp/src/abis/zylith-abi.json +++ b/asp/src/abis/zylith-abi.json @@ -1,12 +1,12 @@ [ { - "name": "ZylithImpl", "type": "impl", + "name": "ZylithImpl", "interface_name": "zylith::interfaces::izylith::IZylith" }, { - "name": "core::integer::u256", "type": "struct", + "name": "core::integer::u256", "members": [ { "name": "low", @@ -19,8 +19,8 @@ ] }, { - "name": "core::bool", "type": "enum", + "name": "core::bool", "variants": [ { "name": "False", @@ -33,12 +33,12 @@ ] }, { - "name": "zylith::interfaces::izylith::IZylith", "type": "interface", + "name": "zylith::interfaces::izylith::IZylith", "items": [ { - "name": "initialize", "type": "function", + "name": "initialize", "inputs": [ { "name": "token0", @@ -65,8 +65,8 @@ "state_mutability": "external" }, { - "name": "private_deposit", "type": "function", + "name": "private_deposit", "inputs": [ { "name": "token", @@ -85,17 +85,9 @@ "state_mutability": "external" }, { - "name": "private_swap", "type": "function", + "name": "private_swap", "inputs": [ - { - "name": "proof", - "type": "core::array::Array::" - }, - { - "name": "public_inputs", - "type": "core::array::Array::" - }, { "name": "zero_for_one", "type": "core::bool" @@ -111,6 +103,14 @@ { "name": "new_commitment", "type": "core::felt252" + }, + { + "name": "proof", + "type": "core::array::Array::" + }, + { + "name": "public_inputs", + "type": "core::array::Array::" } ], "outputs": [ @@ -121,17 +121,9 @@ "state_mutability": "external" }, { - "name": "private_withdraw", "type": "function", + "name": "private_withdraw", "inputs": [ - { - "name": "proof", - "type": "core::array::Array::" - }, - { - "name": "public_inputs", - "type": "core::array::Array::" - }, { "name": "token", "type": "core::starknet::contract_address::ContractAddress" @@ -143,30 +135,30 @@ { "name": "amount", "type": "core::integer::u128" + }, + { + "name": "proof", + "type": "core::array::Array::" + }, + { + "name": "public_inputs", + "type": "core::array::Array::" } ], "outputs": [], "state_mutability": "external" }, { - "name": "private_mint_liquidity", "type": "function", + "name": "private_mint_liquidity", "inputs": [ { - "name": "proof", - "type": "core::array::Array::" - }, - { - "name": "public_inputs", - "type": "core::array::Array::" - }, - { - "name": "tick_lower", - "type": "core::integer::i32" + "name": "tick_lower_felt", + "type": "core::felt252" }, { - "name": "tick_upper", - "type": "core::integer::i32" + "name": "tick_upper_felt", + "type": "core::felt252" }, { "name": "liquidity", @@ -175,6 +167,14 @@ { "name": "new_commitment", "type": "core::felt252" + }, + { + "name": "proof", + "type": "core::array::Array::" + }, + { + "name": "public_inputs", + "type": "core::array::Array::" } ], "outputs": [ @@ -185,24 +185,16 @@ "state_mutability": "external" }, { - "name": "private_burn_liquidity", "type": "function", + "name": "private_burn_liquidity", "inputs": [ { - "name": "proof", - "type": "core::array::Array::" - }, - { - "name": "public_inputs", - "type": "core::array::Array::" - }, - { - "name": "tick_lower", - "type": "core::integer::i32" + "name": "tick_lower_felt", + "type": "core::felt252" }, { - "name": "tick_upper", - "type": "core::integer::i32" + "name": "tick_upper_felt", + "type": "core::felt252" }, { "name": "liquidity", @@ -211,6 +203,14 @@ { "name": "new_commitment", "type": "core::felt252" + }, + { + "name": "proof", + "type": "core::array::Array::" + }, + { + "name": "public_inputs", + "type": "core::array::Array::" } ], "outputs": [ @@ -221,28 +221,28 @@ "state_mutability": "external" }, { - "name": "private_collect", "type": "function", + "name": "private_collect", "inputs": [ { - "name": "proof", - "type": "core::array::Array::" + "name": "tick_lower_felt", + "type": "core::felt252" }, { - "name": "public_inputs", - "type": "core::array::Array::" + "name": "tick_upper_felt", + "type": "core::felt252" }, { - "name": "tick_lower", - "type": "core::integer::i32" + "name": "new_commitment", + "type": "core::felt252" }, { - "name": "tick_upper", - "type": "core::integer::i32" + "name": "proof", + "type": "core::array::Array::" }, { - "name": "new_commitment", - "type": "core::felt252" + "name": "public_inputs", + "type": "core::array::Array::" } ], "outputs": [ @@ -253,8 +253,8 @@ "state_mutability": "external" }, { - "name": "mint", "type": "function", + "name": "mint", "inputs": [ { "name": "tick_lower", @@ -277,8 +277,8 @@ "state_mutability": "external" }, { - "name": "swap", "type": "function", + "name": "swap", "inputs": [ { "name": "zero_for_one", @@ -301,8 +301,8 @@ "state_mutability": "external" }, { - "name": "burn", "type": "function", + "name": "burn", "inputs": [ { "name": "tick_lower", @@ -325,8 +325,8 @@ "state_mutability": "external" }, { - "name": "collect", "type": "function", + "name": "collect", "inputs": [ { "name": "tick_lower", @@ -345,8 +345,8 @@ "state_mutability": "external" }, { - "name": "get_merkle_root", "type": "function", + "name": "get_merkle_root", "inputs": [], "outputs": [ { @@ -356,8 +356,8 @@ "state_mutability": "view" }, { - "name": "is_nullifier_spent", "type": "function", + "name": "is_nullifier_spent", "inputs": [ { "name": "nullifier", @@ -372,8 +372,8 @@ "state_mutability": "view" }, { - "name": "is_root_known", "type": "function", + "name": "is_root_known", "inputs": [ { "name": "root", @@ -388,8 +388,8 @@ "state_mutability": "view" }, { - "name": "get_known_roots_count", "type": "function", + "name": "get_known_roots_count", "inputs": [], "outputs": [ { @@ -397,12 +397,23 @@ } ], "state_mutability": "view" + }, + { + "type": "function", + "name": "get_version", + "inputs": [], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" } ] }, { - "name": "constructor", "type": "constructor", + "name": "constructor", "inputs": [ { "name": "owner", @@ -427,336 +438,336 @@ ] }, { - "kind": "struct", - "name": "zylith::clmm::pool::Initialize", "type": "event", + "name": "zylith::clmm::pool::Initialize", + "kind": "struct", "members": [ { - "kind": "data", "name": "sqrt_price_x128", - "type": "core::integer::u256" + "type": "core::integer::u256", + "kind": "data" }, { - "kind": "data", "name": "tick", - "type": "core::integer::i32" + "type": "core::integer::i32", + "kind": "data" } ] }, { - "kind": "struct", - "name": "zylith::clmm::pool::Swap", "type": "event", + "name": "zylith::clmm::pool::Swap", + "kind": "struct", "members": [ { - "kind": "data", "name": "sender", - "type": "core::starknet::contract_address::ContractAddress" + "type": "core::starknet::contract_address::ContractAddress", + "kind": "data" }, { - "kind": "data", "name": "zero_for_one", - "type": "core::bool" + "type": "core::bool", + "kind": "data" }, { - "kind": "data", "name": "amount0", - "type": "core::integer::i128" + "type": "core::integer::i128", + "kind": "data" }, { - "kind": "data", "name": "amount1", - "type": "core::integer::i128" + "type": "core::integer::i128", + "kind": "data" }, { - "kind": "data", "name": "sqrt_price_x128", - "type": "core::integer::u256" + "type": "core::integer::u256", + "kind": "data" }, { - "kind": "data", "name": "liquidity", - "type": "core::integer::u128" + "type": "core::integer::u128", + "kind": "data" }, { - "kind": "data", "name": "tick", - "type": "core::integer::i32" + "type": "core::integer::i32", + "kind": "data" } ] }, { - "kind": "struct", - "name": "zylith::clmm::pool::Mint", "type": "event", + "name": "zylith::clmm::pool::Mint", + "kind": "struct", "members": [ { - "kind": "data", "name": "sender", - "type": "core::starknet::contract_address::ContractAddress" + "type": "core::starknet::contract_address::ContractAddress", + "kind": "data" }, { - "kind": "data", "name": "owner", - "type": "core::starknet::contract_address::ContractAddress" + "type": "core::starknet::contract_address::ContractAddress", + "kind": "data" }, { - "kind": "data", "name": "tick_lower", - "type": "core::integer::i32" + "type": "core::integer::i32", + "kind": "data" }, { - "kind": "data", "name": "tick_upper", - "type": "core::integer::i32" + "type": "core::integer::i32", + "kind": "data" }, { - "kind": "data", "name": "amount", - "type": "core::integer::u128" + "type": "core::integer::u128", + "kind": "data" }, { - "kind": "data", "name": "amount0", - "type": "core::integer::u128" + "type": "core::integer::u128", + "kind": "data" }, { - "kind": "data", "name": "amount1", - "type": "core::integer::u128" + "type": "core::integer::u128", + "kind": "data" } ] }, { - "kind": "struct", - "name": "zylith::clmm::pool::Burn", "type": "event", + "name": "zylith::clmm::pool::Burn", + "kind": "struct", "members": [ { - "kind": "data", "name": "owner", - "type": "core::starknet::contract_address::ContractAddress" + "type": "core::starknet::contract_address::ContractAddress", + "kind": "data" }, { - "kind": "data", "name": "tick_lower", - "type": "core::integer::i32" + "type": "core::integer::i32", + "kind": "data" }, { - "kind": "data", "name": "tick_upper", - "type": "core::integer::i32" + "type": "core::integer::i32", + "kind": "data" }, { - "kind": "data", "name": "amount", - "type": "core::integer::u128" + "type": "core::integer::u128", + "kind": "data" }, { - "kind": "data", "name": "amount0", - "type": "core::integer::u128" + "type": "core::integer::u128", + "kind": "data" }, { - "kind": "data", "name": "amount1", - "type": "core::integer::u128" + "type": "core::integer::u128", + "kind": "data" } ] }, { - "kind": "struct", - "name": "zylith::clmm::pool::Collect", "type": "event", + "name": "zylith::clmm::pool::Collect", + "kind": "struct", "members": [ { - "kind": "data", "name": "owner", - "type": "core::starknet::contract_address::ContractAddress" + "type": "core::starknet::contract_address::ContractAddress", + "kind": "data" }, { - "kind": "data", "name": "tick_lower", - "type": "core::integer::i32" + "type": "core::integer::i32", + "kind": "data" }, { - "kind": "data", "name": "tick_upper", - "type": "core::integer::i32" + "type": "core::integer::i32", + "kind": "data" }, { - "kind": "data", "name": "amount0", - "type": "core::integer::u128" + "type": "core::integer::u128", + "kind": "data" }, { - "kind": "data", "name": "amount1", - "type": "core::integer::u128" + "type": "core::integer::u128", + "kind": "data" } ] }, { - "kind": "enum", - "name": "zylith::clmm::pool::PoolEvent", "type": "event", + "name": "zylith::clmm::pool::PoolEvent", + "kind": "enum", "variants": [ { - "kind": "nested", "name": "Initialize", - "type": "zylith::clmm::pool::Initialize" + "type": "zylith::clmm::pool::Initialize", + "kind": "nested" }, { - "kind": "nested", "name": "Swap", - "type": "zylith::clmm::pool::Swap" + "type": "zylith::clmm::pool::Swap", + "kind": "nested" }, { - "kind": "nested", "name": "Mint", - "type": "zylith::clmm::pool::Mint" + "type": "zylith::clmm::pool::Mint", + "kind": "nested" }, { - "kind": "nested", "name": "Burn", - "type": "zylith::clmm::pool::Burn" + "type": "zylith::clmm::pool::Burn", + "kind": "nested" }, { - "kind": "nested", "name": "Collect", - "type": "zylith::clmm::pool::Collect" + "type": "zylith::clmm::pool::Collect", + "kind": "nested" } ] }, { - "kind": "struct", - "name": "zylith::privacy::deposit::Deposit", "type": "event", + "name": "zylith::privacy::deposit::Deposit", + "kind": "struct", "members": [ { - "kind": "data", "name": "commitment", - "type": "core::felt252" + "type": "core::felt252", + "kind": "data" }, { - "kind": "data", "name": "leaf_index", - "type": "core::integer::u32" + "type": "core::integer::u32", + "kind": "data" }, { - "kind": "data", "name": "root", - "type": "core::felt252" + "type": "core::felt252", + "kind": "data" } ] }, { - "kind": "struct", - "name": "zylith::privacy::deposit::NullifierSpent", "type": "event", + "name": "zylith::privacy::deposit::NullifierSpent", + "kind": "struct", "members": [ { - "kind": "data", "name": "nullifier", - "type": "core::felt252" + "type": "core::felt252", + "kind": "data" } ] }, { - "kind": "enum", - "name": "zylith::privacy::deposit::PrivacyEvent", "type": "event", + "name": "zylith::privacy::deposit::PrivacyEvent", + "kind": "enum", "variants": [ { - "kind": "nested", "name": "Deposit", - "type": "zylith::privacy::deposit::Deposit" + "type": "zylith::privacy::deposit::Deposit", + "kind": "nested" }, { - "kind": "nested", "name": "NullifierSpent", - "type": "zylith::privacy::deposit::NullifierSpent" + "type": "zylith::privacy::deposit::NullifierSpent", + "kind": "nested" } ] }, { - "kind": "struct", - "name": "zylith::zylith::Zylith::Initialized", "type": "event", + "name": "zylith::zylith::Zylith::Initialized", + "kind": "struct", "members": [ { - "kind": "data", "name": "token0", - "type": "core::starknet::contract_address::ContractAddress" + "type": "core::starknet::contract_address::ContractAddress", + "kind": "data" }, { - "kind": "data", "name": "token1", - "type": "core::starknet::contract_address::ContractAddress" + "type": "core::starknet::contract_address::ContractAddress", + "kind": "data" }, { - "kind": "data", "name": "fee", - "type": "core::integer::u128" + "type": "core::integer::u128", + "kind": "data" }, { - "kind": "data", "name": "tick_spacing", - "type": "core::integer::i32" + "type": "core::integer::i32", + "kind": "data" }, { - "kind": "data", "name": "sqrt_price_x128", - "type": "core::integer::u256" + "type": "core::integer::u256", + "kind": "data" } ] }, { - "kind": "struct", - "name": "zylith::zylith::Zylith::ProofRejected", "type": "event", + "name": "zylith::zylith::Zylith::ProofRejected", + "kind": "struct", "members": [ { - "kind": "data", "name": "proof_type", - "type": "core::felt252" + "type": "core::felt252", + "kind": "data" }, { - "kind": "data", "name": "caller", - "type": "core::starknet::contract_address::ContractAddress" + "type": "core::starknet::contract_address::ContractAddress", + "kind": "data" }, { - "kind": "data", "name": "error", - "type": "core::felt252" + "type": "core::felt252", + "kind": "data" } ] }, { - "kind": "enum", - "name": "zylith::zylith::Zylith::Event", "type": "event", + "name": "zylith::zylith::Zylith::Event", + "kind": "enum", "variants": [ { - "kind": "nested", "name": "PoolEvent", - "type": "zylith::clmm::pool::PoolEvent" + "type": "zylith::clmm::pool::PoolEvent", + "kind": "nested" }, { - "kind": "nested", "name": "PrivacyEvent", - "type": "zylith::privacy::deposit::PrivacyEvent" + "type": "zylith::privacy::deposit::PrivacyEvent", + "kind": "nested" }, { - "kind": "nested", "name": "Initialized", - "type": "zylith::zylith::Zylith::Initialized" + "type": "zylith::zylith::Zylith::Initialized", + "kind": "nested" }, { - "kind": "nested", "name": "ProofRejected", - "type": "zylith::zylith::Zylith::ProofRejected" + "type": "zylith::zylith::Zylith::ProofRejected", + "kind": "nested" } ] } diff --git a/asp/src/bin/initialize_pool.rs b/asp/src/bin/initialize_pool.rs index 3787ea9..9d2d7ea 100644 --- a/asp/src/bin/initialize_pool.rs +++ b/asp/src/bin/initialize_pool.rs @@ -19,7 +19,7 @@ async fn main() -> Result<(), Box> { let rpc_url = std::env::var("STARKNET_RPC") .unwrap_or_else(|_| "https://starknet-sepolia-rpc.publicnode.com".to_string()); let zylith_address = std::env::var("ZYLITH_CONTRACT") - .unwrap_or_else(|_| "0x00cf52fa0d4f080faac7e780ae5b7298047c1626db180ad7bd628fa87860dfba".to_string()); + .unwrap_or_else(|_| "0x00c692a0a7b34ffe8c5484e6db9488dc881ceae9c9b05d67de21387ea9f3edd6".to_string()); // Get private key from environment or use default for testing let private_key_hex = std::env::var("PRIVATE_KEY") diff --git a/asp/src/main.rs b/asp/src/main.rs index 279010b..eb97fc8 100644 --- a/asp/src/main.rs +++ b/asp/src/main.rs @@ -63,7 +63,7 @@ async fn main() { let rpc_url = std::env::var("RPC_URL") .unwrap_or_else(|_| "https://api.cartridge.gg/x/starknet/sepolia".to_string()); let contract_address = std::env::var("CONTRACT_ADDRESS").unwrap_or_else(|_| { - "0x00cf52fa0d4f080faac7e780ae5b7298047c1626db180ad7bd628fa87860dfba".to_string() + "0x00c692a0a7b34ffe8c5484e6db9488dc881ceae9c9b05d67de21387ea9f3edd6".to_string() }); // Validate ABIs on startup diff --git a/asp/start.sh b/asp/start.sh index 376b7c2..f213005 100755 --- a/asp/start.sh +++ b/asp/start.sh @@ -31,7 +31,7 @@ echo -e "${BLUE}=== Zylith ASP Server ===${NC}" # Configurar variables de entorno export RPC_URL="${RPC_URL:-https://api.cartridge.gg/x/starknet/sepolia}" -export CONTRACT_ADDRESS="${CONTRACT_ADDRESS:-0x00cf52fa0d4f080faac7e780ae5b7298047c1626db180ad7bd628fa87860dfba}" +export CONTRACT_ADDRESS="${CONTRACT_ADDRESS:-0x00c692a0a7b34ffe8c5484e6db9488dc881ceae9c9b05d67de21387ea9f3edd6}" export PORT="${PORT:-3000}" echo -e "${YELLOW}ConfiguraciΓ³n:${NC}" diff --git a/circuits/proof_script_1766861888677913151.js b/circuits/proof_script_1766861888677913151.js new file mode 100644 index 0000000..4ded53e --- /dev/null +++ b/circuits/proof_script_1766861888677913151.js @@ -0,0 +1,25 @@ + + const snarkjs = require('snarkjs'); + const fs = require('fs'); + + (async () => { + try { + console.log('Generating proof...'); + const startTime = Date.now(); + + const { proof, publicSignals } = await snarkjs.groth16.prove( + '/home/ryzen/Desktop/dev/starknet-bounty/circuits/build/zkeys/swap.zkey', + '/tmp/swap_witness_1766861888677913151.wtns' + ); + + const elapsed = ((Date.now() - startTime) / 1000).toFixed(2); + console.log('Proof generated in', elapsed, 'seconds'); + + fs.writeFileSync('/tmp/swap_proof_1766861888677913151.json', JSON.stringify(proof, null, 2)); + fs.writeFileSync('/tmp/swap_public_1766861888677913151.json', JSON.stringify(publicSignals, null, 2)); + } catch (error) { + console.error('Error:', error.message); + process.exit(1); + } + })(); + \ No newline at end of file diff --git a/circuits/scripts/finalize_verifiers.sh b/circuits/scripts/finalize_verifiers.sh new file mode 100755 index 0000000..90a23e4 --- /dev/null +++ b/circuits/scripts/finalize_verifiers.sh @@ -0,0 +1,42 @@ +#!/bin/bash +set -e + +# This script assumes pot16_prepared.ptau exists + +CIRCUITS=("membership" "withdraw" "lp" "swap") + +for CIRCUIT in "${CIRCUITS[@]}"; do + echo "Generating keys for $CIRCUIT..." + + # Setup + ./node_modules/.bin/snarkjs groth16 setup out/$CIRCUIT.r1cs pot15_prepared.ptau out/${CIRCUIT}_0000.zkey + + # Contribute (dummy randomness) + ./node_modules/.bin/snarkjs zkey contribute out/${CIRCUIT}_0000.zkey out/${CIRCUIT}_final.zkey --name="Relayer" -v -e="random entropy" + + # Export Verification Key + ./node_modules/.bin/snarkjs zkey export verificationkey out/${CIRCUIT}_final.zkey out/${CIRCUIT}_vk.json + + echo "Generating Cairo Verifier for $CIRCUIT..." + source venv/bin/activate + export PATH="$(pwd)/mock_bin:$PATH" + # Garaga generation + # Output path structure: zylith/src/privacy/verifiers//groth16_verifier.cairo + # We might need to move them manually if garaga doesn't support custom output paths perfectly or if we want specific naming + + garaga gen --system groth16 --vk out/${CIRCUIT}_vk.json --project-name $CIRCUIT + + # Move generated files to correct location in zylith project + mkdir -p ../zylith/src/privacy/verifiers/$CIRCUIT + # Garaga generates a project structure. We need to extract the relevant contract. + # Usually: /src/groth16_verifier.cairo + cp $CIRCUIT/src/groth16_verifier.cairo ../zylith/src/privacy/verifiers/$CIRCUIT/groth16_verifier.cairo + cp $CIRCUIT/src/groth16_verifier_constants.cairo ../zylith/src/privacy/verifiers/$CIRCUIT/groth16_verifier_constants.cairo + + # Cleanup generated project + rm -rf $CIRCUIT + + echo "$CIRCUIT done!" +done + +echo "All verifiers generated and moved." diff --git a/circuits/scripts/generate_proof_keys.sh b/circuits/scripts/generate_proof_keys.sh new file mode 100755 index 0000000..a178fca --- /dev/null +++ b/circuits/scripts/generate_proof_keys.sh @@ -0,0 +1,54 @@ +#!/bin/bash +set -e + +# Powers of Tau file +# Using Hermez POT15 (pre-generated, trusted setup ceremony) +# POT15 supports up to 2^15 = 32,768 constraints +# Our circuits have ~20,946 constraints, so POT15 is sufficient +# Use prepared POT file for groth16 setup (required for phase2) +PTAU_PREPARED="pot15_prepared.ptau" +PTAU_FINAL="pot15_final.ptau" +PTAU_URL="https://storage.googleapis.com/zkevm/ptau/powersOfTau28_hez_final_15.ptau" + +# Check if prepared POT exists, if not prepare it +if [ ! -f "$PTAU_PREPARED" ]; then + # First ensure we have the final POT file + if [ ! -f "$PTAU_FINAL" ]; then + echo "Downloading Powers of Tau (POT15)..." + curl -L -o "$PTAU_FINAL" "$PTAU_URL" + echo "POT15 downloaded successfully!" + fi + + # Prepare POT for phase2 (required for groth16) + echo "Preparing POT file for phase2 (this may take a few minutes)..." + ./node_modules/.bin/snarkjs powersoftau prepare phase2 $PTAU_FINAL $PTAU_PREPARED + echo "POT prepared successfully!" +else + echo "Prepared POT file already exists, using it..." +fi + +# Use prepared POT file for groth16 setup +PTAU_TO_USE="$PTAU_PREPARED" + +# Key Generation for each circuit +CIRCUITS=("membership" "withdraw" "lp" "swap") + +for CIRCUIT in "${CIRCUITS[@]}"; do + echo "Generating keys for $CIRCUIT..." + + # Remove old keys if they exist (they're invalid after circuit changes) + rm -f out/${CIRCUIT}_0000.zkey out/${CIRCUIT}_final.zkey out/${CIRCUIT}_vk.json + + # Setup - use prepared POT file + ./node_modules/.bin/snarkjs groth16 setup out/$CIRCUIT.r1cs $PTAU_TO_USE out/${CIRCUIT}_0000.zkey + + # Contribute (dummy randomness) + ./node_modules/.bin/snarkjs zkey contribute out/${CIRCUIT}_0000.zkey out/${CIRCUIT}_final.zkey --name="Zylith" -e="random entropy $CIRCUIT" + + # Export Verification Key + ./node_modules/.bin/snarkjs zkey export verificationkey out/${CIRCUIT}_final.zkey out/${CIRCUIT}_vk.json + + echo "$CIRCUIT keys generated!" +done + +echo "All keys generated successfully." diff --git a/circuits/scripts/test_position_commitment_direct.js b/circuits/scripts/test_position_commitment_direct.js new file mode 100644 index 0000000..58ecdc2 --- /dev/null +++ b/circuits/scripts/test_position_commitment_direct.js @@ -0,0 +1,58 @@ +#!/usr/bin/env node +/** + * Test directo para calcular position_commitment + * Usa el mismo cΓ³digo que generate_test_fixtures.js + */ +const { generatePositionCommitment } = require('../circuits/scripts/utils.js'); + +async function main() { + const args = process.argv.slice(2); + + if (args.length < 3) { + console.error('Usage: node test_position_commitment_direct.js '); + console.error('Example: node test_position_commitment_direct.js 123 -1000 1000'); + process.exit(1); + } + + const secret = BigInt(args[0]); + const tickLower = parseInt(args[1]); + const tickUpper = parseInt(args[2]); + + console.log('='.repeat(70)); + console.log('πŸ§ͺ Test de position_commitment'); + console.log('='.repeat(70)); + console.log(`Secret: ${secret.toString()}`); + console.log(`Tick Lower: ${tickLower}`); + console.log(`Tick Upper: ${tickUpper}`); + console.log(`Expected tick_sum: ${tickLower + tickUpper}`); + console.log(); + + try { + const positionCommitment = await generatePositionCommitment(secret, tickLower, tickUpper); + const tickSum = BigInt(tickLower) + BigInt(tickUpper); + + console.log('βœ… CΓ‘lculo exitoso'); + console.log(); + console.log('πŸ“‹ Resultados:'); + console.log(` tick_sum: ${tickSum.toString()}`); + console.log(` position_commitment: 0x${positionCommitment.toString(16)}`); + console.log(); + console.log('='.repeat(70)); + console.log('πŸ’‘ Compara este position_commitment con el que espera el circuito'); + console.log('='.repeat(70)); + + // Output JSON for Python to parse + console.log(JSON.stringify({ + tick_sum: tickSum.toString(), + position_commitment: `0x${positionCommitment.toString(16)}` + })); + + } catch (error) { + console.error('❌ Error:', error.message); + console.error(error.stack); + process.exit(1); + } +} + +main(); + diff --git a/circuits/scripts/test_position_commitment_fixture.js b/circuits/scripts/test_position_commitment_fixture.js new file mode 100644 index 0000000..108895d --- /dev/null +++ b/circuits/scripts/test_position_commitment_fixture.js @@ -0,0 +1,52 @@ +#!/usr/bin/env node +/** + * Test usando generate_test_fixtures.js que ya funciona + * Calcula position_commitment con los mismos valores que se usan en los tests + */ +const { generatePositionCommitment } = require('../circuits/scripts/utils.js'); + +async function main() { + const args = process.argv.slice(2); + + // Valores de prueba (puedes cambiarlos) + const secret = args[0] ? BigInt(args[0]) : 123n; // TEST_SECRET_IN del fixture + const tickLower = args[1] ? parseInt(args[1]) : -600; + const tickUpper = args[2] ? parseInt(args[2]) : 600; + + console.log('='.repeat(70)); + console.log('πŸ§ͺ Test de position_commitment (usando utils.js)'); + console.log('='.repeat(70)); + console.log(`Secret: ${secret.toString()}`); + console.log(`Tick Lower: ${tickLower}`); + console.log(`Tick Upper: ${tickUpper}`); + console.log(`Expected tick_sum: ${tickLower + tickUpper}`); + console.log(); + + try { + console.log('πŸ“ž Calculando position_commitment...'); + const positionCommitment = await generatePositionCommitment(secret, tickLower, tickUpper); + const tickSum = BigInt(tickLower) + BigInt(tickUpper); + + console.log('βœ… CΓ‘lculo exitoso'); + console.log(); + console.log('πŸ“‹ Resultados:'); + console.log(` tick_sum: ${tickSum.toString()}`); + console.log(` position_commitment: 0x${positionCommitment.toString(16)}`); + console.log(); + console.log('='.repeat(70)); + + // Output JSON for Python to parse (last line) + console.log(JSON.stringify({ + tick_sum: tickSum.toString(), + position_commitment: `0x${positionCommitment.toString(16)}` + })); + + } catch (error) { + console.error('❌ Error:', error.message); + console.error(error.stack); + process.exit(1); + } +} + +main(); + diff --git a/frontend/README.md b/frontend/README.md index cf6a97b..b8c23f1 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -44,7 +44,7 @@ npm install Create a `.env.local` file: ```env -NEXT_PUBLIC_ZYLITH_CONTRACT=0x00cf52fa0d4f080faac7e780ae5b7298047c1626db180ad7bd628fa87860dfba +NEXT_PUBLIC_ZYLITH_CONTRACT=0x00c692a0a7b34ffe8c5484e6db9488dc881ceae9c9b05d67de21387ea9f3edd6 NEXT_PUBLIC_ASP_URL=http://localhost:3000 NEXT_PUBLIC_RPC_URL=https://starknet-sepolia.public.blastapi.io/rpc/v0_7 ``` diff --git a/frontend/src/components/portfolio/__tests__/NotesList.test.tsx b/frontend/src/components/portfolio/__tests__/NotesList.test.tsx index c503144..31466e5 100644 --- a/frontend/src/components/portfolio/__tests__/NotesList.test.tsx +++ b/frontend/src/components/portfolio/__tests__/NotesList.test.tsx @@ -127,7 +127,7 @@ describe("NotesList - Note Management (TODO 4.4)", () => { // Test leaf index extraction logic const mockEvent = { from_address: - "0x00cf52fa0d4f080faac7e780ae5b7298047c1626db180ad7bd628fa87860dfba", + "0x00c692a0a7b34ffe8c5484e6db9488dc881ceae9c9b05d67de21387ea9f3edd6", keys: [ "0x9149d2123147c5f43d258257fef0b7b969db78269369ebcf5ebb9eef8592f2", ], @@ -146,7 +146,7 @@ describe("NotesList - Note Management (TODO 4.4)", () => { // Test fallback when leaf index is not found const mockEvent = { from_address: - "0x00cf52fa0d4f080faac7e780ae5b7298047c1626db180ad7bd628fa87860dfba", + "0x00c692a0a7b34ffe8c5484e6db9488dc881ceae9c9b05d67de21387ea9f3edd6", keys: [ "0x9149d2123147c5f43d258257fef0b7b969db78269369ebcf5ebb9eef8592f2", ], diff --git a/frontend/src/hooks/__tests__/use-private-deposit.test.ts b/frontend/src/hooks/__tests__/use-private-deposit.test.ts index a950e2d..bc409cb 100644 --- a/frontend/src/hooks/__tests__/use-private-deposit.test.ts +++ b/frontend/src/hooks/__tests__/use-private-deposit.test.ts @@ -21,7 +21,7 @@ jest.mock("@/lib/commitment", () => ({ jest.mock("@/lib/config", () => ({ CONFIG: { ZYLITH_CONTRACT: - "0x00cf52fa0d4f080faac7e780ae5b7298047c1626db180ad7bd628fa87860dfba", + "0x00c692a0a7b34ffe8c5484e6db9488dc881ceae9c9b05d67de21387ea9f3edd6", }, })); @@ -78,7 +78,7 @@ describe("usePrivateDeposit - Core Logic", () => { // Test event parsing logic const mockEvent = { from_address: - "0x00cf52fa0d4f080faac7e780ae5b7298047c1626db180ad7bd628fa87860dfba", + "0x00c692a0a7b34ffe8c5484e6db9488dc881ceae9c9b05d67de21387ea9f3edd6", keys: [ "0x9149d2123147c5f43d258257fef0b7b969db78269369ebcf5ebb9eef8592f2", ], @@ -98,7 +98,7 @@ describe("usePrivateDeposit - Core Logic", () => { // Test that deposit events have the correct structure const validEvent = { from_address: - "0x00cf52fa0d4f080faac7e780ae5b7298047c1626db180ad7bd628fa87860dfba", + "0x00c692a0a7b34ffe8c5484e6db9488dc881ceae9c9b05d67de21387ea9f3edd6", keys: [ "0x9149d2123147c5f43d258257fef0b7b969db78269369ebcf5ebb9eef8592f2", ], diff --git a/frontend/src/hooks/use-liquidity.ts b/frontend/src/hooks/use-liquidity.ts index e749eed..bd21bde 100644 --- a/frontend/src/hooks/use-liquidity.ts +++ b/frontend/src/hooks/use-liquidity.ts @@ -8,7 +8,7 @@ import { usePortfolioStore } from "./use-portfolio" import { useLPPositionStore } from "@/stores/use-lp-position-store" import { generateNote, Note, generatePositionCommitment } from "@/lib/commitment" import { ZylithContractClient } from "@/lib/contracts/zylith-contract" -import { Contract, Account, CallData } from "starknet" +import { Contract, Account } from "starknet" import { CONFIG } from "@/lib/config" import zylithAbi from "@/lib/abis/zylith-abi.json" import { validateNote } from "@/lib/note-validation" @@ -628,6 +628,10 @@ export function useLiquidity() { console.log(` - liquidity: ${liquidityStr} (u128)`) console.log(` - new_commitment: ${newCommitmentStr} (felt252)`) console.log(` - position_commitment: ${normalizedPublicInputs[6]} (felt252)`) + + console.log(`[Frontend] πŸ” Debug - Array values:`) + console.log(` - normalizedProof:`, normalizedProof) + console.log(` - normalizedPublicInputs:`, normalizedPublicInputs) // Verify that the felt252 values match what's in public_inputs // The contract will verify that public_inputs[2] == tick_lower_felt @@ -648,24 +652,28 @@ export function useLiquidity() { console.log(` - liquidity: u128 = ${liquidityStr}`) console.log(` - new_commitment: felt252 = ${newCommitmentStr}`) - // Create Contract instance with account as provider - // This ensures Starknet.js handles all type serialization automatically - const contract = new Contract( - zylithAbi, - CONFIG.ZYLITH_CONTRACT, - account // ← CRITICAL: Pass account as provider for proper serialization - ) - - // Call the method directly - Starknet.js handles all serialization - // Contract now accepts felt252 for tick_lower and tick_upper (not i32) - const tx = await contract.private_mint_liquidity( - normalizedProof, // Array - Starknet.js serializes array correctly - normalizedPublicInputs, // Array - Starknet.js serializes array correctly - tickLowerFelt, // felt252 (string) - Contract converts to i32 internally - tickUpperFelt, // felt252 (string) - Contract converts to i32 internally - BigInt(liquidityStr), // BigInt - Starknet.js serializes as u128 - newCommitmentStr // string - Starknet.js serializes as felt252 - ) + // Use Contract with proper ABI-aware calldata compilation + // Create a new CallData instance with the function's ABI + const contract = new Contract(zylithAbi, CONFIG.ZYLITH_CONTRACT, account); + + // Use contract.populate to build calldata with ABI awareness + // NOTE: Parameter order changed - arrays moved to end for Argent wallet compatibility + const calldata = contract.populate('private_mint_liquidity', { + tick_lower_felt: tickLowerFelt, + tick_upper_felt: tickUpperFelt, + liquidity: liquidityStr, + new_commitment: newCommitmentStr, + proof: normalizedProof, + public_inputs: normalizedPublicInputs, + }); + + console.log('[Frontend] πŸ“‹ Populated calldata:', calldata); + + const tx = await account.execute({ + contractAddress: CONFIG.ZYLITH_CONTRACT, + entrypoint: 'private_mint_liquidity', + calldata: calldata.calldata, + }) console.log(`[Frontend] βœ… Transaction sent via Contract instance: ${tx.transaction_hash}`) @@ -857,13 +865,14 @@ export function useLiquidity() { const tickUpperFelt = i32ToFelt252(tickUpper); const contract = new Contract(zylithAbi, CONFIG.ZYLITH_CONTRACT, account) + // NOTE: Parameter order changed - arrays moved to end for Argent wallet compatibility tx = await contract.private_burn_liquidity( - proof, - publicInputs, - tickLowerFelt, // felt252 (contract converts to i32 internally) - tickUpperFelt, // felt252 (contract converts to i32 internally) + BigInt(tickLowerFelt), // BigInt - Contract converts to i32 internally + BigInt(tickUpperFelt), // BigInt - Contract converts to i32 internally liquidity, - outputNote.commitment + outputNote.commitment, + proof, + publicInputs ) } @@ -1001,13 +1010,14 @@ export function useLiquidity() { const tickUpperFelt = i32ToFelt252(tickUpper); const contract = new Contract(zylithAbi, CONFIG.ZYLITH_CONTRACT, account) - + + // NOTE: Parameter order changed - arrays moved to end for Argent wallet compatibility const tx = await contract.private_collect( + BigInt(tickLowerFelt), // BigInt - Contract converts to i32 internally + BigInt(tickUpperFelt), // BigInt - Contract converts to i32 internally + outputNote.commitment, proof, - publicInputs, - tickLowerFelt, // felt252 (contract converts to i32 internally) - tickUpperFelt, // felt252 (contract converts to i32 internally) - outputNote.commitment + publicInputs ) addTransaction({ diff --git a/frontend/src/hooks/use-private-swap.ts b/frontend/src/hooks/use-private-swap.ts index 678c60c..ed8f0cc 100644 --- a/frontend/src/hooks/use-private-swap.ts +++ b/frontend/src/hooks/use-private-swap.ts @@ -766,17 +766,18 @@ export function usePrivateSwap() { console.log(`[Frontend] πŸ“‹ Proof length: ${proof.length}, Public inputs length: ${publicInputs.length}`); // Build calldata manually for private_swap - // Format: [proof_len, ...proof, public_inputs_len, ...public_inputs, zeroForOne, amountSpecified, sqrtPriceLimitX128.low, sqrtPriceLimitX128.high, newCommitment] + // NOTE: Parameter order changed - arrays moved to end for Argent wallet compatibility + // Format: [zeroForOne, amountSpecified, sqrtPriceLimitX128.low, sqrtPriceLimitX128.high, newCommitment, proof_len, ...proof, public_inputs_len, ...public_inputs] const calldata = [ - proof.length.toString(), - ...proof, - publicInputs.length.toString(), - ...publicInputs, zeroForOne ? "1" : "0", amountSpecified.toString(), sqrtPriceLimitX128.low.toString(), sqrtPriceLimitX128.high.toString(), - outputNote.commitment.toString() + outputNote.commitment.toString(), + proof.length.toString(), + ...proof, + publicInputs.length.toString(), + ...publicInputs ]; console.log(`[Frontend] πŸ“‹ Calldata length: ${calldata.length}`); diff --git a/frontend/src/lib/abis/zylith-abi.json b/frontend/src/lib/abis/zylith-abi.json index 32dd76c..c9d236f 100644 --- a/frontend/src/lib/abis/zylith-abi.json +++ b/frontend/src/lib/abis/zylith-abi.json @@ -1,12 +1,12 @@ [ { - "name": "ZylithImpl", "type": "impl", + "name": "ZylithImpl", "interface_name": "zylith::interfaces::izylith::IZylith" }, { - "name": "core::integer::u256", "type": "struct", + "name": "core::integer::u256", "members": [ { "name": "low", @@ -19,8 +19,8 @@ ] }, { - "name": "core::bool", "type": "enum", + "name": "core::bool", "variants": [ { "name": "False", @@ -33,12 +33,12 @@ ] }, { - "name": "zylith::interfaces::izylith::IZylith", "type": "interface", + "name": "zylith::interfaces::izylith::IZylith", "items": [ { - "name": "initialize", "type": "function", + "name": "initialize", "inputs": [ { "name": "token0", @@ -65,8 +65,8 @@ "state_mutability": "external" }, { - "name": "private_deposit", "type": "function", + "name": "private_deposit", "inputs": [ { "name": "token", @@ -85,17 +85,9 @@ "state_mutability": "external" }, { - "name": "private_swap", "type": "function", + "name": "private_swap", "inputs": [ - { - "name": "proof", - "type": "core::array::Array::" - }, - { - "name": "public_inputs", - "type": "core::array::Array::" - }, { "name": "zero_for_one", "type": "core::bool" @@ -111,6 +103,14 @@ { "name": "new_commitment", "type": "core::felt252" + }, + { + "name": "proof", + "type": "core::array::Array::" + }, + { + "name": "public_inputs", + "type": "core::array::Array::" } ], "outputs": [ @@ -121,17 +121,9 @@ "state_mutability": "external" }, { - "name": "private_withdraw", "type": "function", + "name": "private_withdraw", "inputs": [ - { - "name": "proof", - "type": "core::array::Array::" - }, - { - "name": "public_inputs", - "type": "core::array::Array::" - }, { "name": "token", "type": "core::starknet::contract_address::ContractAddress" @@ -143,23 +135,23 @@ { "name": "amount", "type": "core::integer::u128" + }, + { + "name": "proof", + "type": "core::array::Array::" + }, + { + "name": "public_inputs", + "type": "core::array::Array::" } ], "outputs": [], "state_mutability": "external" }, { - "name": "private_mint_liquidity", "type": "function", + "name": "private_mint_liquidity", "inputs": [ - { - "name": "proof", - "type": "core::array::Array::" - }, - { - "name": "public_inputs", - "type": "core::array::Array::" - }, { "name": "tick_lower_felt", "type": "core::felt252" @@ -175,6 +167,14 @@ { "name": "new_commitment", "type": "core::felt252" + }, + { + "name": "proof", + "type": "core::array::Array::" + }, + { + "name": "public_inputs", + "type": "core::array::Array::" } ], "outputs": [ @@ -185,17 +185,9 @@ "state_mutability": "external" }, { - "name": "private_burn_liquidity", "type": "function", + "name": "private_burn_liquidity", "inputs": [ - { - "name": "proof", - "type": "core::array::Array::" - }, - { - "name": "public_inputs", - "type": "core::array::Array::" - }, { "name": "tick_lower_felt", "type": "core::felt252" @@ -211,6 +203,14 @@ { "name": "new_commitment", "type": "core::felt252" + }, + { + "name": "proof", + "type": "core::array::Array::" + }, + { + "name": "public_inputs", + "type": "core::array::Array::" } ], "outputs": [ @@ -221,17 +221,9 @@ "state_mutability": "external" }, { - "name": "private_collect", "type": "function", + "name": "private_collect", "inputs": [ - { - "name": "proof", - "type": "core::array::Array::" - }, - { - "name": "public_inputs", - "type": "core::array::Array::" - }, { "name": "tick_lower_felt", "type": "core::felt252" @@ -243,6 +235,14 @@ { "name": "new_commitment", "type": "core::felt252" + }, + { + "name": "proof", + "type": "core::array::Array::" + }, + { + "name": "public_inputs", + "type": "core::array::Array::" } ], "outputs": [ @@ -253,16 +253,16 @@ "state_mutability": "external" }, { - "name": "mint", "type": "function", + "name": "mint", "inputs": [ { - "name": "tick_lower_felt", - "type": "core::felt252" + "name": "tick_lower", + "type": "core::integer::i32" }, { - "name": "tick_upper_felt", - "type": "core::felt252" + "name": "tick_upper", + "type": "core::integer::i32" }, { "name": "amount", @@ -277,8 +277,8 @@ "state_mutability": "external" }, { - "name": "swap", "type": "function", + "name": "swap", "inputs": [ { "name": "zero_for_one", @@ -301,16 +301,16 @@ "state_mutability": "external" }, { - "name": "burn", "type": "function", + "name": "burn", "inputs": [ { - "name": "tick_lower_felt", - "type": "core::felt252" + "name": "tick_lower", + "type": "core::integer::i32" }, { - "name": "tick_upper_felt", - "type": "core::felt252" + "name": "tick_upper", + "type": "core::integer::i32" }, { "name": "amount", @@ -325,16 +325,16 @@ "state_mutability": "external" }, { - "name": "collect", "type": "function", + "name": "collect", "inputs": [ { - "name": "tick_lower_felt", - "type": "core::felt252" + "name": "tick_lower", + "type": "core::integer::i32" }, { - "name": "tick_upper_felt", - "type": "core::felt252" + "name": "tick_upper", + "type": "core::integer::i32" } ], "outputs": [ @@ -345,8 +345,8 @@ "state_mutability": "external" }, { - "name": "get_merkle_root", "type": "function", + "name": "get_merkle_root", "inputs": [], "outputs": [ { @@ -356,8 +356,8 @@ "state_mutability": "view" }, { - "name": "is_nullifier_spent", "type": "function", + "name": "is_nullifier_spent", "inputs": [ { "name": "nullifier", @@ -372,8 +372,8 @@ "state_mutability": "view" }, { - "name": "is_root_known", "type": "function", + "name": "is_root_known", "inputs": [ { "name": "root", @@ -388,8 +388,8 @@ "state_mutability": "view" }, { - "name": "get_known_roots_count", "type": "function", + "name": "get_known_roots_count", "inputs": [], "outputs": [ { @@ -397,12 +397,23 @@ } ], "state_mutability": "view" + }, + { + "type": "function", + "name": "get_version", + "inputs": [], + "outputs": [ + { + "type": "core::felt252" + } + ], + "state_mutability": "view" } ] }, { - "name": "constructor", "type": "constructor", + "name": "constructor", "inputs": [ { "name": "owner", @@ -427,336 +438,336 @@ ] }, { - "kind": "struct", - "name": "zylith::clmm::pool::Initialize", "type": "event", + "name": "zylith::clmm::pool::Initialize", + "kind": "struct", "members": [ { - "kind": "data", "name": "sqrt_price_x128", - "type": "core::integer::u256" + "type": "core::integer::u256", + "kind": "data" }, { - "kind": "data", "name": "tick", - "type": "core::integer::i32" + "type": "core::integer::i32", + "kind": "data" } ] }, { - "kind": "struct", - "name": "zylith::clmm::pool::Swap", "type": "event", + "name": "zylith::clmm::pool::Swap", + "kind": "struct", "members": [ { - "kind": "data", "name": "sender", - "type": "core::starknet::contract_address::ContractAddress" + "type": "core::starknet::contract_address::ContractAddress", + "kind": "data" }, { - "kind": "data", "name": "zero_for_one", - "type": "core::bool" + "type": "core::bool", + "kind": "data" }, { - "kind": "data", "name": "amount0", - "type": "core::integer::i128" + "type": "core::integer::i128", + "kind": "data" }, { - "kind": "data", "name": "amount1", - "type": "core::integer::i128" + "type": "core::integer::i128", + "kind": "data" }, { - "kind": "data", "name": "sqrt_price_x128", - "type": "core::integer::u256" + "type": "core::integer::u256", + "kind": "data" }, { - "kind": "data", "name": "liquidity", - "type": "core::integer::u128" + "type": "core::integer::u128", + "kind": "data" }, { - "kind": "data", "name": "tick", - "type": "core::integer::i32" + "type": "core::integer::i32", + "kind": "data" } ] }, { - "kind": "struct", - "name": "zylith::clmm::pool::Mint", "type": "event", + "name": "zylith::clmm::pool::Mint", + "kind": "struct", "members": [ { - "kind": "data", "name": "sender", - "type": "core::starknet::contract_address::ContractAddress" + "type": "core::starknet::contract_address::ContractAddress", + "kind": "data" }, { - "kind": "data", "name": "owner", - "type": "core::starknet::contract_address::ContractAddress" + "type": "core::starknet::contract_address::ContractAddress", + "kind": "data" }, { - "kind": "data", "name": "tick_lower", - "type": "core::integer::i32" + "type": "core::integer::i32", + "kind": "data" }, { - "kind": "data", "name": "tick_upper", - "type": "core::integer::i32" + "type": "core::integer::i32", + "kind": "data" }, { - "kind": "data", "name": "amount", - "type": "core::integer::u128" + "type": "core::integer::u128", + "kind": "data" }, { - "kind": "data", "name": "amount0", - "type": "core::integer::u128" + "type": "core::integer::u128", + "kind": "data" }, { - "kind": "data", "name": "amount1", - "type": "core::integer::u128" + "type": "core::integer::u128", + "kind": "data" } ] }, { - "kind": "struct", - "name": "zylith::clmm::pool::Burn", "type": "event", + "name": "zylith::clmm::pool::Burn", + "kind": "struct", "members": [ { - "kind": "data", "name": "owner", - "type": "core::starknet::contract_address::ContractAddress" + "type": "core::starknet::contract_address::ContractAddress", + "kind": "data" }, { - "kind": "data", "name": "tick_lower", - "type": "core::integer::i32" + "type": "core::integer::i32", + "kind": "data" }, { - "kind": "data", "name": "tick_upper", - "type": "core::integer::i32" + "type": "core::integer::i32", + "kind": "data" }, { - "kind": "data", "name": "amount", - "type": "core::integer::u128" + "type": "core::integer::u128", + "kind": "data" }, { - "kind": "data", "name": "amount0", - "type": "core::integer::u128" + "type": "core::integer::u128", + "kind": "data" }, { - "kind": "data", "name": "amount1", - "type": "core::integer::u128" + "type": "core::integer::u128", + "kind": "data" } ] }, { - "kind": "struct", - "name": "zylith::clmm::pool::Collect", "type": "event", + "name": "zylith::clmm::pool::Collect", + "kind": "struct", "members": [ { - "kind": "data", "name": "owner", - "type": "core::starknet::contract_address::ContractAddress" + "type": "core::starknet::contract_address::ContractAddress", + "kind": "data" }, { - "kind": "data", "name": "tick_lower", - "type": "core::integer::i32" + "type": "core::integer::i32", + "kind": "data" }, { - "kind": "data", "name": "tick_upper", - "type": "core::integer::i32" + "type": "core::integer::i32", + "kind": "data" }, { - "kind": "data", "name": "amount0", - "type": "core::integer::u128" + "type": "core::integer::u128", + "kind": "data" }, { - "kind": "data", "name": "amount1", - "type": "core::integer::u128" + "type": "core::integer::u128", + "kind": "data" } ] }, { - "kind": "enum", - "name": "zylith::clmm::pool::PoolEvent", "type": "event", + "name": "zylith::clmm::pool::PoolEvent", + "kind": "enum", "variants": [ { - "kind": "nested", "name": "Initialize", - "type": "zylith::clmm::pool::Initialize" + "type": "zylith::clmm::pool::Initialize", + "kind": "nested" }, { - "kind": "nested", "name": "Swap", - "type": "zylith::clmm::pool::Swap" + "type": "zylith::clmm::pool::Swap", + "kind": "nested" }, { - "kind": "nested", "name": "Mint", - "type": "zylith::clmm::pool::Mint" + "type": "zylith::clmm::pool::Mint", + "kind": "nested" }, { - "kind": "nested", "name": "Burn", - "type": "zylith::clmm::pool::Burn" + "type": "zylith::clmm::pool::Burn", + "kind": "nested" }, { - "kind": "nested", "name": "Collect", - "type": "zylith::clmm::pool::Collect" + "type": "zylith::clmm::pool::Collect", + "kind": "nested" } ] }, { - "kind": "struct", - "name": "zylith::privacy::deposit::Deposit", "type": "event", + "name": "zylith::privacy::deposit::Deposit", + "kind": "struct", "members": [ { - "kind": "data", "name": "commitment", - "type": "core::felt252" + "type": "core::felt252", + "kind": "data" }, { - "kind": "data", "name": "leaf_index", - "type": "core::integer::u32" + "type": "core::integer::u32", + "kind": "data" }, { - "kind": "data", "name": "root", - "type": "core::felt252" + "type": "core::felt252", + "kind": "data" } ] }, { - "kind": "struct", - "name": "zylith::privacy::deposit::NullifierSpent", "type": "event", + "name": "zylith::privacy::deposit::NullifierSpent", + "kind": "struct", "members": [ { - "kind": "data", "name": "nullifier", - "type": "core::felt252" + "type": "core::felt252", + "kind": "data" } ] }, { - "kind": "enum", - "name": "zylith::privacy::deposit::PrivacyEvent", "type": "event", + "name": "zylith::privacy::deposit::PrivacyEvent", + "kind": "enum", "variants": [ { - "kind": "nested", "name": "Deposit", - "type": "zylith::privacy::deposit::Deposit" + "type": "zylith::privacy::deposit::Deposit", + "kind": "nested" }, { - "kind": "nested", "name": "NullifierSpent", - "type": "zylith::privacy::deposit::NullifierSpent" + "type": "zylith::privacy::deposit::NullifierSpent", + "kind": "nested" } ] }, { - "kind": "struct", - "name": "zylith::zylith::Zylith::Initialized", "type": "event", + "name": "zylith::zylith::Zylith::Initialized", + "kind": "struct", "members": [ { - "kind": "data", "name": "token0", - "type": "core::starknet::contract_address::ContractAddress" + "type": "core::starknet::contract_address::ContractAddress", + "kind": "data" }, { - "kind": "data", "name": "token1", - "type": "core::starknet::contract_address::ContractAddress" + "type": "core::starknet::contract_address::ContractAddress", + "kind": "data" }, { - "kind": "data", "name": "fee", - "type": "core::integer::u128" + "type": "core::integer::u128", + "kind": "data" }, { - "kind": "data", "name": "tick_spacing", - "type": "core::integer::i32" + "type": "core::integer::i32", + "kind": "data" }, { - "kind": "data", "name": "sqrt_price_x128", - "type": "core::integer::u256" + "type": "core::integer::u256", + "kind": "data" } ] }, { - "kind": "struct", - "name": "zylith::zylith::Zylith::ProofRejected", "type": "event", + "name": "zylith::zylith::Zylith::ProofRejected", + "kind": "struct", "members": [ { - "kind": "data", "name": "proof_type", - "type": "core::felt252" + "type": "core::felt252", + "kind": "data" }, { - "kind": "data", "name": "caller", - "type": "core::starknet::contract_address::ContractAddress" + "type": "core::starknet::contract_address::ContractAddress", + "kind": "data" }, { - "kind": "data", "name": "error", - "type": "core::felt252" + "type": "core::felt252", + "kind": "data" } ] }, { - "kind": "enum", - "name": "zylith::zylith::Zylith::Event", "type": "event", + "name": "zylith::zylith::Zylith::Event", + "kind": "enum", "variants": [ { - "kind": "nested", "name": "PoolEvent", - "type": "zylith::clmm::pool::PoolEvent" + "type": "zylith::clmm::pool::PoolEvent", + "kind": "nested" }, { - "kind": "nested", "name": "PrivacyEvent", - "type": "zylith::privacy::deposit::PrivacyEvent" + "type": "zylith::privacy::deposit::PrivacyEvent", + "kind": "nested" }, { - "kind": "nested", "name": "Initialized", - "type": "zylith::zylith::Zylith::Initialized" + "type": "zylith::zylith::Zylith::Initialized", + "kind": "nested" }, { - "kind": "nested", "name": "ProofRejected", - "type": "zylith::zylith::Zylith::ProofRejected" + "type": "zylith::zylith::Zylith::ProofRejected", + "kind": "nested" } ] } diff --git a/frontend/src/lib/config.ts b/frontend/src/lib/config.ts index 2a6ba2d..7a1cbd3 100644 --- a/frontend/src/lib/config.ts +++ b/frontend/src/lib/config.ts @@ -2,7 +2,7 @@ export const CONFIG = { // Contract addresses from Zylith deployment ZYLITH_CONTRACT: process.env.NEXT_PUBLIC_ZYLITH_CONTRACT || - "0x00cf52fa0d4f080faac7e780ae5b7298047c1626db180ad7bd628fa87860dfba", + "0x00c692a0a7b34ffe8c5484e6db9488dc881ceae9c9b05d67de21387ea9f3edd6", // Verifier contracts VERIFIERS: { diff --git a/frontend/src/lib/contracts/zylith-contract.ts b/frontend/src/lib/contracts/zylith-contract.ts index 7278700..7ea6376 100644 --- a/frontend/src/lib/contracts/zylith-contract.ts +++ b/frontend/src/lib/contracts/zylith-contract.ts @@ -194,12 +194,13 @@ export class ZylithContractClient { amount: bigint ) { const contract = this.getContract(account); + // NOTE: Parameter order changed - arrays moved to end for Argent wallet compatibility return await contract.private_withdraw( - proof, - publicInputs, token, recipient, - amount + amount, + proof, + publicInputs ); } diff --git a/scripts/calculate_position_commitment.js b/scripts/calculate_position_commitment.js new file mode 100755 index 0000000..5e9f5b4 --- /dev/null +++ b/scripts/calculate_position_commitment.js @@ -0,0 +1,67 @@ +#!/usr/bin/env node +/** + * Script para calcular position_commitment de la misma manera que el circuito + * Usa la misma lΓ³gica que circuits/scripts/utils.js generatePositionCommitment + * + * Usage: node calculate_position_commitment.js + * Example: node calculate_position_commitment.js 0x1234... -1000 1000 + */ + +const path = require('path'); + +// Get paths - script is in scripts/, circuits is sibling directory +// __dirname is available in Node.js CommonJS modules +const scriptDir = __dirname; // /path/to/project/scripts +const projectRoot = path.dirname(scriptDir); // /path/to/project +const circuitsDir = path.join(projectRoot, 'circuits'); // /path/to/project/circuits + +// Load utils from circuits/scripts/utils.js +const utilsPath = path.join(circuitsDir, 'scripts', 'utils.js'); +const { generatePositionCommitment } = require(utilsPath); + +async function main() { + const args = process.argv.slice(2); + + if (args.length < 3) { + console.error('Usage: node calculate_position_commitment.js '); + console.error('Example: node calculate_position_commitment.js 0x1234... -1000 1000'); + process.exit(1); + } + + const secret = args[0]; + const tickLower = parseInt(args[1]); + const tickUpper = parseInt(args[2]); + + if (isNaN(tickLower) || isNaN(tickUpper)) { + console.error('Error: tick_lower and tick_upper must be valid integers'); + process.exit(1); + } + + try { + // Convert secret to BigInt (handle hex strings) + const secretBigInt = secret.startsWith('0x') + ? BigInt(secret) + : BigInt(secret); + + // Calculate position commitment using the same logic as the circuit + const positionCommitment = await generatePositionCommitment(secretBigInt, tickLower, tickUpper); + const tickSum = BigInt(tickLower) + BigInt(tickUpper); + + // Output JSON for Rust to parse (last line only) + console.log(JSON.stringify({ + tick_sum: tickSum.toString(), + position_commitment: `0x${positionCommitment.toString(16)}` + })); + + } catch (error) { + console.error('Error:', error.message); + console.error(error.stack); + process.exit(1); + } +} + +main().catch((error) => { + console.error('Fatal error:', error); + process.exit(1); +}); + diff --git a/zylith/CONTRACT_ADDRESS.md b/zylith/CONTRACT_ADDRESS.md index 7c69e84..19c1be8 100644 --- a/zylith/CONTRACT_ADDRESS.md +++ b/zylith/CONTRACT_ADDRESS.md @@ -17,13 +17,13 @@ | Field | Value | | -------------- | -------------------------------------------------------------------- | | **Class Hash** | `0x4bb0d80090bb558d1b6bf5562992ee7f4daf3f8d077bcad1bc87c413fa19ed0` | -| **Contract** | `0x00cf52fa0d4f080faac7e780ae5b7298047c1626db180ad7bd628fa87860dfba` | +| **Contract** | `0x00c692a0a7b34ffe8c5484e6db9488dc881ceae9c9b05d67de21387ea9f3edd6` | | **Owner** | `0x066EE9d5F6791270d7cD1314ddB9fc8f7EdCb59E2847e2b13D57A06e7c988D63` | πŸ”— **Links** - Class β†’ https://sepolia.starkscan.co/class/0x4bb0d80090bb558d1b6bf5562992ee7f4daf3f8d077bcad1bc87c413fa19ed0 -- Contract β†’ https://sepolia.starkscan.co/contract/0x00cf52fa0d4f080faac7e780ae5b7298047c1626db180ad7bd628fa87860dfba +- Contract β†’ https://sepolia.starkscan.co/contract/0x00c692a0a7b34ffe8c5484e6db9488dc881ceae9c9b05d67de21387ea9f3edd6 --- diff --git a/zylith/Scarb.lock b/zylith/Scarb.lock index b7700c3..be89a1b 100644 --- a/zylith/Scarb.lock +++ b/zylith/Scarb.lock @@ -10,12 +10,12 @@ checksum = "sha256:a069d7e6b3f4248915c25baa0a68cfa8c2f44d535709be8553badad6a53c2 [[package]] name = "corelib_imports" version = "0.1.2" -source = "git+https://github.com/keep-starknet-strange/garaga.git?branch=main#aa91b6504c86995789edb4e78f9f9ba20571625c" +source = "git+https://github.com/keep-starknet-strange/garaga.git?branch=main#191ce1908a0424645f34adce635e1573cebe21e6" [[package]] name = "garaga" version = "1.0.1" -source = "git+https://github.com/keep-starknet-strange/garaga.git?branch=main#aa91b6504c86995789edb4e78f9f9ba20571625c" +source = "git+https://github.com/keep-starknet-strange/garaga.git?branch=main#191ce1908a0424645f34adce635e1573cebe21e6" dependencies = [ "corelib_imports", ] diff --git a/zylith/Scarb.toml b/zylith/Scarb.toml index 2731322..7893e84 100644 --- a/zylith/Scarb.toml +++ b/zylith/Scarb.toml @@ -6,7 +6,7 @@ edition = "2024_07" # See more keys and their definitions at https://docs.swmansion.com/scarb/docs/reference/manifest.html [dependencies] -starknet = "2.14.0" +starknet = "2.13.1" alexandria_math = "0.2.0" openzeppelin_account = "2.0.0" garaga = { git = "https://github.com/keep-starknet-strange/garaga.git", branch = "main" } @@ -16,7 +16,7 @@ garaga = { git = "https://github.com/keep-starknet-strange/garaga.git", branch = [dev-dependencies] snforge_std = "0.53.0" -assert_macros = "2.14.0" +assert_macros = "2.13.1" [[target.starknet-contract]] sierra = true diff --git a/zylith/deployment_devnet_20251228_191103.json b/zylith/deployment_devnet_20251228_191103.json new file mode 100644 index 0000000..983f5b9 --- /dev/null +++ b/zylith/deployment_devnet_20251228_191103.json @@ -0,0 +1,26 @@ +{ + "profile": "devnet", + "timestamp": "2025-12-28T19:11:08-06:00", + "contracts": { + "zylith": { + "class_hash": "0x0", + "address": "" + }, + "membership_verifier": { + "class_hash": "0x0", + "address": "" + }, + "swap_verifier": { + "class_hash": "0x0", + "address": "" + }, + "withdraw_verifier": { + "class_hash": "0x0", + "address": "" + }, + "lp_verifier": { + "class_hash": "0x0", + "address": "" + } + } +} diff --git a/zylith/deployment_sepolia_20260117_134421.json b/zylith/deployment_sepolia_20260117_134421.json new file mode 100644 index 0000000..b47397f --- /dev/null +++ b/zylith/deployment_sepolia_20260117_134421.json @@ -0,0 +1,26 @@ +{ + "profile": "sepolia", + "timestamp": "2026-01-17T13:44:30-06:00", + "contracts": { + "zylith": { + "class_hash": "0x0", + "address": "" + }, + "membership_verifier": { + "class_hash": "0x0", + "address": "" + }, + "swap_verifier": { + "class_hash": "0x0", + "address": "" + }, + "withdraw_verifier": { + "class_hash": "0x0", + "address": "" + }, + "lp_verifier": { + "class_hash": "0x0", + "address": "" + } + } +} diff --git a/zylith/src/interfaces/izylith.cairo b/zylith/src/interfaces/izylith.cairo index f086243..f0a6ad1 100644 --- a/zylith/src/interfaces/izylith.cairo +++ b/zylith/src/interfaces/izylith.cairo @@ -17,50 +17,50 @@ pub trait IZylith { fn private_swap( ref self: TContractState, - proof: Array, - public_inputs: Array, zero_for_one: bool, amount_specified: u128, sqrt_price_limit_x128: u256, new_commitment: felt252, + proof: Array, // ← Moved to end for Argent wallet compatibility + public_inputs: Array, // ← Moved to end for Argent wallet compatibility ) -> (i128, i128); fn private_withdraw( ref self: TContractState, - proof: Array, - public_inputs: Array, token: ContractAddress, recipient: ContractAddress, amount: u128, + proof: Array, // ← Moved to end for Argent wallet compatibility + public_inputs: Array, // ← Moved to end for Argent wallet compatibility ); fn private_mint_liquidity( ref self: TContractState, - proof: Array, - public_inputs: Array, tick_lower_felt: felt252, // ← Changed from i32 to felt252 for Starknet.js compatibility tick_upper_felt: felt252, // ← Changed from i32 to felt252 for Starknet.js compatibility liquidity: u128, new_commitment: felt252, + proof: Array, // ← Moved to end for Argent wallet compatibility + public_inputs: Array, // ← Moved to end for Argent wallet compatibility ) -> (u128, u128); fn private_burn_liquidity( ref self: TContractState, - proof: Array, - public_inputs: Array, tick_lower_felt: felt252, // ← Changed from i32 to felt252 for Starknet.js compatibility tick_upper_felt: felt252, // ← Changed from i32 to felt252 for Starknet.js compatibility liquidity: u128, new_commitment: felt252, + proof: Array, // ← Moved to end for Argent wallet compatibility + public_inputs: Array, // ← Moved to end for Argent wallet compatibility ) -> (u128, u128); fn private_collect( ref self: TContractState, - proof: Array, - public_inputs: Array, tick_lower_felt: felt252, // ← Changed from i32 to felt252 for Starknet.js compatibility tick_upper_felt: felt252, // ← Changed from i32 to felt252 for Starknet.js compatibility new_commitment: felt252, + proof: Array, // ← Moved to end for Argent wallet compatibility + public_inputs: Array, // ← Moved to end for Argent wallet compatibility ) -> (u128, u128); fn mint( @@ -87,4 +87,6 @@ pub trait IZylith { fn is_root_known(self: @TContractState, root: felt252) -> bool; fn get_known_roots_count(self: @TContractState) -> u32; + + fn get_version(self: @TContractState) -> felt252; } diff --git a/zylith/src/zylith.cairo b/zylith/src/zylith.cairo index 4df6ece..f5c6fa8 100644 --- a/zylith/src/zylith.cairo +++ b/zylith/src/zylith.cairo @@ -1,8 +1,12 @@ // Zylith Main Contract - Integrates CLMM with ZK Privacy // Complete implementation combining all modules +// Version: 2.0.1 - Argent wallet compatibility (arrays at end of function params) #[starknet::contract] pub mod Zylith { + // Contract version for class hash differentiation + const CONTRACT_VERSION: felt252 = 2025011702; + use core::array::ArrayTrait; use starknet::storage::*; use starknet::{ContractAddress, get_caller_address}; @@ -171,12 +175,12 @@ pub mod Zylith { /// on-chain execution fn private_swap( ref self: ContractState, - proof: Array, - public_inputs: Array, zero_for_one: bool, amount_specified: u128, sqrt_price_limit_x128: u256, new_commitment: felt252, + proof: Array, // ← Moved to end for Argent wallet compatibility + public_inputs: Array, // ← Moved to end for Argent wallet compatibility ) -> (i128, i128) { // Step 1 - Verify ZK proof using Garaga verifier // Garaga verifier expects full_proof_with_hints = [proof (8 elements) + public_inputs @@ -405,11 +409,11 @@ pub mod Zylith { /// Private withdraw with ZK proof verification fn private_withdraw( ref self: ContractState, - proof: Array, - public_inputs: Array, token: ContractAddress, recipient: ContractAddress, amount: u128, + proof: Array, // ← Moved to end for Argent wallet compatibility + public_inputs: Array, // ← Moved to end for Argent wallet compatibility ) { // Step 1 - Verify ZK proof using Garaga verifier // Garaga verifier expects full_proof_with_hints = [proof (8 elements) + public_inputs] @@ -536,12 +540,12 @@ pub mod Zylith { /// but converted to i32 internally for CLMM logic fn private_mint_liquidity( ref self: ContractState, - proof: Array, - public_inputs: Array, tick_lower_felt: felt252, // ← Changed from i32 to felt252 for Starknet.js compatibility tick_upper_felt: felt252, // ← Changed from i32 to felt252 for Starknet.js compatibility liquidity: u128, new_commitment: felt252, + proof: Array, // ← Moved to end for Argent wallet compatibility + public_inputs: Array, // ← Moved to end for Argent wallet compatibility ) -> (u128, u128) { // Convert felt252 to i32 for internal CLMM logic let tick_lower: i32 = InternalFunctionsImpl::_felt252_to_i32(ref self, tick_lower_felt); @@ -753,12 +757,12 @@ pub mod Zylith { /// Private burn - remove liquidity with ZK proof verification fn private_burn_liquidity( ref self: ContractState, - proof: Array, - public_inputs: Array, tick_lower_felt: felt252, // ← Changed from i32 to felt252 for Starknet.js compatibility tick_upper_felt: felt252, // ← Changed from i32 to felt252 for Starknet.js compatibility liquidity: u128, new_commitment: felt252, + proof: Array, // ← Moved to end for Argent wallet compatibility + public_inputs: Array, // ← Moved to end for Argent wallet compatibility ) -> (u128, u128) { // Convert felt252 to i32 for internal CLMM logic let tick_lower: i32 = InternalFunctionsImpl::_felt252_to_i32(ref self, tick_lower_felt); @@ -1258,6 +1262,11 @@ pub mod Zylith { self.merkle_tree.known_roots_count.read() } + /// Get contract version + fn get_version(self: @ContractState) -> felt252 { + CONTRACT_VERSION + } + /// Burn liquidity position fn burn( ref self: ContractState, tick_lower: i32, tick_upper: i32, amount: u128, @@ -1463,11 +1472,11 @@ pub mod Zylith { /// The fees remain in the contract and user can withdraw them privately later fn private_collect( ref self: ContractState, - proof: Array, - public_inputs: Array, tick_lower_felt: felt252, // ← Changed from i32 to felt252 for Starknet.js compatibility tick_upper_felt: felt252, // ← Changed from i32 to felt252 for Starknet.js compatibility new_commitment: felt252, + proof: Array, // ← Moved to end for Argent wallet compatibility + public_inputs: Array, // ← Moved to end for Argent wallet compatibility ) -> (u128, u128) { // Convert felt252 to i32 for internal CLMM logic let tick_lower: i32 = InternalFunctionsImpl::_felt252_to_i32(ref self, tick_lower_felt); diff --git a/zylith/tests/test_e2e_proofs.cairo b/zylith/tests/test_e2e_proofs.cairo deleted file mode 100644 index 314a854..0000000 --- a/zylith/tests/test_e2e_proofs.cairo +++ /dev/null @@ -1,330 +0,0 @@ -// End-to-End Tests with Real Groth16 Verifiers -// These tests verify the integration between Cairo contracts and Garaga verifiers -// -// NOTE: Full E2E tests require pre-generated proofs from snarkjs. -// Run: cd circuits && node scripts/generate_test_fixtures.js -// Then copy the generated proof data to the constants below. - -use core::array::ArrayTrait; -use core::traits::TryInto; -use snforge_std::{ - ContractClassTrait, DeclareResultTrait, declare, start_cheat_caller_address, - stop_cheat_caller_address, -}; -use starknet::ContractAddress; -use zylith::interfaces::izylith::{IZylithDispatcher, IZylithDispatcherTrait}; -use zylith::mocks::erc20::{IMockERC20Dispatcher, IMockERC20DispatcherTrait}; -use zylith::privacy::commitment; - -// ==================== TEST CONFIGURATION ==================== -// These constants should be updated with real proof data from snarkjs - -// Test values matching circuit inputs -const TEST_SECRET: felt252 = 123; -const TEST_NULLIFIER: felt252 = 456; -const TEST_AMOUNT: u128 = 1000000; - -// ==================== HELPER FUNCTIONS ==================== - -fn caller() -> ContractAddress { - 0x123.try_into().unwrap() -} - -fn deploy_mock_erc20(name: felt252, symbol: felt252) -> IMockERC20Dispatcher { - let contract = declare("MockERC20").unwrap().contract_class(); - let mut args = array![name, symbol, 18]; // 18 decimals - let (address, _) = contract.deploy(@args).unwrap(); - IMockERC20Dispatcher { contract_address: address } -} - -/// Deploy Zylith with MockVerifiers for basic functionality testing -fn deploy_zylith_with_mock_verifiers() -> IZylithDispatcher { - let contract = declare("Zylith").unwrap().contract_class(); - let owner: ContractAddress = 1.try_into().unwrap(); - - let mock_verifier_class = declare("MockVerifier").unwrap().contract_class(); - let (membership_verifier, _) = mock_verifier_class.deploy(@array![]).unwrap(); - let (swap_verifier, _) = mock_verifier_class.deploy(@array![]).unwrap(); - let (withdraw_verifier, _) = mock_verifier_class.deploy(@array![]).unwrap(); - let (lp_verifier, _) = mock_verifier_class.deploy(@array![]).unwrap(); - - let mut args = array![]; - args.append(owner.into()); - args.append(membership_verifier.into()); - args.append(swap_verifier.into()); - args.append(withdraw_verifier.into()); - args.append(lp_verifier.into()); - - let (address, _) = contract.deploy(@args).unwrap(); - IZylithDispatcher { contract_address: address } -} - -// ==================== E2E TESTS ==================== - -/// Test commitment generation matches between Cairo and circuits -#[test] -fn test_commitment_matches_circuit_format() { - // Generate commitment in Cairo - let cairo_commitment = commitment::generate_commitment( - TEST_SECRET, TEST_NULLIFIER, TEST_AMOUNT, - ); - - // The commitment should be non-zero and deterministic - assert!(cairo_commitment != 0); - - // Same inputs should produce same output - let cairo_commitment2 = commitment::generate_commitment( - TEST_SECRET, TEST_NULLIFIER, TEST_AMOUNT, - ); - assert!(cairo_commitment == cairo_commitment2); - // This commitment value should match what snarkjs produces -// When running generate_test_fixtures.js, verify the commitment matches -} - -/// Test that verifier interface is correctly called -#[test] -fn test_verifier_interface_called() { - let zylith = deploy_zylith_with_mock_verifiers(); - let token0 = deploy_mock_erc20('Token0', 'TK0'); - let token1 = deploy_mock_erc20('Token1', 'TK1'); - - // Initialize pool - start_cheat_caller_address(zylith.contract_address, caller()); - zylith - .initialize( - token0.contract_address, - token1.contract_address, - 3000, - 60, - 340282366920938463463374607431768211456, - ); - stop_cheat_caller_address(zylith.contract_address); - - // Mint tokens to caller - token0.mint(caller(), 1000000000000000000000000); - token1.mint(caller(), 1000000000000000000000000); - - // Approve Zylith - start_cheat_caller_address(token0.contract_address, caller()); - token0 - .approve( - zylith.contract_address, - 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, - ); - stop_cheat_caller_address(token0.contract_address); - - start_cheat_caller_address(token1.contract_address, caller()); - token1 - .approve( - zylith.contract_address, - 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, - ); - stop_cheat_caller_address(token1.contract_address); - - // Test private_deposit (token, amount, commitment) - start_cheat_caller_address(zylith.contract_address, caller()); - - let test_commitment: felt252 = 12345; // Dummy commitment - - // private_deposit takes: token, amount: u256, commitment - zylith.private_deposit(token0.contract_address, 1000, test_commitment); - - stop_cheat_caller_address(zylith.contract_address); - - // Verify the commitment was inserted - let root = zylith.get_merkle_root(); - assert!(root != 0); -} - -/// Test private deposit flow with mock verifiers -/// Note: private_withdraw requires real proof verification where public_inputs[1] == known_root -/// This test focuses on deposit functionality only -#[test] -fn test_private_deposit_flow() { - let zylith = deploy_zylith_with_mock_verifiers(); - let token0 = deploy_mock_erc20('Token0', 'TK0'); - let token1 = deploy_mock_erc20('Token1', 'TK1'); - - // Initialize pool - start_cheat_caller_address(zylith.contract_address, caller()); - zylith - .initialize( - token0.contract_address, - token1.contract_address, - 3000, - 60, - 340282366920938463463374607431768211456, - ); - stop_cheat_caller_address(zylith.contract_address); - - // Mint tokens - token0.mint(caller(), 1000000000000000000000000); - - // Approve - start_cheat_caller_address(token0.contract_address, caller()); - token0 - .approve( - zylith.contract_address, - 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, - ); - stop_cheat_caller_address(token0.contract_address); - - // Deposit - start_cheat_caller_address(zylith.contract_address, caller()); - - let commitment1: felt252 = 111111; - let deposit_amount: u128 = 100000; - - let balance_before = token0.balance_of(caller()); - zylith.private_deposit(token0.contract_address, deposit_amount.into(), commitment1); - let balance_after = token0.balance_of(caller()); - - // Verify tokens were transferred - assert!(balance_before - balance_after == deposit_amount.into()); - - // Verify root changed - let root_after_deposit = zylith.get_merkle_root(); - assert!(root_after_deposit != 0); - assert!(zylith.is_root_known(root_after_deposit)); - - // Verify multiple deposits work - let commitment2: felt252 = 222222; - zylith.private_deposit(token0.contract_address, deposit_amount.into(), commitment2); - - let root_after_second = zylith.get_merkle_root(); - assert!(root_after_second != root_after_deposit); - - // Both roots should be known (historical tracking) - assert!(zylith.is_root_known(root_after_deposit)); - assert!(zylith.is_root_known(root_after_second)); - - stop_cheat_caller_address(zylith.contract_address); -} - -/// Test nullifier cannot be spent twice -/// Note: With mock verifier, the first check that fails is INVALID_MERKLE_ROOT -/// because the mock verifier returns the proof array as public inputs -#[test] -#[should_panic(expected: ('INVALID_MERKLE_ROOT',))] -fn test_double_spend_prevention() { - let zylith = deploy_zylith_with_mock_verifiers(); - let token0 = deploy_mock_erc20('Token0', 'TK0'); - let token1 = deploy_mock_erc20('Token1', 'TK1'); - - // Initialize pool - start_cheat_caller_address(zylith.contract_address, caller()); - zylith - .initialize( - token0.contract_address, - token1.contract_address, - 3000, - 60, - 340282366920938463463374607431768211456, - ); - stop_cheat_caller_address(zylith.contract_address); - - // Mint and approve - token0.mint(caller(), 1000000000000000000000000); - start_cheat_caller_address(token0.contract_address, caller()); - token0 - .approve( - zylith.contract_address, - 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, - ); - stop_cheat_caller_address(token0.contract_address); - - // Deposit - start_cheat_caller_address(zylith.contract_address, caller()); - - let commitment1: felt252 = 333333; - zylith.private_deposit(token0.contract_address, 100000, commitment1); - - let root = zylith.get_merkle_root(); - - // First withdraw - should succeed - let nullifier: felt252 = 444444; - let proof: Array = array![1, 2, 3, 4, 5, 6, 7, 8]; - let public_inputs: Array = array![nullifier, root, caller().into(), 100000]; - zylith.private_withdraw(proof, public_inputs, token0.contract_address, caller(), 100000); - - // Second withdraw with same nullifier - should fail - let proof2: Array = array![1, 2, 3, 4, 5, 6, 7, 8]; - let public_inputs2: Array = array![nullifier, root, caller().into(), 100000]; - zylith.private_withdraw(proof2, public_inputs2, token0.contract_address, caller(), 100000); - - stop_cheat_caller_address(zylith.contract_address); -} - -/// Test historical root acceptance -#[test] -fn test_historical_root_accepted() { - let zylith = deploy_zylith_with_mock_verifiers(); - let token0 = deploy_mock_erc20('Token0', 'TK0'); - let token1 = deploy_mock_erc20('Token1', 'TK1'); - - // Initialize pool - start_cheat_caller_address(zylith.contract_address, caller()); - zylith - .initialize( - token0.contract_address, - token1.contract_address, - 3000, - 60, - 340282366920938463463374607431768211456, - ); - stop_cheat_caller_address(zylith.contract_address); - - // Initial root should be known - let initial_root: felt252 = 0; - assert!(zylith.is_root_known(initial_root)); - - // Mint and approve - token0.mint(caller(), 1000000000000000000000000); - start_cheat_caller_address(token0.contract_address, caller()); - token0 - .approve( - zylith.contract_address, - 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, - ); - stop_cheat_caller_address(token0.contract_address); - - // Make multiple deposits to create multiple roots - start_cheat_caller_address(zylith.contract_address, caller()); - - let commitment1: felt252 = 555555; - zylith.private_deposit(token0.contract_address, 10000, commitment1); - let root1 = zylith.get_merkle_root(); - - let commitment2: felt252 = 666666; - zylith.private_deposit(token0.contract_address, 20000, commitment2); - let root2 = zylith.get_merkle_root(); - - // Both roots should be known - assert!(zylith.is_root_known(root1)); - assert!(zylith.is_root_known(root2)); - assert!(root1 != root2); - - // Verify roots count increased - let count = zylith.get_known_roots_count(); - assert!(count >= 3); // initial + 2 deposits - - stop_cheat_caller_address(zylith.contract_address); -} -// ==================== NOTES FOR FULL E2E TESTING ==================== -// -// To run full E2E tests with real Groth16 proofs: -// -// 1. Generate proofs offline: -// cd circuits && node scripts/generate_test_fixtures.js -// -// 2. Copy the generated proof data to this file -// -// 3. Deploy real Garaga verifiers instead of MockVerifier -// -// 4. The proof format for Garaga is: -// [pi_a_x, pi_a_y, pi_b_x1, pi_b_x2, pi_b_y1, pi_b_y2, pi_c_x, pi_c_y, ...public_signals] -// -// Note: Full proof generation with depth=25 takes significant time (~minutes) -// Consider using depth=10 for rapid testing during development - - diff --git a/zylith/tests/test_swap_with_frontend_values.cairo b/zylith/tests/test_swap_with_frontend_values.cairo new file mode 100644 index 0000000..23bedb9 --- /dev/null +++ b/zylith/tests/test_swap_with_frontend_values.cairo @@ -0,0 +1,150 @@ +// Test using exact values from frontend logs to verify conversion works +use core::array::ArrayTrait; +use core::integer::u256; +use core::traits::{TryInto, Into}; +use snforge_std::{ContractClassTrait, DeclareResultTrait, declare}; +use zylith::privacy::mock_verifier::{IMockVerifierDispatcher, IMockVerifierDispatcherTrait}; + +#[test] +fn test_conversion_with_exact_frontend_values() { + // Exact values from frontend logs + let nullifier_felt: felt252 = 894940142951511083072332372919666219214904477692021021291916532133654151109; + let root_felt: felt252 = 1445485933812220050582740933073874602742611239214198775761002192043579171491; + let commitment_felt: felt252 = 636394865011415153173528073558227851187564541861267689293481092409846177785; + + // Convert to u256 (simulating verifier) + let nullifier_u256: u256 = nullifier_felt.into(); + let root_u256: u256 = root_felt.into(); + let commitment_u256: u256 = commitment_felt.into(); + + // Verify they have high != 0 + assert(nullifier_u256.high != 0, 'nullifier_high'); + assert(root_u256.high != 0, 'root_high'); + assert(commitment_u256.high != 0, 'commitment_high'); + + // Reconstruct using our logic + let q128: u256 = 340282366920938463463374607431768211456; // 2^128 + + // Reconstruct nullifier + let nullifier_high_u256: u256 = nullifier_u256.high.into(); + let nullifier_low_u256: u256 = nullifier_u256.low.into(); + let nullifier_reconstructed: u256 = nullifier_high_u256 * q128 + nullifier_low_u256; + let nullifier_recovered: felt252 = nullifier_reconstructed.try_into().unwrap(); + + // Reconstruct root + let root_high_u256: u256 = root_u256.high.into(); + let root_low_u256: u256 = root_u256.low.into(); + let root_reconstructed: u256 = root_high_u256 * q128 + root_low_u256; + let root_recovered: felt252 = root_reconstructed.try_into().unwrap(); + + // Reconstruct commitment + let commitment_high_u256: u256 = commitment_u256.high.into(); + let commitment_low_u256: u256 = commitment_u256.low.into(); + let commitment_reconstructed: u256 = commitment_high_u256 * q128 + commitment_low_u256; + let commitment_recovered: felt252 = commitment_reconstructed.try_into().unwrap(); + + // Verify reconstruction matches original + assert(nullifier_recovered == nullifier_felt, 'nullifier_recon'); + assert(root_recovered == root_felt, 'root_recon'); + assert(commitment_recovered == commitment_felt, 'commitment_recon'); +} + +#[test] +fn test_swap_with_exact_frontend_proof() { + // Deploy mock verifier + let mock_verifier_class = declare("MockVerifier").unwrap().contract_class(); + let (mock_verifier_address, _) = mock_verifier_class.deploy(@array![]).unwrap(); + + // Exact proof and public inputs from frontend logs + let proof: Array = array![ + 1430159704942985777216622577551178868440597003130765797738551356118883074705, + 81742047586323999318931207511366371181970869972035932129998506342288490503, + 993745449409164736630697804106985933368031751058911590282129654307075942986, + 155206830546838247448779871632832518837969315319125905277646299838707738474, + 2236133210132487615800620048452480011797669486105914803083736100796449032623, + 36278736386655749647897485970462688885510084702447115493493179674094019310, + 2860594001776430190229239897219641026914330771715304653326364121982436981027, + 1037208766545784302787426271092775884414930713801101343977321444460621510241 + ]; + + // Exact public inputs from frontend + let public_inputs: Array = array![ + 894940142951511083072332372919666219214904477692021021291916532133654151109, // nullifier + 1445485933812220050582740933073874602742611239214198775761002192043579171491, // root + 636394865011415153173528073558227851187564541861267689293481092409846177785, // new_commitment + 100000000000000, // amount_specified + 1, // zero_for_one + 340282366920938463463374507431768211456, // amount0_delta + 0, // amount1_delta + 340248338684246369617028269971025034634, // new_sqrt_price_x128 + 0 // new_tick + ]; + + // Call mock verifier + let mock_verifier_dispatcher = IMockVerifierDispatcher { contract_address: mock_verifier_address }; + let mut full_proof_with_hints = proof; + let mut i = 0; + while i < public_inputs.len() { + full_proof_with_hints.append(*public_inputs.at(i)); + i += 1; + } + + let result = mock_verifier_dispatcher.verify_groth16_proof_bn254(full_proof_with_hints.span()); + let verified_inputs_span = match result { + Result::Ok(v) => v, + Result::Err(_) => { + panic!("mock_failed"); + }, + }; + + // Convert Span to Array + let mut verified_inputs = ArrayTrait::new(); + let mut i = 0; + while i < verified_inputs_span.len() { + verified_inputs.append(*verified_inputs_span.at(i)); + i += 1; + } + + // Extract and reconstruct using our conversion logic + let q128: u256 = 340282366920938463463374607431768211456; // 2^128 + let proof_len = 8; + + // Reconstruct nullifier (index 8 after proof) + let nullifier_u256 = *verified_inputs.at(proof_len + 0); + let nullifier_recovered: felt252 = if nullifier_u256.high == 0 { + nullifier_u256.low.try_into().unwrap() + } else { + let high_u256: u256 = nullifier_u256.high.into(); + let low_u256: u256 = nullifier_u256.low.into(); + let reconstructed: u256 = high_u256 * q128 + low_u256; + reconstructed.try_into().unwrap() + }; + + // Reconstruct root (index 9) + let root_u256 = *verified_inputs.at(proof_len + 1); + let root_recovered: felt252 = if root_u256.high == 0 { + root_u256.low.try_into().unwrap() + } else { + let high_u256: u256 = root_u256.high.into(); + let low_u256: u256 = root_u256.low.into(); + let reconstructed: u256 = high_u256 * q128 + low_u256; + reconstructed.try_into().unwrap() + }; + + // Reconstruct commitment (index 10) + let commitment_u256 = *verified_inputs.at(proof_len + 2); + let commitment_recovered: felt252 = if commitment_u256.high == 0 { + commitment_u256.low.try_into().unwrap() + } else { + let high_u256: u256 = commitment_u256.high.into(); + let low_u256: u256 = commitment_u256.low.into(); + let reconstructed: u256 = high_u256 * q128 + low_u256; + reconstructed.try_into().unwrap() + }; + + // Verify reconstruction matches original + assert(nullifier_recovered == *public_inputs.at(0), 'nullifier_mock'); + assert(root_recovered == *public_inputs.at(1), 'root_mock'); + assert(commitment_recovered == *public_inputs.at(2), 'commitment_mock'); +} + diff --git a/zylith/tests/test_u256_to_felt252_conversion.cairo b/zylith/tests/test_u256_to_felt252_conversion.cairo new file mode 100644 index 0000000..3eb514a --- /dev/null +++ b/zylith/tests/test_u256_to_felt252_conversion.cairo @@ -0,0 +1,202 @@ +use core::array::ArrayTrait; +use core::integer::u256; +use core::traits::{TryInto, Into}; +use snforge_std::{declare, ContractClassTrait, DeclareResultTrait}; +use zylith::privacy::mock_verifier::{IMockVerifier, IMockVerifierDispatcher, IMockVerifierDispatcherTrait}; + +#[test] +fn test_u256_to_felt252_conversion_with_large_values() { + // Test values that are >= 2^128 (will have high != 0 when converted to u256) + // These are the actual values from the ASP logs + let nullifier_felt: felt252 = 894940142951511083072332372919666219214904477692021021291916532133654151109; + let root_felt: felt252 = 1445485933812220050582740933073874602742611239214198775761002192043579171491; + let commitment_felt: felt252 = 636394865011415153173528073558227851187564541861267689293481092409846177785; + + // Convert to u256 (simulating what the verifier does) + let nullifier_u256: u256 = nullifier_felt.into(); + let root_u256: u256 = root_felt.into(); + let commitment_u256: u256 = commitment_felt.into(); + + // Verify they have high != 0 + assert(nullifier_u256.high != 0, 'nullifier_high'); + assert(root_u256.high != 0, 'root_high'); + assert(commitment_u256.high != 0, 'commitment_high'); + + // Reconstruct using our logic: high * 2^128 + low + let q128: u256 = 340282366920938463463374607431768211456; // 2^128 + + // Reconstruct nullifier + let nullifier_high_u256: u256 = nullifier_u256.high.into(); + let nullifier_low_u256: u256 = nullifier_u256.low.into(); + let nullifier_reconstructed: u256 = nullifier_high_u256 * q128 + nullifier_low_u256; + let nullifier_recovered: felt252 = nullifier_reconstructed.try_into().unwrap(); + + // Reconstruct root + let root_high_u256: u256 = root_u256.high.into(); + let root_low_u256: u256 = root_u256.low.into(); + let root_reconstructed: u256 = root_high_u256 * q128 + root_low_u256; + let root_recovered: felt252 = root_reconstructed.try_into().unwrap(); + + // Reconstruct commitment + let commitment_high_u256: u256 = commitment_u256.high.into(); + let commitment_low_u256: u256 = commitment_u256.low.into(); + let commitment_reconstructed: u256 = commitment_high_u256 * q128 + commitment_low_u256; + let commitment_recovered: felt252 = commitment_reconstructed.try_into().unwrap(); + + // Verify reconstruction matches original + assert(nullifier_recovered == nullifier_felt, 'nullifier_recon'); + assert(root_recovered == root_felt, 'root_recon'); + assert(commitment_recovered == commitment_felt, 'commitment_recon'); +} + +#[test] +fn test_u256_to_felt252_conversion_with_small_values() { + // Test values that are < 2^128 (will have high == 0 when converted to u256) + let small_felt: felt252 = 123456789; + let small_u256: u256 = small_felt.into(); + + // Verify it has high == 0 + assert(small_u256.high == 0, 'small_high'); + + // Reconstruct using our logic (should just use .low) + let small_recovered: felt252 = if small_u256.high == 0 { + small_u256.low.try_into().unwrap() + } else { + let q128: u256 = 340282366920938463463374607431768211456; // 2^128 + let high_u256: u256 = small_u256.high.into(); + let low_u256: u256 = small_u256.low.into(); + let reconstructed: u256 = high_u256 * q128 + low_u256; + reconstructed.try_into().unwrap() + }; + + // Verify reconstruction matches original + assert(small_recovered == small_felt, 'small_recon'); +} + +#[test] +fn test_u256_to_felt252_conversion_edge_cases() { + // Test value exactly at 2^128 + let q128_felt: felt252 = 340282366920938463463374607431768211456; // 2^128 + let q128_u256: u256 = q128_felt.into(); + + // Should have high == 1 and low == 0 + assert(q128_u256.high == 1, 'q128_high'); + assert(q128_u256.low == 0, 'q128_low'); + + // Reconstruct + let q128_high_u256: u256 = q128_u256.high.into(); + let q128_low_u256: u256 = q128_u256.low.into(); + let q128_reconstructed: u256 = q128_high_u256 * 340282366920938463463374607431768211456 + q128_low_u256; + let q128_recovered: felt252 = q128_reconstructed.try_into().unwrap(); + + // Verify reconstruction matches original + assert(q128_recovered == q128_felt, 'q128_recon'); + + // Test value just below 2^128 + let below_q128_felt: felt252 = 340282366920938463463374607431768211455; // 2^128 - 1 + let below_q128_u256: u256 = below_q128_felt.into(); + + // Should have high == 0 + assert(below_q128_u256.high == 0, 'below_q128_high'); + + // Reconstruct (should just use .low) + let below_q128_recovered: felt252 = below_q128_u256.low.try_into().unwrap(); + + // Verify reconstruction matches original + assert(below_q128_recovered == below_q128_felt, 'below_q128_recon'); +} + +#[test] +fn test_u256_to_felt252_conversion_with_mock_verifier() { + // Deploy mock verifier + let mock_verifier_class = declare("MockVerifier").unwrap().contract_class(); + let (mock_verifier_address, _) = mock_verifier_class.deploy(@array![]).unwrap(); + + // Create test values >= 2^128 + let nullifier_felt: felt252 = 894940142951511083072332372919666219214904477692021021291916532133654151109; + let root_felt: felt252 = 1445485933812220050582740933073874602742611239214198775761002192043579171491; + let commitment_felt: felt252 = 636394865011415153173528073558227851187564541861267689293481092409846177785; + + // MockVerifier converts felt252 to u256 by doing val.into() + // This simulates what the real Garaga verifier does + let proof: Array = array![1, 2, 3, 4, 5, 6, 7, 8]; + let public_inputs: Array = array![ + nullifier_felt, + root_felt, + commitment_felt, + 100000000000000, + 1, + 340282366920938463463374507431768211456, + 0, + 340248338684246369617028269971025034634, + 0 + ]; + + // Call mock verifier (it returns u256 values) + let mock_verifier_dispatcher = IMockVerifierDispatcher { contract_address: mock_verifier_address }; + let mut full_proof_with_hints = proof; + let mut i = 0; + while i < public_inputs.len() { + full_proof_with_hints.append(*public_inputs.at(i)); + i += 1; + } + + let result = mock_verifier_dispatcher.verify_groth16_proof_bn254(full_proof_with_hints.span()); + let verified_inputs_span = match result { + Result::Ok(v) => v, + Result::Err(_) => { + panic!("mock_failed"); + }, + }; + + // Convert Span to Array for easier access + // Note: MockVerifier returns ALL values (proof + public_inputs), so we need to skip the proof + // Proof has 8 elements, so public inputs start at index 8 + let mut verified_inputs = ArrayTrait::new(); + let mut i = 0; + while i < verified_inputs_span.len() { + verified_inputs.append(*verified_inputs_span.at(i)); + i += 1; + } + + // Extract and reconstruct values (using our conversion logic) + // Public inputs start after the proof (8 elements) + let proof_len = 8; + let q128: u256 = 340282366920938463463374607431768211456; // 2^128 + + let nullifier_u256 = *verified_inputs.at(proof_len + 0); + let nullifier_recovered: felt252 = if nullifier_u256.high == 0 { + nullifier_u256.low.try_into().unwrap() + } else { + let high_u256: u256 = nullifier_u256.high.into(); + let low_u256: u256 = nullifier_u256.low.into(); + let reconstructed: u256 = high_u256 * q128 + low_u256; + reconstructed.try_into().unwrap() + }; + + let root_u256 = *verified_inputs.at(proof_len + 1); + let root_recovered: felt252 = if root_u256.high == 0 { + root_u256.low.try_into().unwrap() + } else { + let high_u256: u256 = root_u256.high.into(); + let low_u256: u256 = root_u256.low.into(); + let reconstructed: u256 = high_u256 * q128 + low_u256; + reconstructed.try_into().unwrap() + }; + + let commitment_u256 = *verified_inputs.at(proof_len + 2); + let commitment_recovered: felt252 = if commitment_u256.high == 0 { + commitment_u256.low.try_into().unwrap() + } else { + let high_u256: u256 = commitment_u256.high.into(); + let low_u256: u256 = commitment_u256.low.into(); + let reconstructed: u256 = high_u256 * q128 + low_u256; + reconstructed.try_into().unwrap() + }; + + // Verify reconstruction matches original + assert(nullifier_recovered == nullifier_felt, 'nullifier_mock'); + assert(root_recovered == root_felt, 'root_mock'); + assert(commitment_recovered == commitment_felt, 'commitment_mock'); +} + From 674d0a491cc4cfb3845aeac2cac07ac25ee3d27e Mon Sep 17 00:00:00 2001 From: KevinMB0220 Date: Sat, 17 Jan 2026 15:13:43 -0600 Subject: [PATCH 2/2] fix problems --- frontend/src/hooks/use-liquidity.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/frontend/src/hooks/use-liquidity.ts b/frontend/src/hooks/use-liquidity.ts index 3467af4..53b59cb 100644 --- a/frontend/src/hooks/use-liquidity.ts +++ b/frontend/src/hooks/use-liquidity.ts @@ -1074,13 +1074,14 @@ export function useLiquidity() { CONFIG.ZYLITH_CONTRACT, account ); + // NOTE: Parameter order changed - arrays moved to end for Argent wallet compatibility tx = await contract.private_burn_liquidity( - proof, - publicInputs, tickLowerFelt, // felt252 (contract converts to i32 internally) tickUpperFelt, // felt252 (contract converts to i32 internally) liquidity, - outputNote.commitment + outputNote.commitment, + proof, // Array moved to end + publicInputs // Array moved to end ); } @@ -1239,12 +1240,13 @@ export function useLiquidity() { account ); + // NOTE: Parameter order changed - arrays moved to end for Argent wallet compatibility const tx = await contract.private_collect( - proof, - publicInputs, tickLowerFelt, // felt252 (contract converts to i32 internally) tickUpperFelt, // felt252 (contract converts to i32 internally) - outputNote.commitment + outputNote.commitment, + proof, // Array moved to end + publicInputs // Array moved to end ); addTransaction({