Skip to main content

aleph_types/account/
mod.rs

1#[cfg(feature = "account-evm")]
2mod evm;
3#[cfg(feature = "account-sol")]
4mod solana;
5
6#[cfg(feature = "account-evm")]
7pub use evm::EvmAccount;
8#[cfg(feature = "account-sol")]
9pub use solana::SolanaAccount;
10
11use crate::chain::{Address, Chain, Signature};
12use crate::item_hash::ItemHash;
13use crate::message::MessageType;
14use crate::message::pending::PendingMessage;
15use crate::message::unsigned::UnsignedMessage;
16use thiserror::Error;
17
18#[derive(Debug, Error)]
19#[non_exhaustive]
20pub enum SignError {
21    #[error("signing failed: {0}")]
22    SigningFailed(String),
23}
24
25#[derive(Debug, Error)]
26#[non_exhaustive]
27pub enum AccountError {
28    #[error("chain {0} is not supported by this account type")]
29    UnsupportedChain(Chain),
30    #[error("invalid private key: {0}")]
31    InvalidKey(String),
32}
33
34pub trait Account: Send + Sync {
35    fn chain(&self) -> Chain;
36    fn address(&self) -> &Address;
37    fn sign_raw(&self, buffer: &[u8]) -> Result<Signature, SignError>;
38}
39
40pub fn verification_buffer(
41    chain: &Chain,
42    sender: &Address,
43    message_type: MessageType,
44    item_hash: &ItemHash,
45) -> String {
46    format!("{chain}\n{sender}\n{message_type}\n{item_hash}")
47}
48
49pub fn sign_message<A: Account>(
50    account: &A,
51    unsigned: UnsignedMessage,
52) -> Result<PendingMessage, SignError> {
53    let buffer = verification_buffer(
54        &account.chain(),
55        account.address(),
56        unsigned.message_type,
57        &unsigned.item_hash,
58    );
59    let signature = account.sign_raw(buffer.as_bytes())?;
60
61    Ok(PendingMessage {
62        chain: account.chain(),
63        sender: account.address().clone(),
64        signature,
65        message_type: unsigned.message_type,
66        item_type: unsigned.item_type,
67        item_content: unsigned.item_content,
68        item_hash: unsigned.item_hash,
69        time: unsigned.time,
70        channel: unsigned.channel,
71    })
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77    use crate::{address, item_hash};
78
79    #[test]
80    fn test_verification_buffer_format() {
81        let chain = Chain::Ethereum;
82        let sender = address!("0xB68B9D4f3771c246233823ed1D3Add451055F9Ef");
83        let message_type = MessageType::Post;
84        let hash = item_hash!("d281eb8a69ba1f4dda2d71aaf3ded06caa92edd690ef3d0632f41aa91167762c");
85
86        let buffer = verification_buffer(&chain, &sender, message_type, &hash);
87
88        assert_eq!(
89            buffer,
90            "ETH\n\
91             0xB68B9D4f3771c246233823ed1D3Add451055F9Ef\n\
92             POST\n\
93             d281eb8a69ba1f4dda2d71aaf3ded06caa92edd690ef3d0632f41aa91167762c"
94        );
95    }
96}