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]);