Merge pull request #31 from logos-blockchain/Pravdyvy/mnemonic-updates

Mnemonic updates
This commit is contained in:
Moudy 2026-06-24 12:03:58 +02:00 committed by GitHub
commit 5537c0065e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 11155 additions and 785 deletions

11277
flake.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -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:logos-blockchain/lssa?rev=cf3639d8252040d13b3d4e933feb19b42c76e14a"; # v0.1.2
logos-execution-zone.url = "github:logos-blockchain/lssa?rev=4d055c71a77d4b3aa147dfe8e1673afb3217840b"; # latest mnemonic updates, to be replaced after merging
};
outputs = inputs@{ logos-module-builder, ... }:

View File

@ -55,6 +55,7 @@ constexpr auto NullifierPublicKey = "nullifier_public_key";
constexpr auto ViewingPublicKey = "viewing_public_key";
constexpr auto AccountId = "account_id";
constexpr auto IsPublic = "is_public";
constexpr auto Secrets = "secrets";
} // namespace JsonKeys
bool hexToBytes(const std::string& hex, std::vector<uint8_t>& output_bytes, int expectedLength = -1) {
@ -127,6 +128,23 @@ std::string transferResultToJson(const FfiTransferResult* result, const std::str
return obj.dump();
}
// Builds JSON { success, tx_hash, secrets, error } for both success (result + empty error) and failure (nullptr + errorMessage) in case of generic transaction.
std::string genericTransactionResultToJson(const FfiTransactionResult* result, const std::string& errorMessage) {
nlohmann::json obj = nlohmann::json::object();
const bool isError = !errorMessage.empty();
obj[JsonKeys::Success] = !isError && result && result->success;
obj[JsonKeys::TxHash] = (!isError && result && result->tx_hash) ? std::string(result->tx_hash) : std::string();
std::vector<std::string> secrets;
if (!isError && result && result->secrets_data) {
for (uintptr_t i = 0; i < result->secrets_size; ++i) {
secrets.push_back(bytes32ToHex(result->secrets_data[i]));
}
}
obj[JsonKeys::Secrets] = secrets;
obj[JsonKeys::Error] = errorMessage;
return obj.dump();
}
std::string ffiAccountToJson(const FfiAccount& account) {
nlohmann::json obj = nlohmann::json::object();
obj[JsonKeys::ProgramOwner] = bytesToHex(reinterpret_cast<const uint8_t*>(account.program_owner.data), 32);
@ -573,8 +591,13 @@ std::string LogosExecutionZoneWalletModule::transfer_shielded(
return transferResultToJson(nullptr, "transfer_shielded: amount_le16_hex must be 32 hex characters (16 bytes)");
}
// ToDo: Bandaid, I am not sure, how exactly identifiers should be used.
FfiU128 identifier {};
// ToDo: Add keycard support
const char *key_path = nullptr;
FfiTransferResult result{};
const WalletFfiError error = wallet_ffi_transfer_shielded(walletHandle, &fromId, &toKeys, &amount, &result);
const WalletFfiError error = wallet_ffi_transfer_shielded(walletHandle, &fromId, &toKeys, &identifier, &amount, key_path, &result);
free(const_cast<uint8_t*>(toKeys.viewing_public_key));
if (error != SUCCESS) {
fprintf(stderr, "transfer_shielded: wallet FFI error %d\n", error);
@ -637,8 +660,11 @@ std::string LogosExecutionZoneWalletModule::transfer_private(
return transferResultToJson(nullptr, "transfer_private: amount_le16_hex must be 32 hex characters (16 bytes)");
}
// ToDo: Bandaid, I am not sure, how exactly identifiers should be used.
FfiU128 identifier {};
FfiTransferResult result{};
const WalletFfiError error = wallet_ffi_transfer_private(walletHandle, &fromId, &toKeys, &amount, &result);
const WalletFfiError error = wallet_ffi_transfer_private(walletHandle, &fromId, &toKeys, &identifier, &amount, &result);
free(const_cast<uint8_t*>(toKeys.viewing_public_key));
if (error != SUCCESS) {
fprintf(stderr, "transfer_private: wallet FFI error %d\n", error);
@ -666,8 +692,11 @@ std::string LogosExecutionZoneWalletModule::transfer_shielded_owned(
return transferResultToJson(nullptr, "transfer_shielded_owned: amount_le16_hex must be 32 hex characters (16 bytes)");
}
// ToDo: Add keycard support
const char *key_path = nullptr;
FfiTransferResult result{};
const WalletFfiError error = wallet_ffi_transfer_shielded_owned(walletHandle, &fromId, &toId, &amount, &result);
const WalletFfiError error = wallet_ffi_transfer_shielded_owned(walletHandle, &fromId, &toId, &amount, key_path, &result);
if (error != SUCCESS) {
fprintf(stderr, "transfer_shielded_owned: wallet FFI error %d\n", error);
return transferResultToJson(nullptr, "transfer_shielded_owned: wallet FFI error " + std::to_string(error));
@ -739,22 +768,300 @@ std::string LogosExecutionZoneWalletModule::register_private_account(const std::
return resultJson;
}
std::vector<uint8_t> LogosExecutionZoneWalletModule::token_elf() {
FfiProgram ffi_program{};
WalletFfiError error = wallet_ffi_token_elf(&ffi_program);
if (error != SUCCESS) {
fprintf(stderr, "token_elf: wallet FFI error %d\n", error);
return std::vector<uint8_t>{};
}
std::vector<uint8_t> result(ffi_program.elf_data,
ffi_program.elf_data + ffi_program.elf_size);
wallet_ffi_free_ffi_program(&ffi_program);
return result;
}
std::vector<uint8_t> LogosExecutionZoneWalletModule::amm_elf() {
FfiProgram ffi_program{};
WalletFfiError error = wallet_ffi_token_elf(&ffi_program);
if (error != SUCCESS) {
fprintf(stderr, "amm_elf: wallet FFI error %d\n", error);
return std::vector<uint8_t>{};
}
std::vector<uint8_t> result(ffi_program.elf_data,
ffi_program.elf_data + ffi_program.elf_size);
wallet_ffi_free_ffi_program(&ffi_program);
return result;
}
std::vector<uint8_t> LogosExecutionZoneWalletModule::ata_elf() {
FfiProgram ffi_program{};
WalletFfiError error = wallet_ffi_token_elf(&ffi_program);
if (error != SUCCESS) {
fprintf(stderr, "ata_elf: wallet FFI error %d\n", error);
return std::vector<uint8_t>{};
}
std::vector<uint8_t> result(ffi_program.elf_data,
ffi_program.elf_data + ffi_program.elf_size);
wallet_ffi_free_ffi_program(&ffi_program);
return result;
}
std::vector<uint8_t> LogosExecutionZoneWalletModule::authenticated_transfer_elf() {
FfiProgram ffi_program{};
WalletFfiError error = wallet_ffi_token_elf(&ffi_program);
if (error != SUCCESS) {
fprintf(stderr, "authenticated_transfer_elf: wallet FFI error %d\n", error);
return std::vector<uint8_t>{};
}
std::vector<uint8_t> result(ffi_program.elf_data,
ffi_program.elf_data + ffi_program.elf_size);
wallet_ffi_free_ffi_program(&ffi_program);
return result;
}
std::string LogosExecutionZoneWalletModule::send_generic_public_transaction(
const std::vector<std::string>& account_ids,
const std::vector<bool>& signing_requirements,
const std::vector<uint32_t>& instruction,
const std::vector<uint8_t>& program_elf,
const std::vector<std::vector<uint8_t>>& program_dependencies
) {
std::vector<FfiAccountIdentity> identities_resolved;
identities_resolved.reserve(account_ids.size());
for (int i = 0; i < account_ids.size(); ++i) {
FfiAccountIdentity acc_identity{};
FfiBytes32 id{};
if (!hexToBytes32(account_ids[i], &id)) {
fprintf(stderr, "wallet_ffi_resolve_public_account: invalid account_id_hex");
return transferResultToJson(nullptr, std::string("wallet_ffi_resolve_public_account: invalid account_id_hex"));
}
WalletFfiError error = wallet_ffi_resolve_public_account(id, signing_requirements[i], &acc_identity);
if (error != SUCCESS) {
fprintf(stderr, "wallet_ffi_resolve_public_account failed for index %d: wallet FFI error %d\n", i, error);
return transferResultToJson(nullptr, std::string("wallet_ffi_resolve_public_account: wallet FFI error ") + std::to_string(error));
}
identities_resolved.push_back(acc_identity);
}
const FfiAccountIdentity *account_identities = identities_resolved.data();
uintptr_t account_identities_size = static_cast<uintptr_t>(identities_resolved.size());
const uint32_t* input_instruction_data = instruction.data();
uintptr_t input_instruction_data_size = static_cast<uintptr_t>(instruction.size());
FfiProgram main_program {};
const uint8_t *program_elf_data = program_elf.data();
uintptr_t program_elf_size = static_cast<uintptr_t>(program_elf.size());
main_program.elf_data = program_elf_data;
main_program.elf_size = program_elf_size;
std::vector<FfiProgram> ffi_program_dependencies;
ffi_program_dependencies.reserve(program_dependencies.size());
for (int i = 0; i < program_dependencies.size(); ++i) {
FfiProgram program{};
const uint8_t *program_elf_data = program_dependencies[i].data();
uintptr_t program_elf_size = static_cast<uintptr_t>(program_dependencies[i].size());
program.elf_data = program_elf_data;
program.elf_size = program_elf_size;
ffi_program_dependencies.push_back(program);
}
const FfiProgram *dependencies_data = ffi_program_dependencies.data();
uintptr_t dependencies_size = static_cast<uintptr_t>(ffi_program_dependencies.size());
FfiProgramWithDependencies program_with_dependencies {};
program_with_dependencies.program = main_program;
program_with_dependencies.deps = dependencies_data;
program_with_dependencies.deps_size = dependencies_size;
FfiTransactionResult result {};
const WalletFfiError error = wallet_ffi_send_generic_public_transaction(
walletHandle,
account_identities,
account_identities_size,
input_instruction_data,
input_instruction_data_size,
&program_with_dependencies,
&result
);
for (FfiAccountIdentity& acc_identity : identities_resolved) {
wallet_ffi_free_account_identity(&acc_identity);
}
if (error != SUCCESS) {
fprintf(stderr, "send_generic_public_transaction: wallet FFI error %d\n", error);
return transferResultToJson(nullptr, std::string("send_generic_public_transaction: wallet FFI error ") + std::to_string(error));
}
std::string resultJson = genericTransactionResultToJson(&result, std::string());
wallet_ffi_free_transaction_result(&result);
return resultJson;
}
std::string LogosExecutionZoneWalletModule::send_generic_private_transaction(
const std::vector<std::string>& account_ids,
const std::vector<uint32_t>& instruction,
const std::vector<uint8_t>& program_elf,
const std::vector<std::vector<uint8_t>>& program_dependencies
) {
std::vector<FfiAccountIdentity> identities_resolved;
identities_resolved.reserve(account_ids.size());
for (int i = 0; i < account_ids.size(); ++i) {
FfiAccountIdentity acc_identity{};
FfiBytes32 id{};
if (!hexToBytes32(account_ids[i], &id)) {
fprintf(stderr, "wallet_ffi_resolve_private_account: invalid account_id_hex");
return transferResultToJson(nullptr, std::string("wallet_ffi_resolve_private_account: invalid account_id_hex"));
}
WalletFfiError error = wallet_ffi_resolve_private_account(walletHandle, id, &acc_identity);
if (error != SUCCESS) {
fprintf(stderr, "wallet_ffi_resolve_private_account failed for index %d: wallet FFI error %d\n", i, error);
return transferResultToJson(nullptr, std::string("wallet_ffi_resolve_private_account: wallet FFI error ") + std::to_string(error));
}
identities_resolved.push_back(acc_identity);
}
const FfiAccountIdentity *account_identities = identities_resolved.data();
uintptr_t account_identities_size = static_cast<uintptr_t>(identities_resolved.size());
const uint32_t* input_instruction_data = instruction.data();
uintptr_t input_instruction_data_size = static_cast<uintptr_t>(instruction.size());
FfiProgram main_program {};
const uint8_t *program_elf_data = program_elf.data();
uintptr_t program_elf_size = static_cast<uintptr_t>(program_elf.size());
main_program.elf_data = program_elf_data;
main_program.elf_size = program_elf_size;
std::vector<FfiProgram> ffi_program_dependencies;
ffi_program_dependencies.reserve(program_dependencies.size());
for (int i = 0; i < program_dependencies.size(); ++i) {
FfiProgram program{};
const uint8_t *program_elf_data = program_dependencies[i].data();
uintptr_t program_elf_size = static_cast<uintptr_t>(program_dependencies[i].size());
program.elf_data = program_elf_data;
program.elf_size = program_elf_size;
ffi_program_dependencies.push_back(program);
}
const FfiProgram *dependencies_data = ffi_program_dependencies.data();
uintptr_t dependencies_size = static_cast<uintptr_t>(ffi_program_dependencies.size());
FfiProgramWithDependencies program_with_dependencies {};
program_with_dependencies.program = main_program;
program_with_dependencies.deps = dependencies_data;
program_with_dependencies.deps_size = dependencies_size;
FfiTransactionResult result {};
const WalletFfiError error = wallet_ffi_send_generic_private_transaction(
walletHandle,
account_identities,
account_identities_size,
input_instruction_data,
input_instruction_data_size,
&program_with_dependencies,
&result
);
for (FfiAccountIdentity& acc_identity : identities_resolved) {
wallet_ffi_free_account_identity(&acc_identity);
}
if (error != SUCCESS) {
fprintf(stderr, "send_generic_private_transaction: wallet FFI error %d\n", error);
return transferResultToJson(nullptr, std::string("send_generic_private_transaction: wallet FFI error ") + std::to_string(error));
}
std::string resultJson = genericTransactionResultToJson(&result, std::string());
wallet_ffi_free_transaction_result(&result);
return resultJson;
}
std::string LogosExecutionZoneWalletModule::send_program_deployment_transaction(
const std::vector<uint8_t>& program_elf
) {
FfiTransactionResult result {};
const uint8_t *program_elf_data = program_elf.data();
uintptr_t program_elf_size = static_cast<uintptr_t>(program_elf.size());
const WalletFfiError error = wallet_ffi_program_deployment(
walletHandle,
program_elf_data,
program_elf_size,
&result
);
if (error != SUCCESS) {
fprintf(stderr, "send_program_deployment_transaction: wallet FFI error %d\n", error);
return transferResultToJson(nullptr, std::string("send_program_deployment_transaction: wallet FFI error ") + std::to_string(error));
}
std::string resultJson = genericTransactionResultToJson(&result, std::string());
wallet_ffi_free_transaction_result(&result);
return resultJson;
}
// === Wallet Lifecycle ===
int64_t LogosExecutionZoneWalletModule::create_new(
std::string LogosExecutionZoneWalletModule::create_new(
const std::string& config_path,
const std::string& storage_path,
const std::string& password
) {
if (walletHandle) {
fprintf(stderr, "create_new: wallet is already open\n");
return INTERNAL_ERROR;
return {};
}
walletHandle = wallet_ffi_create_new(config_path.c_str(), storage_path.c_str(), password.c_str());
if (!walletHandle) {
FfiCreateWalletOutput create_output = wallet_ffi_create_new(config_path.c_str(), storage_path.c_str(), password.c_str());
if (!create_output.wallet) {
fprintf(stderr, "create_new: wallet_ffi_create_new returned null\n");
return INTERNAL_ERROR;
return {};
}
walletHandle = create_output.wallet;
std::string mnemonic(create_output.mnemonic);
wallet_ffi_free_string(create_output.mnemonic);
return mnemonic;
}
int64_t LogosExecutionZoneWalletModule::restore_storage(const std::string& mnemonic, const std::string password, uint32_t depth) {
const WalletFfiError error = wallet_ffi_restore_data(walletHandle, mnemonic.c_str(), password.c_str(), depth);
if (error != SUCCESS) {
fprintf(stderr, "restore_storage: wallet FFI error %d\n", error);
return error;
}
return SUCCESS;
@ -791,4 +1098,4 @@ std::string LogosExecutionZoneWalletModule::get_sequencer_addr() {
std::string value(addr);
wallet_ffi_free_string(addr);
return value;
}
}

View File

@ -30,10 +30,12 @@ public:
std::string version() const;
// === Wallet Lifecycle ===
int64_t create_new(const std::string& config_path, const std::string& storage_path, const std::string& password);
std::string create_new(const std::string& config_path, const std::string& storage_path, const std::string& password);
int64_t open(const std::string& config_path, const std::string& storage_path);
int64_t save();
int64_t restore_storage(const std::string& mnemonic, const std::string password, uint32_t depth);
// === Account Management ===
std::string create_account_public();
std::string create_account_private();
@ -70,6 +72,28 @@ public:
std::string register_public_account(const std::string& account_id_hex);
std::string register_private_account(const std::string& account_id_hex);
std::vector<uint8_t> authenticated_transfer_elf();
std::vector<uint8_t> token_elf();
std::vector<uint8_t> amm_elf();
std::vector<uint8_t> ata_elf();
std::string send_generic_public_transaction(
const std::vector<std::string>& account_ids,
const std::vector<bool>& signing_requirements,
const std::vector<uint32_t>& instruction,
const std::vector<uint8_t>& program_elf,
const std::vector<std::vector<uint8_t>>& program_dependencies
);
std::string send_generic_private_transaction(
const std::vector<std::string>& account_ids,
const std::vector<uint32_t>& instruction,
const std::vector<uint8_t>& program_elf,
const std::vector<std::vector<uint8_t>>& program_dependencies
);
std::string send_program_deployment_transaction(
const std::vector<uint8_t>& program_elf
);
// === Configuration ===
std::string get_sequencer_addr();

View File

@ -47,10 +47,15 @@ extern "C" {
// === Lifecycle ===
WalletHandle* wallet_ffi_create_new(const char*, const char*, const char*) {
FfiCreateWalletOutput wallet_ffi_create_new(const char*, const char*, const char*) {
LOGOS_CMOCK_RECORD("wallet_ffi_create_new");
const int ok = LOGOS_CMOCK_RETURN(int, "wallet_ffi_create_new");
return ok ? reinterpret_cast<WalletHandle*>(&g_fakeWallet) : nullptr;
const char* mnemonic_ok = LOGOS_CMOCK_RETURN_STRING("wallet_ffi_create_new");
FfiCreateWalletOutput output;
char* mn_char = strdup((mnemonic_ok && *mnemonic_ok) ? mnemonic_ok : "word word");
output.mnemonic = mn_char;
output.wallet = ok ? reinterpret_cast<WalletHandle*>(&g_fakeWallet) : nullptr;
return output;
}
WalletHandle* wallet_ffi_open(const char*, const char*) {
@ -68,6 +73,12 @@ void wallet_ffi_destroy(WalletHandle*) {
LOGOS_CMOCK_RECORD("wallet_ffi_destroy");
}
WalletFfiError wallet_ffi_restore_data(WalletHandle*, const char*, const char*, uint32_t) {
LOGOS_CMOCK_RECORD("wallet_ffi_restore_data");
const int err = LOGOS_CMOCK_RETURN(int, "wallet_ffi_restore_data");
return static_cast<WalletFfiError>(err);
}
// === Account management ===
WalletFfiError wallet_ffi_create_account_public(WalletHandle*, FfiBytes32* out_id) {
@ -134,6 +145,15 @@ WalletFfiError wallet_ffi_get_balance(WalletHandle*, const FfiBytes32*, bool, ui
return static_cast<WalletFfiError>(err);
}
static WalletFfiError fillProgram(const char* key, FfiProgram *ffi_program) {
const int err = LogosCMockStore::instance().getReturn<int>(key);
if (err == 0 && ffi_program) {
memset(const_cast<uint8_t*>(ffi_program->elf_data), 0xAA, 100);
ffi_program->elf_size = 100;
}
return static_cast<WalletFfiError>(err);
}
static WalletFfiError fillAccount(const char* key, FfiAccount* out_account) {
const int err = LogosCMockStore::instance().getReturn<int>(key);
if (err == 0 && out_account) {
@ -148,6 +168,53 @@ static WalletFfiError fillAccount(const char* key, FfiAccount* out_account) {
return static_cast<WalletFfiError>(err);
}
static WalletFfiError fillPublicAccountIdentity(const char* key, FfiAccountIdentity *out_account_identity) {
const int err = LogosCMockStore::instance().getReturn<int>(key);
if (err == 0 && out_account_identity) {
out_account_identity->kind = FfiAccountIdentityKind::PUBLIC;
memset(out_account_identity->account_id.data, 0xAA, sizeof(out_account_identity->account_id));
out_account_identity->key_path = nullptr;
memset(out_account_identity->nullifier_secret_key.data, 0x00, sizeof(out_account_identity->nullifier_secret_key));
memset(out_account_identity->nullifier_public_key.data, 0x00, sizeof(out_account_identity->nullifier_public_key));
out_account_identity->viewing_public_key = nullptr;
out_account_identity->viewing_public_key_len = 0;
memset(out_account_identity->identifier.data, 0x01, sizeof(out_account_identity->identifier));
}
return static_cast<WalletFfiError>(err);
}
static WalletFfiError fillPrivateAccountIdentity(const char* key, FfiAccountIdentity *out_account_identity) {
const int err = LogosCMockStore::instance().getReturn<int>(key);
if (err == 0 && out_account_identity) {
out_account_identity->kind = FfiAccountIdentityKind::PRIVATE_OWNED;
memset(out_account_identity->account_id.data, 0xAB, sizeof(out_account_identity->account_id));
out_account_identity->key_path = nullptr;
memset(out_account_identity->nullifier_secret_key.data, 0x11, sizeof(out_account_identity->nullifier_secret_key));
memset(out_account_identity->nullifier_public_key.data, 0x22, sizeof(out_account_identity->nullifier_public_key));
out_account_identity->viewing_public_key = nullptr;
out_account_identity->viewing_public_key_len = 0;
memset(out_account_identity->identifier.data, 0x01, sizeof(out_account_identity->identifier));
}
return static_cast<WalletFfiError>(err);
}
static WalletFfiError fillTransactionResult(const char* key, FfiTransactionResult *out_result) {
const int err = LogosCMockStore::instance().getReturn<int>(key);
if (out_result) {
out_result->success = (err == 0);
if (err == 0) {
const char* tx = LogosCMockStore::instance().getReturnString("transaction_tx_hash");
// getReturnString yields "" (non-null) when unset; fall back to a default.
out_result->tx_hash = strdup((tx && *tx) ? tx : "0xmocktxhash2");
} else {
out_result->tx_hash = nullptr;
}
out_result->secrets_data = nullptr;
out_result->secrets_size = 0;
}
return static_cast<WalletFfiError>(err);
}
WalletFfiError wallet_ffi_get_account_public(WalletHandle*, const FfiBytes32*, FfiAccount* out_account) {
LOGOS_CMOCK_RECORD("wallet_ffi_get_account_public");
return fillAccount("wallet_ffi_get_account_public", out_account);
@ -275,7 +342,10 @@ WalletFfiError wallet_ffi_transfer_public(
}
WalletFfiError wallet_ffi_transfer_shielded(
WalletHandle*, const FfiBytes32*, const FfiPrivateAccountKeys*, const uint8_t (*)[16], FfiTransferResult* out_result) {
WalletHandle*, const FfiBytes32*, const FfiPrivateAccountKeys*, const FfiU128*,
const uint8_t (*)[16],
const char*,
FfiTransferResult* out_result) {
LOGOS_CMOCK_RECORD("wallet_ffi_transfer_shielded");
return fillTransferResult("wallet_ffi_transfer_shielded", out_result);
}
@ -287,13 +357,16 @@ WalletFfiError wallet_ffi_transfer_deshielded(
}
WalletFfiError wallet_ffi_transfer_private(
WalletHandle*, const FfiBytes32*, const FfiPrivateAccountKeys*, const uint8_t (*)[16], FfiTransferResult* out_result) {
WalletHandle*, const FfiBytes32*, const FfiPrivateAccountKeys*, const FfiU128*,
const uint8_t (*)[16], FfiTransferResult* out_result) {
LOGOS_CMOCK_RECORD("wallet_ffi_transfer_private");
return fillTransferResult("wallet_ffi_transfer_private", out_result);
}
WalletFfiError wallet_ffi_transfer_shielded_owned(
WalletHandle*, const FfiBytes32*, const FfiBytes32*, const uint8_t (*)[16], FfiTransferResult* out_result) {
WalletHandle*, const FfiBytes32*, const FfiBytes32*, const uint8_t (*)[16],
const char *,
FfiTransferResult* out_result) {
LOGOS_CMOCK_RECORD("wallet_ffi_transfer_shielded_owned");
return fillTransferResult("wallet_ffi_transfer_shielded_owned", out_result);
}
@ -322,6 +395,88 @@ void wallet_ffi_free_transfer_result(FfiTransferResult* result) {
}
}
WalletFfiError wallet_ffi_transfer_elf(FfiProgram *ffi_program) {
LOGOS_CMOCK_RECORD("wallet_ffi_transfer_elf");
return fillProgram("wallet_ffi_transfer_elf", ffi_program);
}
WalletFfiError wallet_ffi_token_elf(FfiProgram *ffi_program) {
LOGOS_CMOCK_RECORD("wallet_ffi_token_elf");
return fillProgram("wallet_ffi_token_elf", ffi_program);
}
WalletFfiError wallet_ffi_ata_elf(FfiProgram *ffi_program) {
LOGOS_CMOCK_RECORD("wallet_ffi_ata_elf");
return fillProgram("wallet_ffi_ata_elf", ffi_program);
}
WalletFfiError wallet_ffi_amm_elf(FfiProgram *ffi_program) {
LOGOS_CMOCK_RECORD("wallet_ffi_amm_elf");
return fillProgram("wallet_ffi_amm_elf", ffi_program);
}
WalletFfiError wallet_ffi_resolve_public_account(FfiBytes32 account_id, bool needs_sign, FfiAccountIdentity *out_account_identity) {
LOGOS_CMOCK_RECORD("wallet_ffi_resolve_public_account");
return fillPublicAccountIdentity("wallet_ffi_resolve_public_account", out_account_identity);
}
WalletFfiError wallet_ffi_resolve_private_account(WalletHandle *handle, FfiBytes32 account_id, FfiAccountIdentity *out_account_identity){
LOGOS_CMOCK_RECORD("wallet_ffi_resolve_private_account");
return fillPrivateAccountIdentity("wallet_ffi_resolve_private_account", out_account_identity);
}
void wallet_ffi_free_instruction_words(FfiInstructionWords *words){
LOGOS_CMOCK_RECORD("wallet_ffi_free_instruction_words");
if (words && words->instruction_words) {
free(words->instruction_words);
words->instruction_words = nullptr;
words->instruction_words_size = 0;
}
}
void wallet_ffi_free_account_identity(FfiAccountIdentity *account_identity){
LOGOS_CMOCK_RECORD("wallet_ffi_free_account_identity");
if (account_identity && account_identity->viewing_public_key) {
free(const_cast<uint8_t*>(account_identity->viewing_public_key));
account_identity->viewing_public_key = nullptr;
account_identity->viewing_public_key_len = 0;
}
}
void wallet_ffi_free_transaction_result(FfiTransactionResult *result) {
LOGOS_CMOCK_RECORD("wallet_ffi_free_transaction_result");
if (result && result->tx_hash) {
free(const_cast<char*>(result->tx_hash));
result->tx_hash = nullptr;
}
}
void wallet_ffi_free_ffi_program(FfiProgram *ffi_program) {
LOGOS_CMOCK_RECORD("wallet_ffi_free_ffi_program");
if (ffi_program && ffi_program->elf_data) {
free(const_cast<uint8_t*>(ffi_program->elf_data));
ffi_program->elf_data = nullptr;
ffi_program->elf_size = 0;
}
}
WalletFfiError wallet_ffi_send_generic_public_transaction(WalletHandle *handle, const FfiAccountIdentity *account_identities,
uintptr_t account_identities_size, const uint32_t *instruction_words, uintptr_t instruction_words_size,
const FfiProgramWithDependencies *program_with_dependencies, FfiTransactionResult *out_result) {
LOGOS_CMOCK_RECORD("wallet_ffi_send_generic_public_transaction");
return fillTransactionResult("wallet_ffi_send_generic_public_transaction", out_result);
}
WalletFfiError wallet_ffi_send_generic_private_transaction(WalletHandle *handle, const FfiAccountIdentity *account_identities,
uintptr_t account_identities_size, const uint32_t *instruction_words, uintptr_t instruction_words_size,
const FfiProgramWithDependencies *program_with_dependencies, FfiTransactionResult *out_result){
LOGOS_CMOCK_RECORD("wallet_ffi_send_generic_private_transaction");
return fillTransactionResult("wallet_ffi_send_generic_private_transaction", out_result);
}
WalletFfiError wallet_ffi_program_deployment(WalletHandle *handle, const uint8_t *elf_data, uintptr_t elf_size,
FfiTransactionResult *out_result) {
LOGOS_CMOCK_RECORD("wallet_ffi_program_deployment");
return fillTransactionResult("wallet_ffi_program_deployment", out_result);
}
// === Configuration ===
char* wallet_ffi_get_sequencer_addr(WalletHandle*) {

View File

@ -75,13 +75,104 @@ typedef struct FfiTransferResult {
char* tx_hash;
} FfiTransferResult;
/**
* Enumeration to represent kinds of `FfiAccountIdentity`.
*/
typedef enum FfiAccountIdentityKind {
PUBLIC = 0,
PUBLIC_NO_SIGN = 1,
PUBLIC_KEYCARD = 2,
PRIVATE_OWNED = 3,
PRIVATE_FOREIGN = 4,
PRIVATE_PDA_OWNED = 5,
PRIVATE_PDA_FOREIGN = 6,
PRIVATE_SHARED = 7,
PRIVATE_PDA_SHARED = 8,
} FfiAccountIdentityKind;
/**
* U128 - 16 bytes little endian.
*/
typedef struct FfiU128 {
uint8_t data[16];
} FfiU128;
typedef struct FfiInstructionWords {
uint32_t *instruction_words;
uintptr_t instruction_words_size;
enum WalletFfiError error;
} FfiInstructionWords;
/**
* Struct representing an account identity, given to `AccountManager` at intialization.
*/
typedef struct FfiAccountIdentity {
enum FfiAccountIdentityKind kind;
struct FfiBytes32 account_id;
/**
* C-compatible string.
*/
char *key_path;
struct FfiBytes32 nullifier_secret_key;
struct FfiBytes32 nullifier_public_key;
const uint8_t *viewing_public_key;
uintptr_t viewing_public_key_len;
struct FfiU128 identifier;
} FfiAccountIdentity;
/**
* Intended to be created manually.
*/
typedef struct FfiProgram {
const uint8_t *elf_data;
uintptr_t elf_size;
} FfiProgram;
/**
* Intended to be created manually.
*/
typedef struct FfiProgramWithDependencies {
struct FfiProgram program;
const struct FfiProgram *deps;
uintptr_t deps_size;
} FfiProgramWithDependencies;
/**
* Result of a generic transaction operation.
*/
typedef struct FfiTransactionResult {
/**
* Transaction hash (null-terminated string, or null on failure).
*/
char *tx_hash;
/**
* Whether the transaction succeeded.
*/
bool success;
const struct FfiBytes32 *secrets_data;
/**
* Public transactions have 0 secrets.
*/
uintptr_t secrets_size;
} FfiTransactionResult;
typedef struct FfiCreateWalletOutput {
struct WalletHandle *wallet;
/**
* C compatible(null terminated) string.
*/
char *mnemonic;
} FfiCreateWalletOutput;
// === Lifecycle ===
WalletHandle* wallet_ffi_create_new(const char* config_path, const char* storage_path, const char* password);
FfiCreateWalletOutput wallet_ffi_create_new(const char* config_path, const char* storage_path, const char* password);
WalletHandle* wallet_ffi_open(const char* config_path, const char* storage_path);
int wallet_ffi_save(WalletHandle* handle);
void wallet_ffi_destroy(WalletHandle* handle);
WalletFfiError wallet_ffi_restore_data(WalletHandle *handle, const char *mnemonic, const char *password, uint32_t depth);
// === Account management ===
WalletFfiError wallet_ffi_create_account_public(WalletHandle* handle, FfiBytes32* out_id);
@ -144,16 +235,22 @@ WalletFfiError wallet_ffi_transfer_public(
const uint8_t (*amount)[16], FfiTransferResult* out_result);
WalletFfiError wallet_ffi_transfer_shielded(
WalletHandle* handle, const FfiBytes32* from, const FfiPrivateAccountKeys* to_keys,
const uint8_t (*amount)[16], FfiTransferResult* out_result);
const FfiU128 *to_identifier,
const uint8_t (*amount)[16],
const char *key_path,
FfiTransferResult* out_result);
WalletFfiError wallet_ffi_transfer_deshielded(
WalletHandle* handle, const FfiBytes32* from, const FfiBytes32* to,
const uint8_t (*amount)[16], FfiTransferResult* out_result);
WalletFfiError wallet_ffi_transfer_private(
WalletHandle* handle, const FfiBytes32* from, const FfiPrivateAccountKeys* to_keys,
const FfiU128 *to_identifier,
const uint8_t (*amount)[16], FfiTransferResult* out_result);
WalletFfiError wallet_ffi_transfer_shielded_owned(
WalletHandle* handle, const FfiBytes32* from, const FfiBytes32* to,
const uint8_t (*amount)[16], FfiTransferResult* out_result);
const uint8_t (*amount)[16],
const char *key_path,
FfiTransferResult* out_result);
WalletFfiError wallet_ffi_transfer_private_owned(
WalletHandle* handle, const FfiBytes32* from, const FfiBytes32* to,
const uint8_t (*amount)[16], FfiTransferResult* out_result);
@ -161,7 +258,43 @@ 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_transfer_elf(FfiProgram *ffi_program);
WalletFfiError wallet_ffi_token_elf(FfiProgram *ffi_program);
WalletFfiError wallet_ffi_ata_elf(FfiProgram *ffi_program);
WalletFfiError wallet_ffi_amm_elf(FfiProgram *ffi_program);
WalletFfiError wallet_ffi_send_generic_public_transaction(WalletHandle *handle,
const FfiAccountIdentity *account_identities,
uintptr_t account_identities_size,
const uint32_t *instruction_words,
uintptr_t instruction_words_size,
const FfiProgramWithDependencies *program_with_dependencies,
FfiTransactionResult *out_result);
WalletFfiError wallet_ffi_send_generic_private_transaction(WalletHandle *handle,
const FfiAccountIdentity *account_identities,
uintptr_t account_identities_size,
const uint32_t *instruction_words,
uintptr_t instruction_words_size,
const FfiProgramWithDependencies *program_with_dependencies,
FfiTransactionResult *out_result);
WalletFfiError wallet_ffi_program_deployment(WalletHandle *handle,
const uint8_t *elf_data,
uintptr_t elf_size,
FfiTransactionResult *out_result);
WalletFfiError wallet_ffi_resolve_public_account(FfiBytes32 account_id,
bool needs_sign,
FfiAccountIdentity *out_account_identity);
WalletFfiError wallet_ffi_resolve_private_account(WalletHandle *handle,
FfiBytes32 account_id,
FfiAccountIdentity *out_account_identity);
void wallet_ffi_free_instruction_words(FfiInstructionWords *words);
void wallet_ffi_free_account_identity(FfiAccountIdentity *account_identity);
void wallet_ffi_free_transfer_result(FfiTransferResult* result);
void wallet_ffi_free_transaction_result(FfiTransactionResult *result);
void wallet_ffi_free_ffi_program(FfiProgram *ffi_program);
// === Configuration ===

View File

@ -374,10 +374,10 @@ LOGOS_TEST(create_new_success_then_double_open_fails) {
t.mockCFunction("wallet_ffi_create_new").returns(1); // non-null handle
LogosExecutionZoneWalletModule module;
LOGOS_ASSERT_EQ(module.create_new("/cfg", "/store", "pw"), static_cast<int64_t>(SUCCESS));
LOGOS_ASSERT_TRUE(!module.create_new("/cfg", "/store", "pw").empty());
LOGOS_ASSERT(t.cFunctionCalled("wallet_ffi_create_new"));
// Second attempt: already open.
LOGOS_ASSERT_EQ(module.create_new("/cfg", "/store", "pw"), static_cast<int64_t>(INTERNAL_ERROR));
LOGOS_ASSERT_EQ(module.create_new("/cfg", "/store", "pw"), "");
}
LOGOS_TEST(create_new_null_handle_returns_internal_error) {
@ -385,7 +385,7 @@ LOGOS_TEST(create_new_null_handle_returns_internal_error) {
t.mockCFunction("wallet_ffi_create_new").returns(0); // null handle
LogosExecutionZoneWalletModule module;
LOGOS_ASSERT_EQ(module.create_new("/cfg", "/store", "pw"), static_cast<int64_t>(INTERNAL_ERROR));
LOGOS_ASSERT_EQ(module.create_new("/cfg", "/store", "pw"), "");
}
LOGOS_TEST(open_success) {