pub mod mnemonic;
mod signer;
pub mod v4r2;
pub mod v5r1;
mod version;
pub use self::{signer::*, version::*};
use core::marker::PhantomData;
use std::sync::Arc;
use chrono::{DateTime, Utc};
use num_bigint::BigUint;
use tlb_ton::{
Cell, MsgAddress,
action::SendMsgAction,
message::{CommonMsgInfo, ExternalInMsgInfo, Message},
ser::{CellBuilderError, CellSerializeExt},
state_init::StateInit,
};
pub struct Wallet<V> {
address: MsgAddress,
wallet_id: u32,
keypair: KeyPair,
_phantom: PhantomData<V>,
}
impl<V> Wallet<V>
where
V: WalletVersion,
{
#[inline]
pub const fn new(address: MsgAddress, keypair: KeyPair, wallet_id: u32) -> Self {
Self {
address,
wallet_id,
keypair,
_phantom: PhantomData,
}
}
#[inline]
pub fn derive(
workchain_id: i32,
keypair: KeyPair,
wallet_id: u32,
) -> Result<Self, CellBuilderError> {
Ok(Self::new(
MsgAddress::derive(workchain_id, V::state_init(wallet_id, keypair.public_key))?,
keypair,
wallet_id,
))
}
#[inline]
pub fn derive_default(keypair: KeyPair) -> Result<Self, CellBuilderError> {
Self::derive(0, keypair, V::DEFAULT_WALLET_ID)
}
#[inline]
pub const fn address(&self) -> MsgAddress {
self.address
}
#[inline]
pub const fn wallet_id(&self) -> u32 {
self.wallet_id
}
#[inline]
pub const fn public_key(&self) -> &[u8; PUBLIC_KEY_LENGTH] {
&self.keypair.public_key
}
#[inline]
pub fn create_sign_body(
&self,
expire_at: DateTime<Utc>,
seqno: u32,
msgs: impl IntoIterator<Item = SendMsgAction>,
) -> V::SignBody {
V::create_sign_body(self.wallet_id, expire_at, seqno, msgs)
}
#[inline]
pub fn sign(&self, msg: impl AsRef<[u8]>) -> anyhow::Result<[u8; 64]> {
self.keypair.sign(msg)
}
#[inline]
pub fn create_external_message(
&self,
expire_at: DateTime<Utc>,
seqno: u32,
msgs: impl IntoIterator<Item = SendMsgAction>,
state_init: bool,
) -> anyhow::Result<Message<V::ExternalMsgBody, Arc<Cell>, V::Data>> {
let sign_body = self.create_sign_body(expire_at, seqno, msgs);
let signature = self.sign_body(&sign_body)?;
let body = V::wrap_signed_external(sign_body, signature);
let wrapped = self.wrap_external_msg(body, state_init);
Ok(wrapped)
}
#[inline]
pub fn sign_body(&self, msg: &V::SignBody) -> anyhow::Result<[u8; 64]> {
self.sign(msg.to_cell()?.hash())
}
#[inline]
pub fn wrap_external_msg(
&self,
body: V::ExternalMsgBody,
state_init: bool,
) -> Message<V::ExternalMsgBody, Arc<Cell>, V::Data> {
Message {
info: CommonMsgInfo::ExternalIn(ExternalInMsgInfo {
src: MsgAddress::NULL,
dst: self.address(),
import_fee: BigUint::ZERO,
}),
init: state_init.then(|| self.state_init()),
body,
}
}
#[inline]
pub fn state_init(&self) -> StateInit<Arc<Cell>, V::Data> {
V::state_init(self.wallet_id(), *self.public_key())
}
}