use std::borrow::Cow;
use std::fmt::{Debug, Display, Formatter};
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use serde_aux::prelude::*;
use tonlib_core::types::{TonHashParseError, TON_HASH_LEN};
use tonlib_core::{TonHash, TonTxId};
use super::TonLibraryId;
use crate::tl::stack::{TvmCell, TvmStack};
use crate::tl::Base64Standard;
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[serde(tag = "@type")]
pub enum KeyStoreType {
#[serde(rename = "keyStoreTypeDirectory")]
Directory { directory: String },
#[serde(rename = "keyStoreTypeInMemory")]
InMemory,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct Config {
pub config: String,
pub blockchain_name: Option<String>,
pub use_callbacks_for_network: bool,
pub ignore_cache: bool,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct Options {
pub config: Config,
pub keystore_type: KeyStoreType,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[serde(tag = "@type", rename = "options.configInfo")]
pub struct OptionsConfigInfo {
pub default_wallet_id: String,
pub default_rwallet_init_public_key: String,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct OptionsInfo {
pub config_info: OptionsConfigInfo,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct AccountAddress {
pub account_address: String,
}
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
pub struct InternalTransactionId {
#[serde(deserialize_with = "deserialize_number_from_string")]
pub lt: i64,
#[serde(with = "Base64Standard")]
pub hash: Vec<u8>,
}
lazy_static! {
pub static ref NULL_TRANSACTION_ID: InternalTransactionId = InternalTransactionId {
lt: 0i64,
hash: vec![0u8; 32]
};
}
impl InternalTransactionId {
pub fn hash_string(&self) -> String {
hex::encode(self.hash.as_slice())
}
pub fn to_formatted_string(&self) -> String {
format!("{}:{}", self.lt, self.hash_string())
}
}
impl From<TonTxId> for InternalTransactionId {
fn from(value: TonTxId) -> Self {
InternalTransactionId {
lt: value.lt,
hash: value.hash.to_vec(),
}
}
}
impl TryFrom<InternalTransactionId> for TonTxId {
type Error = TonHashParseError;
fn try_from(value: InternalTransactionId) -> Result<Self, Self::Error> {
let ton_tx_id = TonTxId {
lt: value.lt,
hash: TonHash::try_from(value.hash)?,
};
Ok(ton_tx_id)
}
}
impl Display for InternalTransactionId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(self.to_formatted_string().as_str())
}
}
impl Debug for InternalTransactionId {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str(self.to_formatted_string().as_str())
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct BlockId {
pub workchain: i32,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub shard: i64,
pub seqno: i32,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct BlockIdExt {
pub workchain: i32,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub shard: i64,
pub seqno: i32,
#[serde(with = "Base64Standard")]
pub root_hash: Vec<u8>,
#[serde(with = "Base64Standard")]
pub file_hash: Vec<u8>,
}
impl BlockIdExt {
pub fn to_block_id(&self) -> BlockId {
BlockId {
workchain: self.workchain,
shard: self.shard,
seqno: self.seqno,
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct RawFullAccountState {
#[serde(deserialize_with = "deserialize_number_from_string")]
pub balance: i64,
#[serde(with = "Base64Standard")]
pub code: Vec<u8>,
#[serde(with = "Base64Standard")]
pub data: Vec<u8>,
pub last_transaction_id: InternalTransactionId,
pub block_id: BlockIdExt,
#[serde(with = "Base64Standard")]
pub frozen_hash: Vec<u8>,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub sync_utime: i64,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct RawMessage {
pub source: AccountAddress,
pub destination: AccountAddress,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub value: i64,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub fwd_fee: i64,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub ihr_fee: i64,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub created_lt: i64,
#[serde(with = "Base64Standard")]
pub body_hash: Vec<u8>,
pub msg_data: MsgData,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct RawTransaction {
pub address: AccountAddress,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub utime: i64,
#[serde(with = "Base64Standard")]
pub data: Vec<u8>,
pub transaction_id: InternalTransactionId,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub fee: i64,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub storage_fee: i64,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub other_fee: i64,
#[serde(skip_serializing_if = "Option::is_none")]
pub in_msg: Option<RawMessage>,
pub out_msgs: Vec<RawMessage>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct RawTransactions {
pub transactions: Vec<RawTransaction>,
pub previous_transaction_id: InternalTransactionId,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct RawExtMessageInfo {
#[serde(with = "Base64Standard")]
pub hash: Vec<u8>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct PChanConfig {
pub alice_public_key: String,
pub alice_address: AccountAddress,
pub bob_public_key: String,
pub bob_address: AccountAddress,
pub init_timeout: i32,
pub close_timeout: i32,
pub channel_id: i64,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct RWalletLimit {
pub seconds: i32,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub value: i64,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct RWalletConfig {
#[serde(deserialize_with = "deserialize_number_from_string")]
pub start_at: i64,
pub limits: Vec<RWalletLimit>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[serde(tag = "@type")]
pub enum AccountState {
#[serde(rename = "raw.accountState")]
Raw {
#[serde(with = "Base64Standard")]
code: Vec<u8>,
#[serde(with = "Base64Standard")]
data: Vec<u8>,
#[serde(with = "Base64Standard")]
frozen_hash: Vec<u8>,
},
#[serde(rename = "wallet.v3.accountState")]
WalletV3 {
#[serde(deserialize_with = "deserialize_number_from_string")]
wallet_id: i64,
seqno: i32,
},
#[serde(rename = "wallet.v4.accountState")]
WalletV4 {
#[serde(deserialize_with = "deserialize_number_from_string")]
wallet_id: i64,
seqno: i32,
},
#[serde(rename = "wallet.highload.v1.accountState")]
WalletHighloadV1 {
#[serde(deserialize_with = "deserialize_number_from_string")]
wallet_id: i64,
seqno: i32,
},
#[serde(rename = "wallet.highload.v2.accountState")]
WalletHighloadV2 {
#[serde(deserialize_with = "deserialize_number_from_string")]
wallet_id: i64,
},
#[serde(rename = "dns.accountState")]
DNS {
#[serde(deserialize_with = "deserialize_number_from_string")]
wallet_id: i64,
},
#[serde(rename = "rwallet.accountState")]
RWallet {
#[serde(deserialize_with = "deserialize_number_from_string")]
wallet_id: i64,
seqno: i32,
#[serde(deserialize_with = "deserialize_number_from_string")]
unlocked_balance: i64,
config: RWalletConfig,
},
#[serde(rename = "uninited.accountState")]
Uninited {
#[serde(with = "Base64Standard")]
frozen_hash: Vec<u8>,
},
#[serde(rename = "pchan.accountState")]
PChan {
config: PChanConfig,
state: PChanState,
description: String,
},
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[serde(tag = "@type")]
pub enum PChanState {
#[serde(rename = "pchan.stateInit")]
Init {
#[serde(rename = "signed_A")]
signed_a: bool,
#[serde(rename = "signed_B")]
signed_b: bool,
#[serde(rename = "min_A")]
min_a: i64,
#[serde(rename = "min_B")]
min_b: i64,
expire_at: i64,
#[serde(rename = "A")]
a: i64,
#[serde(rename = "B")]
b: i64,
},
#[serde(rename = "pchan.stateClose")]
Close {
#[serde(rename = "signed_A")]
signed_a: bool,
#[serde(rename = "signed_B")]
signed_b: bool,
#[serde(rename = "min_A")]
min_a: i64,
#[serde(rename = "min_B")]
min_b: i64,
expire_at: i64,
#[serde(rename = "A")]
a: i64,
#[serde(rename = "B")]
b: i64,
},
#[serde(rename = "pchan.statePayout")]
Payout {
#[serde(rename = "A")]
a: i64,
#[serde(rename = "B")]
b: i64,
},
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct FullAccountState {
pub address: AccountAddress,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub balance: i64,
pub last_transaction_id: InternalTransactionId,
pub block_id: BlockIdExt,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub sync_utime: i64,
pub account_state: AccountState,
pub revision: i32,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[serde(tag = "@type")]
pub enum SyncState {
#[serde(rename = "syncStateDone")]
Done,
#[serde(rename = "syncStateInProgress")]
InProgress {
from_seqno: i32,
to_seqno: i32,
current_seqno: i32,
},
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[serde(tag = "@type")]
pub enum MsgData {
#[serde(rename = "msg.dataRaw")]
Raw {
#[serde(with = "Base64Standard")]
body: Vec<u8>,
#[serde(with = "Base64Standard")]
init_state: Vec<u8>,
},
#[serde(rename = "msg.dataText")]
Text {
#[serde(with = "Base64Standard")]
text: Vec<u8>,
},
#[serde(rename = "msg.dataDecryptedText")]
DecryptedText {
#[serde(with = "Base64Standard")]
text: Vec<u8>,
},
#[serde(rename = "msg.dataEncryptedText")]
EncryptedText {
#[serde(with = "Base64Standard")]
text: Vec<u8>,
},
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct SmcInfo {
#[serde(deserialize_with = "deserialize_number_from_string")]
pub id: i64,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[serde(tag = "@type")]
pub enum SmcMethodId {
#[serde(rename = "smc.methodIdNumber")]
Number { number: i32 },
#[serde(rename = "smc.methodIdName")]
Name { name: Cow<'static, str> },
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct SmcRunResult {
pub gas_used: i64,
pub stack: TvmStack,
pub exit_code: i32,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct SmcLibraryEntry {
#[serde(with = "Base64Standard")]
pub hash: Vec<u8>,
#[serde(with = "Base64Standard")]
pub data: Vec<u8>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct SmcLibraryResult {
pub result: Vec<SmcLibraryEntry>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
#[serde(tag = "@type", rename_all = "camelCase")]
pub enum SmcLibraryQueryExt {
#[serde(rename = "smc.libraryQueryExt.one")]
One { hash: [u8; TON_HASH_LEN] },
#[serde(rename = "smc.libraryQueryExt.scanBoc")]
ScanBoc {
#[serde(with = "Base64Standard")]
boc: Vec<u8>,
max_libs: i32,
},
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct SmcLibraryResultExt {
#[serde(with = "Base64Standard")]
pub dict_boc: Vec<u8>,
pub libs_ok: Vec<TonLibraryId>,
pub libs_not_found: Vec<TonLibraryId>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct UpdateSyncState {
pub sync_state: SyncState,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct LogVerbosityLevel {
pub verbosity_level: u32,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct LiteServerInfo {
#[serde(deserialize_with = "deserialize_number_from_string")]
pub now: i64,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub version: i32,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub capabilities: i64,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct BlocksMasterchainInfo {
pub last: BlockIdExt,
#[serde(with = "Base64Standard")]
pub state_root_hash: Vec<u8>,
pub init: BlockIdExt,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct BlocksShards {
pub shards: Vec<BlockIdExt>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct BlocksAccountTransactionId {
#[serde(with = "Base64Standard")]
pub account: Vec<u8>,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub lt: i64,
}
lazy_static! {
pub static ref NULL_BLOCKS_ACCOUNT_TRANSACTION_ID: BlocksAccountTransactionId =
BlocksAccountTransactionId {
account: vec![0u8; 32],
lt: 0i64,
};
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct BlocksShortTxId {
pub mode: u32,
#[serde(with = "Base64Standard")]
pub account: Vec<u8>,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub lt: i64,
#[serde(with = "Base64Standard")]
pub hash: Vec<u8>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct BlocksTransactions {
pub id: BlockIdExt,
pub req_count: i32,
pub incomplete: bool,
pub transactions: Vec<BlocksShortTxId>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct BlocksTransactionsExt {
pub id: BlockIdExt,
pub req_count: i32,
pub incomplete: bool,
pub transactions: Vec<RawTransaction>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct BlocksHeader {
pub id: BlockIdExt,
pub global_id: i32,
pub version: i32,
pub flags: i32,
pub after_merge: bool,
pub after_split: bool,
pub before_split: bool,
pub want_merge: bool,
pub want_split: bool,
pub validator_list_hash_short: i32,
pub catchain_seqno: i32,
pub min_ref_mc_seqno: i32,
pub is_key_block: bool,
pub prev_key_block_seqno: i32,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub start_lt: i64,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub end_lt: i64,
#[serde(deserialize_with = "deserialize_number_from_string")]
pub gen_utime: i64,
pub vert_seqno: Option<i32>,
pub prev_blocks: Option<Vec<BlockIdExt>>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash)]
pub struct ConfigInfo {
pub config: TvmCell,
}
#[cfg(test)]
mod tests {
use std::borrow::Cow;
use tokio_test::assert_err;
use tonlib_core::{TonTxId, TransactionIdParseError};
use crate::tl::SmcMethodId;
#[test]
fn internal_transaction_id_parse_format_works() -> anyhow::Result<()> {
let id_str =
"33256211000003:b98dfa033a963f3bb9985f173ef2c6c9449be78a043ec1fc5965fe24a6d615a3";
let tx_id: TonTxId = id_str.parse()?;
assert_eq!(tx_id.lt, 33256211000003);
assert_eq!(
tx_id.hash_string(),
"b98dfa033a963f3bb9985f173ef2c6c9449be78a043ec1fc5965fe24a6d615a3"
);
let res = format!("{}", tx_id);
assert_eq!(res, id_str);
Ok(())
}
#[test]
fn internal_transaction_id_parse_base64_works() -> anyhow::Result<()> {
let id_str = "33256211000003:uY36AzqWPzu5mF8XPvLGyUSb54oEPsH8WWX+JKbWFaM=";
let tx_id: TonTxId = id_str.parse()?;
assert_eq!(tx_id.lt, 33256211000003);
assert_eq!(
tx_id.hash_string(),
"b98dfa033a963f3bb9985f173ef2c6c9449be78a043ec1fc5965fe24a6d615a3"
);
Ok(())
}
#[test]
fn internal_transaction_id_parse_base64_no_pad_works() -> anyhow::Result<()> {
let id_str = "33256211000003:uY36AzqWPzu5mF8XPvLGyUSb54oEPsH8WWX+JKbWFaM";
let tx_id: TonTxId = id_str.parse()?;
assert_eq!(tx_id.lt, 33256211000003);
assert_eq!(
tx_id.hash_string(),
"b98dfa033a963f3bb9985f173ef2c6c9449be78a043ec1fc5965fe24a6d615a3"
);
Ok(())
}
#[test]
fn internal_transaction_id_parse_err_works() -> anyhow::Result<()> {
let r: Result<TonTxId, TransactionIdParseError> =
"33256211000003:uY36AzqWPzu5mF8XPvLGyUSb54oEPsH8WWX+JKbWFa".parse(); assert_err!(r);
let r: Result<TonTxId, TransactionIdParseError> =
"33256211000003::uY36AzqWPzu5mF8XPvLGyUSb54oEPsH8WWX+JKbWFaM".parse(); assert_err!(r);
let r: Result<TonTxId, TransactionIdParseError> =
"33256211000003uY36AzqWPzu5mF8XPvLGyUSb54oEPsH8WWX+JKbWFaM".parse(); assert_err!(r);
let r: Result<TonTxId, TransactionIdParseError> =
"33256211000003:uY36AzqWPzu5mF8XPvLGyUSb54oEPsH8WWX+JKbWFaMZ".parse(); assert_err!(r);
let r: Result<TonTxId, TransactionIdParseError> =
"33256211000003:uY36AzqWPzu5mF8XPvLGyUSb54oEPsH8WWX+JKbWFaM ".parse(); assert_err!(r);
let r: Result<TonTxId, TransactionIdParseError> =
"z33256211000003:uY36AzqWPzu5mF8XPvLGyUSb54oEPsH8WWX+JKbWFaM".parse(); assert_err!(r);
let r: Result<TonTxId, TransactionIdParseError> =
"33256211000003:b98dfa033a963f3bb9985f173ef2c6c9449be78a043ec1fc5965fe24a6d615a3B4" .parse();
assert_err!(r);
let r: Result<TonTxId, TransactionIdParseError> =
"33256211000003:b98dfa033a963f3bb9985f173ef2c6c9449be78a043ec1fc5965fe24a6d615".parse(); assert_err!(r);
let r: Result<TonTxId, TransactionIdParseError> =
"33256211000003:b98dfa033a963f3bb9985f173ef2c6c9449be78a043ec1fc5965fe24a6d615a3 " .parse();
assert_err!(r);
Ok(())
}
#[test]
fn test_smc_method_id_serde() -> anyhow::Result<()> {
let method_name = "get_jetton_data";
let method_id = SmcMethodId::Name {
name: Cow::Borrowed(method_name),
};
let json = serde_json::to_string(&method_id)?;
let result: SmcMethodId = serde_json::from_str(json.as_str())?;
assert_eq!(method_id, result);
Ok(())
}
}