diff --git a/src/i_logos_execution_zone_wallet_module.h b/src/i_logos_execution_zone_wallet_module.h index def8a41..755c6fc 100644 --- a/src/i_logos_execution_zone_wallet_module.h +++ b/src/i_logos_execution_zone_wallet_module.h @@ -88,6 +88,11 @@ class ILogosExecutionZoneWalletModule { virtual QString register_public_account(const QString& account_id_hex) = 0; virtual QString register_private_account(const QString& account_id_hex) = 0; + /// Submit an arbitrary public transaction. + /// tx_json: {"program_id":"hex","accounts":["hex",...],"instruction":"hex","signer_account":"hex"} + /// Returns tx_hash on success, empty string on failure. + virtual QString send_public_transaction(const QString& tx_json) = 0; + // Wallet Lifecycle virtual int create_new( const QString& config_path, diff --git a/src/logos_execution_zone_wallet_module.cpp b/src/logos_execution_zone_wallet_module.cpp index 1ff02dc..2341b56 100644 --- a/src/logos_execution_zone_wallet_module.cpp +++ b/src/logos_execution_zone_wallet_module.cpp @@ -785,3 +785,66 @@ QString LogosExecutionZoneWalletModule::get_sequencer_addr() { wallet_ffi_free_string(addr); return result; } + +// === Generic Transaction === + +QString LogosExecutionZoneWalletModule::send_public_transaction(const QString& tx_json) { + const QJsonDocument doc = QJsonDocument::fromJson(tx_json.toUtf8()); + if (!doc.isObject()) { + qWarning() << "send_public_transaction: invalid JSON"; + return transferResultToJson(nullptr, QStringLiteral("invalid JSON")); + } + + const QJsonObject obj = doc.object(); + + // Parse program_id (32 bytes hex) + FfiBytes32 programId{}; + if (!hexToBytes32(obj["program_id"].toString(), &programId)) { + qWarning() << "send_public_transaction: invalid program_id"; + return transferResultToJson(nullptr, QStringLiteral("invalid program_id")); + } + + // Parse accounts array + const QJsonArray accountsArr = obj["accounts"].toArray(); + std::vector accounts(accountsArr.size()); + for (int i = 0; i < accountsArr.size(); ++i) { + if (!hexToBytes32(accountsArr[i].toString(), &accounts[i])) { + qWarning() << "send_public_transaction: invalid account at index" << i; + return transferResultToJson(nullptr, QStringLiteral("invalid account hex")); + } + } + + // Parse instruction (hex-encoded raw bytes) + QByteArray instrBytes; + if (!hexToBytes(obj["instruction"].toString(), instrBytes)) { + qWarning() << "send_public_transaction: invalid instruction hex"; + return transferResultToJson(nullptr, QStringLiteral("invalid instruction hex")); + } + + // Parse signer + FfiBytes32 signer{}; + if (!hexToBytes32(obj["signer_account"].toString(), &signer)) { + qWarning() << "send_public_transaction: invalid signer_account"; + return transferResultToJson(nullptr, QStringLiteral("invalid signer_account")); + } + + FfiTransferResult result{}; + const WalletFfiError error = wallet_ffi_send_public_transaction( + walletHandle, + &programId, + accounts.data(), + accounts.size(), + reinterpret_cast(instrBytes.constData()), + static_cast(instrBytes.size()), + &signer, + &result); + + if (error != SUCCESS) { + qWarning() << "send_public_transaction: wallet FFI error" << error; + return transferResultToJson(nullptr, QStringLiteral("wallet FFI error ") + QString::number(error)); + } + + QString resultJson = transferResultToJson(&result, QString()); + wallet_ffi_free_transfer_result(&result); + return resultJson; +} diff --git a/src/logos_execution_zone_wallet_module.h b/src/logos_execution_zone_wallet_module.h index 1ac0005..8cf8bc1 100644 --- a/src/logos_execution_zone_wallet_module.h +++ b/src/logos_execution_zone_wallet_module.h @@ -114,6 +114,7 @@ class LogosExecutionZoneWalletModule : public QObject, public PluginInterface, p ) override; Q_INVOKABLE QString register_public_account(const QString& account_id_hex) override; Q_INVOKABLE QString register_private_account(const QString& account_id_hex) override; + Q_INVOKABLE QString send_public_transaction(const QString& tx_json) override; // Wallet Lifecycle Q_INVOKABLE int create_new(const QString& config_path, const QString& storage_path, const QString& password) override;