diff --git a/flake.lock b/flake.lock index 00fcc70..44f3706 100644 --- a/flake.lock +++ b/flake.lock @@ -2716,17 +2716,17 @@ "rust-rapidsnark": "rust-rapidsnark" }, "locked": { - "lastModified": 1785613650, - "narHash": "sha256-lGh9fMClqOwHzuHVzpeft8b7qdHJFlYfCsZTCmbQB9A=", + "lastModified": 1785628651, + "narHash": "sha256-bLT0PfnIBKDZ2bjwevgk0qt0Juya32m5f9jwlQk2g2w=", "owner": "3esmit", "repo": "logos-execution-zone", - "rev": "3a96a23f7feecfc32b3f31beafd4f1768c691e42", + "rev": "7b47fba28e8c1e1ebff30ed16989df94820c0dee", "type": "github" }, "original": { "owner": "3esmit", "repo": "logos-execution-zone", - "rev": "3a96a23f7feecfc32b3f31beafd4f1768c691e42", + "rev": "7b47fba28e8c1e1ebff30ed16989df94820c0dee", "type": "github" } }, diff --git a/flake.nix b/flake.nix index 4cce445..f62f3fe 100644 --- a/flake.nix +++ b/flake.nix @@ -4,7 +4,7 @@ inputs = { logos-module-builder.url = "github:logos-co/logos-module-builder"; nix-bundle-lgx.url = "github:logos-co/nix-bundle-lgx"; - logos-execution-zone.url = "github:3esmit/logos-execution-zone?rev=3a96a23f7feecfc32b3f31beafd4f1768c691e42"; + logos-execution-zone.url = "github:3esmit/logos-execution-zone?rev=7b47fba28e8c1e1ebff30ed16989df94820c0dee"; }; outputs = inputs@{ logos-module-builder, ... }: diff --git a/src/lez_core_module.cpp b/src/lez_core_module.cpp index db5d049..ec416ab 100644 --- a/src/lez_core_module.cpp +++ b/src/lez_core_module.cpp @@ -70,14 +70,31 @@ constexpr auto Secrets = "secrets"; constexpr std::string_view LezTestnetSequencerAddress = "https://testnet.lez.logos.co"; constexpr std::string_view LezTestnetAuthenticatedTransferProgramId = "dcbbfebcd59399961ed9973b8307dc475fd4c5ca5779aacfe7588f7dbc3f4a71"; +constexpr std::string_view LezLocalDevelopmentSequencerAddress = + "http://127.0.0.1:3040"; -bool isLezTestnetSequencer(std::string address) { +void normalizeSequencerAddress(std::string& address) { while (!address.empty() && address.back() == '/') { address.pop_back(); } +} + +bool isLezTestnetSequencer(std::string address) { + normalizeSequencerAddress(address); return address == LezTestnetSequencerAddress; } +bool isLezLocalDevelopmentSequencer(std::string address) { + normalizeSequencerAddress(address); + return address == LezLocalDevelopmentSequencerAddress; +} + +std::string programIdToHex(const FfiProgramId& programId) { + return bytesToHex( + reinterpret_cast(programId.data), + sizeof(programId.data)); +} + std::vector authenticatedTransferWords(const uint8_t (&amount)[16]) { std::vector words; words.reserve(5); @@ -895,7 +912,8 @@ std::string LEZCoreModule::register_public_account(const std::string& account_id return transferResultToJson(nullptr, "register_public_account: invalid account_id_hex"); } - if (isLezTestnetSequencer(get_sequencer_addr())) { + const std::string sequencerAddress = get_sequencer_addr(); + if (isLezTestnetSequencer(sequencerAddress)) { // AuthenticatedTransferInstruction::Initialize is enum variant 1. return send_generic_public_transaction( {account_id_hex}, @@ -905,6 +923,28 @@ std::string LEZCoreModule::register_public_account(const std::string& account_id ); } + if (isLezLocalDevelopmentSequencer(sequencerAddress)) { + FfiProgramId programId{}; + const WalletFfiError error = + wallet_ffi_authenticated_transfer_program_id(&programId); + if (error != SUCCESS) { + fprintf(stderr, + "register_public_account: local program id FFI error %d\n", + error); + return transferResultToJson( + nullptr, + "register_public_account: local program id FFI error " + + std::to_string(error)); + } + // AuthenticatedTransferInstruction::Initialize is enum variant 1. + return send_generic_public_transaction( + {account_id_hex}, + {true}, + {1}, + programIdToHex(programId) + ); + } + FfiTransferResult result{}; const WalletFfiError error = wallet_ffi_register_public_account(walletHandle, &id, &result); if (error != SUCCESS) { diff --git a/tests/mocks/mock_wallet_ffi.cpp b/tests/mocks/mock_wallet_ffi.cpp index c9037a2..eded1b2 100644 --- a/tests/mocks/mock_wallet_ffi.cpp +++ b/tests/mocks/mock_wallet_ffi.cpp @@ -450,6 +450,15 @@ WalletFfiError wallet_ffi_register_public_account(WalletHandle*, const FfiBytes3 return fillTransferResult("wallet_ffi_register_public_account", out_result); } +WalletFfiError wallet_ffi_authenticated_transfer_program_id(FfiProgramId* out_program_id) { + LOGOS_CMOCK_RECORD("wallet_ffi_authenticated_transfer_program_id"); + const int err = LOGOS_CMOCK_RETURN(int, "wallet_ffi_authenticated_transfer_program_id"); + if (err == 0 && out_program_id) { + memset(out_program_id->data, 0x42, sizeof(out_program_id->data)); + } + return static_cast(err); +} + WalletFfiError wallet_ffi_register_private_account(WalletHandle*, const FfiBytes32*, FfiTransferResult* out_result) { LOGOS_CMOCK_RECORD("wallet_ffi_register_private_account"); return fillTransferResult("wallet_ffi_register_private_account", out_result); diff --git a/tests/stubs/wallet_ffi.h b/tests/stubs/wallet_ffi.h index 953bc66..0852290 100644 --- a/tests/stubs/wallet_ffi.h +++ b/tests/stubs/wallet_ffi.h @@ -294,6 +294,7 @@ WalletFfiError wallet_ffi_transfer_private_owned( WalletFfiError wallet_ffi_register_public_account(WalletHandle* handle, const FfiBytes32* account_id, FfiTransferResult* out_result); WalletFfiError wallet_ffi_register_private_account(WalletHandle* handle, const FfiBytes32* account_id, FfiTransferResult* out_result); +WalletFfiError wallet_ffi_authenticated_transfer_program_id(FfiProgramId* out_program_id); WalletFfiError wallet_ffi_transfer_elf(FfiProgram *ffi_program); WalletFfiError wallet_ffi_token_elf(FfiProgram *ffi_program); diff --git a/tests/test_lez_core.cpp b/tests/test_lez_core.cpp index c9f8f16..c8bf062 100644 --- a/tests/test_lez_core.cpp +++ b/tests/test_lez_core.cpp @@ -491,6 +491,29 @@ LOGOS_TEST(register_public_account_uses_convenience_path_outside_testnet) { LOGOS_ASSERT_TRUE(obj["success"].get()); } +LOGOS_TEST(register_public_account_uses_local_development_program) { + auto t = LogosTestContext("logos_execution_zone"); + t.mockCFunction("wallet_ffi_get_sequencer_addr").returns("http://127.0.0.1:3040/"); + LEZCoreModule module; + + const nlohmann::json obj = parseObject(module.register_public_account(VALID_ID)); + + LOGOS_ASSERT_EQ(t.cFunctionCallCount("wallet_ffi_get_sequencer_addr"), 1); + LOGOS_ASSERT(t.cFunctionCalled("wallet_ffi_authenticated_transfer_program_id")); + LOGOS_ASSERT(t.cFunctionCalled("wallet_ffi_send_generic_public_transaction")); + LOGOS_ASSERT_FALSE(t.cFunctionCalled("wallet_ffi_register_public_account")); + LOGOS_ASSERT_TRUE(obj["success"].get()); + LOGOS_ASSERT_EQ(MockWalletFfiCapture::lastGenericPublicInstructionWords.size(), static_cast(1)); + LOGOS_ASSERT_EQ(MockWalletFfiCapture::lastGenericPublicInstructionWords[0], static_cast(1)); + const std::array expected_program_id = { + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, + }; + LOGOS_ASSERT(MockWalletFfiCapture::lastGenericPublicProgramId == expected_program_id); +} + LOGOS_TEST(register_public_account_uses_deployed_testnet_program) { auto t = LogosTestContext("logos_execution_zone"); t.mockCFunction("wallet_ffi_get_sequencer_addr").returns("https://testnet.lez.logos.co");