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 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);
|
void dummy_export(void);
|
||||||
|
|
||||||
|
@ -249,10 +275,6 @@ struct CResult_____c_char derive_zip32(uint8_t coin,
|
||||||
bool has_address,
|
bool has_address,
|
||||||
uint32_t 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______u8 get_account_list(uint8_t coin);
|
||||||
|
|
||||||
struct CResult_u32 get_available_account_id(uint8_t coin, uint32_t id);
|
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_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_cuda(void);
|
||||||
|
|
||||||
bool has_metal(void);
|
bool has_metal(void);
|
||||||
|
|
|
@ -13,7 +13,7 @@ use std::sync::{Mutex, MutexGuard};
|
||||||
use rusqlite::Connection;
|
use rusqlite::Connection;
|
||||||
use tokio::sync::Semaphore;
|
use tokio::sync::Semaphore;
|
||||||
use zcash_primitives::transaction::builder::Progress;
|
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;
|
static mut POST_COBJ: Option<ffi::DartPostCObjectFnType> = None;
|
||||||
|
|
||||||
|
@ -804,13 +804,130 @@ pub unsafe extern "C" fn derive_zip32(
|
||||||
to_cresult_str(res())
|
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]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn save_send_template(coin: u8, template: *mut c_char) -> CResult<u32> {
|
pub unsafe extern "C" fn get_account_list(coin: u8) -> CResult<*const u8> {
|
||||||
from_c_str!(template);
|
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 res = || {
|
||||||
let c = CoinConfig::get(coin);
|
let c = CoinConfig::get(coin);
|
||||||
let db = c.db()?;
|
let db = c.db()?;
|
||||||
let template: SendTemplate = serde_json::from_str(&template)?;
|
let template = flatbuffers::root::<SendTemplate>(&template)?;
|
||||||
let id = db.store_template(&template)?;
|
let id = db.store_template(&template)?;
|
||||||
Ok(id)
|
Ok(id)
|
||||||
};
|
};
|
||||||
|
@ -828,81 +945,38 @@ pub unsafe extern "C" fn delete_send_template(coin: u8, id: u32) -> CResult<u8>
|
||||||
to_cresult(res())
|
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]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn get_account_list(coin: u8) -> CResult<*const u8> {
|
pub unsafe extern "C" fn get_contacts(coin: u8) -> CResult<*const u8> {
|
||||||
let res = |coin: u8, id: u32, connection: &Connection| {
|
let res = |connection: &Connection| {
|
||||||
let accounts = crate::db::read::get_account_list(connection)?;
|
let data = crate::db::read::get_contacts(connection)?;
|
||||||
Ok(accounts)
|
Ok(data)
|
||||||
};
|
};
|
||||||
to_cresult_bytes(with_account(coin, 0, res))
|
to_cresult_bytes(with_account(coin, 0, res))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn get_available_account_id(coin: u8, id: u32) -> CResult<u32> {
|
pub unsafe extern "C" fn get_pnl_txs(coin: u8, id: u32, timestamp: u32) -> CResult<*const u8> {
|
||||||
let res = |coin: u8, id: u32, connection: &Connection| {
|
let res = |connection: &Connection| {
|
||||||
let new_id = crate::db::read::get_available_account_id(connection, id)?;
|
let data = crate::db::read::get_pnl_txs(connection, id, timestamp)?;
|
||||||
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)?;
|
|
||||||
Ok(data)
|
Ok(data)
|
||||||
};
|
};
|
||||||
to_cresult_bytes(with_account(coin, id, res))
|
to_cresult_bytes(with_account(coin, id, res))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn get_db_height(coin: u8) -> CResult<*const u8> {
|
pub unsafe extern "C" fn get_historical_prices(coin: u8, id: u32, timestamp: u32, currency: *mut c_char) -> CResult<*const u8> {
|
||||||
let res = |coin: u8, _id: u32, connection: &Connection| {
|
from_c_str!(currency);
|
||||||
let data = crate::db::read::get_db_height(connection)?;
|
let res = |connection: &Connection| {
|
||||||
|
let data = crate::db::read::get_historical_prices(connection, timestamp, ¤cy)?;
|
||||||
Ok(data)
|
Ok(data)
|
||||||
};
|
};
|
||||||
to_cresult_bytes(with_account(coin, 0, res))
|
to_cresult_bytes(with_account(coin, 0, res))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn get_notes(coin: u8, id: u32) -> CResult<*const u8> {
|
pub unsafe extern "C" fn get_spendings(coin: u8, id: u32, timestamp: u32) -> CResult<*const u8> {
|
||||||
let res = |coin: u8, id: u32, connection: &Connection| {
|
let res = |connection: &Connection| {
|
||||||
let data = crate::db::read::get_notes(connection, id)?;
|
let data = crate::db::read::get_spendings(connection, id, timestamp)?;
|
||||||
Ok(data)
|
Ok(data)
|
||||||
};
|
};
|
||||||
to_cresult_bytes(with_account(coin, id, res))
|
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 mod read;
|
||||||
|
|
||||||
pub use backup::FullEncryptedBackup;
|
pub use backup::FullEncryptedBackup;
|
||||||
use crate::template::SendTemplate;
|
use crate::db::data_generated::fb::SendTemplate;
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub const DEFAULT_DB_PATH: &str = "zec.db";
|
pub const DEFAULT_DB_PATH: &str = "zec.db";
|
||||||
|
@ -1195,21 +1195,21 @@ impl DbAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn store_template(&self, t: &SendTemplate) -> anyhow::Result<u32> {
|
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 \
|
self.connection.execute("INSERT INTO \
|
||||||
send_templates(title, address, amount, fiat_amount, fee_included, fiat, include_reply_to, subject, body) \
|
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)",
|
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,
|
params![t.title().unwrap(), t.address().unwrap(), t.amount(), t.fiat_amount(), t.fee_included(), t.fiat().unwrap(),
|
||||||
t.memo.include_reply_to, t.memo.subject, t.memo.body])?;
|
t.include_reply_to(), t.subject().unwrap(), t.body().unwrap()])?;
|
||||||
self.connection.last_insert_rowid() as u32
|
self.connection.last_insert_rowid() as u32
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
self.connection.execute("UPDATE send_templates SET \
|
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 \
|
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",
|
WHERE id_send_template=?10",
|
||||||
params![t.title, t.address, t.amount, t.fiat_amount, t.fee_included, t.fiat,
|
params![t.title().unwrap(), t.address().unwrap(), t.amount(), t.fiat_amount(), t.fee_included(), t.fiat().unwrap(),
|
||||||
t.memo.include_reply_to, t.memo.subject, t.memo.body, t.id])?;
|
t.include_reply_to(), t.subject().unwrap(), t.body().unwrap(), t.id()])?;
|
||||||
t.id
|
t.id()
|
||||||
};
|
};
|
||||||
Ok(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)
|
Ok(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_txs(connection: &Connection, id: u32) -> Result<Vec<u8>> {
|
||||||
/* final id = row['id_note'];
|
let mut builder = flatbuffers::FlatBufferBuilder::new();
|
||||||
final height = row['height'];
|
let mut stmt = connection.prepare(
|
||||||
final timestamp = DateTime.fromMillisecondsSinceEpoch(row['timestamp'] * 1000);
|
"SELECT id_tx, txid, height, timestamp, t.address, c.name AS cname, a.name AS aname, value, memo FROM transactions t \
|
||||||
final orchard = row['orchard'] != 0;
|
LEFT JOIN contacts c ON t.address = c.address \
|
||||||
final excluded = (row['excluded'] ?? 0) != 0;
|
LEFT JOIN accounts a ON a.address = t.address \
|
||||||
final spent = row['spent'] == 0;
|
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")?;
|
||||||
final rows = await db.rawQuery("SELECT height, timestamp FROM blocks WHERE height = (SELECT MAX(height) FROM blocks)");
|
tx_id.reverse();
|
||||||
if (rows.isNotEmpty) {
|
let tx_id = hex::encode(&tx_id);
|
||||||
final row = rows.first;
|
let short_tx_id = tx_id[..8].to_string();
|
||||||
final height = row['height'] as int;
|
let timestamp: u32 = row.get("timestamp")?;
|
||||||
final timestampEpoch = row['timestamp'] as int;
|
let contact_name: Option<String> = row.get("cname")?;
|
||||||
final timestamp = DateTime.fromMillisecondsSinceEpoch(timestampEpoch * 1000);
|
let account_name: Option<String> = row.get("aname")?;
|
||||||
final blockInfo = BlockInfo(height, timestamp);
|
let name = contact_name.or(account_name).unwrap_or(String::new());
|
||||||
return blockInfo;
|
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",
|
pub fn get_messages(connection: &Connection, id: u32) -> Result<Vec<u8>> {
|
||||||
[id])) ?? 0;
|
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 {
|
pub fn get_prev_next_message(connection: &Connection, subject: &str, height: u32, account: u32) -> Result<Vec<u8>> {
|
||||||
return Sqflite.firstIntValue(await db.rawQuery("SELECT SUM(value) FROM received_notes WHERE account = ?1 AND spent IS NULL AND orchard = 1",
|
let mut builder = flatbuffers::FlatBufferBuilder::new();
|
||||||
[id])) ?? 0;
|
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(
|
pub fn get_templates(connection: &Connection) -> Result<Vec<u8>> {
|
||||||
"SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND (spent IS NULL OR spent = 0)",
|
let mut builder = flatbuffers::FlatBufferBuilder::new();
|
||||||
[id])) ?? 0;
|
let mut stmt = connection.prepare(
|
||||||
final shieldedBalance = Sqflite.firstIntValue(await db.rawQuery(
|
"SELECT id_send_template, title, address, amount, fiat_amount, fee_included, fiat, include_reply_to, subject, body FROM send_templates")?;
|
||||||
"SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND spent IS NULL",
|
let rows = stmt.query_map([], |row| {
|
||||||
[id])) ?? 0;
|
let id_msg: u32 = row.get("id_send_template")?;
|
||||||
final unconfirmedSpentBalance = Sqflite.firstIntValue(await db.rawQuery(
|
let title: String = row.get("title")?;
|
||||||
"SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND spent = 0",
|
let address: String = row.get("address")?;
|
||||||
[id])) ?? 0;
|
let amount: i64 = row.get("amount")?;
|
||||||
final underConfirmedBalance = Sqflite.firstIntValue(await db.rawQuery(
|
let fiat_amount: f64 = row.get("fiat_amount")?;
|
||||||
"SELECT SUM(value) AS value FROM received_notes WHERE account = ?1 AND spent IS NULL AND height > ?2",
|
let fee_included: bool = row.get("fee_included")?;
|
||||||
[id, confirmHeight])) ?? 0;
|
let fiat: String = row.get("fiat")?;
|
||||||
final excludedBalance = Sqflite.firstIntValue(await db.rawQuery(
|
let include_reply_to: bool = row.get("include_reply_to")?;
|
||||||
"SELECT SUM(value) FROM received_notes WHERE account = ?1 AND spent IS NULL "
|
let subject: String = row.get("subject")?;
|
||||||
"AND height <= ?2 AND excluded",
|
let body: String = row.get("body")?;
|
||||||
[id, confirmHeight])) ?? 0;
|
|
||||||
|
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]);
|
let template = SendTemplate::create(&mut builder, &SendTemplateArgs {
|
||||||
await db.execute("UPDATE accounts SET name = ?2 WHERE id_account = ?1",
|
id: id_msg,
|
||||||
|
title: Some(title),
|
||||||
|
address: Some(address),
|
||||||
final List<Map> res1 = await db.rawQuery(
|
amount: amount as u64,
|
||||||
"SELECT address FROM taddrs WHERE account = ?1", [id]);
|
fiat_amount,
|
||||||
final taddress = res1.isNotEmpty ? res1[0]['address'] : "";
|
fee_included,
|
||||||
return taddress;
|
fiat: Some(fiat),
|
||||||
|
include_reply_to,
|
||||||
|
subject: Some(subject),
|
||||||
// check that the account still exists
|
body: Some(body),
|
||||||
// if not, pick any account
|
});
|
||||||
// if there are none, return 0
|
Ok(template)
|
||||||
Future<AccountId?> getAvailableAccountId() async {
|
})?;
|
||||||
final List<Map> res1 = await db.rawQuery(
|
let mut templates = vec![];
|
||||||
"SELECT 1 FROM accounts WHERE id_account = ?1", [id]);
|
for r in rows {
|
||||||
if (res1.isNotEmpty)
|
templates.push(r?);
|
||||||
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;
|
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 {
|
pub fn get_spendings(connection: &Connection, id: u32, timestamp: u32) -> Result<Vec<u8>> {
|
||||||
List<Account> accounts = [];
|
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(
|
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),"
|
"SELECT SUM(value) as v, t.address, c.name FROM transactions t LEFT JOIN contacts c ON t.address = c.address "
|
||||||
"accounts2 AS (SELECT id_account, name, COALESCE(sum(nv), 0) AS balance FROM notes GROUP by id_account) "
|
"WHERE account = ?1 AND timestamp >= ?2 AND value < 0 GROUP BY t.address ORDER BY v ASC LIMIT 5",
|
||||||
"SELECT a.id_account, a.name, a.balance FROM accounts2 a",
|
[accountId, range.start ~/ 1000]);
|
||||||
[]);
|
final spendings = res.map((row) {
|
||||||
for (var r in res) {
|
final address = row['address'] ?? "";
|
||||||
final int id = r['id_account'];
|
final value = -row['v'] / ZECUNIT;
|
||||||
final account = Account(
|
final contact = row['name'];
|
||||||
coin,
|
return Spending(address, value, contact);
|
||||||
id,
|
}).toList();
|
||||||
r['name'],
|
|
||||||
r['balance'],
|
|
||||||
0,
|
"SELECT timestamp, price FROM historical_prices WHERE timestamp >= ?2 AND currency = ?1",
|
||||||
null);
|
|
||||||
accounts.add(account);
|
|
||||||
}
|
|
||||||
return accounts;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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(
|
final List<Map> res1 = await db.rawQuery(
|
||||||
"SELECT 1 FROM accounts WHERE id_account = ?1", [id]);
|
"SELECT timestamp, value FROM transactions WHERE timestamp >= ?2 AND account = ?1",
|
||||||
if (res1.isNotEmpty)
|
[accountId, range.start ~/ 1000]);
|
||||||
return AccountId(coin, id);
|
|
||||||
final List<Map> res2 = await db.rawQuery(
|
|
||||||
"SELECT id_account FROM accounts", []);
|
List<Map> res = await db.rawQuery(
|
||||||
if (res2.isNotEmpty) {
|
"SELECT id, name, address FROM contacts WHERE address <> '' ORDER BY name");
|
||||||
final id = res2[0]['id_account'];
|
for (var c in res) {
|
||||||
return AccountId(coin, id);
|
final contact = Contact(c['id'], c['name'], c['address']);
|
||||||
}
|
contacts.add(contact);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String> getTAddr() async {
|
|
||||||
final List<Map> res1 = await db.rawQuery(
|
Future<int?> getPrevMessage(String subject, int height, int account) async {
|
||||||
"SELECT address FROM taddrs WHERE account = ?1", [id]);
|
final id = await Sqflite.firstIntValue(await db.rawQuery(
|
||||||
final taddress = res1.isNotEmpty ? res1[0]['address'] : "";
|
"SELECT MAX(id) FROM messages WHERE subject = ?1 AND height < ?2 and account = ?3",
|
||||||
return taddress;
|
[subject, height, account]));
|
||||||
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<String?> getSK() async {
|
Future<int?> getNextMessage(String subject, int height, int account) async {
|
||||||
final List<Map> res1 = await db.rawQuery(
|
final id = await Sqflite.firstIntValue(await db.rawQuery(
|
||||||
"SELECT sk FROM accounts WHERE id_account = ?1", [id]);
|
"SELECT MIN(id) FROM messages WHERE subject = ?1 AND height > ?2 and account = ?3",
|
||||||
final sk = res1.isNotEmpty ? res1[0]['address'] : null;
|
[subject, height, account]));
|
||||||
return sk;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> changeAccountName(String name) async {
|
|
||||||
await db.execute("UPDATE accounts SET name = ?2 WHERE id_account = ?1",
|
final id = row['id'];
|
||||||
[id, name]);
|
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;
|
// mod wallet;
|
||||||
/// accounts, sync, payments, etc.
|
/// accounts, sync, payments, etc.
|
||||||
pub mod api;
|
pub mod api;
|
||||||
pub mod template;
|
|
||||||
|
|
||||||
#[cfg(feature = "ledger")]
|
#[cfg(feature = "ledger")]
|
||||||
mod 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