1use crate::versatus_rust::{
2 Address, ContractResult, FunctionInputs, SmartContract, SmartContractInputs,
3 SmartContractOutputs,
4};
5use anyhow::{anyhow, Result};
6use ethnum::U256;
7use serde_derive::{Deserialize, Serialize};
8
9#[derive(Debug, Serialize, Deserialize, Clone)]
11#[serde(rename_all = "camelCase")]
12pub enum Erc20Inputs {
13 Name(),
14 Symbol(),
15 Decimals(),
16 TotalSupply(),
17 BalanceOf {
18 address: Address,
19 },
20 Transfer {
21 address: Address,
22 value: U256,
23 },
24 TransferFrom {
25 from: Address,
26 to: Address,
27 value: U256,
28 },
29 Approve {
30 address: Address,
31 value: U256,
32 },
33 Allowance {
34 owner: Address,
35 spender: Address,
36 },
37}
38
39#[derive(Debug, Serialize, Deserialize, Clone)]
41#[serde(rename_all = "camelCase")]
42pub enum Erc20Result {
43 Name(String),
44 Symbol(String),
45 Decimals(u8),
46 TotalSupply(U256),
47 BalanceOf(U256),
48 Transfer(Erc20TransferEvent),
49 TransferFrom(Erc20TransferEvent),
50 Approve(Erc20ApprovalEvent),
51 Allowance(U256),
52}
53
54pub trait Erc20 {
56 fn name(&self) -> Result<String>;
58 fn symbol(&self) -> Result<String>;
60 fn decimals(&self) -> Result<u8>;
63 fn total_supply(&self) -> Result<U256>;
65 fn balance_of(&self, owner: Address) -> Result<U256>;
67 fn transfer(&self, to: Address, value: U256) -> Result<Erc20TransferEvent>;
70 fn transfer_from(&self, from: Address, to: Address, value: U256) -> Result<Erc20TransferEvent>;
79 fn approve(&self, spender: Address, value: U256) -> Result<Erc20ApprovalEvent>;
87 fn allowance(&self, owner: Address, spender: Address) -> Result<U256>;
89}
90
91#[derive(Debug, Serialize, Deserialize, Clone)]
93#[serde(rename_all = "camelCase")]
94pub struct Erc20TransferEvent {
95 pub from: Address,
96 pub to: Address,
97 pub value: U256,
98}
99
100#[derive(Debug, Serialize, Deserialize, Clone)]
102#[serde(rename_all = "camelCase")]
103pub struct Erc20ApprovalEvent {
104 pub owner: Address,
105 pub spender: Address,
106 pub value: U256,
107}
108
109pub fn process_erc20<T: Erc20 + SmartContract>(contract: &mut T) -> Result<()> {
110 let mut input = SmartContractInputs::gather()?;
112
113 contract.receive_inputs(&mut input)?;
115
116 let result: Erc20Result;
117
118 match input.contract_input.contract_fn.as_str() {
120 "allowance" => {
122 let owner: Address;
123 let spender: Address;
124 result = {
125 match input.contract_input.function_inputs {
126 FunctionInputs::Erc20(Erc20Inputs::Allowance {
127 owner: in_owner,
128 spender: in_spender,
129 }) => {
130 owner = in_owner;
131 spender = in_spender;
132 }
133 _ => return Err(anyhow!("Contract inputs don't match allowance function")),
134 }
135 Erc20Result::Allowance(contract.allowance(owner, spender)?)
136 }
137 }
138 "approve" => {
139 let spender: Address;
140 let value: U256;
141 result = {
142 match input.contract_input.function_inputs {
143 FunctionInputs::Erc20(Erc20Inputs::Approve {
144 address: in_spender,
145 value: in_value,
146 }) => {
147 spender = in_spender;
148 value = in_value;
149 }
150 _ => return Err(anyhow!("Contract inputs don't match approve function")),
151 }
152 Erc20Result::Approve(contract.approve(spender, value)?)
153 }
154 }
155 "balance_of" => {
156 let addr: Address;
157 result = {
158 match input.contract_input.function_inputs {
159 FunctionInputs::Erc20(Erc20Inputs::BalanceOf { address: in_addr }) => {
160 addr = in_addr;
161 }
162 _ => return Err(anyhow!("Contract inputs don't match balance_of function")),
163 }
164 Erc20Result::BalanceOf(contract.balance_of(addr)?)
165 }
166 }
167 "total_supply" => {
168 result = Erc20Result::TotalSupply(contract.total_supply()?);
169 }
170 "transfer" => {
171 let to: Address;
172 let value: U256;
173 result = {
174 match input.contract_input.function_inputs {
175 FunctionInputs::Erc20(Erc20Inputs::Transfer {
176 address: in_to,
177 value: in_value,
178 }) => {
179 to = in_to;
180 value = in_value;
181 }
182 _ => return Err(anyhow!("Contract inputs don't match transfer function")),
183 }
184 Erc20Result::Transfer(contract.transfer(to, value)?)
185 }
186 }
187 "transfer_from" => {
188 let from: Address;
189 let to: Address;
190 let value: U256;
191 result = {
192 match input.contract_input.function_inputs {
193 FunctionInputs::Erc20(Erc20Inputs::TransferFrom {
194 from: in_from,
195 to: in_to,
196 value: in_value,
197 }) => {
198 from = in_from;
199 to = in_to;
200 value = in_value;
201 }
202 _ => {
203 return Err(anyhow!(
204 "Contract inputs don't match transfer_from function"
205 ))
206 }
207 }
208 Erc20Result::TransferFrom(contract.transfer_from(from, to, value)?)
209 }
210 }
211 "name" => {
212 result = Erc20Result::Name(contract.name()?);
213 }
214 "symbol" => {
215 result = Erc20Result::Symbol(contract.symbol()?);
216 }
217 "decimals" => {
218 result = Erc20Result::Decimals(contract.decimals()?);
219 }
220 _ => {
221 return Err(anyhow!(
222 "Invalid contract function: {}",
223 &input.contract_input.contract_fn
224 ))
225 }
226 }
227
228 let output = SmartContractOutputs {
229 result: vec![ContractResult::Erc20(result)],
230 };
231
232 output.commit()?;
233 Ok(())
234}