This commit is contained in:
Hanh 2022-12-30 21:31:54 +08:00
parent 97ae66956d
commit 74d8a5f04c
7 changed files with 3348 additions and 898 deletions

View File

@ -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);

View File

@ -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, &currency)?;
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))

View File

@ -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

View File

@ -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")?;
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;
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());
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;
let from = builder.create_string(&from);
let to = builder.create_string(&to);
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 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?);
}
return null;
}
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)
}
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)
}
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);
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?);
}
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)
}
Future<List<Account>> getAccountList() async {
List<Account> accounts = [];
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(&quotes);
let quotes = QuoteVec::create(&mut builder, &QuoteVecArgs { values: Some(quotes) });
builder.finish(quotes, None);
let data = builder.finished_data().to_vec();
Ok(data)
}
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);
"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",
final List<Map> res1 = await db.rawQuery(
"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);
}
return accounts;
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;
}
// 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;
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<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<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<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;
*/

View File

@ -100,7 +100,6 @@ mod zip32;
// mod wallet;
/// accounts, sync, payments, etc.
pub mod api;
pub mod template;
#[cfg(feature = "ledger")]
mod ledger;

View File

@ -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,
}