versatus_rust/versatus_rust.rs
1use anyhow::Result;
2use ethnum::U256;
3use serde_derive::{Deserialize, Serialize};
4use serde_hex::{SerHex, StrictPfx};
5use std::io::{self, Read, Write};
6
7/// This trait will generally be implemented by all Smart Contracts, as it gives us a way to make
8/// all of the contract's inputs available to the contract itself.
9pub trait SmartContract {
10 /// A function to receive contract inputs. If the contract doesn't do anything with inputs,
11 /// this can be empty. It can also do validation on the inputs and return an error if there is
12 /// a problem with the input data provided. In general, smart contracts will likely want to
13 /// stash this somewhere in &self for use in smart contract functions.
14 fn receive_inputs(&mut self, inputs: &mut SmartContractInputs) -> Result<()>;
15}
16
17/// SmartContractInputs represents the entire bundle of inputs sent into a Versatus smart contract.
18/// It is a collection of input data from a variety of locations, including the contract caller,
19/// and the protocol accounts database.
20#[derive(Debug, Serialize, Deserialize, Clone)]
21#[serde(rename_all = "camelCase")]
22pub struct SmartContractInputs {
23 /// Version of the compute stack and API/ABI
24 pub version: i32,
25 /// Account info as provided by the protocol
26 pub account_info: AccountInfo,
27 /// Protocol inputs as provided by the protocol
28 pub protocol_input: ProtocolInputs,
29 /// Application inputs as provided by the application via the protocol
30 pub contract_input: ContractInputs,
31}
32
33impl SmartContractInputs {
34 /// Read JSON data on stdin and deserialise it to a set of Rust data structures.
35 pub fn gather() -> Result<Self> {
36 let mut json_data: Vec<u8> = vec![];
37 let _num_bytes = io::stdin().read_to_end(&mut json_data)?;
38 Ok(serde_json::from_slice(&json_data)?)
39 }
40
41 /// Returns a copy of the associated account information
42 pub fn account_info(&self) -> AccountInfo {
43 self.account_info.clone()
44 }
45
46 /// Returns the address of the associated account
47 pub fn account_addr(&self) -> Address {
48 self.account_info.account_address.clone()
49 }
50}
51
52/// ContractInputs is a structure representing the inputs to a smart contract and generally equates
53/// to what the Versatus protocol would receive on a public RPC request to execute a contract.
54#[derive(Debug, Serialize, Deserialize, Clone)]
55#[serde(rename_all = "camelCase")]
56pub struct ContractInputs {
57 /// A string representing a function within the contract to call. This allows
58 /// a single WASM binary to provide multiple functionalities. The idea would
59 /// be that a main() function in the contract could switch between them based
60 /// on a comparison with this value.
61 pub contract_fn: String,
62 /// Inputs passed from the caller to pass into the contract function.
63 pub function_inputs: FunctionInputs,
64}
65
66/// ProtocolInputs represents inputs provided from the protocol that may be useful in smart
67/// contracts.
68#[derive(Debug, Serialize, Deserialize, Clone)]
69#[serde(rename_all = "camelCase")]
70pub struct ProtocolInputs {
71 /// An internal version number for the protocol at this point in time
72 pub version: i32,
73 /// The block number/height of the block currently being processed
74 pub block_height: u64,
75 /// The timestamp of the block currently being processed
76 pub block_time: u64,
77}
78
79/// AccountInfo represents the state of the account calling the smart contract and is provided by
80/// the Versatus protocol.
81#[derive(Debug, Serialize, Deserialize, Clone)]
82#[serde(rename_all = "camelCase")]
83pub struct AccountInfo {
84 /// Address of the smart contract's blockchain account
85 pub account_address: Address,
86 /// Current balance of the smart contract's account at last block
87 pub account_balance: U256,
88}
89
90/// FunctionInputs represents the data provided by the contract caller to be used as inputs into
91/// the function being called within the smart contract.
92#[derive(Debug, Serialize, Deserialize, Clone)]
93#[serde(rename_all = "camelCase")]
94pub enum FunctionInputs {
95 Erc20(crate::eip20::Erc20Inputs),
96}
97
98/// A high-level struct representing the output of a smart contract.
99#[derive(Debug, Serialize, Deserialize, Clone)]
100#[serde(rename_all = "camelCase")]
101pub struct SmartContractOutputs {
102 pub result: Vec<ContractResult>,
103}
104
105/// A smart contract result. Will generally equate to one of a number of known contract types, such
106/// as ERC20 or ERC721.
107#[derive(Debug, Serialize, Deserialize, Clone)]
108#[serde(rename_all = "camelCase")]
109pub enum ContractResult {
110 Erc20(crate::eip20::Erc20Result),
111 Erc721(()),
112}
113
114impl SmartContractOutputs {
115 /// Writes smart contract output on stdout.
116 pub fn commit(&self) -> Result<()> {
117 Ok(io::stdout().write_all(serde_json::to_string(&self)?.as_bytes())?)
118 }
119}
120
121/// A structure to represent an address (a slice of 20 bytes)
122#[derive(Clone, Debug, Serialize, Deserialize)]
123pub struct Address(#[serde(with = "SerHex::<StrictPfx>")] pub [u8; 20]);