wip
This commit is contained in:
parent
97ae66956d
commit
74d8a5f04c
84
binding.h
84
binding.h
|
@ -78,33 +78,59 @@ typedef struct CResult______u8 {
|
|||
|
||||
#define ShieldedNoteVec_VT_NOTES 4
|
||||
|
||||
#define AdressbookEntry_VT_ID_ADDRESS 4
|
||||
#define ShieldedTx_VT_TX_ID 6
|
||||
|
||||
#define AdressbookEntry_VT_ADDRESS 8
|
||||
#define ShieldedTx_VT_SHORT_TX_ID 10
|
||||
|
||||
#define Addressbook_VT_CONTACTS 6
|
||||
#define ShieldedTx_VT_ADDRESS 18
|
||||
|
||||
#define AccountBalance_VT_COIN 4
|
||||
#define ShieldedTx_VT_MEMO 20
|
||||
|
||||
#define AccountBalance_VT_ID_ACCOUNT 6
|
||||
#define ShieldedTxVec_VT_TXS 4
|
||||
|
||||
#define AccountBalance_VT_TBALANCE 12
|
||||
#define Message_VT_ID_MSG 4
|
||||
|
||||
#define ZMessage_VT_TX_ID 6
|
||||
#define Message_VT_ID_TX 6
|
||||
|
||||
#define ZMessage_VT_INCOMING 8
|
||||
#define Message_VT_FROM 12
|
||||
|
||||
#define ZMessage_VT_SENDER 10
|
||||
#define Message_VT_TO 14
|
||||
|
||||
#define ZMessage_VT_RECIPIENT 12
|
||||
#define Message_VT_SUBJECT 16
|
||||
|
||||
#define ZMessage_VT_SUBJECT 14
|
||||
#define Message_VT_BODY 18
|
||||
|
||||
#define ZMessage_VT_BODY 16
|
||||
#define Message_VT_READ 20
|
||||
|
||||
#define ZMessage_VT_READ 22
|
||||
#define Message_VT_INCOMING 22
|
||||
|
||||
#define ZMessages_VT_MESSAGES 4
|
||||
#define MessageVec_VT_MESSAGES 4
|
||||
|
||||
#define PrevNext_VT_PREV 4
|
||||
|
||||
#define PrevNext_VT_NEXT 6
|
||||
|
||||
#define SendTemplate_VT_TITLE 6
|
||||
|
||||
#define SendTemplate_VT_AMOUNT 10
|
||||
|
||||
#define SendTemplate_VT_FIAT_AMOUNT 12
|
||||
|
||||
#define SendTemplate_VT_FEE_INCLUDED 14
|
||||
|
||||
#define SendTemplate_VT_FIAT 16
|
||||
|
||||
#define SendTemplate_VT_INCLUDE_REPLY_TO 18
|
||||
|
||||
#define SendTemplateVec_VT_TEMPLATES 4
|
||||
|
||||
#define ContactVec_VT_CONTACTS 4
|
||||
|
||||
#define TxTimeValueVec_VT_VALUES 4
|
||||
|
||||
#define Quote_VT_PRICE 6
|
||||
|
||||
#define Spending_VT_RECIPIENT 4
|
||||
|
||||
void dummy_export(void);
|
||||
|
||||
|
@ -249,10 +275,6 @@ struct CResult_____c_char derive_zip32(uint8_t coin,
|
|||
bool has_address,
|
||||
uint32_t address);
|
||||
|
||||
struct CResult_u32 save_send_template(uint8_t coin, char *template_);
|
||||
|
||||
struct CResult_u8 delete_send_template(uint8_t coin, uint32_t id);
|
||||
|
||||
struct CResult______u8 get_account_list(uint8_t coin);
|
||||
|
||||
struct CResult_u32 get_available_account_id(uint8_t coin, uint32_t id);
|
||||
|
@ -269,6 +291,32 @@ struct CResult______u8 get_db_height(uint8_t coin);
|
|||
|
||||
struct CResult______u8 get_notes(uint8_t coin, uint32_t id);
|
||||
|
||||
struct CResult______u8 get_txs(uint8_t coin, uint32_t id);
|
||||
|
||||
struct CResult______u8 get_messages(uint8_t coin, uint32_t id);
|
||||
|
||||
struct CResult______u8 get_prev_next_message(uint8_t coin,
|
||||
uint32_t id,
|
||||
char *subject,
|
||||
uint32_t height);
|
||||
|
||||
struct CResult______u8 get_templates(uint8_t coin);
|
||||
|
||||
struct CResult_u32 save_send_template(uint8_t coin, uint8_t *template_, uint64_t len);
|
||||
|
||||
struct CResult_u8 delete_send_template(uint8_t coin, uint32_t id);
|
||||
|
||||
struct CResult______u8 get_contacts(uint8_t coin);
|
||||
|
||||
struct CResult______u8 get_pnl_txs(uint8_t coin, uint32_t id, uint32_t timestamp);
|
||||
|
||||
struct CResult______u8 get_historical_prices(uint8_t coin,
|
||||
uint32_t id,
|
||||
uint32_t timestamp,
|
||||
char *currency);
|
||||
|
||||
struct CResult______u8 get_spendings(uint8_t coin, uint32_t id, uint32_t timestamp);
|
||||
|
||||
bool has_cuda(void);
|
||||
|
||||
bool has_metal(void);
|
||||
|
|
|
@ -13,7 +13,7 @@ use std::sync::{Mutex, MutexGuard};
|
|||
use rusqlite::Connection;
|
||||
use tokio::sync::Semaphore;
|
||||
use zcash_primitives::transaction::builder::Progress;
|
||||
use crate::template::SendTemplate;
|
||||
use crate::db::data_generated::fb::SendTemplate;
|
||||
|
||||
static mut POST_COBJ: Option<ffi::DartPostCObjectFnType> = None;
|
||||
|
||||
|
@ -804,13 +804,130 @@ pub unsafe extern "C" fn derive_zip32(
|
|||
to_cresult_str(res())
|
||||
}
|
||||
|
||||
fn with_account<T, F: Fn(&Connection) -> anyhow::Result<T>>(coin: u8, id: u32, f: F) -> anyhow::Result<T> {
|
||||
let c = CoinConfig::get(coin);
|
||||
let db = c.db()?;
|
||||
let connection = &db.connection;
|
||||
f(connection)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn save_send_template(coin: u8, template: *mut c_char) -> CResult<u32> {
|
||||
from_c_str!(template);
|
||||
pub unsafe extern "C" fn get_account_list(coin: u8) -> CResult<*const u8> {
|
||||
let res = |connection: &Connection| {
|
||||
let accounts = crate::db::read::get_account_list(connection)?;
|
||||
Ok(accounts)
|
||||
};
|
||||
to_cresult_bytes(with_account(coin, 0, res))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_available_account_id(coin: u8, id: u32) -> CResult<u32> {
|
||||
let res = |connection: &Connection| {
|
||||
let new_id = crate::db::read::get_available_account_id(connection, id)?;
|
||||
Ok(new_id)
|
||||
};
|
||||
to_cresult(with_account(coin, id, res))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_t_addr(coin: u8, id: u32) -> CResult<*mut c_char> {
|
||||
let res = |connection: &Connection| {
|
||||
let address = crate::db::read::get_t_addr(connection, id)?;
|
||||
Ok(address)
|
||||
};
|
||||
to_cresult_str(with_account(coin, id, res))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_sk(coin: u8, id: u32) -> CResult<*mut c_char> {
|
||||
let res = |connection: &Connection| {
|
||||
let sk = crate::db::read::get_sk(connection, id)?;
|
||||
Ok(sk)
|
||||
};
|
||||
to_cresult_str(with_account(coin, id, res))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn update_account_name(coin: u8, id: u32, name: *mut c_char) -> CResult<u8> {
|
||||
from_c_str!(name);
|
||||
let res = |connection: &Connection| {
|
||||
crate::db::read::update_account_name(connection, id, &name)?;
|
||||
Ok(0)
|
||||
};
|
||||
to_cresult(with_account(coin, id, res))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_balances(coin: u8, id: u32, confirmed_height: u32) -> CResult<*const u8> {
|
||||
let res = |connection: &Connection| {
|
||||
let data = crate::db::read::get_balances(connection, id, confirmed_height)?;
|
||||
Ok(data)
|
||||
};
|
||||
to_cresult_bytes(with_account(coin, id, res))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_db_height(coin: u8) -> CResult<*const u8> {
|
||||
let res = |connection: &Connection| {
|
||||
let data = crate::db::read::get_db_height(connection)?;
|
||||
Ok(data)
|
||||
};
|
||||
to_cresult_bytes(with_account(coin, 0, res))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_notes(coin: u8, id: u32) -> CResult<*const u8> {
|
||||
let res = |connection: &Connection| {
|
||||
let data = crate::db::read::get_notes(connection, id)?;
|
||||
Ok(data)
|
||||
};
|
||||
to_cresult_bytes(with_account(coin, id, res))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_txs(coin: u8, id: u32) -> CResult<*const u8> {
|
||||
let res = |connection: &Connection| {
|
||||
let data = crate::db::read::get_txs(connection, id)?;
|
||||
Ok(data)
|
||||
};
|
||||
to_cresult_bytes(with_account(coin, id, res))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_messages(coin: u8, id: u32) -> CResult<*const u8> {
|
||||
let res = |connection: &Connection| {
|
||||
let data = crate::db::read::get_messages(connection, id)?;
|
||||
Ok(data)
|
||||
};
|
||||
to_cresult_bytes(with_account(coin, id, res))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_prev_next_message(coin: u8, id: u32, subject: *mut c_char, height: u32) -> CResult<*const u8> {
|
||||
from_c_str!(subject);
|
||||
let res = |connection: &Connection| {
|
||||
let data = crate::db::read::get_prev_next_message(connection, &subject, height, id)?;
|
||||
Ok(data)
|
||||
};
|
||||
to_cresult_bytes(with_account(coin, id, res))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_templates(coin: u8) -> CResult<*const u8> {
|
||||
let res = |connection: &Connection| {
|
||||
let data = crate::db::read::get_templates(connection)?;
|
||||
Ok(data)
|
||||
};
|
||||
to_cresult_bytes(with_account(coin, 0, res))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn save_send_template(coin: u8, template: *mut u8, len: u64) -> CResult<u32> {
|
||||
let template: Vec<u8> = Vec::from_raw_parts(template, len as usize, len as usize);
|
||||
let res = || {
|
||||
let c = CoinConfig::get(coin);
|
||||
let db = c.db()?;
|
||||
let template: SendTemplate = serde_json::from_str(&template)?;
|
||||
let template = flatbuffers::root::<SendTemplate>(&template)?;
|
||||
let id = db.store_template(&template)?;
|
||||
Ok(id)
|
||||
};
|
||||
|
@ -828,81 +945,38 @@ pub unsafe extern "C" fn delete_send_template(coin: u8, id: u32) -> CResult<u8>
|
|||
to_cresult(res())
|
||||
}
|
||||
|
||||
fn with_account<T, F: Fn(u8, u32, &Connection) -> anyhow::Result<T>>(coin: u8, id: u32, f: F) -> anyhow::Result<T> {
|
||||
let c = CoinConfig::get(coin);
|
||||
let db = c.db()?;
|
||||
let connection = &db.connection;
|
||||
f(coin, id, connection)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_account_list(coin: u8) -> CResult<*const u8> {
|
||||
let res = |coin: u8, id: u32, connection: &Connection| {
|
||||
let accounts = crate::db::read::get_account_list(connection)?;
|
||||
Ok(accounts)
|
||||
pub unsafe extern "C" fn get_contacts(coin: u8) -> CResult<*const u8> {
|
||||
let res = |connection: &Connection| {
|
||||
let data = crate::db::read::get_contacts(connection)?;
|
||||
Ok(data)
|
||||
};
|
||||
to_cresult_bytes(with_account(coin, 0, res))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_available_account_id(coin: u8, id: u32) -> CResult<u32> {
|
||||
let res = |coin: u8, id: u32, connection: &Connection| {
|
||||
let new_id = crate::db::read::get_available_account_id(connection, id)?;
|
||||
Ok(new_id)
|
||||
};
|
||||
to_cresult(with_account(coin, id, res))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_t_addr(coin: u8, id: u32) -> CResult<*mut c_char> {
|
||||
let res = |coin: u8, id: u32, connection: &Connection| {
|
||||
let address = crate::db::read::get_t_addr(connection, id)?;
|
||||
Ok(address)
|
||||
};
|
||||
to_cresult_str(with_account(coin, id, res))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_sk(coin: u8, id: u32) -> CResult<*mut c_char> {
|
||||
let res = |coin: u8, id: u32, connection: &Connection| {
|
||||
let sk = crate::db::read::get_sk(connection, id)?;
|
||||
Ok(sk)
|
||||
};
|
||||
to_cresult_str(with_account(coin, id, res))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn update_account_name(coin: u8, id: u32, name: *mut c_char) -> CResult<u8> {
|
||||
from_c_str!(name);
|
||||
let res = |coin: u8, id: u32, connection: &Connection| {
|
||||
crate::db::read::update_account_name(connection, id, &name)?;
|
||||
Ok(0)
|
||||
};
|
||||
to_cresult(with_account(coin, id, res))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_balances(coin: u8, id: u32, confirmed_height: u32) -> CResult<*const u8> {
|
||||
let res = |coin: u8, id: u32, connection: &Connection| {
|
||||
let data = crate::db::read::get_balances(connection, id, confirmed_height)?;
|
||||
pub unsafe extern "C" fn get_pnl_txs(coin: u8, id: u32, timestamp: u32) -> CResult<*const u8> {
|
||||
let res = |connection: &Connection| {
|
||||
let data = crate::db::read::get_pnl_txs(connection, id, timestamp)?;
|
||||
Ok(data)
|
||||
};
|
||||
to_cresult_bytes(with_account(coin, id, res))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_db_height(coin: u8) -> CResult<*const u8> {
|
||||
let res = |coin: u8, _id: u32, connection: &Connection| {
|
||||
let data = crate::db::read::get_db_height(connection)?;
|
||||
pub unsafe extern "C" fn get_historical_prices(coin: u8, id: u32, timestamp: u32, currency: *mut c_char) -> CResult<*const u8> {
|
||||
from_c_str!(currency);
|
||||
let res = |connection: &Connection| {
|
||||
let data = crate::db::read::get_historical_prices(connection, timestamp, ¤cy)?;
|
||||
Ok(data)
|
||||
};
|
||||
to_cresult_bytes(with_account(coin, 0, res))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn get_notes(coin: u8, id: u32) -> CResult<*const u8> {
|
||||
let res = |coin: u8, id: u32, connection: &Connection| {
|
||||
let data = crate::db::read::get_notes(connection, id)?;
|
||||
pub unsafe extern "C" fn get_spendings(coin: u8, id: u32, timestamp: u32) -> CResult<*const u8> {
|
||||
let res = |connection: &Connection| {
|
||||
let data = crate::db::read::get_spendings(connection, id, timestamp)?;
|
||||
Ok(data)
|
||||
};
|
||||
to_cresult_bytes(with_account(coin, id, res))
|
||||
|
|
14
src/db.rs
14
src/db.rs
|
@ -30,7 +30,7 @@ pub mod data_generated;
|
|||
pub mod read;
|
||||
|
||||
pub use backup::FullEncryptedBackup;
|
||||
use crate::template::SendTemplate;
|
||||
use crate::db::data_generated::fb::SendTemplate;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const DEFAULT_DB_PATH: &str = "zec.db";
|
||||
|
@ -1195,21 +1195,21 @@ impl DbAdapter {
|
|||
}
|
||||
|
||||
pub fn store_template(&self, t: &SendTemplate) -> anyhow::Result<u32> {
|
||||
let id = if t.id == 0 {
|
||||
let id = if t.id() == 0 {
|
||||
self.connection.execute("INSERT INTO \
|
||||
send_templates(title, address, amount, fiat_amount, fee_included, fiat, include_reply_to, subject, body) \
|
||||
VALUES (?1,?2,?3,?4,?5,?6,?7,?8,?9)",
|
||||
params![t.title, t.address, t.amount, t.fiat_amount, t.fee_included, t.fiat,
|
||||
t.memo.include_reply_to, t.memo.subject, t.memo.body])?;
|
||||
params![t.title().unwrap(), t.address().unwrap(), t.amount(), t.fiat_amount(), t.fee_included(), t.fiat().unwrap(),
|
||||
t.include_reply_to(), t.subject().unwrap(), t.body().unwrap()])?;
|
||||
self.connection.last_insert_rowid() as u32
|
||||
}
|
||||
else {
|
||||
self.connection.execute("UPDATE send_templates SET \
|
||||
title=?1, address=?2, amount=?3, fiat_amount=?4, fee_included=?5, fiat=?6, include_reply_to=?7, subject=?8, body=?9 \
|
||||
WHERE id_send_template=?10",
|
||||
params![t.title, t.address, t.amount, t.fiat_amount, t.fee_included, t.fiat,
|
||||
t.memo.include_reply_to, t.memo.subject, t.memo.body, t.id])?;
|
||||
t.id
|
||||
params![t.title().unwrap(), t.address().unwrap(), t.amount(), t.fiat_amount(), t.fee_included(), t.fiat().unwrap(),
|
||||
t.include_reply_to(), t.subject().unwrap(), t.body().unwrap(), t.id()])?;
|
||||
t.id()
|
||||
};
|
||||
Ok(id)
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
429
src/db/read.rs
429
src/db/read.rs
|
@ -178,138 +178,343 @@ pub fn get_notes(connection: &Connection, id: u32) -> Result<Vec<u8>> {
|
|||
Ok(data)
|
||||
}
|
||||
|
||||
|
||||
/* final id = row['id_note'];
|
||||
final height = row['height'];
|
||||
final timestamp = DateTime.fromMillisecondsSinceEpoch(row['timestamp'] * 1000);
|
||||
final orchard = row['orchard'] != 0;
|
||||
final excluded = (row['excluded'] ?? 0) != 0;
|
||||
final spent = row['spent'] == 0;
|
||||
|
||||
|
||||
|
||||
|
||||
final rows = await db.rawQuery("SELECT height, timestamp FROM blocks WHERE height = (SELECT MAX(height) FROM blocks)");
|
||||
if (rows.isNotEmpty) {
|
||||
final row = rows.first;
|
||||
final height = row['height'] as int;
|
||||
final timestampEpoch = row['timestamp'] as int;
|
||||
final timestamp = DateTime.fromMillisecondsSinceEpoch(timestampEpoch * 1000);
|
||||
final blockInfo = BlockInfo(height, timestamp);
|
||||
return blockInfo;
|
||||
pub fn get_txs(connection: &Connection, id: u32) -> Result<Vec<u8>> {
|
||||
let mut builder = flatbuffers::FlatBufferBuilder::new();
|
||||
let mut stmt = connection.prepare(
|
||||
"SELECT id_tx, txid, height, timestamp, t.address, c.name AS cname, a.name AS aname, value, memo FROM transactions t \
|
||||
LEFT JOIN contacts c ON t.address = c.address \
|
||||
LEFT JOIN accounts a ON a.address = t.address \
|
||||
WHERE account = ?1 ORDER BY height DESC")?;
|
||||
let rows = stmt.query_map(params![id], |row| {
|
||||
let id_tx: u32 = row.get("id_tx")?;
|
||||
let height: u32 = row.get("height")?;
|
||||
let mut tx_id: Vec<u8> = row.get("txid")?;
|
||||
tx_id.reverse();
|
||||
let tx_id = hex::encode(&tx_id);
|
||||
let short_tx_id = tx_id[..8].to_string();
|
||||
let timestamp: u32 = row.get("timestamp")?;
|
||||
let contact_name: Option<String> = row.get("cname")?;
|
||||
let account_name: Option<String> = row.get("aname")?;
|
||||
let name = contact_name.or(account_name).unwrap_or(String::new());
|
||||
let value: i64 = row.get("value")?;
|
||||
let address: Option<String> = row.get("address")?;
|
||||
let memo: Option<String> = row.get("memo")?;
|
||||
let address = address.unwrap_or(String::new());
|
||||
let memo = memo.unwrap_or(String::new());
|
||||
let tx_id = builder.create_string(&tx_id);
|
||||
let short_tx_id = builder.create_string(&short_tx_id);
|
||||
let name = builder.create_string(&name);
|
||||
let address = builder.create_string(&address);
|
||||
let memo = builder.create_string(&memo);
|
||||
let tx = ShieldedTx::create(&mut builder, &ShieldedTxArgs {
|
||||
id: id_tx,
|
||||
height,
|
||||
tx_id: Some(tx_id),
|
||||
short_tx_id: Some(short_tx_id),
|
||||
timestamp,
|
||||
name: Some(name),
|
||||
value: value as u64,
|
||||
address: Some(address),
|
||||
memo: Some(memo),
|
||||
});
|
||||
Ok(tx)
|
||||
})?;
|
||||
let mut txs = vec![];
|
||||
for r in rows {
|
||||
txs.push(r?);
|
||||
}
|
||||
return null;
|
||||
let txs = builder.create_vector(&txs);
|
||||
let txs = ShieldedTxVec::create(&mut builder, &ShieldedTxVecArgs { txs: Some(txs) });
|
||||
builder.finish(txs, None);
|
||||
let data = builder.finished_data().to_vec();
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
return Sqflite.firstIntValue(await db.rawQuery("SELECT SUM(value) FROM received_notes WHERE account = ?1 AND spent IS NULL AND orchard = 0",
|
||||
[id])) ?? 0;
|
||||
pub fn get_messages(connection: &Connection, id: u32) -> Result<Vec<u8>> {
|
||||
let mut builder = flatbuffers::FlatBufferBuilder::new();
|
||||
let mut stmt = connection.prepare(
|
||||
"SELECT m.id, m.id_tx, m.timestamp, m.sender, m.recipient, m.incoming, c.name as scontact, a.name as saccount, c2.name as rcontact, a2.name as raccount, \
|
||||
subject, body, height, read FROM messages m \
|
||||
LEFT JOIN contacts c ON m.sender = c.address \
|
||||
LEFT JOIN accounts a ON m.sender = a.address \
|
||||
LEFT JOIN contacts c2 ON m.recipient = c2.address \
|
||||
LEFT JOIN accounts a2 ON m.recipient = a2.address \
|
||||
WHERE account = ?1 ORDER BY timestamp DESC")?;
|
||||
let rows = stmt.query_map(params![id], |row| {
|
||||
let id_msg: u32 = row.get("id")?;
|
||||
let id_tx: Option<u32> = row.get("id_tx")?;
|
||||
let timestamp: u32 = row.get("timestamp")?;
|
||||
let height: u32 = row.get("height")?;
|
||||
let sender: Option<String> = row.get("sender")?;
|
||||
let scontact: Option<String> = row.get("scontact")?;
|
||||
let saccount: Option<String> = row.get("saccount")?;
|
||||
let recipient: Option<String> = row.get("recipient")?;
|
||||
let rcontact: Option<String> = row.get("rcontact")?;
|
||||
let raccount: Option<String> = row.get("raccount")?;
|
||||
let subject: String = row.get("subject")?;
|
||||
let body: String = row.get("body")?;
|
||||
let read: bool = row.get("read")?;
|
||||
let incoming: bool = row.get("incoming")?;
|
||||
|
||||
let id_tx = id_tx.unwrap_or(0);
|
||||
let from = scontact.or(saccount).or(sender).unwrap_or(String::new());
|
||||
let to = rcontact.or(raccount).or(recipient).unwrap_or(String::new());
|
||||
|
||||
let from = builder.create_string(&from);
|
||||
let to = builder.create_string(&to);
|
||||
let subject = builder.create_string(&subject);
|
||||
let body = builder.create_string(&body);
|
||||
|
||||
let message = Message::create(&mut builder, &MessageArgs {
|
||||
id_msg,
|
||||
id_tx,
|
||||
height,
|
||||
timestamp,
|
||||
from: Some(from),
|
||||
to: Some(to),
|
||||
subject: Some(subject),
|
||||
body: Some(body),
|
||||
read,
|
||||
incoming
|
||||
});
|
||||
Ok(message)
|
||||
})?;
|
||||
let mut messages = vec![];
|
||||
for r in rows {
|
||||
messages.push(r?);
|
||||
}
|
||||
let messages = builder.create_vector(&messages);
|
||||
let messages = MessageVec::create(&mut builder, &MessageVecArgs { messages: Some(messages) });
|
||||
builder.finish(messages, None);
|
||||
let data = builder.finished_data().to_vec();
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
Future<int> getOrchardBalance() async {
|
||||
return Sqflite.firstIntValue(await db.rawQuery("SELECT SUM(value) FROM received_notes WHERE account = ?1 AND spent IS NULL AND orchard = 1",
|
||||
[id])) ?? 0;
|
||||
pub fn get_prev_next_message(connection: &Connection, subject: &str, height: u32, account: u32) -> Result<Vec<u8>> {
|
||||
let mut builder = flatbuffers::FlatBufferBuilder::new();
|
||||
let prev = connection.query_row("SELECT MAX(id) FROM messages WHERE subject = ?1 AND height < ?2 and account = ?3",
|
||||
params![subject, height, account], |row| {
|
||||
let id: Option<u32> = row.get(0)?;
|
||||
Ok(id)
|
||||
})?.unwrap_or(0);
|
||||
let next = connection.query_row("SELECT MIN(id) FROM messages WHERE subject = ?1 AND height > ?2 and account = ?3",
|
||||
params![subject, height, account], |row| {
|
||||
let id: Option<u32> = row.get(0)?;
|
||||
Ok(id)
|
||||
})?.unwrap_or(0);
|
||||
let prev_next = PrevNext::create(&mut builder, &PrevNextArgs { prev, next });
|
||||
builder.finish(prev_next, None);
|
||||
let data = builder.finished_data().to_vec();
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
final balance = Sqflite.firstIntValue(await db.rawQuery(
|
||||
"SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND (spent IS NULL OR spent = 0)",
|
||||
[id])) ?? 0;
|
||||
final shieldedBalance = Sqflite.firstIntValue(await db.rawQuery(
|
||||
"SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND spent IS NULL",
|
||||
[id])) ?? 0;
|
||||
final unconfirmedSpentBalance = Sqflite.firstIntValue(await db.rawQuery(
|
||||
"SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND spent = 0",
|
||||
[id])) ?? 0;
|
||||
final underConfirmedBalance = Sqflite.firstIntValue(await db.rawQuery(
|
||||
"SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND spent IS NULL AND height > ?2",
|
||||
[id, confirmHeight])) ?? 0;
|
||||
final excludedBalance = Sqflite.firstIntValue(await db.rawQuery(
|
||||
"SELECT SUM(value) FROM received_notes WHERE account = ?1 AND spent IS NULL "
|
||||
"AND height <= ?2 AND excluded",
|
||||
[id, confirmHeight])) ?? 0;
|
||||
pub fn get_templates(connection: &Connection) -> Result<Vec<u8>> {
|
||||
let mut builder = flatbuffers::FlatBufferBuilder::new();
|
||||
let mut stmt = connection.prepare(
|
||||
"SELECT id_send_template, title, address, amount, fiat_amount, fee_included, fiat, include_reply_to, subject, body FROM send_templates")?;
|
||||
let rows = stmt.query_map([], |row| {
|
||||
let id_msg: u32 = row.get("id_send_template")?;
|
||||
let title: String = row.get("title")?;
|
||||
let address: String = row.get("address")?;
|
||||
let amount: i64 = row.get("amount")?;
|
||||
let fiat_amount: f64 = row.get("fiat_amount")?;
|
||||
let fee_included: bool = row.get("fee_included")?;
|
||||
let fiat: String = row.get("fiat")?;
|
||||
let include_reply_to: bool = row.get("include_reply_to")?;
|
||||
let subject: String = row.get("subject")?;
|
||||
let body: String = row.get("body")?;
|
||||
|
||||
let title = builder.create_string(&title);
|
||||
let address = builder.create_string(&address);
|
||||
let fiat = builder.create_string(&fiat);
|
||||
let subject = builder.create_string(&subject);
|
||||
let body = builder.create_string(&body);
|
||||
|
||||
|
||||
"", [id]);
|
||||
await db.execute("UPDATE accounts SET name = ?2 WHERE id_account = ?1",
|
||||
|
||||
|
||||
final List<Map> res1 = await db.rawQuery(
|
||||
"SELECT address FROM taddrs WHERE account = ?1", [id]);
|
||||
final taddress = res1.isNotEmpty ? res1[0]['address'] : "";
|
||||
return taddress;
|
||||
|
||||
|
||||
// check that the account still exists
|
||||
// if not, pick any account
|
||||
// if there are none, return 0
|
||||
Future<AccountId?> getAvailableAccountId() async {
|
||||
final List<Map> res1 = await db.rawQuery(
|
||||
"SELECT 1 FROM accounts WHERE id_account = ?1", [id]);
|
||||
if (res1.isNotEmpty)
|
||||
return AccountId(coin, id);
|
||||
final List<Map> res2 = await db.rawQuery(
|
||||
"SELECT id_account FROM accounts", []);
|
||||
if (res2.isNotEmpty) {
|
||||
final id = res2[0]['id_account'];
|
||||
return AccountId(coin, id);
|
||||
let template = SendTemplate::create(&mut builder, &SendTemplateArgs {
|
||||
id: id_msg,
|
||||
title: Some(title),
|
||||
address: Some(address),
|
||||
amount: amount as u64,
|
||||
fiat_amount,
|
||||
fee_included,
|
||||
fiat: Some(fiat),
|
||||
include_reply_to,
|
||||
subject: Some(subject),
|
||||
body: Some(body),
|
||||
});
|
||||
Ok(template)
|
||||
})?;
|
||||
let mut templates = vec![];
|
||||
for r in rows {
|
||||
templates.push(r?);
|
||||
}
|
||||
return null;
|
||||
let templates = builder.create_vector(&templates);
|
||||
let templates = SendTemplateVec::create(&mut builder, &SendTemplateVecArgs { templates: Some(templates) });
|
||||
builder.finish(templates, None);
|
||||
let data = builder.finished_data().to_vec();
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub fn get_contacts(connection: &Connection) -> Result<Vec<u8>> {
|
||||
let mut builder = flatbuffers::FlatBufferBuilder::new();
|
||||
let mut stmt = connection.prepare(
|
||||
"SELECT id, name, address FROM contacts WHERE address <> '' ORDER BY name")?;
|
||||
let rows = stmt.query_map([], |row| {
|
||||
let id: u32 = row.get("id")?;
|
||||
let name: String = row.get("name")?;
|
||||
let address: String = row.get("address")?;
|
||||
let name = builder.create_string(&name);
|
||||
let address = builder.create_string(&address);
|
||||
let contact = Contact::create(&mut builder, &ContactArgs {
|
||||
id,
|
||||
name: Some(name),
|
||||
address: Some(address),
|
||||
});
|
||||
Ok(contact)
|
||||
})?;
|
||||
let mut contacts = vec![];
|
||||
for r in rows {
|
||||
contacts.push(r?);
|
||||
}
|
||||
let contacts = builder.create_vector(&contacts);
|
||||
let contacts = ContactVec::create(&mut builder, &ContactVecArgs { contacts: Some(contacts) });
|
||||
builder.finish(contacts, None);
|
||||
let data = builder.finished_data().to_vec();
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub fn get_pnl_txs(connection: &Connection, id: u32, timestamp: u32) -> Result<Vec<u8>> {
|
||||
let mut builder = flatbuffers::FlatBufferBuilder::new();
|
||||
let mut stmt = connection.prepare(
|
||||
"SELECT timestamp, value FROM transactions WHERE timestamp >= ?2 AND account = ?1 ORDER BY timestamp DESC")?;
|
||||
let rows = stmt.query_map([id, timestamp], |row| {
|
||||
let timestamp: u32 = row.get(0)?;
|
||||
let value: i64 = row.get(1)?;
|
||||
let tx = TxTimeValue::create(&mut builder, &TxTimeValueArgs {
|
||||
timestamp, value: value as u64 });
|
||||
Ok(tx)
|
||||
})?;
|
||||
let mut txs = vec![];
|
||||
for r in rows {
|
||||
txs.push(r?);
|
||||
}
|
||||
let txs = builder.create_vector(&txs);
|
||||
let txs = TxTimeValueVec::create(&mut builder, &TxTimeValueVecArgs { values: Some(txs) });
|
||||
builder.finish(txs, None);
|
||||
let data = builder.finished_data().to_vec();
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
pub fn get_historical_prices(connection: &Connection, timestamp: u32, currency: &str) -> Result<Vec<u8>> {
|
||||
let mut builder = flatbuffers::FlatBufferBuilder::new();
|
||||
let mut stmt = connection.prepare(
|
||||
"SELECT timestamp, price FROM historical_prices WHERE timestamp >= ?2 AND currency = ?1")?;
|
||||
let rows = stmt.query_map(params![currency, timestamp], |row| {
|
||||
let timestamp: u32 = row.get(0)?;
|
||||
let price: f64 = row.get(1)?;
|
||||
let quote = Quote::create(&mut builder, &QuoteArgs {
|
||||
timestamp, price });
|
||||
Ok(quote)
|
||||
})?;
|
||||
let mut quotes = vec![];
|
||||
for r in rows {
|
||||
quotes.push(r?);
|
||||
}
|
||||
let quotes = builder.create_vector("es);
|
||||
let quotes = QuoteVec::create(&mut builder, &QuoteVecArgs { values: Some(quotes) });
|
||||
builder.finish(quotes, None);
|
||||
let data = builder.finished_data().to_vec();
|
||||
Ok(data)
|
||||
}
|
||||
|
||||
Future<List<Account>> getAccountList() async {
|
||||
List<Account> accounts = [];
|
||||
pub fn get_spendings(connection: &Connection, id: u32, timestamp: u32) -> Result<Vec<u8>> {
|
||||
let mut builder = flatbuffers::FlatBufferBuilder::new();
|
||||
let mut stmt = connection.prepare(
|
||||
"SELECT SUM(value) as v, t.address, c.name FROM transactions t LEFT JOIN contacts c ON t.address = c.address \
|
||||
WHERE account = ?1 AND timestamp >= ?2 AND value < 0 GROUP BY t.address ORDER BY v ASC LIMIT 5")?;
|
||||
let rows = stmt.query_map([id, timestamp], |row| {
|
||||
let value: i64 = row.get(0)?;
|
||||
let address: Option<String> = row.get(1)?;
|
||||
let name: Option<String> = row.get(2)?;
|
||||
|
||||
let recipient = name.or(address);
|
||||
let recipient = recipient.unwrap_or(String::new());
|
||||
let recipient = builder.create_string(&recipient);
|
||||
|
||||
let spending = Spending::create(&mut builder, &SpendingArgs {
|
||||
recipient: Some(recipient),
|
||||
amount: (-value) as u64,
|
||||
});
|
||||
Ok(spending)
|
||||
})?;
|
||||
let mut spendings = vec![];
|
||||
for r in rows {
|
||||
spendings.push(r?);
|
||||
}
|
||||
let spendings = builder.create_vector(&spendings);
|
||||
let spendings = SpendingVec::create(&mut builder, &SpendingVecArgs { values: Some(spendings) });
|
||||
builder.finish(spendings, None);
|
||||
let data = builder.finished_data().to_vec();
|
||||
Ok(data)
|
||||
}
|
||||
/*
|
||||
|
||||
"SELECT timestamp, value FROM transactions WHERE account = ?1 AND timestamp >= ?2 ORDER BY timestamp DESC",
|
||||
|
||||
final List<Map> res = await db.rawQuery(
|
||||
"WITH notes AS (SELECT a.id_account, a.name, CASE WHEN r.spent IS NULL THEN r.value ELSE 0 END AS nv FROM accounts a LEFT JOIN received_notes r ON a.id_account = r.account),"
|
||||
"accounts2 AS (SELECT id_account, name, COALESCE(sum(nv), 0) AS balance FROM notes GROUP by id_account) "
|
||||
"SELECT a.id_account, a.name, a.balance FROM accounts2 a",
|
||||
[]);
|
||||
for (var r in res) {
|
||||
final int id = r['id_account'];
|
||||
final account = Account(
|
||||
coin,
|
||||
id,
|
||||
r['name'],
|
||||
r['balance'],
|
||||
0,
|
||||
null);
|
||||
accounts.add(account);
|
||||
}
|
||||
return accounts;
|
||||
}
|
||||
"SELECT SUM(value) as v, t.address, c.name FROM transactions t LEFT JOIN contacts c ON t.address = c.address "
|
||||
"WHERE account = ?1 AND timestamp >= ?2 AND value < 0 GROUP BY t.address ORDER BY v ASC LIMIT 5",
|
||||
[accountId, range.start ~/ 1000]);
|
||||
final spendings = res.map((row) {
|
||||
final address = row['address'] ?? "";
|
||||
final value = -row['v'] / ZECUNIT;
|
||||
final contact = row['name'];
|
||||
return Spending(address, value, contact);
|
||||
}).toList();
|
||||
|
||||
|
||||
"SELECT timestamp, price FROM historical_prices WHERE timestamp >= ?2 AND currency = ?1",
|
||||
|
||||
|
||||
// check that the account still exists
|
||||
// if not, pick any account
|
||||
// if there are none, return 0
|
||||
Future<AccountId?> getAvailableAccountId() async {
|
||||
final List<Map> res1 = await db.rawQuery(
|
||||
"SELECT 1 FROM accounts WHERE id_account = ?1", [id]);
|
||||
if (res1.isNotEmpty)
|
||||
return AccountId(coin, id);
|
||||
final List<Map> res2 = await db.rawQuery(
|
||||
"SELECT id_account FROM accounts", []);
|
||||
if (res2.isNotEmpty) {
|
||||
final id = res2[0]['id_account'];
|
||||
return AccountId(coin, id);
|
||||
}
|
||||
return null;
|
||||
"SELECT timestamp, value FROM transactions WHERE timestamp >= ?2 AND account = ?1",
|
||||
[accountId, range.start ~/ 1000]);
|
||||
|
||||
|
||||
List<Map> res = await db.rawQuery(
|
||||
"SELECT id, name, address FROM contacts WHERE address <> '' ORDER BY name");
|
||||
for (var c in res) {
|
||||
final contact = Contact(c['id'], c['name'], c['address']);
|
||||
contacts.add(contact);
|
||||
}
|
||||
|
||||
Future<String> getTAddr() async {
|
||||
final List<Map> res1 = await db.rawQuery(
|
||||
"SELECT address FROM taddrs WHERE account = ?1", [id]);
|
||||
final taddress = res1.isNotEmpty ? res1[0]['address'] : "";
|
||||
return taddress;
|
||||
|
||||
Future<int?> getPrevMessage(String subject, int height, int account) async {
|
||||
final id = await Sqflite.firstIntValue(await db.rawQuery(
|
||||
"SELECT MAX(id) FROM messages WHERE subject = ?1 AND height < ?2 and account = ?3",
|
||||
[subject, height, account]));
|
||||
return id;
|
||||
}
|
||||
|
||||
Future<String?> getSK() async {
|
||||
final List<Map> res1 = await db.rawQuery(
|
||||
"SELECT sk FROM accounts WHERE id_account = ?1", [id]);
|
||||
final sk = res1.isNotEmpty ? res1[0]['address'] : null;
|
||||
return sk;
|
||||
Future<int?> getNextMessage(String subject, int height, int account) async {
|
||||
final id = await Sqflite.firstIntValue(await db.rawQuery(
|
||||
"SELECT MIN(id) FROM messages WHERE subject = ?1 AND height > ?2 and account = ?3",
|
||||
[subject, height, account]));
|
||||
return id;
|
||||
}
|
||||
|
||||
Future<void> changeAccountName(String name) async {
|
||||
await db.execute("UPDATE accounts SET name = ?2 WHERE id_account = ?1",
|
||||
[id, name]);
|
||||
}
|
||||
|
||||
final id = row['id'];
|
||||
final txId = row['id_tx'] ?? 0;
|
||||
final timestamp = DateTime.fromMillisecondsSinceEpoch(row['timestamp'] * 1000);
|
||||
final height = row['height'];
|
||||
final sender = row['sender'];
|
||||
final from = row['scontact'] ?? row['saccount'] ?? sender;
|
||||
final recipient = row['recipient'];
|
||||
final to = row['rcontact'] ?? row['raccount'] ?? recipient;
|
||||
final subject = row['subject'];
|
||||
final body = row['body'];
|
||||
final read = row['read'] == 1;
|
||||
final incoming = row['incoming'] == 1;
|
||||
*/
|
|
@ -100,7 +100,6 @@ mod zip32;
|
|||
// mod wallet;
|
||||
/// accounts, sync, payments, etc.
|
||||
pub mod api;
|
||||
pub mod template;
|
||||
|
||||
#[cfg(feature = "ledger")]
|
||||
mod ledger;
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
use serde::{Serialize, Deserialize};
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct ZMemo {
|
||||
pub include_reply_to: bool,
|
||||
pub subject: String,
|
||||
pub body: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct SendTemplate {
|
||||
pub id: u32,
|
||||
pub title: String,
|
||||
pub address: String,
|
||||
pub amount: u64,
|
||||
pub fiat_amount: f64,
|
||||
pub fee_included: bool,
|
||||
pub fiat: Option<String>,
|
||||
pub memo: ZMemo,
|
||||
}
|
Loading…
Reference in New Issue