mirror of
https://github.com/mollyim/monero-wallet-sdk.git
synced 2025-01-12 07:59:30 -05:00
lib: add basic transfer funcionality
This commit is contained in:
parent
5c4cfd9d92
commit
c12ae593ae
@ -0,0 +1,8 @@
|
|||||||
|
package im.molly.monero;
|
||||||
|
|
||||||
|
//import im.molly.monero.ITransactionCallback;
|
||||||
|
|
||||||
|
interface IPendingTransfer {
|
||||||
|
// oneway void submit(in ITransactionCallback callback);
|
||||||
|
void close();
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
package im.molly.monero;
|
||||||
|
|
||||||
|
import im.molly.monero.IPendingTransfer;
|
||||||
|
|
||||||
|
oneway interface ITransferRequestCallback {
|
||||||
|
void onTransferCreated(in IPendingTransfer pendingTransfer);
|
||||||
|
// void onDaemonBusy();
|
||||||
|
// void onNoConnectionToDaemon();
|
||||||
|
// void onRPCError(String errorMessage);
|
||||||
|
// void onFailedToGetOutputs();
|
||||||
|
// void onNotEnoughUnlockedMoney(long available, long sentAmount);
|
||||||
|
// void onNotEnoughMoney(long available, long sentAmount);
|
||||||
|
// void onTransactionNotPossible(long available, long transactionAmount, long fee);
|
||||||
|
// void onNotEnoughOutsToMix(int mixinCount, Map<Long, Long> scantyOuts);
|
||||||
|
// void onTransactionNotConstructed();
|
||||||
|
// void onTransactionRejected(String transactionHash, int status);
|
||||||
|
// void onTransactionSumOverflow(String errorMessage);
|
||||||
|
// void onZeroDestination();
|
||||||
|
// void onTransactionTooBig();
|
||||||
|
// void onTransferError(String errorMessage);
|
||||||
|
// void onWalletInternalError(String errorMessage);
|
||||||
|
// void onUnexpectedError(String errorMessage);
|
||||||
|
}
|
@ -1,7 +1,10 @@
|
|||||||
package im.molly.monero;
|
package im.molly.monero;
|
||||||
|
|
||||||
import im.molly.monero.IBalanceListener;
|
import im.molly.monero.IBalanceListener;
|
||||||
|
import im.molly.monero.ITransferRequestCallback;
|
||||||
import im.molly.monero.IWalletCallbacks;
|
import im.molly.monero.IWalletCallbacks;
|
||||||
|
import im.molly.monero.PaymentRequest;
|
||||||
|
import im.molly.monero.SweepRequest;
|
||||||
|
|
||||||
interface IWallet {
|
interface IWallet {
|
||||||
String getAccountPrimaryAddress();
|
String getAccountPrimaryAddress();
|
||||||
@ -11,6 +14,8 @@ interface IWallet {
|
|||||||
oneway void cancelRefresh();
|
oneway void cancelRefresh();
|
||||||
oneway void setRefreshSince(long heightOrTimestamp);
|
oneway void setRefreshSince(long heightOrTimestamp);
|
||||||
oneway void commit(in IWalletCallbacks callback);
|
oneway void commit(in IWalletCallbacks callback);
|
||||||
|
oneway void createPayment(in PaymentRequest request, in ITransferRequestCallback callback);
|
||||||
|
oneway void createSweep(in SweepRequest request, in ITransferRequestCallback callback);
|
||||||
oneway void requestFees(in IWalletCallbacks callback);
|
oneway void requestFees(in IWalletCallbacks callback);
|
||||||
void close();
|
void close();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
package im.molly.monero;
|
||||||
|
|
||||||
|
parcelable PaymentRequest;
|
@ -0,0 +1,3 @@
|
|||||||
|
package im.molly.monero;
|
||||||
|
|
||||||
|
parcelable SweepRequest;
|
@ -69,6 +69,8 @@ set(WALLET2_SOURCES
|
|||||||
src/hardforks/hardforks.cpp
|
src/hardforks/hardforks.cpp
|
||||||
src/mnemonics/electrum-words.cpp
|
src/mnemonics/electrum-words.cpp
|
||||||
src/multisig/multisig.cpp
|
src/multisig/multisig.cpp
|
||||||
|
src/multisig/multisig_clsag_context.cpp
|
||||||
|
src/multisig/multisig_tx_builder_ringct.cpp
|
||||||
src/net/error.cpp
|
src/net/error.cpp
|
||||||
src/net/http.cpp
|
src/net/http.cpp
|
||||||
src/net/i2p_address.cpp
|
src/net/i2p_address.cpp
|
||||||
@ -77,6 +79,7 @@ set(WALLET2_SOURCES
|
|||||||
src/net/socks_connect.cpp
|
src/net/socks_connect.cpp
|
||||||
src/net/tor_address.cpp
|
src/net/tor_address.cpp
|
||||||
src/ringct/bulletproofs.cc
|
src/ringct/bulletproofs.cc
|
||||||
|
src/ringct/bulletproofs_plus.cc
|
||||||
src/ringct/multiexp.cc
|
src/ringct/multiexp.cc
|
||||||
src/ringct/rctCryptoOps.c
|
src/ringct/rctCryptoOps.c
|
||||||
src/ringct/rctOps.cpp
|
src/ringct/rctOps.cpp
|
||||||
|
@ -13,9 +13,11 @@ void InitializeJniCache(JNIEnv* env);
|
|||||||
extern jmethodID HttpResponse_getBody;
|
extern jmethodID HttpResponse_getBody;
|
||||||
extern jmethodID HttpResponse_getCode;
|
extern jmethodID HttpResponse_getCode;
|
||||||
extern jmethodID HttpResponse_getContentType;
|
extern jmethodID HttpResponse_getContentType;
|
||||||
|
extern jmethodID ITransferRequestCb_onTransferCreated;
|
||||||
extern jmethodID Logger_logFromNative;
|
extern jmethodID Logger_logFromNative;
|
||||||
extern jmethodID TxInfo_ctor;
|
extern jmethodID TxInfo_ctor;
|
||||||
extern jmethodID WalletNative_callRemoteNode;
|
extern jmethodID WalletNative_callRemoteNode;
|
||||||
|
extern jmethodID WalletNative_createPendingTransfer;
|
||||||
extern jmethodID WalletNative_onRefresh;
|
extern jmethodID WalletNative_onRefresh;
|
||||||
extern jmethodID WalletNative_onSuspendRefresh;
|
extern jmethodID WalletNative_onSuspendRefresh;
|
||||||
extern ScopedJavaGlobalRef<jclass> TxInfoClass;
|
extern ScopedJavaGlobalRef<jclass> TxInfoClass;
|
||||||
|
5
lib/android/src/main/cpp/wallet/transfer.cc
Normal file
5
lib/android/src/main/cpp/wallet/transfer.cc
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#include "transfer.h"
|
||||||
|
|
||||||
|
namespace monero {
|
||||||
|
|
||||||
|
} // namespace monero
|
21
lib/android/src/main/cpp/wallet/transfer.h
Normal file
21
lib/android/src/main/cpp/wallet/transfer.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#ifndef WALLET_TRANSFER_H_
|
||||||
|
#define WALLET_TRANSFER_H_
|
||||||
|
|
||||||
|
#include "wallet2.h"
|
||||||
|
|
||||||
|
namespace monero {
|
||||||
|
|
||||||
|
using wallet2 = tools::wallet2;
|
||||||
|
|
||||||
|
class PendingTransfer {
|
||||||
|
public:
|
||||||
|
PendingTransfer(const std::vector<wallet2::pending_tx>& ptxs)
|
||||||
|
: m_ptxs(ptxs) {}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<wallet2::pending_tx> m_ptxs;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace monero
|
||||||
|
|
||||||
|
#endif // WALLET_TRANSFER_H_
|
@ -132,6 +132,44 @@ void Wallet::withTxHistory(Consumer consumer) {
|
|||||||
consumer(m_tx_history);
|
consumer(m_tx_history);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<PendingTransfer> Wallet::createPayment(
|
||||||
|
const std::vector<std::string>& addresses,
|
||||||
|
const std::vector<uint64_t>& amounts,
|
||||||
|
uint64_t time_lock,
|
||||||
|
int priority,
|
||||||
|
uint32_t account_index,
|
||||||
|
const std::set<uint32_t>& subaddr_indexes) {
|
||||||
|
std::vector<cryptonote::tx_destination_entry> dsts;
|
||||||
|
dsts.reserve(addresses.size());
|
||||||
|
|
||||||
|
for (size_t i = 0; i < addresses.size(); ++i) {
|
||||||
|
const std::string& address = addresses[i];
|
||||||
|
cryptonote::address_parse_info info;
|
||||||
|
if (!cryptonote::get_account_address_from_str(info, m_wallet.nettype(), address)) {
|
||||||
|
LOG_FATAL("Failed to parse recipient address: %s", address.c_str());
|
||||||
|
}
|
||||||
|
LOG_FATAL_IF(info.has_payment_id);
|
||||||
|
cryptonote::tx_destination_entry de;
|
||||||
|
de.original = address;
|
||||||
|
de.addr = info.address;
|
||||||
|
de.amount = amounts.at(i);
|
||||||
|
de.is_subaddress = info.is_subaddress;
|
||||||
|
de.is_integrated = false;
|
||||||
|
dsts.push_back(de);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto ptxs = m_wallet.create_transactions_2(
|
||||||
|
dsts,
|
||||||
|
m_wallet.default_mixin(),
|
||||||
|
time_lock,
|
||||||
|
priority,
|
||||||
|
{}, /* extra */
|
||||||
|
account_index,
|
||||||
|
subaddr_indexes);
|
||||||
|
|
||||||
|
return std::make_unique<PendingTransfer>(ptxs);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<uint64_t> Wallet::fetchBaseFeeEstimate() {
|
std::vector<uint64_t> Wallet::fetchBaseFeeEstimate() {
|
||||||
return m_wallet.get_dynamic_base_fee_scaling_estimate();
|
return m_wallet.get_dynamic_base_fee_scaling_estimate();
|
||||||
}
|
}
|
||||||
@ -146,8 +184,8 @@ cryptonote::account_base& Wallet::require_account() {
|
|||||||
return m_wallet.get_account();
|
return m_wallet.get_account();
|
||||||
}
|
}
|
||||||
|
|
||||||
const payment_details* find_payment_by_txid(
|
const wallet2::payment_details* Find_payment_by_txid(
|
||||||
const std::list<std::pair<crypto::hash, payment_details>>& pds,
|
const std::list<std::pair<crypto::hash, wallet2::payment_details>>& pds,
|
||||||
const crypto::hash& txid) {
|
const crypto::hash& txid) {
|
||||||
if (txid == crypto::null_hash) {
|
if (txid == crypto::null_hash) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -161,8 +199,8 @@ const payment_details* find_payment_by_txid(
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const confirmed_transfer_details* find_transfer_by_txid(
|
const wallet2::confirmed_transfer_details* Find_transfer_by_txid(
|
||||||
const std::list<std::pair<crypto::hash, confirmed_transfer_details>>& txs,
|
const std::list<std::pair<crypto::hash, wallet2::confirmed_transfer_details>>& txs,
|
||||||
const crypto::hash& txid) {
|
const crypto::hash& txid) {
|
||||||
if (txid == crypto::null_hash) {
|
if (txid == crypto::null_hash) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@ -182,15 +220,15 @@ const confirmed_transfer_details* find_transfer_by_txid(
|
|||||||
void Wallet::captureTxHistorySnapshot(std::vector<TxInfo>& snapshot) {
|
void Wallet::captureTxHistorySnapshot(std::vector<TxInfo>& snapshot) {
|
||||||
snapshot.clear();
|
snapshot.clear();
|
||||||
|
|
||||||
std::vector<transfer_details> tds;
|
std::vector<wallet2::transfer_details> tds;
|
||||||
m_wallet.get_transfers(tds);
|
m_wallet.get_transfers(tds);
|
||||||
|
|
||||||
uint64_t min_height = 0;
|
uint64_t min_height = 0;
|
||||||
|
|
||||||
std::list<std::pair<crypto::hash, payment_details>> pds;
|
std::list<std::pair<crypto::hash, wallet2::payment_details>> pds;
|
||||||
std::list<std::pair<crypto::hash, pool_payment_details>> upds;
|
std::list<std::pair<crypto::hash, wallet2::pool_payment_details>> upds;
|
||||||
std::list<std::pair<crypto::hash, confirmed_transfer_details>> txs;
|
std::list<std::pair<crypto::hash, wallet2::confirmed_transfer_details>> txs;
|
||||||
std::list<std::pair<crypto::hash, unconfirmed_transfer_details>> utxs;
|
std::list<std::pair<crypto::hash, wallet2::unconfirmed_transfer_details>> utxs;
|
||||||
m_wallet.get_payments(pds, min_height);
|
m_wallet.get_payments(pds, min_height);
|
||||||
m_wallet.get_unconfirmed_payments(upds, min_height);
|
m_wallet.get_unconfirmed_payments(upds, min_height);
|
||||||
m_wallet.get_payments_out(txs, min_height);
|
m_wallet.get_payments_out(txs, min_height);
|
||||||
@ -211,13 +249,13 @@ void Wallet::captureTxHistorySnapshot(std::vector<TxInfo>& snapshot) {
|
|||||||
recv.m_unlock_time = td.m_tx.unlock_time;
|
recv.m_unlock_time = td.m_tx.unlock_time;
|
||||||
|
|
||||||
// Check if the payment or transfer exists and update metadata if found.
|
// Check if the payment or transfer exists and update metadata if found.
|
||||||
if (const auto* pd = find_payment_by_txid(pds, td.m_txid)) {
|
if (const auto* pd = Find_payment_by_txid(pds, td.m_txid)) {
|
||||||
recv.m_height = pd->m_block_height;
|
recv.m_height = pd->m_block_height;
|
||||||
recv.m_timestamp = pd->m_timestamp;
|
recv.m_timestamp = pd->m_timestamp;
|
||||||
recv.m_fee = pd->m_fee;
|
recv.m_fee = pd->m_fee;
|
||||||
recv.m_coinbase = pd->m_coinbase;
|
recv.m_coinbase = pd->m_coinbase;
|
||||||
recv.m_state = TxInfo::ON_CHAIN;
|
recv.m_state = TxInfo::ON_CHAIN;
|
||||||
} else if (const auto* tx = find_transfer_by_txid(txs, td.m_txid)) {
|
} else if (const auto* tx = Find_transfer_by_txid(txs, td.m_txid)) {
|
||||||
recv.m_height = tx->m_block_height;
|
recv.m_height = tx->m_block_height;
|
||||||
recv.m_timestamp = tx->m_timestamp;
|
recv.m_timestamp = tx->m_timestamp;
|
||||||
recv.m_fee = tx->m_amount_in - tx->m_amount_out;
|
recv.m_fee = tx->m_amount_in - tx->m_amount_out;
|
||||||
@ -263,7 +301,7 @@ void Wallet::captureTxHistorySnapshot(std::vector<TxInfo>& snapshot) {
|
|||||||
for (const auto& pair: utxs) {
|
for (const auto& pair: utxs) {
|
||||||
const auto& utx = pair.second;
|
const auto& utx = pair.second;
|
||||||
uint64_t fee = utx.m_amount_in - utx.m_amount_out;
|
uint64_t fee = utx.m_amount_in - utx.m_amount_out;
|
||||||
auto state = (utx.m_state == unconfirmed_transfer_details::pending)
|
auto state = (utx.m_state == wallet2::unconfirmed_transfer_details::pending)
|
||||||
? TxInfo::PENDING
|
? TxInfo::PENDING
|
||||||
: TxInfo::FAILED;
|
: TxInfo::FAILED;
|
||||||
|
|
||||||
@ -394,8 +432,8 @@ Wallet::Status Wallet::nonReentrantRefresh(bool skip_coinbase) {
|
|||||||
"Refresh should not be called concurrently");
|
"Refresh should not be called concurrently");
|
||||||
Status ret;
|
Status ret;
|
||||||
std::unique_lock<std::mutex> wallet_lock(m_wallet_mutex);
|
std::unique_lock<std::mutex> wallet_lock(m_wallet_mutex);
|
||||||
m_wallet.set_refresh_type(skip_coinbase ? tools::wallet2::RefreshType::RefreshNoCoinbase
|
m_wallet.set_refresh_type(skip_coinbase ? wallet2::RefreshType::RefreshNoCoinbase
|
||||||
: tools::wallet2::RefreshType::RefreshDefault);
|
: wallet2::RefreshType::RefreshDefault);
|
||||||
while (!m_refresh_canceled) {
|
while (!m_refresh_canceled) {
|
||||||
m_wallet.set_refresh_from_block_height(m_restore_height);
|
m_wallet.set_refresh_from_block_height(m_restore_height);
|
||||||
try {
|
try {
|
||||||
@ -406,10 +444,10 @@ Wallet::Status Wallet::nonReentrantRefresh(bool skip_coinbase) {
|
|||||||
ret = Status::OK;
|
ret = Status::OK;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (const tools::error::no_connection_to_daemon&) {
|
} catch (const error::no_connection_to_daemon&) {
|
||||||
ret = Status::NO_NETWORK_CONNECTIVITY;
|
ret = Status::NO_NETWORK_CONNECTIVITY;
|
||||||
break;
|
break;
|
||||||
} catch (const tools::error::refresh_error&) {
|
} catch (const error::refresh_error&) {
|
||||||
ret = Status::REFRESH_ERROR;
|
ret = Status::REFRESH_ERROR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -481,8 +519,16 @@ Java_im_molly_monero_WalletNative_nativeDispose(
|
|||||||
JNIEnv* env,
|
JNIEnv* env,
|
||||||
jobject thiz,
|
jobject thiz,
|
||||||
jlong handle) {
|
jlong handle) {
|
||||||
auto* wallet = reinterpret_cast<Wallet*>(handle);
|
delete reinterpret_cast<Wallet*>(handle);
|
||||||
delete wallet;
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_im_molly_monero_WalletNative_nativeDisposePendingTransfer(
|
||||||
|
JNIEnv* env,
|
||||||
|
jobject thiz,
|
||||||
|
jlong handle) {
|
||||||
|
delete reinterpret_cast<PendingTransfer*>(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
@ -656,6 +702,66 @@ Java_im_molly_monero_WalletNative_nativeGetTxHistory(
|
|||||||
return j_array;
|
return j_array;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
JNIEXPORT void JNICALL
|
||||||
|
Java_im_molly_monero_WalletNative_nativeCreatePayment(
|
||||||
|
JNIEnv* env,
|
||||||
|
jobject thiz,
|
||||||
|
jlong handle,
|
||||||
|
jobjectArray j_addresses,
|
||||||
|
jlongArray j_amounts,
|
||||||
|
jlong time_lock,
|
||||||
|
jint priority,
|
||||||
|
jint account_index,
|
||||||
|
jintArray j_subaddr_indexes,
|
||||||
|
jobject j_callback) {
|
||||||
|
auto* wallet = reinterpret_cast<Wallet*>(handle);
|
||||||
|
|
||||||
|
const auto& addresses = JavaToNativeVector<std::string, jstring>(
|
||||||
|
env, j_addresses, &JavaToNativeString);
|
||||||
|
const auto& amounts = JavaToNativeLongArray(env, j_amounts);
|
||||||
|
const auto& subaddr_indexes = JavaToNativeIntArray(env, j_subaddr_indexes);
|
||||||
|
|
||||||
|
std::unique_ptr<PendingTransfer> pendingTransfer;
|
||||||
|
|
||||||
|
try {
|
||||||
|
pendingTransfer = wallet->createPayment(
|
||||||
|
addresses,
|
||||||
|
{amounts.begin(), amounts.end()},
|
||||||
|
time_lock, priority,
|
||||||
|
account_index,
|
||||||
|
{subaddr_indexes.begin(), subaddr_indexes.end()});
|
||||||
|
// } catch (error::daemon_busy& e) {
|
||||||
|
// } catch (error::no_connection_to_daemon& e) {
|
||||||
|
// } catch (error::wallet_rpc_error& e) {
|
||||||
|
// } catch (error::get_outs_error& e) {
|
||||||
|
// } catch (error::not_enough_unlocked_money& e) {
|
||||||
|
// } catch (error::not_enough_money& e) {
|
||||||
|
// } catch (error::tx_not_possible& e) {
|
||||||
|
// } catch (error::not_enough_outs_to_mix& e) {
|
||||||
|
// } catch (error::tx_not_constructed& e) {
|
||||||
|
// } catch (error::tx_rejected& e) {
|
||||||
|
// } catch (error::tx_sum_overflow& e) {
|
||||||
|
// } catch (error::zero_amount& e) {
|
||||||
|
// } catch (error::zero_destination& e) {
|
||||||
|
// } catch (error::tx_too_big& e) {
|
||||||
|
// } catch (error::transfer_error& e) {
|
||||||
|
// } catch (error::wallet_internal_error& e) {
|
||||||
|
// } catch (error::wallet_logic_error& e) {
|
||||||
|
// } catch (const std::exception& e) {
|
||||||
|
} catch (...) {
|
||||||
|
LOG_FATAL("Caught unknown exception");
|
||||||
|
}
|
||||||
|
|
||||||
|
jobject j_pending_transfer = CallObjectMethod(
|
||||||
|
env, thiz, WalletNative_createPendingTransfer,
|
||||||
|
NativeToJavaPointer(pendingTransfer.get()));
|
||||||
|
|
||||||
|
CallVoidMethod(env, j_callback,
|
||||||
|
ITransferRequestCb_onTransferCreated,
|
||||||
|
j_pending_transfer);
|
||||||
|
}
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
JNIEXPORT jlongArray JNICALL
|
JNIEXPORT jlongArray JNICALL
|
||||||
Java_im_molly_monero_WalletNative_nativeFetchBaseFeeEstimate(
|
Java_im_molly_monero_WalletNative_nativeFetchBaseFeeEstimate(
|
||||||
|
@ -5,17 +5,17 @@
|
|||||||
|
|
||||||
#include "common/jvm.h"
|
#include "common/jvm.h"
|
||||||
|
|
||||||
|
#include "transfer.h"
|
||||||
#include "http_client.h"
|
#include "http_client.h"
|
||||||
|
|
||||||
#include "wallet2.h"
|
#include "wallet2.h"
|
||||||
|
|
||||||
namespace monero {
|
namespace monero {
|
||||||
|
|
||||||
using transfer_details = tools::wallet2::transfer_details;
|
namespace error = tools::error;
|
||||||
using payment_details = tools::wallet2::payment_details;
|
|
||||||
using pool_payment_details = tools::wallet2::pool_payment_details;
|
using wallet2 = tools::wallet2;
|
||||||
using confirmed_transfer_details = tools::wallet2::confirmed_transfer_details;
|
using i_wallet2_callback = tools::i_wallet2_callback;
|
||||||
using unconfirmed_transfer_details = tools::wallet2::unconfirmed_transfer_details;
|
|
||||||
|
|
||||||
// Basic structure combining transaction details with input or output info.
|
// Basic structure combining transaction details with input or output info.
|
||||||
struct TxInfo {
|
struct TxInfo {
|
||||||
@ -70,7 +70,7 @@ struct TxInfo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Wrapper for wallet2.h core API.
|
// Wrapper for wallet2.h core API.
|
||||||
class Wallet : tools::i_wallet2_callback {
|
class Wallet : i_wallet2_callback {
|
||||||
public:
|
public:
|
||||||
enum Status : int {
|
enum Status : int {
|
||||||
OK = 0,
|
OK = 0,
|
||||||
@ -97,6 +97,14 @@ class Wallet : tools::i_wallet2_callback {
|
|||||||
template<typename Consumer>
|
template<typename Consumer>
|
||||||
void withTxHistory(Consumer consumer);
|
void withTxHistory(Consumer consumer);
|
||||||
|
|
||||||
|
std::unique_ptr<PendingTransfer> createPayment(
|
||||||
|
const std::vector<std::string>& addresses,
|
||||||
|
const std::vector<uint64_t>& amounts,
|
||||||
|
uint64_t time_lock,
|
||||||
|
int priority,
|
||||||
|
uint32_t account_index,
|
||||||
|
const std::set<uint32_t>& subaddr_indexes);
|
||||||
|
|
||||||
std::vector<uint64_t> fetchBaseFeeEstimate();
|
std::vector<uint64_t> fetchBaseFeeEstimate();
|
||||||
|
|
||||||
std::string public_address() const;
|
std::string public_address() const;
|
||||||
@ -115,7 +123,7 @@ class Wallet : tools::i_wallet2_callback {
|
|||||||
private:
|
private:
|
||||||
cryptonote::account_base& require_account();
|
cryptonote::account_base& require_account();
|
||||||
|
|
||||||
tools::wallet2 m_wallet;
|
wallet2 m_wallet;
|
||||||
|
|
||||||
bool m_account_ready;
|
bool m_account_ready;
|
||||||
uint64_t m_restore_height;
|
uint64_t m_restore_height;
|
||||||
|
@ -1,5 +1,8 @@
|
|||||||
package im.molly.monero
|
package im.molly.monero
|
||||||
|
|
||||||
|
import android.os.Parcel
|
||||||
|
import android.os.Parcelable
|
||||||
|
|
||||||
data class AccountAddress(
|
data class AccountAddress(
|
||||||
val publicAddress: PublicAddress,
|
val publicAddress: PublicAddress,
|
||||||
val accountIndex: Int = 0,
|
val accountIndex: Int = 0,
|
||||||
@ -12,11 +15,13 @@ data class AccountAddress(
|
|||||||
init {
|
init {
|
||||||
when (publicAddress) {
|
when (publicAddress) {
|
||||||
is StandardAddress -> require(isPrimaryAddress) {
|
is StandardAddress -> require(isPrimaryAddress) {
|
||||||
"Standard addresses must have subaddress indices set to zero"
|
"Only the primary address is a standard address"
|
||||||
}
|
}
|
||||||
|
|
||||||
is SubAddress -> require(accountIndex != -1 && subAddressIndex != -1) {
|
is SubAddress -> require(accountIndex != -1 && subAddressIndex != -1) {
|
||||||
"Invalid subaddress indices"
|
"Invalid subaddress indices"
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> throw IllegalArgumentException("Unsupported address type")
|
else -> throw IllegalArgumentException("Unsupported address type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package im.molly.monero
|
package im.molly.monero
|
||||||
|
|
||||||
import java.time.Instant
|
|
||||||
|
|
||||||
data class Balance(
|
data class Balance(
|
||||||
val pendingAmount: MoneroAmount,
|
val pendingAmount: MoneroAmount,
|
||||||
val timeLockedAmounts: List<TimeLocked<MoneroAmount>>,
|
val timeLockedAmounts: List<TimeLocked<MoneroAmount>>,
|
||||||
|
@ -15,6 +15,7 @@ data class Block(
|
|||||||
data class BlockHeader(
|
data class BlockHeader(
|
||||||
val height: Int,
|
val height: Int,
|
||||||
val epochSecond: Long,
|
val epochSecond: Long,
|
||||||
|
// val version: ProtocolInfo,
|
||||||
) {
|
) {
|
||||||
val timestamp: Instant
|
val timestamp: Instant
|
||||||
get() = Instant.ofEpochSecond(epochSecond)
|
get() = Instant.ofEpochSecond(epochSecond)
|
||||||
|
@ -6,4 +6,4 @@ package im.molly.monero
|
|||||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CONSTRUCTOR)
|
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CONSTRUCTOR)
|
||||||
@Retention(AnnotationRetention.SOURCE)
|
@Retention(AnnotationRetention.SOURCE)
|
||||||
@MustBeDocumented
|
@MustBeDocumented
|
||||||
annotation class CalledByNative(val fileName: String)
|
annotation class CalledByNative
|
||||||
|
@ -7,7 +7,7 @@ data class DynamicFeeRate(val feePerByte: Map<FeePriority, MoneroAmount>) {
|
|||||||
|
|
||||||
val quantizationMask: MoneroAmount = BigDecimal.TEN.pow(PER_KB_FEE_QUANTIZATION_DECIMALS).xmr
|
val quantizationMask: MoneroAmount = BigDecimal.TEN.pow(PER_KB_FEE_QUANTIZATION_DECIMALS).xmr
|
||||||
|
|
||||||
fun estimateFee(tx: PendingTransaction): Map<FeePriority, MoneroAmount> {
|
fun estimateFee(pendingTransfer: PendingTransfer): Map<FeePriority, MoneroAmount> {
|
||||||
TODO()
|
TODO()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
package im.molly.monero
|
package im.molly.monero
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
@JvmInline
|
@JvmInline
|
||||||
value class HashDigest(private val hashDigest: String) {
|
@Parcelize
|
||||||
|
value class HashDigest(private val hashDigest: String) : Parcelable {
|
||||||
init {
|
init {
|
||||||
require(hashDigest.length == 64) { "Hash length must be 64 hex chars" }
|
require(hashDigest.length == 64) { "Hash length must be 64 hex chars" }
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,7 @@ internal open class Logger(val tag: String) : LogAdapter {
|
|||||||
/**
|
/**
|
||||||
* Log method called from native code.
|
* Log method called from native code.
|
||||||
*/
|
*/
|
||||||
@CalledByNative("logging.cc")
|
@CalledByNative
|
||||||
fun logFromNative(priority: Int, tag: String, msg: String?) {
|
fun logFromNative(priority: Int, tag: String, msg: String?) {
|
||||||
val pri = if (priority in Log.VERBOSE.rangeTo(Log.ASSERT)) priority else Log.ASSERT
|
val pri = if (priority in Log.VERBOSE.rangeTo(Log.ASSERT)) priority else Log.ASSERT
|
||||||
val jniTag = "MoneroJNI.$tag"
|
val jniTag = "MoneroJNI.$tag"
|
||||||
|
@ -15,7 +15,7 @@ enum class MoneroNetwork(val id: Int, val epoch: Long, val epochV2: Pair<Int, Lo
|
|||||||
Stagenet(2, 1518932025, (32000 to 1520937818));
|
Stagenet(2, 1518932025, (32000 to 1520937818));
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromId(value: Int) = values().first { it.id == value }
|
fun fromId(value: Int) = entries.first { it.id == value }
|
||||||
|
|
||||||
fun of(publicAddress: String) = PublicAddress.parse(publicAddress).network
|
fun of(publicAddress: String) = PublicAddress.parse(publicAddress).network
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import kotlinx.coroutines.flow.flow
|
|||||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||||
import kotlin.time.Duration.Companion.seconds
|
import kotlin.time.Duration.Companion.seconds
|
||||||
|
|
||||||
|
@OptIn(ExperimentalCoroutinesApi::class)
|
||||||
class MoneroWallet internal constructor(
|
class MoneroWallet internal constructor(
|
||||||
private val wallet: IWallet,
|
private val wallet: IWallet,
|
||||||
private val storageAdapter: StorageAdapter,
|
private val storageAdapter: StorageAdapter,
|
||||||
@ -53,7 +54,6 @@ class MoneroWallet internal constructor(
|
|||||||
awaitClose { wallet.removeBalanceListener(listener) }
|
awaitClose { wallet.removeBalanceListener(listener) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
|
||||||
suspend fun awaitRefresh(
|
suspend fun awaitRefresh(
|
||||||
ignoreMiningRewards: Boolean = true,
|
ignoreMiningRewards: Boolean = true,
|
||||||
): RefreshResult = suspendCancellableCoroutine { continuation ->
|
): RefreshResult = suspendCancellableCoroutine { continuation ->
|
||||||
@ -67,7 +67,6 @@ class MoneroWallet internal constructor(
|
|||||||
continuation.invokeOnCancellation { wallet.cancelRefresh() }
|
continuation.invokeOnCancellation { wallet.cancelRefresh() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
|
||||||
suspend fun commit(): Boolean = suspendCancellableCoroutine { continuation ->
|
suspend fun commit(): Boolean = suspendCancellableCoroutine { continuation ->
|
||||||
wallet.commit(object : BaseWalletCallbacks() {
|
wallet.commit(object : BaseWalletCallbacks() {
|
||||||
override fun onCommitResult(success: Boolean) {
|
override fun onCommitResult(success: Boolean) {
|
||||||
@ -76,6 +75,21 @@ class MoneroWallet internal constructor(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
suspend fun createTransfer(transferRequest: TransferRequest): PendingTransfer =
|
||||||
|
suspendCancellableCoroutine { continuation ->
|
||||||
|
val callback = object : ITransferRequestCallback.Stub() {
|
||||||
|
override fun onTransferCreated(pendingTransfer: IPendingTransfer) {
|
||||||
|
continuation.resume(PendingTransfer(pendingTransfer)) {
|
||||||
|
pendingTransfer.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
when (transferRequest) {
|
||||||
|
is PaymentRequest -> wallet.createPayment(transferRequest, callback)
|
||||||
|
is SweepRequest -> wallet.createSweep(transferRequest, callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun dynamicFeeRate(): Flow<DynamicFeeRate> = flow {
|
fun dynamicFeeRate(): Flow<DynamicFeeRate> = flow {
|
||||||
while (true) {
|
while (true) {
|
||||||
val fees = requestFees() ?: emptyList()
|
val fees = requestFees() ?: emptyList()
|
||||||
@ -99,7 +113,6 @@ class MoneroWallet internal constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(ExperimentalCoroutinesApi::class)
|
|
||||||
private suspend fun requestFees(): List<MoneroAmount>? =
|
private suspend fun requestFees(): List<MoneroAmount>? =
|
||||||
suspendCancellableCoroutine { continuation ->
|
suspendCancellableCoroutine { continuation ->
|
||||||
wallet.requestFees(object : BaseWalletCallbacks() {
|
wallet.requestFees(object : BaseWalletCallbacks() {
|
||||||
|
14
lib/android/src/main/kotlin/im/molly/monero/PaymentDetail.kt
Normal file
14
lib/android/src/main/kotlin/im/molly/monero/PaymentDetail.kt
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
package im.molly.monero
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class PaymentDetail(
|
||||||
|
val amount: MoneroAmount,
|
||||||
|
val recipientAddress: PublicAddress,
|
||||||
|
) : Parcelable {
|
||||||
|
init {
|
||||||
|
require(amount >= 0) { "Payment amount cannot be negative" }
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +0,0 @@
|
|||||||
package im.molly.monero
|
|
||||||
|
|
||||||
class PendingTransaction
|
|
@ -0,0 +1,10 @@
|
|||||||
|
package im.molly.monero
|
||||||
|
|
||||||
|
class PendingTransfer internal constructor(
|
||||||
|
private val pendingTransfer: IPendingTransfer,
|
||||||
|
) : AutoCloseable {
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
pendingTransfer.close()
|
||||||
|
}
|
||||||
|
}
|
@ -1,14 +1,17 @@
|
|||||||
package im.molly.monero
|
package im.molly.monero
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
import im.molly.monero.util.decodeBase58
|
import im.molly.monero.util.decodeBase58
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
sealed interface PublicAddress {
|
sealed interface PublicAddress : Parcelable {
|
||||||
val address: String
|
val address: String
|
||||||
val network: MoneroNetwork
|
val network: MoneroNetwork
|
||||||
val subAddress: Boolean
|
|
||||||
// viewPublicKey: ByteArray
|
// viewPublicKey: ByteArray
|
||||||
// spendPublicKey: ByteArray
|
// spendPublicKey: ByteArray
|
||||||
|
|
||||||
|
fun isSubAddress(): Boolean
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun parse(publicAddress: String): PublicAddress {
|
fun parse(publicAddress: String): PublicAddress {
|
||||||
val decoded = try {
|
val decoded = try {
|
||||||
@ -38,11 +41,11 @@ sealed interface PublicAddress {
|
|||||||
|
|
||||||
class InvalidAddress(message: String, cause: Throwable? = null) : Exception(message, cause)
|
class InvalidAddress(message: String, cause: Throwable? = null) : Exception(message, cause)
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
data class StandardAddress(
|
data class StandardAddress(
|
||||||
override val address: String,
|
override val address: String,
|
||||||
override val network: MoneroNetwork,
|
override val network: MoneroNetwork,
|
||||||
) : PublicAddress {
|
) : PublicAddress {
|
||||||
override val subAddress = false
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val prefixes = mapOf(
|
val prefixes = mapOf(
|
||||||
@ -52,14 +55,16 @@ data class StandardAddress(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun isSubAddress() = false
|
||||||
|
|
||||||
override fun toString(): String = address
|
override fun toString(): String = address
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
data class SubAddress(
|
data class SubAddress(
|
||||||
override val address: String,
|
override val address: String,
|
||||||
override val network: MoneroNetwork,
|
override val network: MoneroNetwork,
|
||||||
) : PublicAddress {
|
) : PublicAddress {
|
||||||
override val subAddress = true
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val prefixes = mapOf(
|
val prefixes = mapOf(
|
||||||
@ -69,15 +74,17 @@ data class SubAddress(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun isSubAddress() = true
|
||||||
|
|
||||||
override fun toString(): String = address
|
override fun toString(): String = address
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
data class IntegratedAddress(
|
data class IntegratedAddress(
|
||||||
override val address: String,
|
override val address: String,
|
||||||
override val network: MoneroNetwork,
|
override val network: MoneroNetwork,
|
||||||
val paymentId: Long,
|
val paymentId: Long,
|
||||||
) : PublicAddress {
|
) : PublicAddress {
|
||||||
override val subAddress = false
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val prefixes = mapOf(
|
val prefixes = mapOf(
|
||||||
@ -87,5 +94,7 @@ data class IntegratedAddress(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun isSubAddress() = false
|
||||||
|
|
||||||
override fun toString(): String = address
|
override fun toString(): String = address
|
||||||
}
|
}
|
||||||
|
@ -56,9 +56,7 @@ class SecretKey : Destroyable, Closeable, Parcelable {
|
|||||||
parcel.writeByteArray(secret)
|
parcel.writeByteArray(secret)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun describeContents(): Int {
|
override fun describeContents(): Int = 0
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object CREATOR : Parcelable.Creator<SecretKey> {
|
companion object CREATOR : Parcelable.Creator<SecretKey> {
|
||||||
override fun createFromParcel(parcel: Parcel): SecretKey {
|
override fun createFromParcel(parcel: Parcel): SecretKey {
|
||||||
|
@ -2,7 +2,6 @@ package im.molly.monero
|
|||||||
|
|
||||||
data class Transaction(
|
data class Transaction(
|
||||||
val hash: HashDigest,
|
val hash: HashDigest,
|
||||||
// TODO: val version: ProtocolInfo,
|
|
||||||
val state: TxState,
|
val state: TxState,
|
||||||
val network: MoneroNetwork,
|
val network: MoneroNetwork,
|
||||||
val timeLock: UnlockTime?,
|
val timeLock: UnlockTime?,
|
||||||
@ -37,7 +36,3 @@ sealed interface TxState {
|
|||||||
data object OffChain : TxState
|
data object OffChain : TxState
|
||||||
}
|
}
|
||||||
|
|
||||||
data class PaymentDetail(
|
|
||||||
val amount: MoneroAmount,
|
|
||||||
val recipient: PublicAddress,
|
|
||||||
)
|
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
package im.molly.monero
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
sealed interface TransferRequest : Parcelable
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class PaymentRequest(
|
||||||
|
val paymentDetails: List<PaymentDetail>,
|
||||||
|
val sourceAccounts: Set<AccountAddress>,
|
||||||
|
val feePriority: FeePriority? = null,
|
||||||
|
val timeLock: UnlockTime? = null,
|
||||||
|
) : TransferRequest
|
||||||
|
|
||||||
|
@Parcelize
|
||||||
|
data class SweepRequest(
|
||||||
|
val recipientAddress: PublicAddress,
|
||||||
|
val splitCount: Int = 1,
|
||||||
|
val keyImageHashes: List<HashDigest>,
|
||||||
|
val feePriority: FeePriority? = null,
|
||||||
|
val timeLock: UnlockTime? = null,
|
||||||
|
) : TransferRequest
|
@ -7,11 +7,12 @@ import kotlinx.coroutines.*
|
|||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
import kotlin.concurrent.withLock
|
import kotlin.concurrent.withLock
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
class WalletNative private constructor(
|
internal class WalletNative private constructor(
|
||||||
private val network: MoneroNetwork,
|
private val network: MoneroNetwork,
|
||||||
private val storageAdapter: IStorageAdapter,
|
private val storageAdapter: IStorageAdapter,
|
||||||
private val remoteNodeClient: IRemoteNodeClient?,
|
private val remoteNodeClient: IRemoteNodeClient?,
|
||||||
@ -168,6 +169,45 @@ class WalletNative private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun createPayment(request: PaymentRequest, callback: ITransferRequestCallback) {
|
||||||
|
val (amounts, addresses) = request.paymentDetails.map {
|
||||||
|
it.amount.atomicUnits to it.recipientAddress.address
|
||||||
|
}.unzip()
|
||||||
|
|
||||||
|
nativeCreatePayment(
|
||||||
|
handle = handle,
|
||||||
|
addresses = addresses.toTypedArray(),
|
||||||
|
amounts = amounts.toLongArray(),
|
||||||
|
timeLock = request.timeLock?.blockchainTime?.toLong() ?: 0,
|
||||||
|
priority = request.feePriority?.priority ?: 0,
|
||||||
|
accountIndex = 0,
|
||||||
|
subAddressIndexes = IntArray(0),
|
||||||
|
callback = callback,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createSweep(request: SweepRequest, callback: ITransferRequestCallback) {
|
||||||
|
TODO()
|
||||||
|
}
|
||||||
|
|
||||||
|
@CalledByNative
|
||||||
|
private fun createPendingTransfer(handle: Long) = NativePendingTransfer(handle)
|
||||||
|
|
||||||
|
inner class NativePendingTransfer(private val handle: Long) : Closeable,
|
||||||
|
IPendingTransfer.Stub() {
|
||||||
|
|
||||||
|
private val closed = AtomicBoolean()
|
||||||
|
|
||||||
|
override fun close() {
|
||||||
|
if (closed.getAndSet(true)) return
|
||||||
|
nativeDisposePendingTransfer(handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun finalize() {
|
||||||
|
nativeDisposePendingTransfer(handle)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun requestFees(callback: IWalletCallbacks?) {
|
override fun requestFees(callback: IWalletCallbacks?) {
|
||||||
scope.launch(ioDispatcher) {
|
scope.launch(ioDispatcher) {
|
||||||
val fees = nativeFetchBaseFeeEstimate(handle)
|
val fees = nativeFetchBaseFeeEstimate(handle)
|
||||||
@ -191,7 +231,7 @@ class WalletNative private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@CalledByNative("wallet.cc")
|
@CalledByNative
|
||||||
private fun onRefresh(height: Int, timestamp: Long, balanceChanged: Boolean) {
|
private fun onRefresh(height: Int, timestamp: Long, balanceChanged: Boolean) {
|
||||||
balanceListenersLock.withLock {
|
balanceListenersLock.withLock {
|
||||||
if (balanceListeners.isNotEmpty()) {
|
if (balanceListeners.isNotEmpty()) {
|
||||||
@ -208,7 +248,7 @@ class WalletNative private constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@CalledByNative("wallet.cc")
|
@CalledByNative
|
||||||
private fun onSuspendRefresh(suspending: Boolean) {
|
private fun onSuspendRefresh(suspending: Boolean) {
|
||||||
if (suspending) {
|
if (suspending) {
|
||||||
pendingRequestLock.withLock {
|
pendingRequestLock.withLock {
|
||||||
@ -232,7 +272,7 @@ class WalletNative private constructor(
|
|||||||
*
|
*
|
||||||
* Caller must close [HttpResponse.body] upon completion of processing the response.
|
* Caller must close [HttpResponse.body] upon completion of processing the response.
|
||||||
*/
|
*/
|
||||||
@CalledByNative("http_client.cc")
|
@CalledByNative
|
||||||
private fun callRemoteNode(
|
private fun callRemoteNode(
|
||||||
method: String?,
|
method: String?,
|
||||||
path: String?,
|
path: String?,
|
||||||
@ -280,12 +320,25 @@ class WalletNative private constructor(
|
|||||||
|
|
||||||
private external fun nativeCancelRefresh(handle: Long)
|
private external fun nativeCancelRefresh(handle: Long)
|
||||||
private external fun nativeCreate(networkId: Int): Long
|
private external fun nativeCreate(networkId: Int): Long
|
||||||
|
private external fun nativeCreatePayment(
|
||||||
|
handle: Long,
|
||||||
|
addresses: Array<String>,
|
||||||
|
amounts: LongArray,
|
||||||
|
timeLock: Long,
|
||||||
|
priority: Int,
|
||||||
|
accountIndex: Int,
|
||||||
|
subAddressIndexes: IntArray,
|
||||||
|
callback: ITransferRequestCallback,
|
||||||
|
)
|
||||||
|
|
||||||
private external fun nativeDispose(handle: Long)
|
private external fun nativeDispose(handle: Long)
|
||||||
|
private external fun nativeDisposePendingTransfer(handle: Long)
|
||||||
private external fun nativeGetCurrentBlockchainHeight(handle: Long): Int
|
private external fun nativeGetCurrentBlockchainHeight(handle: Long): Int
|
||||||
private external fun nativeGetCurrentBlockchainTimestamp(handle: Long): Long
|
private external fun nativeGetCurrentBlockchainTimestamp(handle: Long): Long
|
||||||
private external fun nativeGetTxHistory(handle: Long): Array<TxInfo>
|
private external fun nativeGetTxHistory(handle: Long): Array<TxInfo>
|
||||||
private external fun nativeGetAccountPrimaryAddress(handle: Long): String
|
private external fun nativeGetAccountPrimaryAddress(handle: Long): String
|
||||||
// private external fun nativeGetAccountSubAddress(handle: Long, accountIndex: Int, subAddressIndex: Int): String
|
|
||||||
|
// private external fun nativeGetAccountSubAddress(handle: Long, accountIndex: Int, subAddressIndex: Int): String
|
||||||
private external fun nativeFetchBaseFeeEstimate(handle: Long): LongArray
|
private external fun nativeFetchBaseFeeEstimate(handle: Long): LongArray
|
||||||
private external fun nativeLoad(handle: Long, fd: Int): Boolean
|
private external fun nativeLoad(handle: Long, fd: Int): Boolean
|
||||||
private external fun nativeNonReentrantRefresh(handle: Long, skipCoinbase: Boolean): Int
|
private external fun nativeNonReentrantRefresh(handle: Long, skipCoinbase: Boolean): Int
|
||||||
|
@ -27,8 +27,7 @@ import java.time.Instant
|
|||||||
* transaction history data.
|
* transaction history data.
|
||||||
*/
|
*/
|
||||||
@Parcelize
|
@Parcelize
|
||||||
internal data class TxInfo
|
internal data class TxInfo @CalledByNative constructor(
|
||||||
@CalledByNative("wallet.cc") constructor(
|
|
||||||
val txHash: String,
|
val txHash: String,
|
||||||
val publicKey: String?,
|
val publicKey: String?,
|
||||||
val keyImage: String?,
|
val keyImage: String?,
|
||||||
@ -170,10 +169,10 @@ private fun TxInfo.toEnote(blockchainHeight: Int): Enote {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun TxInfo.toPaymentDetail(): PaymentDetail? {
|
private fun TxInfo.toPaymentDetail(): PaymentDetail? {
|
||||||
val recipient = PublicAddress.parse(recipient ?: return null)
|
val recipientAddress = PublicAddress.parse(recipient ?: return null)
|
||||||
return PaymentDetail(
|
return PaymentDetail(
|
||||||
amount = MoneroAmount(atomicUnits = amount),
|
amount = MoneroAmount(atomicUnits = amount),
|
||||||
recipient = recipient,
|
recipientAddress = recipientAddress,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ object MoneroMnemonic {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@CalledByNative("mnemonics/mnemonics.cc")
|
@CalledByNative
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
private fun buildMnemonicFromJNI(
|
private fun buildMnemonicFromJNI(
|
||||||
entropy: ByteArray,
|
entropy: ByteArray,
|
||||||
|
Loading…
Reference in New Issue
Block a user