use serde::{Deserialize, Serialize};
use crate::account::Account;
use crate::crypto::{Address, MultisigSignature, Signature};
use crate::{Error, HashDigest, MicroAlgos, Round, VotePK, VRFPK};
const MIN_TXN_FEE: MicroAlgos = MicroAlgos(1000);
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct BaseTransaction {
pub sender: Address,
pub first_valid: Round,
pub last_valid: Round,
pub note: Vec<u8>,
pub genesis_id: String,
pub genesis_hash: HashDigest,
}
#[derive(Debug, Clone, Eq, PartialEq, Deserialize)]
pub struct Transaction {
#[serde(rename = "snd")]
pub sender: Address,
#[serde(rename = "fee")]
pub fee: MicroAlgos,
#[serde(rename = "fv")]
pub first_valid: Round,
#[serde(rename = "lv")]
pub last_valid: Round,
#[serde(with = "serde_bytes", default)]
pub note: Vec<u8>,
#[serde(rename = "gen", default)]
pub genesis_id: String,
#[serde(rename = "gh")]
pub genesis_hash: HashDigest,
#[serde(flatten)]
pub txn_type: TransactionType,
}
#[derive(Debug, Clone, Eq, PartialEq, Deserialize)]
#[serde(tag = "type")]
pub enum TransactionType {
#[serde(rename = "pay")]
Payment(Payment),
#[serde(rename = "keyreg")]
KeyRegistration(KeyRegistration),
}
#[derive(Debug, Clone, Eq, PartialEq, Deserialize)]
pub struct Payment {
#[serde(rename = "amt", default)]
pub amount: MicroAlgos,
#[serde(rename = "rcv")]
pub receiver: Address,
#[serde(rename = "close")]
pub close_remainder_to: Option<Address>,
}
#[derive(Debug, Clone, Eq, PartialEq, Deserialize)]
pub struct KeyRegistration {
#[serde(rename = "votekey")]
pub vote_pk: VotePK,
#[serde(rename = "selkey")]
pub selection_pk: VRFPK,
#[serde(rename = "votefst")]
pub vote_first: Round,
#[serde(rename = "votelst")]
pub vote_last: Round,
#[serde(rename = "votekd")]
pub vote_key_dilution: u64,
}
impl Transaction {
pub fn new(
base: BaseTransaction,
fee_per_byte: MicroAlgos,
txn_type: TransactionType,
) -> Result<Transaction, Error> {
let mut transaction = Transaction {
sender: base.sender,
fee: MicroAlgos(0),
first_valid: base.first_valid,
last_valid: base.last_valid,
note: base.note,
genesis_id: base.genesis_id,
genesis_hash: base.genesis_hash,
txn_type,
};
transaction.fee = MIN_TXN_FEE.max(fee_per_byte * transaction.estimate_size()?);
Ok(transaction)
}
pub fn new_flat_fee(
base: BaseTransaction,
fee: MicroAlgos,
txn_type: TransactionType,
) -> Transaction {
Transaction {
sender: base.sender,
fee,
first_valid: base.first_valid,
last_valid: base.last_valid,
note: base.note,
genesis_id: base.genesis_id,
genesis_hash: base.genesis_hash,
txn_type,
}
}
fn estimate_size(&self) -> Result<u64, Error> {
let account = Account::generate();
let len = rmp_serde::to_vec_named(&account.sign_transaction(self)?)?.len() as u64;
Ok(len)
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub struct SignedTransaction {
#[serde(rename = "msig", skip_serializing_if = "Option::is_none")]
pub multisig: Option<MultisigSignature>,
#[serde(skip_serializing_if = "Option::is_none")]
pub sig: Option<Signature>,
#[serde(rename = "txn")]
pub transaction: Transaction,
#[serde(skip)]
pub transaction_id: String,
}