Skip to main content

ant_act/
act.rs

1use autonomi::{
2    client::payment::PaymentOption, Bytes, Chunk, ChunkAddress, Client, GraphEntry,
3    GraphEntryAddress, PublicKey, SecretKey, XorName,
4};
5use futures::{future::Future, stream, StreamExt};
6use ruint::aliases::U256;
7use serde::{Deserialize, Serialize};
8
9#[derive(Clone, Debug, Serialize, Deserialize)]
10pub struct TokenInfo {
11    pub symbol: String,
12    pub name: String,
13    pub decimals: u8,
14}
15
16pub trait ActExt {
17    fn act_create(
18        &self,
19        name: String,
20        symbol: String,
21        decimals: u8,
22        total_supply: U256,
23        issuer_key: PublicKey,
24        payment: &PaymentOption,
25    ) -> impl Future<Output = Result<(PublicKey, XorName), String>> + Send;
26
27    fn act_unspent(
28        &self,
29        pubkey: &PublicKey,
30        spend: PublicKey,
31    ) -> impl Future<Output = Result<(XorName, U256), String>> + Send;
32
33    fn act_balance(
34        &self,
35        pubkey: &PublicKey,
36        spends: Vec<PublicKey>,
37    ) -> impl Future<Output = Result<U256, String>> + Send;
38
39    fn act_token_info(
40        &self,
41        token_id: &XorName,
42    ) -> impl Future<Output = Result<TokenInfo, String>> + Send;
43}
44
45impl ActExt for Client {
46    async fn act_create(
47        &self,
48        name: String,
49        symbol: String,
50        decimals: u8,
51        total_supply: U256,
52        to: PublicKey,
53        payment: &PaymentOption,
54    ) -> Result<(PublicKey, XorName), String> {
55        // create token info chunk
56        let token_info_bytes = Bytes::from(
57            serde_json::to_string(&TokenInfo {
58                name,
59                symbol,
60                decimals,
61            })
62            .map_err(|e| format!("{}", e))?,
63        );
64
65        let token_info = Chunk::new(token_info_bytes.clone());
66        let (_paid, token_info_address) = self
67            .chunk_put(&token_info, payment.clone())
68            .await
69            .map_err(|e| format!("{}", e))?;
70
71        println!("TokenInfo Chunk: {}", token_info_address);
72
73        let token_id = token_info_address.xorname();
74        println!("TokenId: {}", token_id);
75
76        let genesis_owner = SecretKey::random();
77        println!("Genesis owner: {:?}", genesis_owner);
78
79        let genesis_owner_pubkey = genesis_owner.public_key();
80        let genesis = GraphEntry::new(
81            &genesis_owner,
82            vec![],
83            token_id.0.clone(),
84            vec![(to, total_supply.to_be_bytes())], // all output to issuer
85        );
86        let (_paid, genesis_address) = self
87            .graph_entry_put(genesis, payment.clone())
88            .await
89            .map_err(|e| format!("{}", e))?;
90
91        println!("Genesis GraphEntry: {}", genesis_address);
92        let genesis_spend = *genesis_address.owner();
93
94        assert_eq!(genesis_owner_pubkey, genesis_spend);
95
96        Ok((genesis_spend, *token_id))
97    }
98
99    async fn act_unspent(
100        &self,
101        output: &PublicKey,
102        spend: PublicKey,
103    ) -> Result<(XorName, U256), String> {
104        let tx = self
105            .graph_entry_get(&GraphEntryAddress::new(spend))
106            .await
107            .map_err(|e| format!("{}", e))?;
108
109        let (balance, overflow) = tx
110            .descendants
111            .iter()
112            .filter(|(pk, _data)| pk == output)
113            .map(|(_pk, data)| U256::from_be_bytes(*data))
114            .fold((U256::ZERO, false), |(sum, any_overflow), n| {
115                let (added, this_overflow) = sum.overflowing_add(n);
116                (added, any_overflow || this_overflow)
117            });
118
119        match overflow {
120            false => Ok((XorName(tx.content), balance)),
121            true => Err("Overflow.".into()),
122        }
123    }
124
125    async fn act_balance(
126        &self,
127        pubkey: &PublicKey,
128        spends: Vec<PublicKey>,
129    ) -> Result<U256, String> {
130        let stream = stream::iter(spends);
131
132        stream
133            .fold(Ok(U256::ZERO), |sum_res, spend_pk| async move {
134                let (_token_id, unsp) = self.act_unspent(pubkey, spend_pk).await?;
135
136                match sum_res?.overflowing_add(unsp) {
137                    (added, false) => Ok(added),
138                    (_, true) => Err("Overflow.".into()),
139                }
140            })
141            .await
142    }
143
144    async fn act_token_info(&self, token_id: &XorName) -> Result<TokenInfo, String> {
145        let token_info_address = ChunkAddress::new(*token_id);
146
147        let chunk = self
148            .chunk_get(&token_info_address)
149            .await
150            .map_err(|e| format!("{}", e))?;
151
152        let token_info: TokenInfo =
153            serde_json::from_slice(chunk.value()).map_err(|e| format!("{}", e))?;
154
155        Ok(token_info)
156    }
157
158    //	/// Returns rest amount
159    //	pub async fn act_spend(from: PublicKey, from_spends: Vec<PublicKey>, amount: U256, to: PublicKey, rest_to: PublicKey) -> Result<U256, String> {
160    //
161    //	}
162}