Browse Source

Generate Anchor IDL from Solidity contracts ⚓ (#1104)

* Generate IDL from Solidity contracts
* Deduplicate IDL types
* Add the program id of a contract to the metadata
Signed-off-by: Lucas Steuernagel <lucas.tnagel@gmail.com>
Lucas Steuernagel 2 years ago
parent
commit
0f66274c2c
39 changed files with 4375 additions and 2006 deletions
  1. 1 1
      Cargo.toml
  2. 502 0
      src/abi/anchor.rs
  3. 1 0
      src/abi/mod.rs
  4. 1506 0
      src/abi/tests.rs
  5. 2 0
      src/bin/idl/mod.rs
  6. 0 3
      src/sema/yul/tests/block.rs
  7. 0 3
      src/sema/yul/tests/switch.rs
  8. 106 40
      tests/borsh_encoding.rs
  9. 56 19
      tests/solana.rs
  10. 3 3
      tests/solana_tests/abi.rs
  11. 37 28
      tests/solana_tests/abi_decode.rs
  12. 67 63
      tests/solana_tests/abi_encode.rs
  13. 62 56
      tests/solana_tests/accessor.rs
  14. 22 18
      tests/solana_tests/account_info.rs
  15. 311 281
      tests/solana_tests/arrays.rs
  16. 77 74
      tests/solana_tests/balance.rs
  17. 64 57
      tests/solana_tests/builtin.rs
  18. 113 93
      tests/solana_tests/call.rs
  19. 8 8
      tests/solana_tests/constant.rs
  20. 48 53
      tests/solana_tests/create_contract.rs
  21. 22 10
      tests/solana_tests/destructure.rs
  22. 2 2
      tests/solana_tests/events.rs
  23. 60 52
      tests/solana_tests/expressions.rs
  24. 21 15
      tests/solana_tests/hash.rs
  25. 264 230
      tests/solana_tests/mappings.rs
  26. 53 47
      tests/solana_tests/math.rs
  27. 8 8
      tests/solana_tests/metas.rs
  28. 9 3
      tests/solana_tests/modifiers.rs
  29. 369 324
      tests/solana_tests/primitives.rs
  30. 42 39
      tests/solana_tests/rational.rs
  31. 32 32
      tests/solana_tests/returns.rs
  32. 34 28
      tests/solana_tests/signature_verify.rs
  33. 97 87
      tests/solana_tests/simple.rs
  34. 86 88
      tests/solana_tests/storage.rs
  35. 35 29
      tests/solana_tests/strings.rs
  36. 10 10
      tests/solana_tests/unused_variable_elimination.rs
  37. 2 2
      tests/solana_tests/using.rs
  38. 3 3
      tests/solana_tests/vector_to_slice.rs
  39. 240 197
      tests/solana_tests/yul.rs

+ 1 - 1
Cargo.toml

@@ -51,7 +51,7 @@ codespan-reporting = "0.11"
 phf = { version = "0.11", features = ["macros"] }
 rust-lapper = "1.0"
 bitflags = "1.3"
-anchor-syn = { version = "0.25", features = ["idl"] }
+anchor-syn = { version = "0.26", features = ["idl"] }
 convert_case = "0.6"
 parse-display = "0.6.0"
 parity-scale-codec = "3.1"

+ 502 - 0
src/abi/anchor.rs

@@ -1,7 +1,22 @@
 // SPDX-License-Identifier: Apache-2.0
 
+use crate::sema::ast::{
+    ArrayLength, Contract, Function, Mutability, Namespace, Parameter, StructDecl, StructType, Tag,
+    Type,
+};
+use anchor_syn::idl::{
+    Idl, IdlAccount, IdlAccountItem, IdlEnumVariant, IdlEvent, IdlEventField, IdlField,
+    IdlInstruction, IdlType, IdlTypeDefinition, IdlTypeDefinitionTy,
+};
+use base58::ToBase58;
+use num_traits::ToPrimitive;
+use semver::Version;
+use std::collections::{HashMap, HashSet};
+
 use convert_case::{Boundary, Case, Casing};
+use serde_json::json;
 use sha2::{Digest, Sha256};
+use solang_parser::pt::FunctionTy;
 
 /// Generate discriminator based on the name of the function. This is the 8 byte
 /// value anchor uses to dispatch function calls on. This should match
@@ -17,3 +32,490 @@ pub fn discriminator(namespace: &'static str, name: &str) -> Vec<u8> {
     hasher.update(format!("{}:{}", namespace, normalized));
     hasher.finalize()[..8].to_vec()
 }
+
+/// Generate an Anchor IDL for a Solidity contract.
+pub fn generate_anchor_idl(contract_no: usize, ns: &Namespace) -> Idl {
+    let contract = &ns.contracts[contract_no];
+    let docs = idl_docs(&contract.tags);
+    let mut type_manager = TypeManager::new(ns, contract_no);
+
+    let instructions = idl_instructions(contract_no, contract, &mut type_manager, ns);
+
+    let events = idl_events(contract, &mut type_manager, ns);
+
+    let metadata = contract
+        .program_id
+        .as_ref()
+        .map(|id| json!({"address": id.to_base58()}));
+
+    Idl {
+        version: Version::parse(env!("CARGO_PKG_VERSION"))
+            .unwrap()
+            .to_string(),
+        name: ns.contracts[contract_no].name.clone(),
+        docs,
+        constants: vec![],
+        instructions,
+        state: None,
+        accounts: vec![],
+        types: type_manager.generate_custom_idl_types(),
+        events,
+        errors: None,
+        metadata,
+    }
+}
+
+/// Generate IDL events for a contract.
+fn idl_events(
+    contract: &Contract,
+    type_manager: &mut TypeManager,
+    ns: &Namespace,
+) -> Option<Vec<IdlEvent>> {
+    if contract.emits_events.is_empty() {
+        None
+    } else {
+        let mut events: Vec<IdlEvent> = Vec::with_capacity(contract.emits_events.len());
+        for event_no in &contract.emits_events {
+            let def = &ns.events[*event_no];
+            let mut fields: Vec<IdlEventField> = Vec::with_capacity(def.fields.len());
+            let mut dedup = Deduplicate::new("field".to_owned());
+            for item in &def.fields {
+                let name = dedup.unique_name(item);
+                fields.push(IdlEventField {
+                    name,
+                    ty: type_manager.convert(&item.ty),
+                    index: item.indexed,
+                });
+            }
+
+            events.push(IdlEvent {
+                name: def.name.clone(),
+                fields,
+            });
+        }
+
+        Some(events)
+    }
+}
+
+/// Generate the IDL instructions for a contract.
+fn idl_instructions(
+    contract_no: usize,
+    contract: &Contract,
+    type_manager: &mut TypeManager,
+    ns: &Namespace,
+) -> Vec<IdlInstruction> {
+    let mut instructions: Vec<IdlInstruction> = Vec::new();
+
+    if !contract.have_constructor(ns) {
+        instructions.push(IdlInstruction {
+            name: "new".to_string(),
+            docs: None,
+            accounts: vec![IdlAccountItem::IdlAccount(IdlAccount {
+                name: "data_account".to_string(),
+                is_mut: true,
+                is_signer: false,
+                is_optional: Some(false),
+                docs: None,
+                pda: None,
+                relations: vec![],
+            })],
+            args: vec![],
+            returns: None,
+        })
+    }
+
+    for func_no in contract.all_functions.keys() {
+        if !ns.functions[*func_no].is_public()
+            || matches!(
+                ns.functions[*func_no].ty,
+                FunctionTy::Fallback | FunctionTy::Receive | FunctionTy::Modifier
+            )
+        {
+            continue;
+        }
+
+        let func = &ns.functions[*func_no];
+        let tags = idl_docs(&func.tags);
+
+        let accounts = match &func.mutability {
+            Mutability::Pure(_) => {
+                vec![]
+            }
+            Mutability::View(_) => {
+                vec![IdlAccountItem::IdlAccount(IdlAccount {
+                    name: "data_account".to_string(),
+                    is_mut: false,
+                    is_signer: false,
+                    is_optional: Some(false),
+                    docs: None,
+                    pda: None,
+                    relations: vec![],
+                })]
+            }
+            _ => {
+                vec![IdlAccountItem::IdlAccount(IdlAccount {
+                    name: "data_account".to_string(),
+                    is_mut: true,
+                    is_signer: false,
+                    is_optional: Some(false),
+                    docs: None,
+                    pda: None,
+                    relations: vec![],
+                })]
+            }
+        };
+
+        let mut args: Vec<IdlField> = Vec::with_capacity(func.params.len());
+        let mut dedup = Deduplicate::new("arg".to_owned());
+        for item in &*func.params {
+            let name = dedup.unique_name(item);
+
+            args.push(IdlField {
+                name,
+                docs: None,
+                ty: type_manager.convert(&item.ty),
+            });
+        }
+
+        let name = if func.is_constructor() {
+            "new".to_string()
+        } else if func.mangled_name_contracts.contains(&contract_no) {
+            func.mangled_name.clone()
+        } else {
+            func.name.clone()
+        };
+
+        let returns = if func.returns.is_empty() {
+            None
+        } else if func.returns.len() == 1 {
+            Some(type_manager.convert(&func.returns[0].ty))
+        } else {
+            Some(type_manager.build_struct_for_return(func, &name))
+        };
+
+        instructions.push(IdlInstruction {
+            name,
+            docs: tags,
+            accounts,
+            args,
+            returns,
+        });
+    }
+
+    instructions
+}
+
+/// This struct accounts all the user defined types used in the contract that need to be present
+/// in the IDL 'types' field.
+struct TypeManager<'a> {
+    namespace: &'a Namespace,
+    contract_no: usize,
+    added_types: HashSet<Type>,
+    /// This is a mapping between the IDL type and the tuple
+    /// (index into the types vector, is the type from the current contract?, original type name)
+    added_names: HashMap<String, (usize, Option<String>, String)>,
+    returns_structs: Vec<IdlTypeDefinition>,
+    types: Vec<IdlTypeDefinition>,
+}
+
+impl TypeManager<'_> {
+    fn new(ns: &Namespace, contract_no: usize) -> TypeManager {
+        TypeManager {
+            namespace: ns,
+            added_types: HashSet::new(),
+            added_names: HashMap::new(),
+            types: Vec::new(),
+            returns_structs: Vec::new(),
+            contract_no,
+        }
+    }
+
+    /// Functions with multiple returns must return a struct in Anchor, so we build a return
+    /// struct containing all the returned types.
+    fn build_struct_for_return(&mut self, func: &Function, effective_name: &String) -> IdlType {
+        let mut fields: Vec<IdlField> = Vec::with_capacity(func.returns.len());
+        let mut dedup = Deduplicate::new("return".to_owned());
+        for item in &*func.returns {
+            let name = dedup.unique_name(item);
+
+            fields.push(IdlField {
+                name,
+                docs: None,
+                ty: self.convert(&item.ty),
+            });
+        }
+
+        let name = format!("{}_returns", effective_name);
+        self.returns_structs.push(IdlTypeDefinition {
+            name: name.clone(),
+            docs: Some(vec![format!(
+                "Data structure to hold the multiple returns of function {}",
+                func.name
+            )]),
+            ty: IdlTypeDefinitionTy::Struct { fields },
+        });
+
+        IdlType::Defined(name)
+    }
+
+    /// This function creates an unique name for either a custom struct or enum.
+    fn unique_custom_type_name(&mut self, type_name: &String, contract: &Option<String>) -> String {
+        let (idx, other_contract, real_name) =
+            if let Some((idx, other_contract, real_name)) = self.added_names.get(type_name) {
+                (*idx, other_contract.clone(), real_name.clone())
+            } else {
+                return type_name.clone();
+            };
+
+        // If the existing type was declared outside a contract or if it is from the current contract,
+        // we should change the name of the type we are adding now.
+        if other_contract.is_none()
+            || other_contract.as_ref().unwrap() == &self.namespace.contracts[self.contract_no].name
+        {
+            let new_name = if let Some(this_name) = contract {
+                format!("{}_{}", this_name, type_name)
+            } else {
+                type_name.clone()
+            };
+            self.unique_string(new_name)
+        } else {
+            // If the type we are adding now belongs to the current contract, we change the name
+            // of a previously added IDL type
+            let new_other_name = if let Some(other_name) = &other_contract {
+                format!("{}_{}", other_name, real_name)
+            } else {
+                format!("_{}", real_name)
+            };
+            let unique_name = self.unique_string(new_other_name);
+            self.types[idx].name = unique_name.clone();
+            self.added_names
+                .insert(unique_name, (idx, other_contract, real_name));
+            type_name.clone()
+        }
+    }
+
+    /// Add a struct definition to the TypeManager
+    fn add_struct_definition(&mut self, def: &StructDecl, ty: &Type) {
+        if self.added_types.contains(ty) {
+            return;
+        }
+        self.added_types.insert(ty.clone());
+
+        let docs = idl_docs(&def.tags);
+
+        let mut fields: Vec<IdlField> = Vec::with_capacity(def.fields.len());
+        for item in &def.fields {
+            fields.push(IdlField {
+                name: item.name_as_str().to_string(),
+                docs: None,
+                ty: self.convert(&item.ty),
+            });
+        }
+
+        let name = self.unique_custom_type_name(&def.name, &def.contract);
+
+        self.added_names.insert(
+            name.clone(),
+            (self.types.len(), def.contract.clone(), def.name.clone()),
+        );
+
+        self.types.push(IdlTypeDefinition {
+            name,
+            docs,
+            ty: IdlTypeDefinitionTy::Struct { fields },
+        });
+    }
+
+    /// This function ensures there are no name collisions on the structs created for the functions
+    /// with multiple returns, before returning all the custom types needed for the IDL file.
+    fn generate_custom_idl_types(self) -> Vec<IdlTypeDefinition> {
+        let mut custom_types = self.types;
+        let mut used_names: HashSet<String> = custom_types
+            .iter()
+            .map(|e| e.name.clone())
+            .collect::<HashSet<String>>();
+
+        for item in self.returns_structs {
+            let mut value = 0;
+            let mut name = item.name.clone();
+            while used_names.contains(&name) {
+                value += 1;
+                name = format!("{}_{}", item.name, value);
+            }
+            used_names.insert(name.clone());
+            custom_types.push(IdlTypeDefinition {
+                name,
+                docs: item.docs,
+                ty: item.ty,
+            });
+        }
+
+        custom_types
+    }
+
+    /// Add an enum definition to the TypeManager
+    fn add_enum_definition(&mut self, enum_no: usize, ty: &Type) {
+        if self.added_types.contains(ty) {
+            return;
+        }
+        self.added_types.insert(ty.clone());
+        let def = &self.namespace.enums[enum_no];
+
+        let docs = idl_docs(&def.tags);
+
+        let name = self.unique_custom_type_name(&def.name, &def.contract);
+        self.added_names.insert(
+            name.clone(),
+            (self.types.len(), def.contract.clone(), def.name.clone()),
+        );
+
+        let variants = def
+            .values
+            .iter()
+            .map(|(name, _)| IdlEnumVariant {
+                name: name.clone(),
+                fields: None,
+            })
+            .collect::<Vec<IdlEnumVariant>>();
+
+        self.types.push(IdlTypeDefinition {
+            name,
+            docs,
+            ty: IdlTypeDefinitionTy::Enum { variants },
+        });
+    }
+
+    /// Convert for AST Type to IDL Type
+    fn convert(&mut self, ast_type: &Type) -> IdlType {
+        match ast_type {
+            Type::Bool => IdlType::Bool,
+            Type::Int(n) => match *n {
+                0..=8 => IdlType::I8,
+                9..=16 => IdlType::I16,
+                17..=32 => IdlType::I32,
+                33..=64 => IdlType::I64,
+                65..=128 => IdlType::I128,
+                129..=256 => IdlType::I256,
+                _ => unreachable!("Integers wider than 256 bits are not supported"),
+            },
+            Type::Uint(n) => match *n {
+                0..=8 => IdlType::U8,
+                9..=16 => IdlType::U16,
+                17..=32 => IdlType::U32,
+                33..=64 => IdlType::U64,
+                65..=128 => IdlType::U128,
+                129..=256 => IdlType::U256,
+                _ => unreachable!("Unsigned integers wider than 256 bits are not supported"),
+            },
+            Type::DynamicBytes => IdlType::Bytes,
+            Type::String => IdlType::String,
+            Type::Address(_) | Type::Contract(_) => IdlType::PublicKey,
+            Type::Struct(struct_type) => {
+                let def = struct_type.definition(self.namespace);
+                self.add_struct_definition(def, ast_type);
+                IdlType::Defined(def.name.clone())
+            }
+            Type::Array(ty, dims) => {
+                let mut idl_type = self.convert(ty);
+                for item in dims {
+                    match item {
+                        ArrayLength::Fixed(number) => {
+                            idl_type =
+                                IdlType::Array(Box::new(idl_type), number.to_usize().unwrap());
+                        }
+                        ArrayLength::Dynamic => {
+                            idl_type = IdlType::Vec(Box::new(idl_type));
+                        }
+                        ArrayLength::AnyFixed => {
+                            unreachable!("A parameter cannot have an AnyFixed dimension")
+                        }
+                    }
+                }
+                idl_type
+            }
+            Type::Bytes(dim) => IdlType::Array(Box::new(IdlType::U8), *dim as usize),
+            Type::Enum(enum_no) => {
+                self.add_enum_definition(*enum_no, ast_type);
+                IdlType::Defined(self.namespace.enums[*enum_no].name.clone())
+            }
+            Type::ExternalFunction { .. } => {
+                self.convert(&Type::Struct(StructType::ExternalFunction))
+            }
+            Type::UserType(type_no) => self.convert(&self.namespace.user_types[*type_no].ty),
+            _ => unreachable!("Type should not be in the IDL"),
+        }
+    }
+
+    /// This function ensures that the string we are generating is unique given the names we have in
+    /// self.added_names
+    fn unique_string(&mut self, name: String) -> String {
+        let mut num = 0;
+        let mut unique_name = name.clone();
+        while self.added_names.contains_key(&unique_name) {
+            num += 1;
+            unique_name = format!("{}_{}", name, num);
+        }
+
+        unique_name
+    }
+}
+
+/// Prepare the docs from doc comments.
+fn idl_docs(tags: &[Tag]) -> Option<Vec<String>> {
+    if tags.is_empty() {
+        None
+    } else {
+        Some(
+            tags.iter()
+                .map(|tag| format!("{}: {}", tag.tag, tag.value))
+                .collect::<Vec<String>>(),
+        )
+    }
+}
+
+struct Deduplicate {
+    prefix: String,
+    counter: u16,
+    existing_names: HashSet<String>,
+}
+
+impl Deduplicate {
+    fn new(prefix: String) -> Deduplicate {
+        Deduplicate {
+            prefix,
+            counter: 0,
+            existing_names: HashSet::new(),
+        }
+    }
+
+    fn unique_name(&mut self, param: &Parameter) -> String {
+        if param.id.is_none() || param.id.as_ref().unwrap().name.is_empty() {
+            self.try_prefix()
+        } else {
+            let mut name = param.id.as_ref().unwrap().name.clone();
+            self.try_name(&mut name);
+            name
+        }
+    }
+
+    fn try_prefix(&mut self) -> String {
+        let mut candidate = format!("{}_{}", self.prefix, self.counter);
+        while self.existing_names.contains(&candidate) {
+            self.counter += 1;
+            candidate = format!("{}_{}", self.prefix, self.counter);
+        }
+        self.existing_names.insert(candidate.clone());
+        candidate
+    }
+
+    fn try_name(&mut self, candidate: &mut String) {
+        let mut counter = 0;
+        let prefix = candidate.clone();
+        while self.existing_names.contains(candidate) {
+            counter += 1;
+            *candidate = format!("{}_{}", prefix, counter);
+        }
+        self.existing_names.insert(candidate.clone());
+    }
+}

+ 1 - 0
src/abi/mod.rs

@@ -6,6 +6,7 @@ use crate::Target;
 pub mod anchor;
 pub mod ethereum;
 pub mod substrate;
+mod tests;
 
 pub fn generate_abi(
     contract_no: usize,

+ 1506 - 0
src/abi/tests.rs

@@ -0,0 +1,1506 @@
+// SPDX-License-Identifier: Apache-2.0
+
+#![cfg(test)]
+
+use crate::abi::anchor::generate_anchor_idl;
+use crate::codegen::{OptimizationLevel, Options};
+use crate::file_resolver::FileResolver;
+use crate::sema::ast::Namespace;
+use crate::{codegen, parse_and_resolve, Target};
+use anchor_syn::idl::{
+    IdlAccount, IdlAccountItem, IdlEnumVariant, IdlEvent, IdlEventField, IdlField, IdlType,
+    IdlTypeDefinition, IdlTypeDefinitionTy,
+};
+use semver::Version;
+use serde_json::json;
+use std::ffi::OsStr;
+
+fn generate_namespace(src: &'static str) -> Namespace {
+    let mut cache = FileResolver::new();
+    cache.set_file_contents("test.sol", src.to_string());
+    parse_and_resolve(OsStr::new("test.sol"), &mut cache, Target::Solana)
+}
+
+#[test]
+fn version_name_and_docs() {
+    let src = r#"
+/// @title MyContract
+/// @author Lucas
+contract caller {
+    function doThis(int64 a) public pure returns (int64) {
+        return a + 2;
+    }
+
+    function doThat(int32 b) public pure returns (int32) {
+        return b + 3;
+    }
+
+    function do_call() pure public returns (int64, int32) {
+        return (this.doThis(5), this.doThat(3));
+    }
+}
+    "#;
+
+    let ns = generate_namespace(src);
+    let idl = generate_anchor_idl(0, &ns);
+    assert_eq!(
+        idl.version,
+        Version::parse(env!("CARGO_PKG_VERSION"))
+            .unwrap()
+            .to_string()
+    );
+    assert_eq!(idl.name, "caller");
+    assert!(idl.docs.is_some());
+    assert_eq!(idl.docs.as_ref().unwrap().len(), 2);
+    assert_eq!(idl.docs.as_ref().unwrap()[0], "title: MyContract");
+    assert_eq!(idl.docs.as_ref().unwrap()[1], "author: Lucas");
+}
+
+#[test]
+fn constants_and_types() {
+    let src = r#"
+    contract caller {
+    int32 public constant cte1 = -90;
+    uint64[3] public constant cte2 = [90, 875, 1044];
+    string public constant cte3 = "Rio";
+    string[4] public constant cte4 = ["Baku", "Paris", "Sao Paulo", "Auckland"];
+    MyStruct public constant cte5 = MyStruct(125, "ab");
+    Week public constant cte6 = Week.Tuesday;
+
+    struct MyStruct {
+        uint8 g;
+        bytes2 d;
+    }
+
+    enum Week {Monday, Tuesday, Wednesday}
+}
+    "#;
+    let ns = generate_namespace(src);
+    let idl = generate_anchor_idl(0, &ns);
+
+    assert!(idl.constants.is_empty());
+
+    assert_eq!(idl.types.len(), 2);
+
+    assert_eq!(idl.types[0].name, "MyStruct");
+    assert!(idl.types[0].docs.is_none());
+    assert_eq!(
+        idl.types[0].ty,
+        IdlTypeDefinitionTy::Struct {
+            fields: vec![
+                IdlField {
+                    name: "g".to_string(),
+                    docs: None,
+                    ty: IdlType::U8,
+                },
+                IdlField {
+                    name: "d".to_string(),
+                    docs: None,
+                    ty: IdlType::Array(IdlType::U8.into(), 2)
+                }
+            ]
+        }
+    );
+
+    assert_eq!(idl.types[1].name, "Week");
+    assert!(idl.types[1].docs.is_none());
+    assert_eq!(
+        idl.types[1].ty,
+        IdlTypeDefinitionTy::Enum {
+            variants: vec![
+                IdlEnumVariant {
+                    name: "Monday".to_string(),
+                    fields: None,
+                },
+                IdlEnumVariant {
+                    name: "Tuesday".to_string(),
+                    fields: None,
+                },
+                IdlEnumVariant {
+                    name: "Wednesday".to_string(),
+                    fields: None,
+                }
+            ]
+        }
+    );
+}
+
+#[test]
+fn instructions_and_types() {
+    let src = r#"
+    contract caller {
+
+    string private my_string;
+    uint64 public cte;
+    uint64[] public cte2;
+
+    struct MetaData {
+        bool b;
+        bool c;
+    }
+
+    function sum(uint256 a, int256 b) public pure returns (int256) {
+        MetaData d = MetaData(true, false);
+        return notInIdl(a, d) + b;
+    }
+
+    /// @param c input
+    function setString(string c) public {
+        my_string = c;
+    }
+
+    /// @return the string
+    function getString() public view returns (string) {
+        return my_string;
+    }
+
+    function notInIdl(uint256 c, MetaData dd) private pure returns (int256) {
+        if (dd.a && dd.b) {
+            return 0;
+        }
+        return int256(c);
+    }
+
+    function multipleReturns() public returns (uint64, string) {
+        cte += 1;
+        return (cte, my_string);
+    }
+
+    modifier doSomething() {
+        require(msg.value >= 50);
+        _;
+    }
+
+    fallback() external {
+        setString("error2");
+    }
+}
+    "#;
+
+    let ns = generate_namespace(src);
+    let idl = generate_anchor_idl(0, &ns);
+
+    assert_eq!(idl.instructions.len(), 7);
+
+    // implicit constructor
+    assert_eq!(idl.instructions[0].name, "new");
+    assert!(idl.instructions[0].docs.is_none());
+    assert_eq!(
+        idl.instructions[0].accounts,
+        vec![IdlAccountItem::IdlAccount(IdlAccount {
+            name: "data_account".to_string(),
+            is_mut: true,
+            is_signer: false,
+            is_optional: Some(false),
+            docs: None,
+            pda: None,
+            relations: vec![],
+        })]
+    );
+    assert!(idl.instructions[0].args.is_empty());
+    assert!(idl.instructions[0].returns.is_none());
+
+    // cte accessor function
+    assert_eq!(idl.instructions[1].name, "cte");
+    assert!(idl.instructions[1].docs.is_none());
+    assert_eq!(
+        idl.instructions[1].accounts,
+        vec![IdlAccountItem::IdlAccount(IdlAccount {
+            name: "data_account".to_string(),
+            is_mut: false,
+            is_signer: false,
+            is_optional: Some(false),
+            docs: None,
+            pda: None,
+            relations: vec![],
+        })]
+    );
+    assert!(idl.instructions[1].args.is_empty());
+    assert_eq!(idl.instructions[1].returns, Some(IdlType::U64));
+
+    // cte2 accessor function
+    assert_eq!(idl.instructions[2].name, "cte2");
+    assert!(idl.instructions[2].docs.is_none());
+    assert_eq!(
+        idl.instructions[2].accounts,
+        vec![IdlAccountItem::IdlAccount(IdlAccount {
+            name: "data_account".to_string(),
+            is_mut: false,
+            is_signer: false,
+            is_optional: Some(false),
+            docs: None,
+            pda: None,
+            relations: vec![],
+        })]
+    );
+    assert_eq!(
+        idl.instructions[2].args,
+        vec![IdlField {
+            name: "arg_0".to_string(),
+            docs: None,
+            ty: IdlType::U256,
+        }]
+    );
+    assert_eq!(idl.instructions[2].returns, Some(IdlType::U64));
+
+    // sum function
+    assert_eq!(idl.instructions[3].name, "sum");
+    assert!(idl.instructions[3].docs.is_none());
+    assert!(idl.instructions[3].accounts.is_empty());
+    assert_eq!(
+        idl.instructions[3].args,
+        vec![
+            IdlField {
+                name: "a".to_string(),
+                docs: None,
+                ty: IdlType::U256
+            },
+            IdlField {
+                name: "b".to_string(),
+                docs: None,
+                ty: IdlType::I256
+            }
+        ]
+    );
+    assert_eq!(idl.instructions[3].returns, Some(IdlType::I256));
+
+    assert_eq!(idl.instructions[4].name, "setString");
+    assert_eq!(
+        idl.instructions[4].docs,
+        Some(vec!["param: input".to_string()])
+    );
+    assert_eq!(
+        idl.instructions[4].accounts,
+        vec![IdlAccountItem::IdlAccount(IdlAccount {
+            name: "data_account".to_string(),
+            is_mut: true,
+            is_signer: false,
+            is_optional: Some(false),
+            docs: None,
+            pda: None,
+            relations: vec![],
+        })]
+    );
+    assert_eq!(
+        idl.instructions[4].args,
+        vec![IdlField {
+            name: "c".to_string(),
+            docs: None,
+            ty: IdlType::String
+        }]
+    );
+    assert!(idl.instructions[4].returns.is_none());
+
+    assert_eq!(idl.instructions[5].name, "getString");
+    assert_eq!(
+        idl.instructions[5].docs,
+        Some(vec!["return: the string".to_string()])
+    );
+    assert_eq!(
+        idl.instructions[5].accounts,
+        vec![IdlAccountItem::IdlAccount(IdlAccount {
+            name: "data_account".to_string(),
+            is_mut: false,
+            is_signer: false,
+            is_optional: Some(false),
+            docs: None,
+            pda: None,
+            relations: vec![],
+        })]
+    );
+    assert!(idl.instructions[5].args.is_empty());
+    assert_eq!(idl.instructions[5].returns, Some(IdlType::String));
+
+    assert_eq!(idl.instructions[6].name, "multipleReturns");
+    assert!(idl.instructions[6].docs.is_none());
+    assert_eq!(
+        idl.instructions[6].accounts,
+        vec![IdlAccountItem::IdlAccount(IdlAccount {
+            name: "data_account".to_string(),
+            is_mut: true,
+            is_signer: false,
+            is_optional: Some(false),
+            docs: None,
+            pda: None,
+            relations: vec![],
+        })]
+    );
+    assert!(idl.instructions[6].args.is_empty());
+    assert_eq!(
+        idl.instructions[6].returns,
+        Some(IdlType::Defined("multipleReturns_returns".to_string()))
+    );
+
+    assert!(idl.state.is_none());
+    assert!(idl.accounts.is_empty());
+
+    assert_eq!(idl.types.len(), 1);
+
+    assert_eq!(
+        idl.types[0],
+        IdlTypeDefinition {
+            name: "multipleReturns_returns".to_string(),
+            docs: Some(vec![
+                "Data structure to hold the multiple returns of function multipleReturns"
+                    .to_string()
+            ]),
+            ty: IdlTypeDefinitionTy::Struct {
+                fields: vec![
+                    IdlField {
+                        name: "return_0".to_string(),
+                        docs: None,
+                        ty: IdlType::U64
+                    },
+                    IdlField {
+                        name: "return_1".to_string(),
+                        docs: None,
+                        ty: IdlType::String,
+                    }
+                ]
+            }
+        }
+    );
+
+    assert!(idl.events.is_none());
+    assert!(idl.events.is_none());
+    assert!(idl.metadata.is_none());
+}
+
+#[test]
+fn events() {
+    let src = r#"
+contract caller {
+    enum Color { Yellow, Blue, Green }
+
+    event Event1(bool, string indexed, int8, Color);
+    event Event2(bool a, uint128 indexed cc);
+
+    function emitAll(bool a, string b, int8 d, uint128 e) public {
+        emit Event1(a, b, d, Color.Blue);
+        emit Event2(a, e);
+    }
+}
+    "#;
+
+    let mut ns = generate_namespace(src);
+    // We need this to populate Contract.emit_events
+    codegen::codegen(
+        &mut ns,
+        &Options {
+            dead_storage: false,
+            constant_folding: false,
+            strength_reduce: false,
+            vector_to_slice: false,
+            math_overflow_check: false,
+            common_subexpression_elimination: false,
+            generate_debug_information: false,
+            opt_level: OptimizationLevel::None,
+            log_api_return_codes: false,
+        },
+    );
+
+    let idl = generate_anchor_idl(0, &ns);
+
+    assert_eq!(idl.instructions.len(), 2);
+
+    // implicit constructor
+    assert_eq!(idl.instructions[0].name, "new");
+    assert!(idl.instructions[0].docs.is_none());
+    assert_eq!(
+        idl.instructions[0].accounts,
+        vec![IdlAccountItem::IdlAccount(IdlAccount {
+            name: "data_account".to_string(),
+            is_mut: true,
+            is_signer: false,
+            is_optional: Some(false),
+            docs: None,
+            pda: None,
+            relations: vec![],
+        })]
+    );
+    assert!(idl.instructions[0].args.is_empty());
+    assert!(idl.instructions[0].returns.is_none());
+
+    assert_eq!(idl.instructions[1].name, "emitAll");
+    assert!(idl.instructions[1].docs.is_none());
+    assert_eq!(
+        idl.instructions[1].accounts,
+        vec![IdlAccountItem::IdlAccount(IdlAccount {
+            name: "data_account".to_string(),
+            is_mut: true,
+            is_signer: false,
+            is_optional: Some(false),
+            docs: None,
+            pda: None,
+            relations: vec![],
+        })]
+    );
+    assert_eq!(
+        idl.instructions[1].args,
+        vec![
+            IdlField {
+                name: "a".to_string(),
+                docs: None,
+                ty: IdlType::Bool,
+            },
+            IdlField {
+                name: "b".to_string(),
+                docs: None,
+                ty: IdlType::String,
+            },
+            IdlField {
+                name: "d".to_string(),
+                docs: None,
+                ty: IdlType::I8
+            },
+            IdlField {
+                name: "e".to_string(),
+                docs: None,
+                ty: IdlType::U128,
+            }
+        ]
+    );
+    assert!(idl.instructions[1].returns.is_none());
+
+    assert!(idl.state.is_none());
+    assert!(idl.accounts.is_empty());
+
+    assert_eq!(idl.types.len(), 1);
+
+    assert_eq!(
+        idl.types[0],
+        IdlTypeDefinition {
+            name: "Color".to_string(),
+            docs: None,
+            ty: IdlTypeDefinitionTy::Enum {
+                variants: vec![
+                    IdlEnumVariant {
+                        name: "Yellow".to_string(),
+                        fields: None,
+                    },
+                    IdlEnumVariant {
+                        name: "Blue".to_string(),
+                        fields: None,
+                    },
+                    IdlEnumVariant {
+                        name: "Green".to_string(),
+                        fields: None,
+                    }
+                ]
+            }
+        }
+    );
+
+    assert_eq!(
+        idl.events,
+        Some(vec![
+            IdlEvent {
+                name: "Event1".to_string(),
+                fields: vec![
+                    IdlEventField {
+                        name: "field_0".to_string(),
+                        ty: IdlType::Bool,
+                        index: false,
+                    },
+                    IdlEventField {
+                        name: "field_1".to_string(),
+                        ty: IdlType::String,
+                        index: true,
+                    },
+                    IdlEventField {
+                        name: "field_2".to_string(),
+                        ty: IdlType::I8,
+                        index: false,
+                    },
+                    IdlEventField {
+                        name: "field_3".to_string(),
+                        ty: IdlType::Defined("Color".to_string()),
+                        index: false,
+                    }
+                ],
+            },
+            IdlEvent {
+                name: "Event2".to_string(),
+                fields: vec![
+                    IdlEventField {
+                        name: "a".to_string(),
+                        ty: IdlType::Bool,
+                        index: false,
+                    },
+                    IdlEventField {
+                        name: "cc".to_string(),
+                        ty: IdlType::U128,
+                        index: true,
+                    }
+                ]
+            }
+        ])
+    );
+
+    assert!(idl.errors.is_none());
+    assert!(idl.metadata.is_none());
+}
+
+#[test]
+fn types() {
+    let src = r#"
+    contract caller {
+    event Event1(int24, uint32);
+
+    function myFunc(int24 a, uint32[2][] b, uint32[2][4] d, uint32[][2] e) public {
+        emit Event1(a, b[0][1] + d[1][2] - e[1][0]);
+    }
+}
+    "#;
+
+    let ns = generate_namespace(src);
+    let idl = generate_anchor_idl(0, &ns);
+
+    assert_eq!(idl.instructions.len(), 2);
+
+    // implicit constructor
+    assert_eq!(idl.instructions[0].name, "new");
+    assert!(idl.instructions[0].docs.is_none());
+    assert_eq!(
+        idl.instructions[0].accounts,
+        vec![IdlAccountItem::IdlAccount(IdlAccount {
+            name: "data_account".to_string(),
+            is_mut: true,
+            is_signer: false,
+            is_optional: Some(false),
+            docs: None,
+            pda: None,
+            relations: vec![],
+        })]
+    );
+    assert!(idl.instructions[0].args.is_empty());
+    assert!(idl.instructions[0].returns.is_none());
+
+    assert_eq!(idl.instructions[1].name, "myFunc");
+    assert_eq!(
+        idl.instructions[1].accounts,
+        vec![IdlAccountItem::IdlAccount(IdlAccount {
+            name: "data_account".to_string(),
+            is_mut: true,
+            is_signer: false,
+            is_optional: Some(false),
+            docs: None,
+            pda: None,
+            relations: vec![],
+        })]
+    );
+    assert_eq!(
+        idl.instructions[1].args,
+        vec![
+            IdlField {
+                name: "a".to_string(),
+                docs: None,
+                ty: IdlType::I32,
+            },
+            IdlField {
+                name: "b".to_string(),
+                docs: None,
+                ty: IdlType::Vec(IdlType::Array(IdlType::U32.into(), 2).into()),
+            },
+            IdlField {
+                name: "d".to_string(),
+                docs: None,
+                ty: IdlType::Array(IdlType::Array(IdlType::U32.into(), 2).into(), 4),
+            },
+            IdlField {
+                name: "e".to_string(),
+                docs: None,
+                ty: IdlType::Array(IdlType::Vec(IdlType::U32.into()).into(), 2)
+            }
+        ]
+    );
+    assert!(idl.instructions[1].returns.is_none());
+    assert!(idl.state.is_none());
+    assert!(idl.accounts.is_empty());
+    assert!(idl.types.is_empty());
+    assert!(idl.events.is_none());
+    assert!(idl.errors.is_none());
+    assert!(idl.metadata.is_none());
+}
+
+#[test]
+fn constructor() {
+    let src = r#"
+        contract caller {
+    uint64 b;
+    constructor(uint64 ff) {
+        b = ff;
+    }
+
+    function getNum() public view returns (uint64) {
+        return b;
+    }
+}
+    "#;
+    let ns = generate_namespace(src);
+    let idl = generate_anchor_idl(0, &ns);
+
+    assert_eq!(idl.name, "caller");
+    assert!(idl.docs.is_none());
+    assert!(idl.constants.is_empty());
+
+    assert_eq!(idl.instructions.len(), 2);
+    assert_eq!(idl.instructions[0].name, "new");
+    assert!(idl.instructions[0].docs.is_none());
+    assert_eq!(
+        idl.instructions[0].accounts,
+        vec![IdlAccountItem::IdlAccount(IdlAccount {
+            name: "data_account".to_string(),
+            is_mut: true,
+            is_signer: false,
+            is_optional: Some(false),
+            docs: None,
+            pda: None,
+            relations: vec![],
+        })]
+    );
+    assert_eq!(
+        idl.instructions[0].args,
+        vec![IdlField {
+            name: "ff".to_string(),
+            docs: None,
+            ty: IdlType::U64,
+        },]
+    );
+    assert!(idl.instructions[0].returns.is_none());
+
+    assert_eq!(idl.instructions[1].name, "getNum");
+    assert!(idl.instructions[1].docs.is_none());
+    assert_eq!(
+        idl.instructions[1].accounts,
+        vec![IdlAccountItem::IdlAccount(IdlAccount {
+            name: "data_account".to_string(),
+            is_mut: false,
+            is_signer: false,
+            is_optional: Some(false),
+            docs: None,
+            pda: None,
+            relations: vec![],
+        })]
+    );
+    assert!(idl.instructions[1].args.is_empty());
+    assert_eq!(idl.instructions[1].returns, Some(IdlType::U64));
+
+    assert!(idl.state.is_none());
+    assert!(idl.accounts.is_empty());
+    assert!(idl.types.is_empty());
+    assert!(idl.events.is_none());
+    assert!(idl.errors.is_none());
+    assert!(idl.metadata.is_none());
+}
+
+#[test]
+fn named_returns() {
+    let src = r#"
+contract Testing {
+    function getNum(uint64 a, uint64 b) public pure returns (uint64 ret1, uint64 ret2) {
+        ret1 = a + b;
+        ret2 = a/b;
+    }
+}    "#;
+
+    let ns = generate_namespace(src);
+    let idl = generate_anchor_idl(0, &ns);
+
+    assert_eq!(idl.instructions.len(), 2);
+
+    assert_eq!(idl.instructions[0].name, "new");
+    assert!(idl.instructions[0].returns.is_none());
+    assert!(idl.instructions[0].args.is_empty());
+    assert_eq!(
+        idl.instructions[0].accounts,
+        vec![IdlAccountItem::IdlAccount(IdlAccount {
+            name: "data_account".to_string(),
+            is_mut: true,
+            is_signer: false,
+            is_optional: Some(false),
+            docs: None,
+            pda: None,
+            relations: vec![],
+        })]
+    );
+
+    assert_eq!(idl.instructions[1].name, "getNum");
+    assert_eq!(
+        idl.instructions[1].returns,
+        Some(IdlType::Defined("getNum_returns".to_string()))
+    );
+    assert_eq!(
+        idl.instructions[1].args,
+        vec![
+            IdlField {
+                name: "a".to_string(),
+                docs: None,
+                ty: IdlType::U64
+            },
+            IdlField {
+                name: "b".to_string(),
+                docs: None,
+                ty: IdlType::U64
+            },
+        ]
+    );
+
+    assert_eq!(idl.types.len(), 1);
+    assert_eq!(
+        idl.types[0],
+        IdlTypeDefinition {
+            name: "getNum_returns".to_string(),
+            docs: Some(vec![
+                "Data structure to hold the multiple returns of function getNum".to_string()
+            ]),
+            ty: IdlTypeDefinitionTy::Struct {
+                fields: vec![
+                    IdlField {
+                        name: "ret1".to_string(),
+                        docs: None,
+                        ty: IdlType::U64,
+                    },
+                    IdlField {
+                        name: "ret2".to_string(),
+                        docs: None,
+                        ty: IdlType::U64,
+                    }
+                ],
+            },
+        }
+    );
+}
+
+#[test]
+fn mangled_names() {
+    let src = r#"
+contract Testing {
+    function getNum(uint64 a, uint64 b) public pure returns (uint64 ret1, uint64 ret2) {
+        ret1 = a + b;
+        ret2 = a/b;
+    }
+
+    function getNum(int32 a, int32 b) public pure returns (int32 ret3, int32 ret4) {
+        ret3 = a-b;
+        ret4 = b/a;
+    }
+}
+    "#;
+
+    let ns = generate_namespace(src);
+    let idl = generate_anchor_idl(0, &ns);
+
+    assert_eq!(idl.instructions.len(), 3);
+
+    assert_eq!(idl.instructions[0].name, "new");
+
+    assert_eq!(idl.instructions[1].name, "getNum_uint64_uint64");
+    assert!(idl.instructions[1].docs.is_none());
+    assert!(idl.instructions[1].accounts.is_empty());
+    assert_eq!(idl.instructions[1].args.len(), 2);
+    assert_eq!(
+        idl.instructions[1].args[0],
+        IdlField {
+            name: "a".to_string(),
+            docs: None,
+            ty: IdlType::U64
+        }
+    );
+    assert_eq!(
+        idl.instructions[1].args[1],
+        IdlField {
+            name: "b".to_string(),
+            docs: None,
+            ty: IdlType::U64
+        }
+    );
+    assert_eq!(
+        idl.instructions[1].returns,
+        Some(IdlType::Defined("getNum_uint64_uint64_returns".to_string()))
+    );
+
+    assert_eq!(idl.instructions[2].name, "getNum_int32_int32");
+    assert!(idl.instructions[2].docs.is_none());
+    assert!(idl.instructions[2].accounts.is_empty());
+
+    assert_eq!(idl.instructions[2].args.len(), 2);
+    assert_eq!(
+        idl.instructions[2].args[0],
+        IdlField {
+            name: "a".to_string(),
+            docs: None,
+            ty: IdlType::I32,
+        }
+    );
+    assert_eq!(
+        idl.instructions[2].args[1],
+        IdlField {
+            name: "b".to_string(),
+            docs: None,
+            ty: IdlType::I32
+        }
+    );
+    assert_eq!(
+        idl.instructions[2].returns,
+        Some(IdlType::Defined("getNum_int32_int32_returns".to_string()))
+    );
+
+    assert_eq!(idl.types.len(), 2);
+
+    assert_eq!(
+        idl.types[0],
+        IdlTypeDefinition {
+            name: "getNum_uint64_uint64_returns".to_string(),
+            docs: Some(vec![
+                "Data structure to hold the multiple returns of function getNum".to_string()
+            ]),
+            ty: IdlTypeDefinitionTy::Struct {
+                fields: vec![
+                    IdlField {
+                        name: "ret1".to_string(),
+                        docs: None,
+                        ty: IdlType::U64
+                    },
+                    IdlField {
+                        name: "ret2".to_string(),
+                        docs: None,
+                        ty: IdlType::U64
+                    }
+                ]
+            }
+        }
+    );
+
+    assert_eq!(
+        idl.types[1],
+        IdlTypeDefinition {
+            name: "getNum_int32_int32_returns".to_string(),
+            docs: Some(vec![
+                "Data structure to hold the multiple returns of function getNum".to_string()
+            ]),
+            ty: IdlTypeDefinitionTy::Struct {
+                fields: vec![
+                    IdlField {
+                        name: "ret3".to_string(),
+                        docs: None,
+                        ty: IdlType::I32
+                    },
+                    IdlField {
+                        name: "ret4".to_string(),
+                        docs: None,
+                        ty: IdlType::I32
+                    }
+                ]
+            }
+        }
+    );
+}
+
+#[test]
+fn name_collision() {
+    let str = r#"
+    contract Testing {
+    struct getNum_returns {
+        string str;
+    }
+
+    function getNum(uint64 a, uint64 b, getNum_returns c) public pure returns (uint64 ret1, uint64 ret2) {
+        ret1 = a + b;
+        ret2 = a/b;
+    }
+
+    function doNotGetNum(int32 a, int32 b) public pure returns (int32 ret3, int32 ret4) {
+        ret3 = a-b;
+        ret4 = b/a;
+    }
+}
+    "#;
+
+    let ns = generate_namespace(str);
+    let idl = generate_anchor_idl(0, &ns);
+
+    assert_eq!(idl.types.len(), 3);
+
+    assert_eq!(
+        idl.types[0],
+        IdlTypeDefinition {
+            name: "getNum_returns".to_string(),
+            docs: None,
+            ty: IdlTypeDefinitionTy::Struct {
+                fields: vec![IdlField {
+                    name: "str".to_string(),
+                    docs: None,
+                    ty: IdlType::String,
+                }]
+            },
+        }
+    );
+
+    assert_eq!(
+        idl.types[1],
+        IdlTypeDefinition {
+            name: "getNum_returns_1".to_string(),
+            docs: Some(vec![
+                "Data structure to hold the multiple returns of function getNum".to_string()
+            ]),
+            ty: IdlTypeDefinitionTy::Struct {
+                fields: vec![
+                    IdlField {
+                        name: "ret1".to_string(),
+                        docs: None,
+                        ty: IdlType::U64
+                    },
+                    IdlField {
+                        name: "ret2".to_string(),
+                        docs: None,
+                        ty: IdlType::U64
+                    }
+                ]
+            }
+        }
+    );
+
+    assert_eq!(
+        idl.types[2],
+        IdlTypeDefinition {
+            name: "doNotGetNum_returns".to_string(),
+            docs: Some(vec![
+                "Data structure to hold the multiple returns of function doNotGetNum".to_string()
+            ]),
+            ty: IdlTypeDefinitionTy::Struct {
+                fields: vec![
+                    IdlField {
+                        name: "ret3".to_string(),
+                        docs: None,
+                        ty: IdlType::I32
+                    },
+                    IdlField {
+                        name: "ret4".to_string(),
+                        docs: None,
+                        ty: IdlType::I32
+                    }
+                ]
+            }
+        }
+    );
+}
+
+#[test]
+fn double_name_collision() {
+    let str = r#"
+    contract Testing {
+    struct getNum_returns {
+        string str;
+    }
+
+    struct getNum_returns_1 {
+        bytes bt;
+    }
+
+    function getNum(uint64 a, uint64 b, getNum_returns c) public pure returns (uint64 ret1, uint64 ret2) {
+        ret1 = a + b;
+        ret2 = a/b;
+    }
+
+    function doNotGetNum(int32 a, int32 b, getNum_returns_1 c) public pure returns (int32 ret3, int32 ret4) {
+        ret3 = a-b;
+        ret4 = b/a;
+    }
+}
+    "#;
+
+    let ns = generate_namespace(str);
+    let idl = generate_anchor_idl(0, &ns);
+
+    assert_eq!(idl.types.len(), 4);
+
+    assert_eq!(
+        idl.types[0],
+        IdlTypeDefinition {
+            name: "getNum_returns".to_string(),
+            docs: None,
+            ty: IdlTypeDefinitionTy::Struct {
+                fields: vec![IdlField {
+                    name: "str".to_string(),
+                    docs: None,
+                    ty: IdlType::String,
+                }]
+            },
+        }
+    );
+
+    assert_eq!(
+        idl.types[1],
+        IdlTypeDefinition {
+            name: "getNum_returns_1".to_string(),
+            docs: None,
+            ty: IdlTypeDefinitionTy::Struct {
+                fields: vec![IdlField {
+                    name: "bt".to_string(),
+                    docs: None,
+                    ty: IdlType::Bytes
+                },]
+            }
+        }
+    );
+
+    assert_eq!(
+        idl.types[2],
+        IdlTypeDefinition {
+            name: "getNum_returns_2".to_string(),
+            docs: Some(vec![
+                "Data structure to hold the multiple returns of function getNum".to_string()
+            ]),
+            ty: IdlTypeDefinitionTy::Struct {
+                fields: vec![
+                    IdlField {
+                        name: "ret1".to_string(),
+                        docs: None,
+                        ty: IdlType::U64
+                    },
+                    IdlField {
+                        name: "ret2".to_string(),
+                        docs: None,
+                        ty: IdlType::U64
+                    }
+                ]
+            }
+        }
+    );
+
+    assert_eq!(
+        idl.types[3],
+        IdlTypeDefinition {
+            name: "doNotGetNum_returns".to_string(),
+            docs: Some(vec![
+                "Data structure to hold the multiple returns of function doNotGetNum".to_string()
+            ]),
+            ty: IdlTypeDefinitionTy::Struct {
+                fields: vec![
+                    IdlField {
+                        name: "ret3".to_string(),
+                        docs: None,
+                        ty: IdlType::I32
+                    },
+                    IdlField {
+                        name: "ret4".to_string(),
+                        docs: None,
+                        ty: IdlType::I32
+                    }
+                ]
+            }
+        }
+    );
+}
+
+#[test]
+fn deduplication() {
+    let src = r#"
+    contract a {
+    event myEvent(uint32, uint32 field_0, uint32, int64 field_0_1, int64 field_1, uint128);
+
+    function myFunc(address ff, string) public returns (address, address return_0) {
+        emit myEvent(1, 2, 3, 4, 5, 6);
+
+        return (address(this), ff);
+    }
+}
+    "#;
+
+    let mut ns = generate_namespace(src);
+    // We need this to populate Contract.emit_events
+    codegen::codegen(
+        &mut ns,
+        &Options {
+            dead_storage: false,
+            constant_folding: false,
+            strength_reduce: false,
+            vector_to_slice: false,
+            math_overflow_check: false,
+            common_subexpression_elimination: false,
+            generate_debug_information: false,
+            opt_level: OptimizationLevel::None,
+            log_api_return_codes: false,
+        },
+    );
+
+    let idl = generate_anchor_idl(0, &ns);
+
+    assert_eq!(idl.instructions.len(), 2);
+    assert_eq!(idl.instructions[0].name, "new");
+
+    assert_eq!(idl.instructions[1].name, "myFunc");
+    assert_eq!(
+        idl.instructions[1].args,
+        vec![
+            IdlField {
+                name: "ff".to_string(),
+                docs: None,
+                ty: IdlType::PublicKey,
+            },
+            IdlField {
+                name: "arg_0".to_string(),
+                docs: None,
+                ty: IdlType::String,
+            }
+        ]
+    );
+
+    assert_eq!(idl.types.len(), 1);
+    assert_eq!(
+        idl.types[0],
+        IdlTypeDefinition {
+            name: "myFunc_returns".to_string(),
+            docs: Some(vec![
+                "Data structure to hold the multiple returns of function myFunc".to_owned()
+            ]),
+            ty: IdlTypeDefinitionTy::Struct {
+                fields: vec![
+                    IdlField {
+                        name: "return_0".to_string(),
+                        docs: None,
+                        ty: IdlType::PublicKey
+                    },
+                    IdlField {
+                        name: "return_0_1".to_string(),
+                        docs: None,
+                        ty: IdlType::PublicKey
+                    }
+                ]
+            }
+        }
+    );
+
+    assert!(idl.events.is_some());
+    assert_eq!(idl.events.as_ref().unwrap().len(), 1);
+    assert_eq!(
+        idl.events.as_ref().unwrap()[0],
+        IdlEvent {
+            name: "myEvent".to_string(),
+            fields: vec![
+                IdlEventField {
+                    name: "field_0".to_string(),
+                    ty: IdlType::U32,
+                    index: false,
+                },
+                IdlEventField {
+                    name: "field_0_1".to_string(),
+                    ty: IdlType::U32,
+                    index: false,
+                },
+                IdlEventField {
+                    name: "field_1".to_string(),
+                    ty: IdlType::U32,
+                    index: false,
+                },
+                IdlEventField {
+                    name: "field_0_1_1".to_string(),
+                    ty: IdlType::I64,
+                    index: false,
+                },
+                IdlEventField {
+                    name: "field_1_1".to_string(),
+                    ty: IdlType::I64,
+                    index: false,
+                },
+                IdlEventField {
+                    name: "field_2".to_string(),
+                    ty: IdlType::U128,
+                    index: false,
+                }
+            ]
+        }
+    );
+}
+
+#[test]
+fn duplicate_named_custom_types() {
+    // Other contract comes first
+    let src = r#"
+contract D {
+	struct Foo { int64 f1; }
+}
+contract C {
+	enum Foo { b1, b2, b3 }
+        function f(D.Foo x, Foo y) public pure returns (int64) { return x.f1; }
+}
+    "#;
+
+    let ns = generate_namespace(src);
+    let idl = generate_anchor_idl(1, &ns);
+
+    assert_eq!(idl.types.len(), 2);
+    assert_eq!(idl.types[0].name, "D_Foo");
+    assert_eq!(idl.types[1].name, "Foo");
+
+    // Current contract comes first
+    let src = r#"
+    contract D {
+	struct Foo { int64 f1; }
+}
+contract C {
+	enum Foo { b1, b2, b3 }
+        function f(Foo y, D.Foo x) public pure returns (int64) { return x.f1; }
+}
+    "#;
+
+    let ns = generate_namespace(src);
+    let idl = generate_anchor_idl(1, &ns);
+
+    assert_eq!(idl.types.len(), 2);
+    assert_eq!(idl.types[0].name, "Foo");
+    assert_eq!(idl.types[1].name, "D_Foo");
+
+    // Type outside a contract first
+    let src = r#"
+    contract D {
+	struct Foo { int64 f1; }
+}
+
+enum Foo { b1, b2, b3 }
+
+contract C {
+        function f(Foo y, D.Foo x) public pure returns (int64) { return x.f1; }
+}
+    "#;
+
+    let ns = generate_namespace(src);
+    let idl = generate_anchor_idl(1, &ns);
+    assert_eq!(idl.types.len(), 2);
+    assert_eq!(idl.types[0].name, "Foo");
+    assert_eq!(idl.types[1].name, "D_Foo");
+
+    // Type outside contract second
+    let src = r#"
+    contract D {
+	struct Foo { int64 f1; }
+}
+
+enum Foo { b1, b2, b3 }
+
+contract C {
+        function f(D.Foo x, Foo y) public pure returns (int64) { return x.f1; }
+}
+    "#;
+
+    let ns = generate_namespace(src);
+    let idl = generate_anchor_idl(1, &ns);
+
+    assert_eq!(idl.types.len(), 2);
+    assert_eq!(idl.types[0].name, "D_Foo");
+    assert_eq!(idl.types[1].name, "Foo");
+
+    // Name already exists before
+    let src = r#"
+    contract D {
+	struct Foo { int64 f1; }
+}
+
+enum Foo { b1, b2, b3 }
+
+contract C {
+    struct D_Foo {
+        int64 f2;
+    }
+        function f(Foo y, D_Foo z, D.Foo x) public pure returns (int64) { return x.f1 + z.f2; }
+}
+    "#;
+
+    let ns = generate_namespace(src);
+    let idl = generate_anchor_idl(1, &ns);
+
+    assert_eq!(idl.types.len(), 3);
+    assert_eq!(idl.types[0].name, "Foo");
+    assert_eq!(idl.types[1].name, "D_Foo");
+    assert_eq!(idl.types[2].name, "D_Foo_1");
+
+    // Name already exists after
+    let src = r#"
+    contract D {
+	struct Foo { int64 f1; }
+}
+
+enum Foo { b1, b2, b3 }
+
+contract C {
+    struct D_Foo {
+        int64 f2;
+    }
+        function f(Foo y,  D.Foo x, D_Foo z) public pure returns (int64) { return x.f1 + z.f2; }
+}
+    "#;
+    let ns = generate_namespace(src);
+    let idl = generate_anchor_idl(1, &ns);
+
+    assert_eq!(idl.types.len(), 3);
+    assert_eq!(idl.types[0].name, "Foo");
+    assert_eq!(idl.types[1].name, "D_Foo_1");
+    assert_eq!(idl.types[2].name, "D_Foo");
+
+    // Pathological name as first argument
+    let src = r#"
+    contract D {
+	struct Foo { int64 f1; }
+}
+
+enum Foo { b1, b2, b3 }
+
+contract C {
+    struct D_Foo {
+        int64 f2;
+    }
+        function f(D_Foo z, Foo y,  D.Foo x) public pure returns (int64) { return x.f1 + z.f2; }
+}
+    "#;
+    let ns = generate_namespace(src);
+    let idl = generate_anchor_idl(1, &ns);
+
+    assert_eq!(idl.types.len(), 3);
+    assert_eq!(idl.types[0].name, "D_Foo");
+    assert_eq!(idl.types[1].name, "Foo");
+    assert_eq!(idl.types[2].name, "D_Foo_1");
+
+    let src = r#"
+contract D {
+	struct Foo { int64 f1; }
+}
+
+enum Foo { b1, b2, b3 }
+
+contract C {
+    struct D_Foo {
+        int64 f2;
+    }
+
+    struct D_Foo_1 {
+       int64 f3;
+    }
+
+    function f(D_Foo z, D_Foo_1 k, Foo y,  D.Foo x) public pure returns (int64) { return x.f1 + z.f2 + k.f3; }
+}
+    "#;
+
+    let ns = generate_namespace(src);
+    let idl = generate_anchor_idl(1, &ns);
+
+    assert_eq!(idl.types.len(), 4);
+    assert_eq!(idl.types[0].name, "D_Foo");
+    assert_eq!(idl.types[1].name, "D_Foo_1");
+    assert_eq!(idl.types[2].name, "Foo");
+    assert_eq!(idl.types[3].name, "D_Foo_2");
+
+    let src = r#"
+contract D {
+	struct Foo { int64 f1; }
+}
+
+enum Foo { b1, b2, b3 }
+
+contract C {
+    struct D_Foo {
+        int64 f2;
+    }
+
+    struct D_Foo_1 {
+       int64 f3;
+    }
+
+    function f(D_Foo_1 k, D_Foo z, Foo y,  D.Foo x) public pure returns (int64) { return x.f1 + z.f2 + k.f3; }
+}
+    "#;
+
+    let ns = generate_namespace(src);
+    let idl = generate_anchor_idl(1, &ns);
+
+    assert_eq!(idl.types.len(), 4);
+    assert_eq!(idl.types[0].name, "D_Foo_1");
+    assert_eq!(idl.types[1].name, "D_Foo");
+    assert_eq!(idl.types[2].name, "Foo");
+    assert_eq!(idl.types[3].name, "D_Foo_2");
+
+    let src = r#"
+contract D {
+	struct Foo { int64 f1; }
+}
+
+enum Foo { b1, b2, b3 }
+
+contract C {
+    struct D_Foo {
+        int64 f2;
+    }
+
+    struct D_Foo_1 {
+       int64 f3;
+    }
+
+    function f(D_Foo z, Foo y, D_Foo_1 k, D.Foo x) public pure returns (int64) { return x.f1 + z.f2 + k.f3; }
+}
+    "#;
+
+    let ns = generate_namespace(src);
+    let idl = generate_anchor_idl(1, &ns);
+
+    assert_eq!(idl.types.len(), 4);
+    assert_eq!(idl.types[0].name, "D_Foo");
+    assert_eq!(idl.types[1].name, "Foo");
+    assert_eq!(idl.types[2].name, "D_Foo_1");
+    assert_eq!(idl.types[3].name, "D_Foo_2");
+
+    let src = r#"
+contract D {
+	struct Foo { int64 f1; }
+}
+
+enum Foo { b1, b2, b3 }
+
+contract C {
+    struct D_Foo {
+        int64 f2;
+    }
+
+    struct D_Foo_1 {
+       int64 f3;
+    }
+
+    function f(D_Foo z, Foo y,  D.Foo x, D_Foo_1 k) public pure returns (int64) { return x.f1 + z.f2 + k.f3; }
+}
+    "#;
+
+    let ns = generate_namespace(src);
+    let idl = generate_anchor_idl(1, &ns);
+
+    assert_eq!(idl.types.len(), 4);
+    assert_eq!(idl.types[0].name, "D_Foo");
+    assert_eq!(idl.types[1].name, "Foo");
+    assert_eq!(idl.types[2].name, "D_Foo_2");
+    assert_eq!(idl.types[3].name, "D_Foo_1");
+}
+
+#[test]
+fn program_id() {
+    let src = r#"
+    @program_id("Foo5mMfYo5RhRcWa4NZ2bwFn4Kdhe8rNK5jchxsKrivA")
+contract C {
+    struct D_Foo {
+        int64 f2;
+    }
+
+    struct D_Foo_1 {
+       int64 f3;
+    }
+
+    function f(D_Foo_1 k, D_Foo z) public pure returns (int64) { return z.f2 + k.f3; }
+}
+    "#;
+
+    let ns = generate_namespace(src);
+    let idl = generate_anchor_idl(0, &ns);
+
+    assert!(idl.metadata.is_some());
+    assert_eq!(
+        idl.metadata.unwrap(),
+        json!({"address": "Foo5mMfYo5RhRcWa4NZ2bwFn4Kdhe8rNK5jchxsKrivA"})
+    );
+}

+ 2 - 0
src/bin/idl/mod.rs

@@ -358,6 +358,8 @@ fn idltype_to_solidity(ty: &IdlType, ty_names: &[(String, String)]) -> Result<St
         IdlType::I64 => Ok("int64".to_string()),
         IdlType::U128 => Ok("uint128".to_string()),
         IdlType::I128 => Ok("int128".to_string()),
+        IdlType::U256 => Ok("uint256".to_string()),
+        IdlType::I256 => Ok("int256".to_string()),
         IdlType::F32 => Err("f32".to_string()),
         IdlType::F64 => Err("f64".to_string()),
         IdlType::Bytes => Ok("bytes".to_string()),

+ 0 - 3
src/sema/yul/tests/block.rs

@@ -186,9 +186,6 @@ contract testTypes {
     "#;
 
     let ns = parse(file);
-    for item in ns.diagnostics.iter() {
-        std::println!("{}", item.message);
-    }
     assert!(ns.diagnostics.contains_message("unreachable yul statement"));
 
     let file = r#"

+ 0 - 3
src/sema/yul/tests/switch.rs

@@ -100,9 +100,6 @@ contract testTypes {
     "#;
 
     let ns = parse(file);
-    for item in ns.diagnostics.iter() {
-        std::println!("{}", item.message);
-    }
     assert_eq!(ns.diagnostics.len(), 1);
     assert_eq!(
         ns.diagnostics.iter().next().unwrap().message,

+ 106 - 40
tests/borsh_encoding.rs

@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: Apache-2.0
 
+use anchor_syn::idl::{IdlType, IdlTypeDefinition, IdlTypeDefinitionTy};
 use byte_slice_cast::AsByteSlice;
-use ethabi::{Param, ParamType};
 use num_bigint::{BigInt, Sign};
 use num_traits::ToPrimitive;
 use std::cmp::Ordering;
@@ -54,8 +54,6 @@ impl BorshToken {
                 for item in data {
                     item.encode(buffer);
                 }
-                std::println!("len: {}", buffer.len());
-                std::println!("buffer: {:?}", buffer);
             }
             BorshToken::Array(arr) => {
                 let len = arr.len() as u32;
@@ -84,6 +82,20 @@ impl BorshToken {
     pub fn into_fixed_bytes(self) -> Option<Vec<u8>> {
         match self {
             BorshToken::FixedBytes(value) => Some(value),
+            BorshToken::FixedArray(vec) => {
+                let mut response: Vec<u8> = Vec::with_capacity(vec.len());
+                for elem in vec {
+                    match elem {
+                        BorshToken::Uint { width, value } => {
+                            assert_eq!(width, 8);
+                            response.push(value.to_u8().unwrap());
+                        }
+                        _ => unreachable!("Array cannot be converted to fixed bytes"),
+                    }
+                }
+                Some(response)
+            }
+            BorshToken::Address(value) => Some(value.to_vec()),
             _ => None,
         }
     }
@@ -102,6 +114,25 @@ impl BorshToken {
             _ => None,
         }
     }
+
+    pub fn unwrap_tuple(self) -> Vec<BorshToken> {
+        match self {
+            BorshToken::Tuple(vec) => vec,
+            _ => panic!("This is not a tuple"),
+        }
+    }
+
+    pub fn uint8_fixed_array(vec: Vec<u8>) -> BorshToken {
+        let mut array: Vec<BorshToken> = Vec::with_capacity(vec.len());
+        for item in &vec {
+            array.push(BorshToken::Uint {
+                width: 8,
+                value: BigInt::from(*item),
+            });
+        }
+
+        BorshToken::FixedArray(array)
+    }
 }
 
 /// Encode a signed integer
@@ -199,18 +230,6 @@ fn encode_uint(width: u16, value: &BigInt, buffer: &mut Vec<u8>) {
     }
 }
 
-/// Decode the output buffer of a function given the description of its parameters
-pub fn decode_output(params: &[Param], data: &[u8]) -> Vec<BorshToken> {
-    let mut offset: usize = 0;
-    let mut decoded: Vec<BorshToken> = Vec::with_capacity(params.len());
-    for item in params {
-        let borsh_token = decode_at_offset(data, &mut offset, &item.kind);
-        decoded.push(borsh_token);
-    }
-
-    decoded
-}
-
 /// Encode the arguments of a function
 pub fn encode_arguments(args: &[BorshToken]) -> Vec<u8> {
     let mut encoded: Vec<u8> = Vec::new();
@@ -222,38 +241,56 @@ pub fn encode_arguments(args: &[BorshToken]) -> Vec<u8> {
 }
 
 /// Decode a parameter at a given offset
-fn decode_at_offset(data: &[u8], offset: &mut usize, ty: &ParamType) -> BorshToken {
+pub fn decode_at_offset(
+    data: &[u8],
+    offset: &mut usize,
+    ty: &IdlType,
+    custom_types: &[IdlTypeDefinition],
+) -> BorshToken {
     match ty {
-        ParamType::Address => {
+        IdlType::PublicKey => {
             let read = &data[*offset..(*offset + 32)];
             (*offset) += 32;
             BorshToken::Address(<[u8; 32]>::try_from(read).unwrap())
         }
-        ParamType::Uint(width) => {
-            let decoding_width = width.next_power_of_two() / 8;
+
+        IdlType::U8
+        | IdlType::U16
+        | IdlType::U32
+        | IdlType::U64
+        | IdlType::U128
+        | IdlType::U256 => {
+            let decoding_width = integer_byte_width(ty);
             let bigint =
                 BigInt::from_bytes_le(Sign::Plus, &data[*offset..(*offset + decoding_width)]);
             (*offset) += decoding_width;
             BorshToken::Uint {
-                width: *width as u16,
+                width: (decoding_width * 8) as u16,
                 value: bigint,
             }
         }
-        ParamType::Int(width) => {
-            let decoding_width = width.next_power_of_two() / 8;
+
+        IdlType::I8
+        | IdlType::I16
+        | IdlType::I32
+        | IdlType::I64
+        | IdlType::I128
+        | IdlType::I256 => {
+            let decoding_width = integer_byte_width(ty);
             let bigint = BigInt::from_signed_bytes_le(&data[*offset..(*offset + decoding_width)]);
             (*offset) += decoding_width;
             BorshToken::Int {
-                width: *width as u16,
+                width: (decoding_width * 8) as u16,
                 value: bigint,
             }
         }
-        ParamType::Bool => {
+
+        IdlType::Bool => {
             let val = data[*offset] == 1;
             (*offset) += 1;
             BorshToken::Bool(val)
         }
-        ParamType::String => {
+        IdlType::String => {
             let mut int_data: [u8; 4] = Default::default();
             int_data.copy_from_slice(&data[*offset..(*offset + 4)]);
             let len = u32::from_le_bytes(int_data) as usize;
@@ -262,37 +299,50 @@ fn decode_at_offset(data: &[u8], offset: &mut usize, ty: &ParamType) -> BorshTok
             (*offset) += len;
             BorshToken::String(read_string.to_string())
         }
-        ParamType::FixedBytes(len) => {
-            let read_data = &data[*offset..(*offset + len)];
-            (*offset) += len;
-            BorshToken::FixedBytes(read_data.to_vec())
-        }
-        ParamType::FixedArray(ty, len) => {
+        IdlType::Array(ty, len) => {
             let mut read_items: Vec<BorshToken> = Vec::with_capacity(*len);
             for _ in 0..*len {
-                read_items.push(decode_at_offset(data, offset, ty));
+                read_items.push(decode_at_offset(data, offset, ty, custom_types));
             }
             BorshToken::FixedArray(read_items)
         }
-        ParamType::Array(ty) => {
+        IdlType::Vec(ty) => {
             let mut int_data: [u8; 4] = Default::default();
             int_data.copy_from_slice(&data[*offset..(*offset + 4)]);
             let len = u32::from_le_bytes(int_data);
             (*offset) += 4;
             let mut read_items: Vec<BorshToken> = Vec::with_capacity(len as usize);
             for _ in 0..len {
-                read_items.push(decode_at_offset(data, offset, ty));
+                read_items.push(decode_at_offset(data, offset, ty, custom_types));
             }
             BorshToken::Array(read_items)
         }
-        ParamType::Tuple(items) => {
-            let mut read_items: Vec<BorshToken> = Vec::with_capacity(items.len());
-            for item in items {
-                read_items.push(decode_at_offset(data, offset, item));
+        IdlType::Defined(value) => {
+            let current_ty = custom_types
+                .iter()
+                .find(|item| &item.name == value)
+                .unwrap();
+
+            match &current_ty.ty {
+                IdlTypeDefinitionTy::Enum { .. } => {
+                    let value = data[*offset];
+                    (*offset) += 1;
+                    BorshToken::Uint {
+                        width: 8,
+                        value: BigInt::from(value),
+                    }
+                }
+                IdlTypeDefinitionTy::Struct { fields } => {
+                    let mut read_items: Vec<BorshToken> = Vec::with_capacity(fields.len());
+                    for item in fields {
+                        read_items.push(decode_at_offset(data, offset, &item.ty, custom_types));
+                    }
+
+                    BorshToken::Tuple(read_items)
+                }
             }
-            BorshToken::Tuple(read_items)
         }
-        ParamType::Bytes => {
+        IdlType::Bytes => {
             let mut int_data: [u8; 4] = Default::default();
             int_data.copy_from_slice(&data[*offset..(*offset + 4)]);
             let len = u32::from_le_bytes(int_data) as usize;
@@ -301,5 +351,21 @@ fn decode_at_offset(data: &[u8], offset: &mut usize, ty: &ParamType) -> BorshTok
             (*offset) += len;
             BorshToken::Bytes(read_data.to_vec())
         }
+
+        IdlType::Option(_) | IdlType::F32 | IdlType::F64 => {
+            unreachable!("Type not available in Solidity")
+        }
+    }
+}
+
+fn integer_byte_width(ty: &IdlType) -> usize {
+    match ty {
+        IdlType::U8 | IdlType::I8 => 1,
+        IdlType::U16 | IdlType::I16 => 2,
+        IdlType::U32 | IdlType::I32 => 4,
+        IdlType::U64 | IdlType::I64 => 8,
+        IdlType::U128 | IdlType::I128 => 16,
+        IdlType::U256 | IdlType::I256 => 32,
+        _ => unreachable!("Not an integer"),
     }
 }

+ 56 - 19
tests/solana.rs

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: Apache-2.0
 
-use crate::borsh_encoding::{decode_output, encode_arguments, BorshToken};
+use crate::borsh_encoding::{decode_at_offset, encode_arguments, BorshToken};
 use base58::{FromBase58, ToBase58};
 use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
 use ethabi::RawLog;
@@ -23,7 +23,8 @@ use solana_rbpf::{
 };
 use solang::compile;
 
-use solang::abi::anchor::discriminator;
+use anchor_syn::idl::Idl;
+use solang::abi::anchor::{discriminator, generate_anchor_idl};
 use solang::{file_resolver::FileResolver, Target};
 use std::{
     cell::{RefCell, RefMut},
@@ -75,7 +76,7 @@ struct VirtualMachine {
 #[derive(Clone)]
 struct Contract {
     program: Account,
-    abi: Option<ethabi::Contract>,
+    idl: Option<Idl>,
     data: Account,
 }
 
@@ -151,9 +152,7 @@ fn build_solidity_with_overflow_check(src: &str, math_overflow_flag: bool) -> Vi
         }
 
         let code = contract.code.get().unwrap();
-
-        let (abistr, _) = solang::abi::generate_abi(contract_no, &ns, code, false);
-        let abi = ethabi::Contract::load(abistr.as_bytes()).unwrap();
+        let idl = generate_anchor_idl(contract_no, &ns);
 
         let program = if let Some(program_id) = &contract.program_id {
             program_id.clone().try_into().unwrap()
@@ -183,7 +182,7 @@ fn build_solidity_with_overflow_check(src: &str, math_overflow_flag: bool) -> Vi
 
         programs.push(Contract {
             program,
-            abi: Some(abi),
+            idl: Some(idl),
             data,
         });
     }
@@ -1384,7 +1383,7 @@ impl<'a> SyscallObject<UserError> for SyscallInvokeSignedC<'a> {
 
                         vm.programs.push(Contract {
                             program: create_account.program_id,
-                            abi: None,
+                            idl: None,
                             data: new_address,
                         });
                     }
@@ -1594,8 +1593,7 @@ impl VirtualMachine {
         res
     }
 
-    /// FIXME: remove name argument
-    fn constructor(&mut self, _name: &str, args: &[BorshToken]) {
+    fn constructor(&mut self, args: &[BorshToken]) {
         self.constructor_expected(0, args)
     }
 
@@ -1606,8 +1604,14 @@ impl VirtualMachine {
         println!("constructor for {}", hex::encode(program.data));
 
         let mut calldata = discriminator("global", "new");
-
-        if program.abi.as_ref().unwrap().constructor.is_some() {
+        if program
+            .idl
+            .as_ref()
+            .unwrap()
+            .instructions
+            .iter()
+            .any(|instr| instr.name == "new")
+        {
             let mut encoded_data = encode_arguments(args);
             calldata.append(&mut encoded_data);
         };
@@ -1623,7 +1627,7 @@ impl VirtualMachine {
         }
     }
 
-    fn function(&mut self, name: &str, args: &[BorshToken]) -> Vec<BorshToken> {
+    fn function(&mut self, name: &str, args: &[BorshToken]) -> Option<BorshToken> {
         let default_metas = self.default_metas();
 
         self.function_metas(&default_metas, name, args)
@@ -1634,14 +1638,27 @@ impl VirtualMachine {
         metas: &[AccountMeta],
         name: &str,
         args: &[BorshToken],
-    ) -> Vec<BorshToken> {
+    ) -> Option<BorshToken> {
         self.return_data = None;
-
         let program = &self.stack[0];
 
         println!("function {} for {}", name, hex::encode(program.data));
 
         let mut calldata = discriminator("global", name);
+
+        let instruction = if let Some(instr) = program
+            .idl
+            .as_ref()
+            .unwrap()
+            .instructions
+            .iter()
+            .find(|item| item.name == name)
+        {
+            instr.clone()
+        } else {
+            panic!("Function '{}' not found", name);
+        };
+
         let mut encoded_args = encode_arguments(args);
         calldata.append(&mut encoded_args);
 
@@ -1660,11 +1677,20 @@ impl VirtualMachine {
             &[]
         };
 
-        let func = &self.stack[0].abi.as_ref().unwrap().functions[name][0];
-        if func.outputs.is_empty() {
+        if let Some(ret) = &instruction.returns {
+            let mut offset: usize = 0;
+            let decoded = decode_at_offset(
+                return_data,
+                &mut offset,
+                ret,
+                &self.stack[0].idl.as_ref().unwrap().types,
+            );
+            assert_eq!(offset, return_data.len());
+            Some(decoded)
+        } else {
             assert_eq!(return_data.len(), 0);
+            None
         }
-        decode_output(&func.outputs, return_data)
     }
 
     fn function_must_fail(
@@ -1678,6 +1704,17 @@ impl VirtualMachine {
 
         let mut calldata = Vec::new();
 
+        if !self.stack[0]
+            .idl
+            .as_ref()
+            .unwrap()
+            .instructions
+            .iter()
+            .any(|item| item.name == name)
+        {
+            panic!("Function '{}' not found", name);
+        }
+
         let selector = discriminator("global", name);
         calldata.extend_from_slice(&selector);
         let mut encoded = encode_arguments(args);
@@ -1757,7 +1794,7 @@ impl VirtualMachine {
 
         self.programs.push(Contract {
             program: *program_id,
-            abi: None,
+            idl: None,
             data: *account,
         });
     }

+ 3 - 3
tests/solana_tests/abi.rs

@@ -45,7 +45,7 @@ fn packed() {
         }"#,
     );
 
-    vm.constructor("bar", &[]);
+    vm.constructor(&[]);
 
     vm.function("test", &[]);
     vm.function("test2", &[]);
@@ -65,7 +65,7 @@ fn inherited() {
         contract bar is foo { }"#,
     );
 
-    vm.constructor("bar", &[]);
+    vm.constructor(&[]);
 
     vm.function("test", &[]);
 
@@ -78,7 +78,7 @@ fn inherited() {
             contract bar is foo { }"#,
     );
 
-    vm.constructor("bar", &[]);
+    vm.constructor(&[]);
 
     vm.function("test", &[]);
 }

+ 37 - 28
tests/solana_tests/abi_decode.rs

@@ -67,7 +67,7 @@ fn integers_bool_enum() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let input = Res1 {
         a: 45,
         b: 9965956609890,
@@ -110,7 +110,7 @@ fn decode_address() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let input = Data {
         address: vm.programs[0].data,
         this: vm.programs[0].data,
@@ -140,7 +140,7 @@ fn string_and_bytes() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let data = Data {
         a: "coffee".to_string(),
         b: b"tea".to_vec(),
@@ -194,7 +194,7 @@ fn primitive_struct() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let data = NoPadStruct { a: 1238, b: 87123 };
     let encoded = data.try_to_vec().unwrap();
     let _ = vm.function("testNoPadStruct", &[BorshToken::Bytes(encoded)]);
@@ -227,13 +227,15 @@ fn returned_string() {
     }
         "#,
     );
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let data = Input {
         rr: "cortado".to_string(),
     };
     let encoded = data.try_to_vec().unwrap();
-    let returns = vm.function("returnedString", &[BorshToken::Bytes(encoded)]);
-    let string = returns[0].clone().into_string().unwrap();
+    let returns = vm
+        .function("returnedString", &[BorshToken::Bytes(encoded)])
+        .unwrap();
+    let string = returns.into_string().unwrap();
     assert_eq!(string, "cortado");
 }
 
@@ -255,7 +257,7 @@ fn test_string_array() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let data = Input {
         a: vec![
             "coffee".to_string(),
@@ -264,8 +266,11 @@ fn test_string_array() {
         ],
     };
     let encoded = data.try_to_vec().unwrap();
-    let returns = vm.function("testStringVector", &[BorshToken::Bytes(encoded)]);
-    let vec = returns[0].clone().into_array().unwrap();
+    let returns = vm
+        .function("testStringVector", &[BorshToken::Bytes(encoded)])
+        .unwrap();
+    let vec = returns.into_array().unwrap();
+
     assert_eq!(vec.len(), 3);
     assert_eq!(vec[0].clone().into_string().unwrap(), "coffee");
     assert_eq!(vec[1].clone().into_string().unwrap(), "tea");
@@ -332,7 +337,7 @@ fn struct_within_struct() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let no_pad = NoPadStruct { a: 89123, b: 12354 };
     let mut tea_is_good = b"tea_is_good".to_vec();
     tea_is_good.append(&mut vec![0; 21]);
@@ -444,7 +449,7 @@ fn struct_in_array() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let mut bytes_string = b"there_is_padding_here".to_vec();
     bytes_string.append(&mut vec![0; 11]);
     let input = Input1 {
@@ -547,7 +552,7 @@ fn arrays() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let input = Input1 {
         complex_array: vec![
             NonConstantStruct {
@@ -682,7 +687,7 @@ fn multi_dimensional_arrays() {
     }
         "#,
     );
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let mut response: Vec<u8> = vec![0; 32];
 
     let input = Input1 {
@@ -776,7 +781,7 @@ fn empty_arrays() {
     }
         "#,
     );
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
 
     let input = Input {
         vec_1: vec![],
@@ -805,7 +810,7 @@ fn external_function() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let input = Input {
         selector: [1, 2, 3, 4, 5, 6, 7, 8],
         address: [
@@ -814,7 +819,11 @@ fn external_function() {
         ],
     };
     let encoded = input.try_to_vec().unwrap();
-    let returns = vm.function("testExternalFunction", &[BorshToken::Bytes(encoded)]);
+
+    let returns = vm
+        .function("testExternalFunction", &[BorshToken::Bytes(encoded)])
+        .unwrap()
+        .unwrap_tuple();
 
     let selector = returns[0].clone().into_fixed_bytes().unwrap();
     assert_eq!(selector, input.selector);
@@ -848,7 +857,7 @@ fn bytes_arrays() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let input = Input {
         item_1: [b"abcd".to_owned(), b"efgh".to_owned()],
         item_2: vec![b"12345".to_owned(), b"67890".to_owned()],
@@ -883,7 +892,7 @@ fn different_types() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let input = Input1 { a: -789, b: 14234 };
     let encoded = input.try_to_vec().unwrap();
     let _ = vm.function("testByteArrays", &[BorshToken::Bytes(encoded)]);
@@ -909,7 +918,7 @@ fn more_elements() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
 
     let input = Input { vec: [1, 4, 5, 6] };
     let encoded = input.try_to_vec().unwrap();
@@ -937,7 +946,7 @@ fn extra_element() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let input = Input {
         vec: vec![-90, 89, -2341],
     };
@@ -966,7 +975,7 @@ fn invalid_type() {
     "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
 
     let input = Input { item: 5 };
     let encoded = input.try_to_vec().unwrap();
@@ -994,7 +1003,7 @@ fn longer_buffer() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
 
     let input = Input {
         item_1: 4,
@@ -1026,7 +1035,7 @@ fn longer_buffer_array() {
             }
         }        "#,
     );
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
 
     let input = Input {
         item_1: 23434,
@@ -1060,7 +1069,7 @@ fn dynamic_array_of_array() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let input = Input {
         vec: vec![[0, 1], [2, -3]],
     };
@@ -1105,7 +1114,7 @@ fn test_struct_validation() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let mut bytes_string = b"struct".to_vec();
     bytes_string.append(&mut vec![0; 26]);
 
@@ -1158,7 +1167,7 @@ fn test_struct_validation_invalid() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let mut bytes_string = b"struct".to_vec();
     bytes_string.append(&mut vec![0; 26]);
 
@@ -1188,7 +1197,7 @@ fn string_fixed_array() {
 }
         "#,
     );
-    vm.constructor("test", &[]);
+    vm.constructor(&[]);
 
     #[derive(Debug, BorshSerialize)]
     struct Input {

+ 67 - 63
tests/solana_tests/abi_encode.rs

@@ -67,9 +67,9 @@ contract Testing {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
-    let returns = vm.function("getThis", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    vm.constructor(&[]);
+    let returns = vm.function("getThis", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = Res1::try_from_slice(&encoded).unwrap();
 
     assert_eq!(decoded.a, 45);
@@ -80,8 +80,8 @@ contract Testing {
     assert_eq!(decoded.day, WeekDay::Wednesday);
     assert!(!decoded.h);
 
-    let returns = vm.function("encodeEnum", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    let returns = vm.function("encodeEnum", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = Res2::try_from_slice(&encoded).unwrap();
 
     assert_eq!(decoded.sunday, WeekDay::Sunday);
@@ -108,9 +108,9 @@ contract Testing {
 }
         "#,
     );
-    vm.constructor("Testing", &[]);
-    let returns = vm.function("getThis", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    vm.constructor(&[]);
+    let returns = vm.function("getThis", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = Response::try_from_slice(&encoded).unwrap();
     assert_eq!(decoded.address, vm.programs[0].data);
     assert_eq!(decoded.this, vm.programs[0].data);
@@ -138,9 +138,9 @@ contract Testing {
       "#,
     );
 
-    vm.constructor("Testing", &[]);
-    let returns = vm.function("getThis", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    vm.constructor(&[]);
+    let returns = vm.function("getThis", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = MyStruct::try_from_slice(&encoded).unwrap();
     assert_eq!(decoded.a, "coffe");
     assert_eq!(decoded.b, b"tea");
@@ -190,15 +190,16 @@ fn primitive_structs() {
 }
         "#,
     );
-    vm.constructor("Testing", &[]);
-    let returns = vm.function("getThis", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    vm.constructor(&[]);
+    let returns = vm.function("getThis", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
+
     let decoded = NoPadStruct::try_from_slice(&encoded).unwrap();
     assert_eq!(decoded.a, 1238);
     assert_eq!(decoded.b, 87123);
 
-    let returns = vm.function("getThat", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    let returns = vm.function("getThat", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = PaddedStruct::try_from_slice(&encoded).unwrap();
     assert_eq!(decoded.a, 12998);
     assert_eq!(decoded.b, 240);
@@ -225,9 +226,12 @@ contract Testing {
       "#,
     );
 
-    vm.constructor("Testing", &[]);
-    let returns = vm.function("testStruct", &[BorshToken::String("nihao".to_string())]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    vm.constructor(&[]);
+
+    let returns = vm
+        .function("testStruct", &[BorshToken::String("nihao".to_string())])
+        .unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = Response::try_from_slice(&encoded).unwrap();
     assert_eq!(decoded.rr, "nihao");
 }
@@ -257,15 +261,15 @@ fn test_string_array() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
-    let returns = vm.function("encode", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    vm.constructor(&[]);
+    let returns = vm.function("encode", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = Response::try_from_slice(&encoded).unwrap();
     assert_eq!(decoded.a.len(), 0);
 
     let _ = vm.function("insertStrings", &[]);
-    let returns = vm.function("encode", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    let returns = vm.function("encode", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = Response::try_from_slice(&encoded).unwrap();
     assert_eq!(decoded.a.len(), 2);
     assert_eq!(decoded.a[0], "tea");
@@ -334,9 +338,9 @@ contract Testing {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
-    let returns = vm.function("testStruct", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    vm.constructor(&[]);
+    let returns = vm.function("testStruct", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = NonConstantStruct::try_from_slice(&encoded).unwrap();
 
     assert_eq!(decoded.a, 890234);
@@ -437,10 +441,10 @@ fn struct_in_array() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let _ = vm.function("addData", &[]);
-    let returns = vm.function("encodeStruct", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    let returns = vm.function("encodeStruct", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = Res1::try_from_slice(&encoded).unwrap();
 
     assert_eq!(decoded.item_1.a, 945);
@@ -450,8 +454,8 @@ fn struct_in_array() {
     let b: [u8; 21] = b"there_is_padding_here".to_owned();
     assert_eq!(&decoded.item_2.c[0..21], b);
 
-    let returns = vm.function("primitiveStruct", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    let returns = vm.function("primitiveStruct", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = Res2::try_from_slice(&encoded).unwrap();
 
     assert_eq!(decoded.item_1.len(), 3);
@@ -462,8 +466,8 @@ fn struct_in_array() {
     assert_eq!(decoded.item_3[0], NoPadStruct { a: 1, b: 2 });
     assert_eq!(decoded.item_3[1], NoPadStruct { a: 3, b: 4 });
 
-    let returns = vm.function("primitiveDynamicArray", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    let returns = vm.function("primitiveDynamicArray", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = Res3::try_from_slice(&encoded).unwrap();
 
     assert_eq!(decoded.item_1.len(), 2);
@@ -537,10 +541,10 @@ fn arrays() {
       "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let _ = vm.function("addData", &[]);
-    let returns = vm.function("encodeArray", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    let returns = vm.function("encodeArray", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = Res1::try_from_slice(&encoded).unwrap();
 
     assert_eq!(decoded.vec_1.len(), 3);
@@ -548,8 +552,8 @@ fn arrays() {
     assert_eq!(decoded.vec_1[1], 5523);
     assert_eq!(decoded.vec_1[2], -89);
 
-    let returns = vm.function("encodeComplex", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    let returns = vm.function("encodeComplex", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = Res2::try_from_slice(&encoded).unwrap();
 
     assert_eq!(decoded.complex_array.len(), 2);
@@ -564,8 +568,8 @@ fn arrays() {
         vec!["cortado".to_string(), "cappuccino".to_string()]
     );
 
-    let returns = vm.function("multiDimArrays", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    let returns = vm.function("multiDimArrays", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = Res3::try_from_slice(&encoded).unwrap();
 
     assert_eq!(decoded.multi_dim[0], [1, 2]);
@@ -650,9 +654,9 @@ contract Testing {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
-    let returns = vm.function("getThis", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    vm.constructor(&[]);
+    let returns = vm.function("getThis", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = Res1::try_from_slice(&encoded).unwrap();
 
     assert_eq!(decoded.item_1.len(), 1);
@@ -709,16 +713,16 @@ contract Testing {
     );
     assert_eq!(decoded.item_2, 5);
 
-    let returns = vm.function("multiDim", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    let returns = vm.function("multiDim", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = Res2::try_from_slice(&encoded).unwrap();
 
     assert_eq!(decoded.item.len(), 1);
     assert_eq!(decoded.item[0][0], [1, 2, 3, 4]);
     assert_eq!(decoded.item[0][1], [5, 6, 7, 8]);
 
-    let returns = vm.function("uniqueDim", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    let returns = vm.function("uniqueDim", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = Res3::try_from_slice(&encoded).unwrap();
 
     assert_eq!(decoded.item.len(), 5);
@@ -771,9 +775,9 @@ fn null_pointer() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
-    let returns = vm.function("test1", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    vm.constructor(&[]);
+    let returns = vm.function("test1", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = Res1::try_from_slice(&encoded).unwrap();
 
     assert_eq!(decoded.item.len(), 5);
@@ -782,8 +786,8 @@ fn null_pointer() {
         assert!(decoded.item[i].f2.is_empty())
     }
 
-    let returns = vm.function("test2", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    let returns = vm.function("test2", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = Res2::try_from_slice(&encoded).unwrap();
 
     assert_eq!(decoded.item.len(), 5);
@@ -818,9 +822,9 @@ fn external_function() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("doThat", &[]);
+    let returns = vm.function("doThat", &[]).unwrap().unwrap_tuple();
     let encoded = returns[2].clone().into_bytes().unwrap();
     let decoded = Res::try_from_slice(&encoded).unwrap();
 
@@ -853,9 +857,9 @@ fn bytes_arrays() {
     }
         "#,
     );
-    vm.constructor("Testing", &[]);
-    let returns = vm.function("testBytesArray", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    vm.constructor(&[]);
+    let returns = vm.function("testBytesArray", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = Res::try_from_slice(&encoded).unwrap();
 
     assert_eq!(&decoded.item_1[0], b"abcd");
@@ -892,9 +896,9 @@ fn uint8_arrays() {
     }"#,
     );
 
-    vm.constructor("Testing", &[]);
-    let returns = vm.function("testBytesArray", &[]);
-    let encoded = returns[0].clone().into_bytes().unwrap();
+    vm.constructor(&[]);
+    let returns = vm.function("testBytesArray", &[]).unwrap();
+    let encoded = returns.into_bytes().unwrap();
     let decoded = Res::try_from_slice(&encoded).unwrap();
 
     assert!(decoded.item_2.is_empty());
@@ -923,9 +927,9 @@ contract caller {
 }"#,
     );
 
-    vm.constructor("caller", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("do_call", &[]);
+    let returns = vm.function("do_call", &[]).unwrap().unwrap_tuple();
     assert_eq!(returns.len(), 2);
     assert_eq!(
         returns[0],

+ 62 - 56
tests/solana_tests/accessor.rs

@@ -13,16 +13,16 @@ fn types() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("f1", &[]);
+    let returns = vm.function("f1", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Int {
+        BorshToken::Int {
             width: 64,
             value: BigInt::from(102u8),
-        }]
+        }
     );
 
     let mut vm = build_solidity(
@@ -32,22 +32,24 @@ fn types() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function(
-        "f1",
-        &[BorshToken::Uint {
-            width: 256,
-            value: BigInt::from(2u8),
-        }],
-    );
+    let returns = vm
+        .function(
+            "f1",
+            &[BorshToken::Uint {
+                width: 256,
+                value: BigInt::from(2u8),
+            }],
+        )
+        .unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Int {
+        BorshToken::Int {
             width: 64,
             value: BigInt::from(5u8)
-        }]
+        }
     );
 
     let mut vm = build_solidity(
@@ -64,28 +66,30 @@ fn types() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
-
-    let returns = vm.function(
-        "f1",
-        &[
-            BorshToken::Uint {
-                width: 256,
-                value: BigInt::one(),
-            },
-            BorshToken::Uint {
-                width: 256,
-                value: BigInt::from(2u8),
-            },
-        ],
-    );
+    vm.constructor(&[]);
+
+    let returns = vm
+        .function(
+            "f1",
+            &[
+                BorshToken::Uint {
+                    width: 256,
+                    value: BigInt::one(),
+                },
+                BorshToken::Uint {
+                    width: 256,
+                    value: BigInt::from(2u8),
+                },
+            ],
+        )
+        .unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Int {
+        BorshToken::Int {
             width: 64,
             value: BigInt::from(2u8),
-        }]
+        }
     );
 
     let mut vm = build_solidity(
@@ -100,22 +104,24 @@ fn types() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function(
-        "f1",
-        &[BorshToken::Int {
-            width: 64,
-            value: BigInt::from(4000u16),
-        }],
-    );
+    let returns = vm
+        .function(
+            "f1",
+            &[BorshToken::Int {
+                width: 64,
+                value: BigInt::from(4000u16),
+            }],
+        )
+        .unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 64,
             value: BigInt::from(2u8)
-        }]
+        }
     );
 }
 
@@ -133,11 +139,11 @@ fn interfaces() {
         "#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("f1", &[]);
+    let returns = vm.function("f1", &[]).unwrap();
 
-    assert_eq!(returns, vec![BorshToken::FixedBytes(b"ab".to_vec())]);
+    assert_eq!(returns, BorshToken::uint8_fixed_array(b"ab".to_vec()));
 }
 
 #[test]
@@ -149,16 +155,16 @@ fn constant() {
         }"#,
     );
 
-    vm.constructor("x", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("z", &[]);
+    let returns = vm.function("z", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::FixedBytes(vec![
+        BorshToken::uint8_fixed_array(vec![
             0, 91, 121, 69, 17, 39, 209, 87, 169, 94, 81, 10, 68, 17, 183, 52, 82, 28, 128, 159,
             31, 73, 168, 235, 90, 61, 46, 198, 102, 241, 168, 79
-        ])]
+        ])
     );
 
     let mut vm = build_solidity(
@@ -168,16 +174,16 @@ fn constant() {
         }"#,
     );
 
-    vm.constructor("x", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("z", &[]);
+    let returns = vm.function("z", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::FixedBytes(vec![
+        BorshToken::uint8_fixed_array(vec![
             190, 212, 99, 127, 110, 196, 102, 135, 47, 156, 116, 193, 201, 43, 100, 230, 152, 184,
             58, 103, 63, 106, 217, 142, 143, 211, 220, 125, 255, 210, 48, 89
-        ])]
+        ])
     );
 
     let mut vm = build_solidity(
@@ -187,15 +193,15 @@ fn constant() {
         }"#,
     );
 
-    vm.constructor("x", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("z", &[]);
+    let returns = vm.function("z", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::FixedBytes(vec![
+        BorshToken::uint8_fixed_array(vec![
             255, 206, 178, 91, 165, 156, 178, 193, 7, 94, 233, 48, 117, 76, 48, 215, 255, 45, 61,
             225
-        ])]
+        ])
     );
 }

+ 22 - 18
tests/solana_tests/account_info.rs

@@ -27,14 +27,16 @@ fn lamports() {
         }"#,
     );
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     vm.account_data.get_mut(&vm.origin).unwrap().lamports = 17672630920854456917u64;
 
-    let returns = vm.function("test", &[BorshToken::Address(vm.origin)]);
+    let returns = vm
+        .function("test", &[BorshToken::Address(vm.origin)])
+        .unwrap();
 
     assert_eq!(
-        returns[0],
+        returns,
         BorshToken::Uint {
             width: 64,
             value: BigInt::from(17672630920854456917u64),
@@ -62,13 +64,13 @@ fn owner() {
         }"#,
     );
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("test", &[]);
+    let returns = vm.function("test", &[]).unwrap();
 
-    let owner = vm.stack[0].program.to_vec();
+    let owner = vm.stack[0].program;
 
-    assert_eq!(returns[0], BorshToken::FixedBytes(owner));
+    assert_eq!(returns, BorshToken::Address(owner));
 }
 
 #[test]
@@ -103,23 +105,25 @@ fn data() {
         }"#,
     );
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     for i in 0..10 {
-        let returns = vm.function(
-            "test",
-            &[BorshToken::Uint {
-                width: 32,
-                value: BigInt::from(i),
-            }],
-        );
+        let returns = vm
+            .function(
+                "test",
+                &[BorshToken::Uint {
+                    width: 32,
+                    value: BigInt::from(i),
+                }],
+            )
+            .unwrap();
 
         let this = &vm.stack[0].data;
 
         let val = vm.account_data[this].data[i];
 
         assert_eq!(
-            returns[0],
+            returns,
             BorshToken::Uint {
                 width: 8,
                 value: BigInt::from(val),
@@ -127,14 +131,14 @@ fn data() {
         );
     }
 
-    let returns = vm.function("test2", &[]);
+    let returns = vm.function("test2", &[]).unwrap();
 
     let this = &vm.stack[0].data;
 
     let val = u32::from_le_bytes(vm.account_data[this].data[1..5].try_into().unwrap());
 
     assert_eq!(
-        returns[0],
+        returns,
         BorshToken::Uint {
             width: 32,
             value: BigInt::from(val),

File diff suppressed because it is too large
+ 311 - 281
tests/solana_tests/arrays.rs


+ 77 - 74
tests/solana_tests/balance.rs

@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: Apache-2.0
 
 use crate::{account_new, build_solidity, AccountState, BorshToken};
-use ethabi::{Function, StateMutability};
+use anchor_syn::idl::IdlInstruction;
 use num_bigint::BigInt;
 
 #[test]
@@ -15,7 +15,7 @@ fn get_balance() {
         }"#,
     );
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     let new = account_new();
 
@@ -28,14 +28,14 @@ fn get_balance() {
         },
     );
 
-    let returns = vm.function("test", &[BorshToken::Address(new)]);
+    let returns = vm.function("test", &[BorshToken::Address(new)]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 64,
             value: BigInt::from(102u8),
-        }]
+        }
     );
 }
 
@@ -50,7 +50,7 @@ fn send_fails() {
         }"#,
     );
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     let new = account_new();
 
@@ -63,18 +63,20 @@ fn send_fails() {
         },
     );
 
-    let returns = vm.function(
-        "send",
-        &[
-            BorshToken::FixedBytes(new.to_vec()),
-            BorshToken::Uint {
-                width: 64,
-                value: BigInt::from(102u8),
-            },
-        ],
-    );
-
-    assert_eq!(returns, vec![BorshToken::Bool(false)]);
+    let returns = vm
+        .function(
+            "send",
+            &[
+                BorshToken::FixedBytes(new.to_vec()),
+                BorshToken::Uint {
+                    width: 64,
+                    value: BigInt::from(102u8),
+                },
+            ],
+        )
+        .unwrap();
+
+    assert_eq!(returns, BorshToken::Bool(false));
 }
 
 #[test]
@@ -92,7 +94,7 @@ fn send_succeeds() {
 
     vm.account_data.get_mut(&vm.stack[0].data).unwrap().lamports = 103;
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     let new = account_new();
 
@@ -105,18 +107,20 @@ fn send_succeeds() {
         },
     );
 
-    let returns = vm.function(
-        "send",
-        &[
-            BorshToken::FixedBytes(new.to_vec()),
-            BorshToken::Uint {
-                width: 64,
-                value: BigInt::from(102u8),
-            },
-        ],
-    );
+    let returns = vm
+        .function(
+            "send",
+            &[
+                BorshToken::FixedBytes(new.to_vec()),
+                BorshToken::Uint {
+                    width: 64,
+                    value: BigInt::from(102u8),
+                },
+            ],
+        )
+        .unwrap();
 
-    assert_eq!(returns, vec![BorshToken::Bool(true)]);
+    assert_eq!(returns, BorshToken::Bool(true));
 
     assert_eq!(vm.account_data.get_mut(&new).unwrap().lamports, 107);
 
@@ -139,7 +143,7 @@ fn send_overflows() {
 
     vm.account_data.get_mut(&vm.stack[0].data).unwrap().lamports = 103;
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     let new = account_new();
 
@@ -152,18 +156,20 @@ fn send_overflows() {
         },
     );
 
-    let returns = vm.function(
-        "send",
-        &[
-            BorshToken::FixedBytes(new.to_vec()),
-            BorshToken::Uint {
-                width: 64,
-                value: BigInt::from(102u8),
-            },
-        ],
-    );
+    let returns = vm
+        .function(
+            "send",
+            &[
+                BorshToken::FixedBytes(new.to_vec()),
+                BorshToken::Uint {
+                    width: 64,
+                    value: BigInt::from(102u8),
+                },
+            ],
+        )
+        .unwrap();
 
-    assert_eq!(returns, vec![BorshToken::Bool(false)]);
+    assert_eq!(returns, BorshToken::Bool(false));
 
     assert_eq!(
         vm.account_data.get_mut(&new).unwrap().lamports,
@@ -189,7 +195,7 @@ fn transfer_succeeds() {
 
     vm.account_data.get_mut(&vm.stack[0].data).unwrap().lamports = 103;
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     let new = account_new();
 
@@ -234,7 +240,7 @@ fn transfer_fails_not_enough() {
 
     vm.account_data.get_mut(&vm.stack[0].data).unwrap().lamports = 103;
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     let new = account_new();
 
@@ -257,7 +263,6 @@ fn transfer_fails_not_enough() {
             },
         ],
     );
-    std::println!("{:?}", res);
     assert!(res.is_err());
 }
 
@@ -276,7 +281,7 @@ fn transfer_fails_overflow() {
 
     vm.account_data.get_mut(&vm.stack[0].data).unwrap().lamports = 103;
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     let new = account_new();
 
@@ -315,24 +320,20 @@ fn fallback() {
 
     vm.account_data.get_mut(&vm.origin).unwrap().lamports = 312;
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
-    if let Some(abi) = &vm.stack[0].abi {
-        let mut abi = abi.clone();
+    if let Some(idl) = &vm.stack[0].idl {
+        let mut idl = idl.clone();
 
-        #[allow(deprecated)]
-        abi.functions.insert(
-            String::from("extinct"),
-            vec![Function {
-                name: "extinct".to_string(),
-                inputs: vec![],
-                outputs: vec![],
-                constant: None,
-                state_mutability: StateMutability::Payable,
-            }],
-        );
+        idl.instructions.push(IdlInstruction {
+            name: "extinct".to_string(),
+            docs: None,
+            accounts: vec![],
+            args: vec![],
+            returns: None,
+        });
 
-        vm.stack[0].abi = Some(abi);
+        vm.stack[0].idl = Some(idl);
     }
 
     vm.function("extinct", &[]);
@@ -355,7 +356,7 @@ fn value_overflows() {
 
     vm.account_data.get_mut(&vm.stack[0].data).unwrap().lamports = 103;
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     let new = account_new();
 
@@ -392,18 +393,20 @@ fn value_overflows() {
     );
     assert_eq!(res.ok(), Some(4294967296));
 
-    let returns = vm.function(
-        "send",
-        &[
-            BorshToken::FixedBytes(new.to_vec()),
-            BorshToken::Uint {
-                width: 128,
-                value: BigInt::from(102u8),
-            },
-        ],
-    );
-
-    assert_eq!(returns, vec![BorshToken::Bool(false)]);
+    let returns = vm
+        .function(
+            "send",
+            &[
+                BorshToken::FixedBytes(new.to_vec()),
+                BorshToken::Uint {
+                    width: 128,
+                    value: BigInt::from(102u8),
+                },
+            ],
+        )
+        .unwrap();
+
+    assert_eq!(returns, BorshToken::Bool(false));
 
     assert_eq!(
         vm.account_data.get_mut(&new).unwrap().lamports,

+ 64 - 57
tests/solana_tests/builtin.rs

@@ -30,76 +30,71 @@ fn builtins() {
         }"#,
     );
 
-    vm.constructor("timestamp", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("mr_now", &[]);
+    let returns = vm.function("mr_now", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 64,
             value: BigInt::from(1620656423u64)
-        }]
+        }
     );
 
-    let returns = vm.function("mr_slot", &[]);
+    let returns = vm.function("mr_slot", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 64,
             value: BigInt::from(70818331u64),
-        }]
+        }
     );
 
-    let returns = vm.function("mr_blocknumber", &[]);
+    let returns = vm.function("mr_blocknumber", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 64,
             value: BigInt::from(70818331u64)
-        },]
+        },
     );
 
-    let returns = vm.function(
-        "msg_data",
-        &[BorshToken::Uint {
-            width: 32,
-            value: BigInt::from(0xdeadcafeu32),
-        }],
-    );
-
-    if let BorshToken::Bytes(v) = &returns[0] {
+    let returns = vm
+        .function(
+            "msg_data",
+            &[BorshToken::Uint {
+                width: 32,
+                value: BigInt::from(0xdeadcafeu32),
+            }],
+        )
+        .unwrap();
+
+    if let BorshToken::Bytes(v) = &returns {
         println!("{}", hex::encode(v));
     }
 
     assert_eq!(
         returns,
-        vec![BorshToken::Bytes(
-            hex::decode("a73fcaa3b216e85afecaadde").unwrap()
-        )]
+        BorshToken::Bytes(hex::decode("a73fcaa3b216e85afecaadde").unwrap())
     );
 
-    let returns = vm.function("sig", &[]);
+    let returns = vm.function("sig", &[]).unwrap();
 
-    if let BorshToken::FixedBytes(v) = &returns[0] {
+    if let Some(v) = returns.clone().into_fixed_bytes() {
         println!("{}", hex::encode(v));
     }
 
     assert_eq!(
         returns,
-        vec![BorshToken::FixedBytes(
-            hex::decode("4b22101a3c98d6cb").unwrap()
-        )]
+        BorshToken::uint8_fixed_array(hex::decode("4b22101a3c98d6cb").unwrap())
     );
 
-    let returns = vm.function("prog", &[]);
+    let returns = vm.function("prog", &[]).unwrap();
 
-    assert_eq!(
-        returns,
-        vec![BorshToken::FixedBytes(vm.stack[0].program.to_vec())]
-    );
+    assert_eq!(returns, BorshToken::Address(vm.stack[0].program));
 }
 
 #[test]
@@ -138,11 +133,13 @@ fn pda() {
         }"#,
     );
 
-    vm.constructor("pda", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("create_pda", &[BorshToken::Bool(true)]);
+    let returns = vm
+        .function("create_pda", &[BorshToken::Bool(true)])
+        .unwrap();
 
-    if let BorshToken::FixedBytes(bs) = &returns[0] {
+    if let Some(bs) = returns.clone().into_fixed_bytes() {
         assert_eq!(
             bs.to_base58(),
             "2fnQrngrQT4SeLcdToJAD96phoEjNL2man2kfRLCASVk"
@@ -151,9 +148,11 @@ fn pda() {
         panic!("{:?} not expected", returns);
     }
 
-    let returns = vm.function("create_pda", &[BorshToken::Bool(false)]);
+    let returns = vm
+        .function("create_pda", &[BorshToken::Bool(false)])
+        .unwrap();
 
-    if let BorshToken::FixedBytes(bs) = &returns[0] {
+    if let Some(bs) = returns.clone().into_fixed_bytes() {
         assert_eq!(
             bs.to_base58(),
             "7YgSsrAiAEJFqBNujFBRsEossqdpV31byeJLBsZ5QSJE"
@@ -162,15 +161,17 @@ fn pda() {
         panic!("{:?} not expected", returns);
     }
 
-    let returns = vm.function(
-        "create_pda2",
-        &[
-            BorshToken::Bytes(b"Talking".to_vec()),
-            BorshToken::Bytes(b"Squirrels".to_vec()),
-        ],
-    );
-
-    if let BorshToken::FixedBytes(bs) = &returns[0] {
+    let returns = vm
+        .function(
+            "create_pda2",
+            &[
+                BorshToken::Bytes(b"Talking".to_vec()),
+                BorshToken::Bytes(b"Squirrels".to_vec()),
+            ],
+        )
+        .unwrap();
+
+    if let Some(bs) = returns.clone().into_fixed_bytes() {
         assert_eq!(
             bs.to_base58(),
             "2fnQrngrQT4SeLcdToJAD96phoEjNL2man2kfRLCASVk"
@@ -179,11 +180,14 @@ fn pda() {
         panic!("{:?} not expected", returns);
     }
 
-    let returns = vm.function("create_pda2_bump", &[BorshToken::Bool(true)]);
+    let returns = vm
+        .function("create_pda2_bump", &[BorshToken::Bool(true)])
+        .unwrap()
+        .unwrap_tuple();
 
-    assert_eq!(returns[1], BorshToken::FixedBytes(vec![255]));
+    assert_eq!(returns[1], BorshToken::uint8_fixed_array(vec![255]));
 
-    if let BorshToken::FixedBytes(bs) = &returns[0] {
+    if let Some(bs) = returns[0].clone().into_fixed_bytes() {
         assert_eq!(
             bs.to_base58(),
             "DZpR2BwsPVtbXxUUbMx5tK58Ln2T9RUtAshtR2ePqDcu"
@@ -192,11 +196,14 @@ fn pda() {
         panic!("{:?} not expected", returns);
     }
 
-    let returns = vm.function("create_pda2_bump", &[BorshToken::Bool(false)]);
+    let returns = vm
+        .function("create_pda2_bump", &[BorshToken::Bool(false)])
+        .unwrap()
+        .unwrap_tuple();
 
-    assert_eq!(returns[1], BorshToken::FixedBytes(vec![255]));
+    assert_eq!(returns[1], BorshToken::uint8_fixed_array(vec![255]));
 
-    if let BorshToken::FixedBytes(bs) = &returns[0] {
+    if let Some(bs) = returns[0].clone().into_fixed_bytes() {
         assert_eq!(
             bs.to_base58(),
             "3Y19WiAiLD8kT8APmtk41NgHEpkYTzx28s1uwAX8LJq4"
@@ -222,9 +229,9 @@ fn test_string_bytes_buffer_write() {
     }
         "#,
     );
-    vm.constructor("Testing", &[]);
-    let returns = vm.function("testStringAndBytes", &[]);
-    let bytes = returns[0].clone().into_bytes().unwrap();
+    vm.constructor(&[]);
+    let returns = vm.function("testStringAndBytes", &[]).unwrap();
+    let bytes = returns.into_bytes().unwrap();
 
     assert_eq!(bytes.len(), 9);
     assert_eq!(&bytes[0..6], b"coffee");
@@ -247,7 +254,7 @@ fn out_of_bounds_bytes_write() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let _ = vm.function("testBytesOut", &[]);
 }
 
@@ -267,6 +274,6 @@ fn out_of_bounds_string_write() {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
     let _ = vm.function("testStringOut", &[]);
 }

+ 113 - 93
tests/solana_tests/call.rs

@@ -28,7 +28,7 @@ fn simple_external_call() {
         }"#,
     );
 
-    vm.constructor("bar1", &[]);
+    vm.constructor(&[]);
 
     vm.function("test_bar", &[BorshToken::String(String::from("yo"))]);
 
@@ -40,7 +40,7 @@ fn simple_external_call() {
 
     vm.set_program(0);
 
-    vm.constructor("bar0", &[]);
+    vm.constructor(&[]);
 
     vm.function(
         "test_bar",
@@ -73,38 +73,42 @@ fn external_call_with_returns() {
         }"#,
     );
 
-    vm.constructor("bar1", &[]);
+    vm.constructor(&[]);
 
-    let res = vm.function(
-        "test_bar",
-        &[BorshToken::Int {
-            width: 64,
-            value: BigInt::from(21),
-        }],
-    );
+    let res = vm
+        .function(
+            "test_bar",
+            &[BorshToken::Int {
+                width: 64,
+                value: BigInt::from(21),
+            }],
+        )
+        .unwrap();
 
     assert_eq!(
         res,
-        vec![BorshToken::Int {
+        BorshToken::Int {
             width: 64,
             value: BigInt::from(24u8)
-        }]
+        }
     );
 
     let bar1_account = vm.stack[0].data;
 
     vm.set_program(0);
 
-    vm.constructor("bar0", &[]);
+    vm.constructor(&[]);
 
-    let res = vm.function("test_other", &[BorshToken::Address(bar1_account)]);
+    let res = vm
+        .function("test_other", &[BorshToken::Address(bar1_account)])
+        .unwrap();
 
     assert_eq!(
         res,
-        vec![BorshToken::Int {
+        BorshToken::Int {
             width: 64,
             value: BigInt::from(15u8)
-        }]
+        }
     );
 }
 
@@ -132,38 +136,42 @@ fn external_raw_call_with_returns() {
         }"#,
     );
 
-    vm.constructor("bar1", &[]);
+    vm.constructor(&[]);
 
-    let res = vm.function(
-        "test_bar",
-        &[BorshToken::Int {
-            width: 64,
-            value: BigInt::from(21u8),
-        }],
-    );
+    let res = vm
+        .function(
+            "test_bar",
+            &[BorshToken::Int {
+                width: 64,
+                value: BigInt::from(21u8),
+            }],
+        )
+        .unwrap();
 
     assert_eq!(
         res,
-        vec![BorshToken::Int {
+        BorshToken::Int {
             width: 64,
             value: BigInt::from(24u8),
-        }]
+        }
     );
 
     let bar1_account = vm.stack[0].data;
 
     vm.set_program(0);
 
-    vm.constructor("bar0", &[]);
+    vm.constructor(&[]);
 
-    let res = vm.function("test_other", &[BorshToken::Address(bar1_account)]);
+    let res = vm
+        .function("test_other", &[BorshToken::Address(bar1_account)])
+        .unwrap();
 
     assert_eq!(
         res,
-        vec![BorshToken::Int {
+        BorshToken::Int {
             width: 64,
             value: BigInt::from(15u8),
-        }]
+        }
     );
 }
 
@@ -187,9 +195,9 @@ fn call_external_func_type() {
     "#,
     );
 
-    vm.constructor("testing", &[]);
+    vm.constructor(&[]);
 
-    let res = vm.function("doTest", &[]);
+    let res = vm.function("doTest", &[]).unwrap().unwrap_tuple();
 
     assert_eq!(
         res,
@@ -234,27 +242,31 @@ fn external_call_with_string_returns() {
         }"#,
     );
 
-    vm.constructor("bar1", &[]);
+    vm.constructor(&[]);
 
-    let res = vm.function(
-        "test_bar",
-        &[BorshToken::Int {
-            width: 64,
-            value: BigInt::from(22u8),
-        }],
-    );
+    let res = vm
+        .function(
+            "test_bar",
+            &[BorshToken::Int {
+                width: 64,
+                value: BigInt::from(22u8),
+            }],
+        )
+        .unwrap();
 
-    assert_eq!(res, vec![BorshToken::String(String::from("foo:22"))]);
+    assert_eq!(res, BorshToken::String(String::from("foo:22")));
 
     let bar1_account = vm.stack[0].data;
 
     vm.set_program(0);
 
-    vm.constructor("bar0", &[]);
+    vm.constructor(&[]);
 
-    let res = vm.function("test_other", &[BorshToken::Address(bar1_account)]);
+    let res = vm
+        .function("test_other", &[BorshToken::Address(bar1_account)])
+        .unwrap();
 
-    assert_eq!(res, vec![BorshToken::String(String::from("foo:7"))]);
+    assert_eq!(res, BorshToken::String(String::from("foo:7")));
 
     vm.function("test_this", &[BorshToken::Address(bar1_account)]);
 }
@@ -283,38 +295,42 @@ fn encode_call() {
         }"#,
     );
 
-    vm.constructor("bar1", &[]);
+    vm.constructor(&[]);
 
-    let res = vm.function(
-        "test_bar",
-        &[BorshToken::Int {
-            width: 64,
-            value: BigInt::from(21u8),
-        }],
-    );
+    let res = vm
+        .function(
+            "test_bar",
+            &[BorshToken::Int {
+                width: 64,
+                value: BigInt::from(21u8),
+            }],
+        )
+        .unwrap();
 
     assert_eq!(
         res,
-        vec![BorshToken::Int {
+        BorshToken::Int {
             width: 64,
             value: BigInt::from(24u8)
-        }]
+        }
     );
 
     let bar1_account = vm.stack[0].data;
 
     vm.set_program(0);
 
-    vm.constructor("bar0", &[]);
+    vm.constructor(&[]);
 
-    let res = vm.function("test_other", &[BorshToken::Address(bar1_account)]);
+    let res = vm
+        .function("test_other", &[BorshToken::Address(bar1_account)])
+        .unwrap();
 
     assert_eq!(
         res,
-        vec![BorshToken::Int {
+        BorshToken::Int {
             width: 64,
             value: BigInt::from(15u8)
-        }]
+        }
     );
 }
 
@@ -347,58 +363,62 @@ fn internal_function_storage() {
         }"#,
     );
 
-    vm.constructor("ft", &[]);
+    vm.constructor(&[]);
 
     let res = vm.function("set_op", &[BorshToken::Bool(true)]);
 
-    assert_eq!(res, vec![]);
+    assert!(res.is_none());
 
-    let res = vm.function(
-        "test",
-        &[
-            BorshToken::Int {
-                width: 32,
-                value: BigInt::from(3u8),
-            },
-            BorshToken::Int {
-                width: 32,
-                value: BigInt::from(5u8),
-            },
-        ],
-    );
+    let res = vm
+        .function(
+            "test",
+            &[
+                BorshToken::Int {
+                    width: 32,
+                    value: BigInt::from(3u8),
+                },
+                BorshToken::Int {
+                    width: 32,
+                    value: BigInt::from(5u8),
+                },
+            ],
+        )
+        .unwrap();
 
     assert_eq!(
         res,
-        vec![BorshToken::Int {
+        BorshToken::Int {
             width: 32,
             value: BigInt::from(15u8)
-        },]
+        }
     );
 
     let res = vm.function("set_op", &[BorshToken::Bool(false)]);
 
-    assert_eq!(res, vec![]);
+    assert!(res.is_none());
 
-    let res = vm.function(
-        "test",
-        &[
-            BorshToken::Int {
-                width: 32,
-                value: BigInt::from(3u8),
-            },
-            BorshToken::Int {
-                width: 32,
-                value: BigInt::from(5u8),
-            },
-        ],
-    );
+    let res = vm
+        .function(
+            "test",
+            &[
+                BorshToken::Int {
+                    width: 32,
+                    value: BigInt::from(3u8),
+                },
+                BorshToken::Int {
+                    width: 32,
+                    value: BigInt::from(5u8),
+                },
+            ],
+        )
+        .unwrap();
 
     assert_eq!(
         res,
-        vec![BorshToken::Int {
+        BorshToken::Int {
             width: 32,
             value: BigInt::from(8u8)
-        }]
+        }
     );
 }
 
@@ -439,7 +459,7 @@ fn raw_call_accounts() {
         }"#,
     );
 
-    vm.constructor("SplToken", &[]);
+    vm.constructor(&[]);
 
     let token = Pubkey(
         "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
@@ -520,7 +540,7 @@ fn pda() {
         }"#,
     );
 
-    vm.constructor("pda", &[]);
+    vm.constructor(&[]);
 
     let test_args = |vm: &VirtualMachine, _instr: &Instruction, signers: &[Pubkey]| {
         assert_eq!(

+ 8 - 8
tests/solana_tests/constant.rs

@@ -20,15 +20,15 @@ fn constant() {
         "#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("f", &[]);
+    let returns = vm.function("f", &[]).unwrap();
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(42u8)
-        }]
+        }
     );
 
     let mut vm = build_solidity(
@@ -46,14 +46,14 @@ fn constant() {
         "#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("f", &[]);
+    let returns = vm.function("f", &[]).unwrap();
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(42u8)
-        }]
+        }
     );
 }

+ 48 - 53
tests/solana_tests/create_contract.rs

@@ -36,7 +36,7 @@ fn simple_create_contract_no_seed() {
 
     vm.set_program(0);
 
-    vm.constructor("bar0", &[]);
+    vm.constructor(&[]);
 
     let program_id: Account = "CPDgqnhHDCsjFkJKMturRQ1QeM9EXZg3EYCeDoRP8pdT"
         .from_base58()
@@ -58,10 +58,12 @@ fn simple_create_contract_no_seed() {
         },
     );
 
-    let bar1 = vm.function(
-        "test_other",
-        &[BorshToken::Address(acc), BorshToken::Address(payer)],
-    );
+    let bar1 = vm
+        .function(
+            "test_other",
+            &[BorshToken::Address(acc), BorshToken::Address(payer)],
+        )
+        .unwrap();
 
     assert_eq!(vm.logs, "bar1 says: yo from bar0");
 
@@ -71,7 +73,7 @@ fn simple_create_contract_no_seed() {
 
     vm.function(
         "call_bar1_at_address",
-        &[bar1[0].clone(), BorshToken::String(String::from("xywoleh"))],
+        &[bar1, BorshToken::String(String::from("xywoleh"))],
     );
 
     assert_eq!(vm.logs, "Hello xywoleh");
@@ -108,7 +110,7 @@ fn simple_create_contract() {
 
     vm.set_program(0);
 
-    vm.constructor("bar0", &[]);
+    vm.constructor(&[]);
 
     let program_id: Account = "CPDgqnhHDCsjFkJKMturRQ1QeM9EXZg3EYCeDoRP8pdT"
         .from_base58()
@@ -119,10 +121,12 @@ fn simple_create_contract() {
     let seed = vm.create_pda(&program_id);
     let payer = account_new();
 
-    let bar1 = vm.function(
-        "test_other",
-        &[BorshToken::Address(seed.0), BorshToken::Address(payer)],
-    );
+    let bar1 = vm
+        .function(
+            "test_other",
+            &[BorshToken::Address(seed.0), BorshToken::Address(payer)],
+        )
+        .unwrap();
 
     assert_eq!(vm.logs, "bar1 says: yo from bar0");
 
@@ -132,7 +136,7 @@ fn simple_create_contract() {
 
     vm.function(
         "call_bar1_at_address",
-        &[bar1[0].clone(), BorshToken::String(String::from("xywoleh"))],
+        &[bar1, BorshToken::String(String::from("xywoleh"))],
     );
 
     assert_eq!(vm.logs, "Hello xywoleh");
@@ -147,7 +151,7 @@ fn create_contract_wrong_program_id() {
         "#,
     );
 
-    vm.constructor("bar0", &[]);
+    vm.constructor(&[]);
 
     let program = &vm.programs[0].program;
     let code = vm.account_data[program].data.clone();
@@ -193,12 +197,12 @@ fn create_contract_with_payer() {
     vm.account_data.get_mut(&data).unwrap().data.truncate(0);
     let payer = account_new();
 
-    vm.constructor("x", &[BorshToken::Address(payer)]);
+    vm.constructor(&[BorshToken::Address(payer)]);
 
-    let ret = vm.function("f", &[]);
+    let ret = vm.function("f", &[]).unwrap();
 
     assert_eq!(
-        ret[0],
+        ret,
         BorshToken::Uint {
             width: 64,
             value: 102.into()
@@ -237,7 +241,7 @@ fn missing_contract() {
 
     vm.set_program(0);
 
-    vm.constructor("bar0", &[]);
+    vm.constructor(&[]);
 
     let missing = account_new();
 
@@ -269,7 +273,7 @@ fn two_contracts() {
 
     vm.set_program(0);
 
-    vm.constructor("bar0", &[]);
+    vm.constructor(&[]);
 
     let program_id: Account = "CPDgqnhHDCsjFkJKMturRQ1QeM9EXZg3EYCeDoRP8pdT"
         .from_base58()
@@ -329,22 +333,19 @@ fn account_with_space() {
 
     let payer = account_new();
 
-    vm.constructor(
-        "bar",
-        &[
-            BorshToken::Uint {
-                width: 64,
-                value: 3.into(),
-            },
-            BorshToken::Address(payer),
-        ],
-    );
+    vm.constructor(&[
+        BorshToken::Uint {
+            width: 64,
+            value: 3.into(),
+        },
+        BorshToken::Address(payer),
+    ]);
 
     assert_eq!(vm.account_data.get_mut(&data).unwrap().data.len(), 3 * 102);
 
-    let ret = vm.function("hello", &[]);
+    let ret = vm.function("hello", &[]).unwrap();
 
-    assert_eq!(ret[0], BorshToken::Bool(true));
+    assert_eq!(ret, BorshToken::Bool(true));
 }
 
 #[test]
@@ -373,19 +374,16 @@ fn account_with_seed() {
 
     let payer = account_new();
 
-    vm.constructor(
-        "bar",
-        &[BorshToken::Bytes(seed.1), BorshToken::Address(payer)],
-    );
+    vm.constructor(&[BorshToken::Bytes(seed.1), BorshToken::Address(payer)]);
 
     assert_eq!(
         vm.account_data.get_mut(&seed.0).unwrap().data.len(),
         511 + 102
     );
 
-    let ret = vm.function("hello", &[]);
+    let ret = vm.function("hello", &[]).unwrap();
 
-    assert_eq!(ret[0], BorshToken::Bool(true));
+    assert_eq!(ret, BorshToken::Bool(true));
 }
 
 #[test]
@@ -417,26 +415,23 @@ fn account_with_seed_bump() {
 
     let payer = account_new();
 
-    vm.constructor(
-        "bar",
-        &[
-            BorshToken::Bytes(seed.1),
-            BorshToken::Address(payer),
-            BorshToken::Uint {
-                width: 8,
-                value: bump.into(),
-            },
-        ],
-    );
+    vm.constructor(&[
+        BorshToken::Bytes(seed.1),
+        BorshToken::Address(payer),
+        BorshToken::Uint {
+            width: 8,
+            value: bump.into(),
+        },
+    ]);
 
     assert_eq!(
         vm.account_data.get_mut(&seed.0).unwrap().data.len(),
         511 + 102
     );
 
-    let ret = vm.function("hello", &[]);
+    let ret = vm.function("hello", &[]).unwrap();
 
-    assert_eq!(ret[0], BorshToken::Bool(true));
+    assert_eq!(ret, BorshToken::Bool(true));
 }
 
 #[test]
@@ -466,16 +461,16 @@ fn account_with_seed_bump_literals() {
 
     vm.stack[0].data = account.0;
 
-    vm.constructor("bar", &[]);
+    vm.constructor(&[]);
 
     assert_eq!(
         vm.account_data.get_mut(&account.0).unwrap().data.len(),
         8192
     );
 
-    let ret = vm.function("hello", &[]);
+    let ret = vm.function("hello", &[]).unwrap();
 
-    assert_eq!(ret[0], BorshToken::Bool(true));
+    assert_eq!(ret, BorshToken::Bool(true));
 }
 
 #[test]
@@ -508,7 +503,7 @@ fn create_child() {
     );
 
     vm.set_program(0);
-    vm.constructor("creator", &[]);
+    vm.constructor(&[]);
 
     let payer = account_new();
 

+ 22 - 10
tests/solana_tests/destructure.rs

@@ -18,9 +18,12 @@ fn conditional_destructure() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("f", &[BorshToken::Bool(true), BorshToken::Bool(true)]);
+    let returns = vm
+        .function("f", &[BorshToken::Bool(true), BorshToken::Bool(true)])
+        .unwrap()
+        .unwrap_tuple();
 
     assert_eq!(
         returns,
@@ -36,7 +39,10 @@ fn conditional_destructure() {
         ]
     );
 
-    let returns = vm.function("f", &[BorshToken::Bool(true), BorshToken::Bool(false)]);
+    let returns = vm
+        .function("f", &[BorshToken::Bool(true), BorshToken::Bool(false)])
+        .unwrap()
+        .unwrap_tuple();
 
     assert_eq!(
         returns,
@@ -52,7 +58,10 @@ fn conditional_destructure() {
         ]
     );
 
-    let returns = vm.function("f", &[BorshToken::Bool(false), BorshToken::Bool(false)]);
+    let returns = vm
+        .function("f", &[BorshToken::Bool(false), BorshToken::Bool(false)])
+        .unwrap()
+        .unwrap_tuple();
 
     assert_eq!(
         returns,
@@ -68,7 +77,10 @@ fn conditional_destructure() {
         ]
     );
 
-    let returns = vm.function("f", &[BorshToken::Bool(false), BorshToken::Bool(true)]);
+    let returns = vm
+        .function("f", &[BorshToken::Bool(false), BorshToken::Bool(true)])
+        .unwrap()
+        .unwrap_tuple();
 
     assert_eq!(
         returns,
@@ -101,9 +113,9 @@ fn casting_destructure() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("f", &[]);
+    let returns = vm.function("f", &[]).unwrap().unwrap_tuple();
 
     assert_eq!(
         returns,
@@ -129,9 +141,9 @@ fn casting_destructure() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("f", &[]);
+    let returns = vm.function("f", &[]).unwrap();
 
-    assert_eq!(returns, vec![BorshToken::String(String::from("Hello")),]);
+    assert_eq!(returns, BorshToken::String(String::from("Hello")));
 }

+ 2 - 2
tests/solana_tests/events.rs

@@ -23,7 +23,7 @@ fn simple_event() {
         }"#,
     );
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     vm.function("go", &[]);
 
@@ -79,7 +79,7 @@ fn less_simple_event() {
         }"#,
     );
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     vm.function("go", &[]);
 

+ 60 - 52
tests/solana_tests/expressions.rs

@@ -20,15 +20,13 @@ fn interfaceid() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("get", &[]);
+    let returns = vm.function("get", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::FixedBytes(
-            0x88632631fac67239u64.to_be_bytes().to_vec()
-        )]
+        BorshToken::uint8_fixed_array(0x88632631fac67239u64.to_be_bytes().to_vec())
     );
 }
 
@@ -59,23 +57,21 @@ fn write_buffer() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("test1", &[]);
+    let returns = vm.function("test1", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Bytes(
-            [0xbc, 0xbc, 0xbd, 0xbe, 8, 7, 6, 5, 4, 3, 2, 1].to_vec()
-        )]
+        BorshToken::Bytes([0xbc, 0xbc, 0xbd, 0xbe, 8, 7, 6, 5, 4, 3, 2, 1].to_vec())
     );
 
-    let returns = vm.function("test2", &[]);
+    let returns = vm.function("test2", &[]).unwrap();
 
     let mut buf = vec![0x42u8, 0x41u8];
     buf.extend_from_slice(&vm.stack[0].program);
 
-    assert_eq!(returns, vec![BorshToken::Bytes(buf)]);
+    assert_eq!(returns, BorshToken::Bytes(buf));
 
     let res = vm.function_must_fail("test3", &[]);
     assert_eq!(res, Ok(4294967296));
@@ -96,14 +92,17 @@ fn read_buffer() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function(
-        "test1",
-        &[BorshToken::Bytes(
-            [0xbc, 0xbc, 0xbd, 0xbe, 8, 7, 6, 5, 4, 3, 2, 1].to_vec(),
-        )],
-    );
+    let returns = vm
+        .function(
+            "test1",
+            &[BorshToken::Bytes(
+                [0xbc, 0xbc, 0xbd, 0xbe, 8, 7, 6, 5, 4, 3, 2, 1].to_vec(),
+            )],
+        )
+        .unwrap()
+        .unwrap_tuple();
 
     assert_eq!(
         returns,
@@ -130,7 +129,10 @@ fn read_buffer() {
     let mut buf = vec![0x42u8, 0x41u8];
     buf.extend_from_slice(&vm.origin);
 
-    let returns = vm.function("test2", &[BorshToken::Bytes(buf.clone())]);
+    let returns = vm
+        .function("test2", &[BorshToken::Bytes(buf.clone())])
+        .unwrap()
+        .unwrap_tuple();
 
     assert_eq!(
         returns,
@@ -139,7 +141,7 @@ fn read_buffer() {
                 width: 16,
                 value: BigInt::from(0x4142u16)
             },
-            BorshToken::FixedBytes(vm.origin.to_vec())
+            BorshToken::Address(vm.origin)
         ]
     );
 
@@ -164,21 +166,25 @@ fn bytes_compare() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function(
-        "test1",
-        &[BorshToken::FixedBytes([0xbc, 0xbc, 0xbd, 0xbe].to_vec())],
-    );
+    let returns = vm
+        .function(
+            "test1",
+            &[BorshToken::FixedBytes([0xbc, 0xbc, 0xbd, 0xbe].to_vec())],
+        )
+        .unwrap();
 
-    assert_eq!(returns, vec![BorshToken::Bool(true)]);
+    assert_eq!(returns, BorshToken::Bool(true));
 
-    let returns = vm.function(
-        "test2",
-        &[BorshToken::FixedBytes([0xbc, 0xbc, 0xbd, 0xbe].to_vec())],
-    );
+    let returns = vm
+        .function(
+            "test2",
+            &[BorshToken::FixedBytes([0xbc, 0xbc, 0xbd, 0xbe].to_vec())],
+        )
+        .unwrap();
 
-    assert_eq!(returns, vec![BorshToken::Bool(false)]);
+    assert_eq!(returns, BorshToken::Bool(false));
 }
 
 #[test]
@@ -194,32 +200,34 @@ fn assignment_in_ternary() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
     for _ in 0..10 {
         let left = rng.gen::<u64>();
         let right = rng.gen::<u64>();
 
-        let returns = vm.function(
-            "minimum",
-            &[
-                BorshToken::Uint {
-                    width: 64,
-                    value: BigInt::from(left),
-                },
-                BorshToken::Uint {
-                    width: 64,
-                    value: BigInt::from(right),
-                },
-            ],
-        );
+        let returns = vm
+            .function(
+                "minimum",
+                &[
+                    BorshToken::Uint {
+                        width: 64,
+                        value: BigInt::from(left),
+                    },
+                    BorshToken::Uint {
+                        width: 64,
+                        value: BigInt::from(right),
+                    },
+                ],
+            )
+            .unwrap();
 
         assert_eq!(
             returns,
-            vec![BorshToken::Uint {
+            BorshToken::Uint {
                 width: 64,
                 value: BigInt::from(std::cmp::min(left, right))
-            },]
+            },
         );
     }
 }
@@ -235,15 +243,15 @@ fn power() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("power", &[]);
+    let returns = vm.function("power", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(2417851639229258349412352u128)
-        },]
+        }
     );
 }

+ 21 - 15
tests/solana_tests/hash.rs

@@ -15,7 +15,7 @@ fn constants_hash_tests() {
         }"##,
     );
 
-    runtime.constructor("tester", &[]);
+    runtime.constructor(&[]);
     runtime.function("test", &[]);
 
     let mut runtime = build_solidity(
@@ -29,7 +29,7 @@ fn constants_hash_tests() {
         }"##,
     );
 
-    runtime.constructor("tester", &[]);
+    runtime.constructor(&[]);
     runtime.function("test", &[]);
 
     let mut runtime = build_solidity(
@@ -43,7 +43,7 @@ fn constants_hash_tests() {
         }"##,
     );
 
-    runtime.constructor("tester", &[]);
+    runtime.constructor(&[]);
     runtime.function("test", &[]);
 }
 
@@ -60,14 +60,16 @@ fn hash_tests() {
         }"##,
     );
 
-    runtime.constructor("tester", &[]);
-    let hash = runtime.function("test", &[BorshToken::Bytes(b"Hello, World!".to_vec())]);
+    runtime.constructor(&[]);
+    let hash = runtime
+        .function("test", &[BorshToken::Bytes(b"Hello, World!".to_vec())])
+        .unwrap();
 
     assert_eq!(
         hash,
-        vec![BorshToken::FixedBytes(
+        BorshToken::uint8_fixed_array(
             hex::decode("527a6a4b9a6da75607546842e0e00105350b1aaf").unwrap()
-        )]
+        )
     );
 
     let mut runtime = build_solidity(
@@ -81,15 +83,17 @@ fn hash_tests() {
         }"##,
     );
 
-    runtime.constructor("tester", &[]);
-    let hash = runtime.function("test", &[BorshToken::Bytes(b"Hello, World!".to_vec())]);
+    runtime.constructor(&[]);
+    let hash = runtime
+        .function("test", &[BorshToken::Bytes(b"Hello, World!".to_vec())])
+        .unwrap();
 
     assert_eq!(
         hash,
-        vec![BorshToken::FixedBytes(
+        BorshToken::uint8_fixed_array(
             hex::decode("dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f")
                 .unwrap()
-        )]
+        )
     );
 
     let mut runtime = build_solidity(
@@ -103,14 +107,16 @@ fn hash_tests() {
         }"##,
     );
 
-    runtime.constructor("tester", &[]);
-    let hash = runtime.function("test", &[BorshToken::Bytes(b"Hello, World!".to_vec())]);
+    runtime.constructor(&[]);
+    let hash = runtime
+        .function("test", &[BorshToken::Bytes(b"Hello, World!".to_vec())])
+        .unwrap();
 
     assert_eq!(
         hash,
-        vec![BorshToken::FixedBytes(
+        BorshToken::uint8_fixed_array(
             hex::decode("acaf3289d7b601cbd114fb36c4d29c85bbfd5e133f14cb355c3fd8d99367964f")
                 .unwrap()
-        )]
+        )
     );
 }

+ 264 - 230
tests/solana_tests/mappings.rs

@@ -25,7 +25,7 @@ fn simple_mapping() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
     for i in 0..10 {
         vm.function(
@@ -44,37 +44,41 @@ fn simple_mapping() {
     }
 
     for i in 0..10 {
-        let returns = vm.function(
-            "get",
-            &[BorshToken::Uint {
-                width: 64,
-                value: BigInt::from(102 + i),
-            }],
-        );
+        let returns = vm
+            .function(
+                "get",
+                &[BorshToken::Uint {
+                    width: 64,
+                    value: BigInt::from(102 + i),
+                }],
+            )
+            .unwrap();
 
         assert_eq!(
             returns,
-            vec![BorshToken::Uint {
+            BorshToken::Uint {
                 width: 64,
                 value: BigInt::from(300331 + i)
-            }]
+            }
         );
     }
 
-    let returns = vm.function(
-        "get",
-        &[BorshToken::Uint {
-            width: 64,
-            value: BigInt::from(101u8),
-        }],
-    );
+    let returns = vm
+        .function(
+            "get",
+            &[BorshToken::Uint {
+                width: 64,
+                value: BigInt::from(101u8),
+            }],
+        )
+        .unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 64,
             value: BigInt::zero()
-        }]
+        }
     );
 
     vm.function(
@@ -86,29 +90,31 @@ fn simple_mapping() {
     );
 
     for i in 0..10 {
-        let returns = vm.function(
-            "get",
-            &[BorshToken::Uint {
-                width: 64,
-                value: BigInt::from(102 + i),
-            }],
-        );
+        let returns = vm
+            .function(
+                "get",
+                &[BorshToken::Uint {
+                    width: 64,
+                    value: BigInt::from(102 + i),
+                }],
+            )
+            .unwrap();
 
         if 102 + i != 104 {
             assert_eq!(
                 returns,
-                vec![BorshToken::Uint {
+                BorshToken::Uint {
                     width: 64,
                     value: BigInt::from(300331 + i)
-                }]
+                }
             );
         } else {
             assert_eq!(
                 returns,
-                vec![BorshToken::Uint {
+                BorshToken::Uint {
                     width: 64,
                     value: BigInt::zero(),
-                }]
+                }
             );
         }
     }
@@ -144,7 +150,7 @@ fn less_simple_mapping() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
     vm.function(
         "set_string",
@@ -171,17 +177,19 @@ fn less_simple_mapping() {
         ],
     );
 
-    let returns = vm.function(
-        "get",
-        &[BorshToken::Uint {
-            width: 256,
-            value: BigInt::from(12313132131321312311213131u128),
-        }],
-    );
+    let returns = vm
+        .function(
+            "get",
+            &[BorshToken::Uint {
+                width: 256,
+                value: BigInt::from(12313132131321312311213131u128),
+            }],
+        )
+        .unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Tuple(vec![
+        BorshToken::Tuple(vec![
             BorshToken::String(String::from("This is a string which should be a little longer than 32 bytes so we the the abi encoder")),
             BorshToken::Array(vec![
                 BorshToken::Int{
@@ -189,7 +197,7 @@ fn less_simple_mapping() {
                     value: BigInt::from(102u8)
                 },
             ]),
-        ])]
+        ])
     );
 }
 
@@ -223,7 +231,7 @@ fn string_mapping() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
     vm.function(
         "set_string",
@@ -244,11 +252,13 @@ fn string_mapping() {
         ],
     );
 
-    let returns = vm.function("get", &[BorshToken::String(String::from("a"))]);
+    let returns = vm
+        .function("get", &[BorshToken::String(String::from("a"))])
+        .unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Tuple(vec![
+        BorshToken::Tuple(vec![
             BorshToken::String(String::from("This is a string which should be a little longer than 32 bytes so we the the abi encoder")),
             BorshToken::Array(vec![
                 BorshToken::Int{
@@ -256,7 +266,7 @@ fn string_mapping() {
                     value: BigInt::from(102u8)
                 },
             ]),
-        ])]
+        ])
     );
 }
 
@@ -283,7 +293,7 @@ fn contract_mapping() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
     let index = BorshToken::Address(account_new());
 
@@ -294,18 +304,18 @@ fn contract_mapping() {
             BorshToken::String(String::from("This is a string which should be a little longer than 32 bytes so we the the abi encoder")),
         ], );
 
-    let returns = vm.function("get", &[index.clone()]);
+    let returns = vm.function("get", &[index.clone()]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::String(String::from("This is a string which should be a little longer than 32 bytes so we the the abi encoder"))]
+        BorshToken::String(String::from("This is a string which should be a little longer than 32 bytes so we the the abi encoder"))
     );
 
     vm.function("rm", &[index.clone()]);
 
-    let returns = vm.function("get", &[index]);
+    let returns = vm.function("get", &[index]).unwrap();
 
-    assert_eq!(returns, vec![BorshToken::String(String::from(""))]);
+    assert_eq!(returns, BorshToken::String(String::from("")));
 }
 
 #[test]
@@ -321,7 +331,7 @@ fn mapping_in_mapping() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
     vm.function(
         "set",
@@ -335,44 +345,50 @@ fn mapping_in_mapping() {
         ],
     );
 
-    let returns = vm.function(
-        "map",
-        &[
-            BorshToken::String(String::from("a")),
-            BorshToken::Int {
-                width: 64,
-                value: BigInt::from(102u8),
-            },
-        ],
-    );
+    let returns = vm
+        .function(
+            "map",
+            &[
+                BorshToken::String(String::from("a")),
+                BorshToken::Int {
+                    width: 64,
+                    value: BigInt::from(102u8),
+                },
+            ],
+        )
+        .unwrap();
 
-    assert_eq!(returns, vec![BorshToken::FixedBytes(vec![0x98])]);
+    assert_eq!(returns, BorshToken::uint8_fixed_array(vec![0x98]));
 
-    let returns = vm.function(
-        "map",
-        &[
-            BorshToken::String(String::from("a")),
-            BorshToken::Int {
-                width: 64,
-                value: BigInt::from(103u8),
-            },
-        ],
-    );
+    let returns = vm
+        .function(
+            "map",
+            &[
+                BorshToken::String(String::from("a")),
+                BorshToken::Int {
+                    width: 64,
+                    value: BigInt::from(103u8),
+                },
+            ],
+        )
+        .unwrap();
 
-    assert_eq!(returns, vec![BorshToken::FixedBytes(vec![0])]);
+    assert_eq!(returns, BorshToken::uint8_fixed_array(vec![0]));
 
-    let returns = vm.function(
-        "map",
-        &[
-            BorshToken::String(String::from("b")),
-            BorshToken::Int {
-                width: 64,
-                value: BigInt::from(102u8),
-            },
-        ],
-    );
+    let returns = vm
+        .function(
+            "map",
+            &[
+                BorshToken::String(String::from("b")),
+                BorshToken::Int {
+                    width: 64,
+                    value: BigInt::from(102u8),
+                },
+            ],
+        )
+        .unwrap();
 
-    assert_eq!(returns, vec![BorshToken::FixedBytes(vec![0])]);
+    assert_eq!(returns, BorshToken::uint8_fixed_array(vec![0]));
 }
 
 #[test]
@@ -405,7 +421,7 @@ fn sparse_array() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
     vm.function(
         "set_string",
@@ -431,17 +447,19 @@ fn sparse_array() {
         ],
     );
 
-    let returns = vm.function(
-        "get",
-        &[BorshToken::Uint {
-            width: 256,
-            value: BigInt::from(909090909u64),
-        }],
-    );
+    let returns = vm
+        .function(
+            "get",
+            &[BorshToken::Uint {
+                width: 256,
+                value: BigInt::from(909090909u64),
+            }],
+        )
+        .unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Tuple(vec![
+        BorshToken::Tuple(vec![
             BorshToken::String(String::from("This is a string which should be a little longer than 32 bytes so we the the abi encoder")),
             BorshToken::Array(vec![
                 BorshToken::Int{
@@ -449,7 +467,7 @@ fn sparse_array() {
                     value: BigInt::from(102u8)
                 },
             ]),
-        ])]
+        ])
     );
 }
 
@@ -483,7 +501,7 @@ fn massive_sparse_array() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
     vm.function(
         "set_string",
@@ -509,17 +527,19 @@ fn massive_sparse_array() {
         ],
     );
 
-    let returns = vm.function(
-        "get",
-        &[BorshToken::Uint {
-            width: 256,
-            value: BigInt::from(786868768768678687686877u128),
-        }],
-    );
+    let returns = vm
+        .function(
+            "get",
+            &[BorshToken::Uint {
+                width: 256,
+                value: BigInt::from(786868768768678687686877u128),
+            }],
+        )
+        .unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Tuple(vec![
+        BorshToken::Tuple(vec![
             BorshToken::String(String::from("This is a string which should be a little longer than 32 bytes so we the the abi encoder")),
             BorshToken::Array(vec![
                 BorshToken::Int {
@@ -527,7 +547,7 @@ fn massive_sparse_array() {
                     value: BigInt::from(102u8)
                 },
             ]),
-        ])]
+        ])
     );
 }
 
@@ -565,7 +585,7 @@ fn mapping_in_dynamic_array() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
     vm.function(
         "setNumber",
@@ -602,50 +622,54 @@ fn mapping_in_dynamic_array() {
 
     for array_no in 0..2 {
         for i in 0..10 {
-            let returns = vm.function(
-                "map",
-                &[
-                    BorshToken::Uint {
-                        width: 256,
-                        value: BigInt::from(array_no),
-                    },
-                    BorshToken::Uint {
-                        width: 64,
-                        value: BigInt::from(102 + i + array_no * 500),
-                    },
-                ],
-            );
+            let returns = vm
+                .function(
+                    "map",
+                    &[
+                        BorshToken::Uint {
+                            width: 256,
+                            value: BigInt::from(array_no),
+                        },
+                        BorshToken::Uint {
+                            width: 64,
+                            value: BigInt::from(102 + i + array_no * 500),
+                        },
+                    ],
+                )
+                .unwrap();
 
             assert_eq!(
                 returns,
-                vec![BorshToken::Uint {
+                BorshToken::Uint {
                     width: 64,
                     value: BigInt::from(300331 + i)
-                },]
+                },
             );
         }
     }
 
-    let returns = vm.function(
-        "map",
-        &[
-            BorshToken::Uint {
-                width: 256,
-                value: BigInt::zero(),
-            },
-            BorshToken::Uint {
-                width: 64,
-                value: BigInt::from(101u8),
-            },
-        ],
-    );
+    let returns = vm
+        .function(
+            "map",
+            &[
+                BorshToken::Uint {
+                    width: 256,
+                    value: BigInt::zero(),
+                },
+                BorshToken::Uint {
+                    width: 64,
+                    value: BigInt::from(101u8),
+                },
+            ],
+        )
+        .unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 64,
             value: BigInt::zero()
-        }]
+        }
     );
 
     vm.function(
@@ -663,78 +687,80 @@ fn mapping_in_dynamic_array() {
     );
 
     for i in 0..10 {
-        let returns = vm.function(
-            "map",
-            &[
-                BorshToken::Uint {
-                    width: 256,
-                    value: BigInt::zero(),
-                },
-                BorshToken::Uint {
-                    width: 64,
-                    value: BigInt::from(102 + i),
-                },
-            ],
-        );
+        let returns = vm
+            .function(
+                "map",
+                &[
+                    BorshToken::Uint {
+                        width: 256,
+                        value: BigInt::zero(),
+                    },
+                    BorshToken::Uint {
+                        width: 64,
+                        value: BigInt::from(102 + i),
+                    },
+                ],
+            )
+            .unwrap();
 
         if 102 + i != 104 {
             assert_eq!(
                 returns,
-                vec![BorshToken::Uint {
+                BorshToken::Uint {
                     width: 64,
                     value: BigInt::from(300331 + i)
-                },]
+                },
             );
         } else {
             assert_eq!(
                 returns,
-                vec![BorshToken::Uint {
+                BorshToken::Uint {
                     width: 64,
                     value: BigInt::zero()
-                }]
+                }
             );
         }
     }
 
-    let returns = vm.function("length", &[]);
+    let returns = vm.function("length", &[]).unwrap();
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 64,
             value: BigInt::from(2u8)
-        }]
+        }
     );
 
     vm.function("pop", &[]);
 
-    let returns = vm.function("length", &[]);
+    let returns = vm.function("length", &[]).unwrap();
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 64,
             value: BigInt::one()
-        }]
+        }
     );
 
     vm.function("pop", &[]);
 
-    let returns = vm.function("length", &[]);
+    let returns = vm.function("length", &[]).unwrap();
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 64,
             value: BigInt::zero()
-        }]
+        }
     );
 
-    let returns = vm.function("number", &[]);
+    let returns = vm.function("number", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Int {
+        BorshToken::Int {
             width: 64,
             value: BigInt::from(2147483647u64)
-        }]
+        }
     );
 }
 
@@ -776,7 +802,7 @@ fn mapping_in_struct_in_dynamic_array() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
     vm.function(
         "setNumber",
@@ -813,50 +839,54 @@ fn mapping_in_struct_in_dynamic_array() {
 
     for array_no in 0..2 {
         for i in 0..10 {
-            let returns = vm.function(
-                "get",
-                &[
-                    BorshToken::Uint {
-                        width: 64,
-                        value: BigInt::from(array_no),
-                    },
-                    BorshToken::Uint {
-                        width: 64,
-                        value: BigInt::from(102 + i + array_no * 500),
-                    },
-                ],
-            );
+            let returns = vm
+                .function(
+                    "get",
+                    &[
+                        BorshToken::Uint {
+                            width: 64,
+                            value: BigInt::from(array_no),
+                        },
+                        BorshToken::Uint {
+                            width: 64,
+                            value: BigInt::from(102 + i + array_no * 500),
+                        },
+                    ],
+                )
+                .unwrap();
 
             assert_eq!(
                 returns,
-                vec![BorshToken::Uint {
+                BorshToken::Uint {
                     width: 256,
                     value: BigInt::from(300331 + i)
-                },]
+                },
             );
         }
     }
 
-    let returns = vm.function(
-        "get",
-        &[
-            BorshToken::Uint {
-                width: 64,
-                value: BigInt::zero(),
-            },
-            BorshToken::Uint {
-                width: 64,
-                value: BigInt::from(101u8),
-            },
-        ],
-    );
+    let returns = vm
+        .function(
+            "get",
+            &[
+                BorshToken::Uint {
+                    width: 64,
+                    value: BigInt::zero(),
+                },
+                BorshToken::Uint {
+                    width: 64,
+                    value: BigInt::from(101u8),
+                },
+            ],
+        )
+        .unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::zero(),
-        },]
+        },
     );
 
     vm.function(
@@ -874,35 +904,37 @@ fn mapping_in_struct_in_dynamic_array() {
     );
 
     for i in 0..10 {
-        let returns = vm.function(
-            "get",
-            &[
-                BorshToken::Uint {
-                    width: 64,
-                    value: BigInt::zero(),
-                },
-                BorshToken::Uint {
-                    width: 64,
-                    value: BigInt::from(102 + i),
-                },
-            ],
-        );
+        let returns = vm
+            .function(
+                "get",
+                &[
+                    BorshToken::Uint {
+                        width: 64,
+                        value: BigInt::zero(),
+                    },
+                    BorshToken::Uint {
+                        width: 64,
+                        value: BigInt::from(102 + i),
+                    },
+                ],
+            )
+            .unwrap();
 
         if 102 + i != 104 {
             assert_eq!(
                 returns,
-                vec![BorshToken::Uint {
+                BorshToken::Uint {
                     width: 256,
                     value: BigInt::from(300331 + i)
-                }]
+                }
             );
         } else {
             assert_eq!(
                 returns,
-                vec![BorshToken::Uint {
+                BorshToken::Uint {
                     width: 256,
                     value: BigInt::zero()
-                }]
+                }
             );
         }
     }
@@ -910,14 +942,14 @@ fn mapping_in_struct_in_dynamic_array() {
     vm.function("pop", &[]);
     vm.function("pop", &[]);
 
-    let returns = vm.function("number", &[]);
+    let returns = vm.function("number", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Int {
+        BorshToken::Int {
             width: 64,
             value: BigInt::from(2147483647u64),
-        }]
+        }
     );
 }
 
@@ -955,22 +987,22 @@ contract DeleteTest {
 
     let sender = account_new();
 
-    vm.constructor("DeleteTest", &[]);
+    vm.constructor(&[]);
     let _ = vm.function("addData", &[BorshToken::Address(sender)]);
     let _ = vm.function("deltest", &[]);
-    let returns = vm.function("get", &[]);
+    let returns = vm.function("get", &[]).unwrap();
     assert_eq!(
         returns,
-        vec![BorshToken::Tuple(vec![
-            BorshToken::FixedBytes(vec![
+        BorshToken::Tuple(vec![
+            BorshToken::Address([
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                 0, 0, 0, 0
             ]),
-            BorshToken::FixedBytes(vec![
+            BorshToken::Address([
                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
                 0, 0, 0, 0
             ])
-        ])],
+        ]),
     );
 }
 
@@ -1016,33 +1048,35 @@ function getArrAmt() public view returns (uint) {
 
     let sender = account_new();
 
-    vm.constructor("CrowdFunding", &[]);
+    vm.constructor(&[]);
 
-    let ret = vm.function("newCampaign", &[BorshToken::Address(sender)]);
+    let ret = vm
+        .function("newCampaign", &[BorshToken::Address(sender)])
+        .unwrap();
 
     assert_eq!(
         ret,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::zero(),
-        }]
+        }
     );
 
-    let ret = vm.function("getAmt", &[]);
+    let ret = vm.function("getAmt", &[]).unwrap();
     assert_eq!(
         ret,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(100u8),
-        }]
+        }
     );
 
-    let ret = vm.function("getArrAmt", &[]);
+    let ret = vm.function("getArrAmt", &[]).unwrap();
     assert_eq!(
         ret,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(105u8),
-        }]
+        }
     );
 }

+ 53 - 47
tests/solana_tests/math.rs

@@ -39,72 +39,78 @@ fn safe_math() {
         }"#,
     );
 
-    vm.constructor("math", &[]);
-
-    let returns = vm.function(
-        "mul_test",
-        &[
-            BorshToken::Uint {
-                width: 256,
-                value: BigInt::from_str("1000000000000000000").unwrap(),
-            },
-            BorshToken::Uint {
-                width: 256,
-                value: BigInt::from_str("4000000000000000000").unwrap(),
-            },
-        ],
-    );
+    vm.constructor(&[]);
+
+    let returns = vm
+        .function(
+            "mul_test",
+            &[
+                BorshToken::Uint {
+                    width: 256,
+                    value: BigInt::from_str("1000000000000000000").unwrap(),
+                },
+                BorshToken::Uint {
+                    width: 256,
+                    value: BigInt::from_str("4000000000000000000").unwrap(),
+                },
+            ],
+        )
+        .unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from_str("4000000000000000000000000000000000000").unwrap(),
-        },]
+        },
     );
 
-    let returns = vm.function(
-        "add_test",
-        &[
-            BorshToken::Uint {
-                width: 256,
-                value: BigInt::from_str("1000000000000000000").unwrap(),
-            },
-            BorshToken::Uint {
-                width: 256,
-                value: BigInt::from_str("4000000000000000000").unwrap(),
-            },
-        ],
-    );
+    let returns = vm
+        .function(
+            "add_test",
+            &[
+                BorshToken::Uint {
+                    width: 256,
+                    value: BigInt::from_str("1000000000000000000").unwrap(),
+                },
+                BorshToken::Uint {
+                    width: 256,
+                    value: BigInt::from_str("4000000000000000000").unwrap(),
+                },
+            ],
+        )
+        .unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from_str("5000000000000000000").unwrap(),
-        },]
+        },
     );
 
-    let returns = vm.function(
-        "sub_test",
-        &[
-            BorshToken::Uint {
-                width: 256,
-                value: BigInt::from_str("4000000000000000000").unwrap(),
-            },
-            BorshToken::Uint {
-                width: 256,
-                value: BigInt::from_str("1000000000000000000").unwrap(),
-            },
-        ],
-    );
+    let returns = vm
+        .function(
+            "sub_test",
+            &[
+                BorshToken::Uint {
+                    width: 256,
+                    value: BigInt::from_str("4000000000000000000").unwrap(),
+                },
+                BorshToken::Uint {
+                    width: 256,
+                    value: BigInt::from_str("1000000000000000000").unwrap(),
+                },
+            ],
+        )
+        .unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from_str("3000000000000000000").unwrap(),
-        },]
+        },
     );
 
     let res = vm.function_must_fail(

+ 8 - 8
tests/solana_tests/metas.rs

@@ -17,18 +17,18 @@ fn use_authority() {
         },
     );
 
-    vm.constructor("AuthorityExample", &[BorshToken::Address(authority)]);
+    vm.constructor(&[BorshToken::Address(authority)]);
 
     let res = vm.function_must_fail("inc", &[]).unwrap();
-    assert!(res != 0);
+    assert_ne!(res, 0);
 
-    let res = vm.function("get", &[]);
+    let res = vm.function("get", &[]).unwrap();
     assert_eq!(
         res,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 64,
             value: 0.into()
-        }]
+        }
     );
 
     let mut metas = vm.default_metas();
@@ -40,12 +40,12 @@ fn use_authority() {
 
     vm.function_metas(&metas, "inc", &[]);
 
-    let res = vm.function("get", &[]);
+    let res = vm.function("get", &[]).unwrap();
     assert_eq!(
         res,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 64,
             value: 1.into()
-        }]
+        }
     );
 }

+ 9 - 3
tests/solana_tests/modifiers.rs

@@ -28,9 +28,12 @@ fn returns_and_phis_needed() {
         }"#,
     );
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("func", &[BorshToken::Bool(false)]);
+    let returns = vm
+        .function("func", &[BorshToken::Bool(false)])
+        .unwrap()
+        .unwrap_tuple();
 
     assert_eq!(
         returns,
@@ -43,7 +46,10 @@ fn returns_and_phis_needed() {
         ]
     );
 
-    let returns = vm.function("func", &[BorshToken::Bool(true)]);
+    let returns = vm
+        .function("func", &[BorshToken::Bool(true)])
+        .unwrap()
+        .unwrap_tuple();
 
     assert_eq!(
         returns,

File diff suppressed because it is too large
+ 369 - 324
tests/solana_tests/primitives.rs


+ 42 - 39
tests/solana_tests/rational.rs

@@ -21,26 +21,26 @@ fn rational() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("test", &[]);
+    let returns = vm.function("test", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(4u8)
-        }]
+        }
     );
 
-    let returns = vm.function("test2", &[]);
+    let returns = vm.function("test2", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(4u8)
-        }]
+        }
     );
 
     let mut vm = build_solidity(
@@ -53,16 +53,16 @@ fn rational() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("test", &[]);
+    let returns = vm.function("test", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(5u8)
-        }]
+        }
     );
 
     let mut vm = build_solidity(
@@ -75,16 +75,16 @@ fn rational() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("test", &[]);
+    let returns = vm.function("test", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(24)
-        }]
+        }
     );
 
     let mut vm = build_solidity(
@@ -97,16 +97,16 @@ fn rational() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("test", &[]);
+    let returns = vm.function("test", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::zero(),
-        }]
+        }
     );
 
     let mut vm = build_solidity(
@@ -119,16 +119,16 @@ fn rational() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("test", &[]);
+    let returns = vm.function("test", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(4u8),
-        }]
+        }
     );
 
     let mut vm = build_solidity(
@@ -140,16 +140,16 @@ fn rational() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("test", &[]);
+    let returns = vm.function("test", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(3u8)
-        }]
+        }
     );
 
     let mut vm = build_solidity(
@@ -161,16 +161,16 @@ fn rational() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("test", &[]);
+    let returns = vm.function("test", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(15600u32)
-        }]
+        }
     );
 
     let mut vm = build_solidity(
@@ -182,15 +182,18 @@ fn rational() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function(
-        "test",
-        &[BorshToken::Uint {
-            width: 64,
-            value: BigInt::from(982451653u32),
-        }],
-    );
+    let returns = vm
+        .function(
+            "test",
+            &[BorshToken::Uint {
+                width: 64,
+                value: BigInt::from(982451653u32),
+            }],
+        )
+        .unwrap()
+        .unwrap_tuple();
 
     assert_eq!(
         returns,

+ 32 - 32
tests/solana_tests/returns.rs

@@ -31,51 +31,51 @@ fn return_single() {
             }
         }"#,
     );
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("f", &[]);
+    let returns = vm.function("f", &[]).unwrap();
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(2u8)
-        },]
+        },
     );
 
-    let returns = vm.function("g", &[]);
+    let returns = vm.function("g", &[]).unwrap();
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(3u8)
-        },]
+        },
     );
 
-    let returns = vm.function("h", &[]);
+    let returns = vm.function("h", &[]).unwrap();
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(2u8)
-        },]
+        },
     );
 
-    let returns = vm.function("i", &[]);
+    let returns = vm.function("i", &[]).unwrap();
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(24u8)
-        },]
+        },
     );
 
-    let returns = vm.function("j", &[]);
+    let returns = vm.function("j", &[]).unwrap();
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(5u8)
-        },]
+        },
     );
 }
 
@@ -90,8 +90,8 @@ fn return_ternary() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
-    let returns = vm.function("f", &[]);
+    vm.constructor(&[]);
+    let returns = vm.function("f", &[]).unwrap().unwrap_tuple();
 
     assert_eq!(
         returns,
@@ -116,8 +116,8 @@ fn return_ternary() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
-    let returns = vm.function("f", &[]);
+    vm.constructor(&[]);
+    let returns = vm.function("f", &[]).unwrap().unwrap_tuple();
 
     assert_eq!(
         returns,
@@ -156,17 +156,17 @@ fn return_nothing() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
     let _returns = vm.function("strange", &[]);
     let _returns = vm.function("inc", &[]);
-    let returns = vm.function("get", &[]);
+    let returns = vm.function("get", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(2u8)
-        },]
+        },
     );
 
     let mut vm = build_solidity(
@@ -192,16 +192,16 @@ fn return_nothing() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
     let _returns = vm.function("f", &[]);
-    let returns = vm.function("get", &[]);
+    let returns = vm.function("get", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(5u8)
-        },]
+        },
     );
 }
 
@@ -220,8 +220,8 @@ fn return_function() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
-    let returns = vm.function("f", &[]);
+    vm.constructor(&[]);
+    let returns = vm.function("f", &[]).unwrap().unwrap_tuple();
 
     assert_eq!(
         returns,
@@ -250,8 +250,8 @@ fn return_function() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
-    let returns = vm.function("f", &[]);
+    vm.constructor(&[]);
+    let returns = vm.function("f", &[]).unwrap().unwrap_tuple();
 
     assert_eq!(
         returns,

+ 34 - 28
tests/solana_tests/signature_verify.rs

@@ -43,7 +43,7 @@ fn verify() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
     let mut csprng = rand_07::thread_rng();
     let keypair: Keypair = Keypair::generate(&mut csprng);
@@ -59,16 +59,18 @@ fn verify() {
     println!("T: SIG: {}", hex::encode(&signature_bs));
     println!("T: MES: {}", hex::encode(message));
 
-    let returns = vm.function(
-        "verify",
-        &[
-            BorshToken::Address(keypair.public.to_bytes()),
-            BorshToken::Bytes(message.to_vec()),
-            BorshToken::Bytes(signature_bs.clone()),
-        ],
-    );
+    let returns = vm
+        .function(
+            "verify",
+            &[
+                BorshToken::Address(keypair.public.to_bytes()),
+                BorshToken::Bytes(message.to_vec()),
+                BorshToken::Bytes(signature_bs.clone()),
+            ],
+        )
+        .unwrap();
 
-    assert_eq!(returns, vec![BorshToken::Bool(false)]);
+    assert_eq!(returns, BorshToken::Bool(false));
 
     let instructions_account: Account = "Sysvar1nstructions1111111111111111111111111"
         .from_base58()
@@ -88,16 +90,18 @@ fn verify() {
 
     println!("Now try for real");
 
-    let returns = vm.function(
-        "verify",
-        &[
-            BorshToken::Address(keypair.public.to_bytes()),
-            BorshToken::Bytes(message.to_vec()),
-            BorshToken::Bytes(signature_bs.clone()),
-        ],
-    );
+    let returns = vm
+        .function(
+            "verify",
+            &[
+                BorshToken::Address(keypair.public.to_bytes()),
+                BorshToken::Bytes(message.to_vec()),
+                BorshToken::Bytes(signature_bs.clone()),
+            ],
+        )
+        .unwrap();
 
-    assert_eq!(returns, vec![BorshToken::Bool(true)]);
+    assert_eq!(returns, BorshToken::Bool(true));
 
     println!("now try with bad signature");
 
@@ -116,16 +120,18 @@ fn verify() {
         },
     );
 
-    let returns = vm.function(
-        "verify",
-        &[
-            BorshToken::Address(keypair.public.to_bytes()),
-            BorshToken::Bytes(message.to_vec()),
-            BorshToken::Bytes(signature_bs),
-        ],
-    );
+    let returns = vm
+        .function(
+            "verify",
+            &[
+                BorshToken::Address(keypair.public.to_bytes()),
+                BorshToken::Bytes(message.to_vec()),
+                BorshToken::Bytes(signature_bs),
+            ],
+        )
+        .unwrap();
 
-    assert_eq!(returns, vec![BorshToken::Bool(false)]);
+    assert_eq!(returns, BorshToken::Bool(false));
 }
 
 fn encode_instructions(public_key: &[u8], signature: &[u8], message: &[u8]) -> Vec<u8> {

+ 97 - 87
tests/solana_tests/simple.rs

@@ -20,7 +20,7 @@ fn simple() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
     assert_eq!(vm.logs, "Hello from constructor");
 
@@ -44,7 +44,7 @@ fn format() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
     assert_eq!(
         vm.logs,
@@ -69,7 +69,7 @@ fn parameters() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
     vm.function(
         "test",
@@ -117,22 +117,24 @@ fn returns() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function(
-        "test",
-        &[BorshToken::Uint {
-            width: 32,
-            value: BigInt::from(10u8),
-        }],
-    );
+    let returns = vm
+        .function(
+            "test",
+            &[BorshToken::Uint {
+                width: 32,
+                value: BigInt::from(10u8),
+            }],
+        )
+        .unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 32,
             value: BigInt::from(100u8)
-        },]
+        }
     );
 
     let mut vm = build_solidity(
@@ -144,15 +146,18 @@ fn returns() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function(
-        "test",
-        &[BorshToken::Uint {
-            width: 64,
-            value: BigInt::from(982451653u64),
-        }],
-    );
+    let returns = vm
+        .function(
+            "test",
+            &[BorshToken::Uint {
+                width: 64,
+                value: BigInt::from(982451653u64),
+            }],
+        )
+        .unwrap()
+        .unwrap_tuple();
 
     assert_eq!(
         returns,
@@ -192,16 +197,16 @@ fn flipper() {
         }"#,
     );
 
-    vm.constructor("flipper", &[BorshToken::Bool(true)]);
+    vm.constructor(&[BorshToken::Bool(true)]);
 
     assert_eq!(
         vm.data()[0..17].to_vec(),
         hex::decode("6fc90ec500000000000000001800000001").unwrap()
     );
 
-    let returns = vm.function("get", &[]);
+    let returns = vm.function("get", &[]).unwrap();
 
-    assert_eq!(returns, vec![BorshToken::Bool(true)]);
+    assert_eq!(returns, BorshToken::Bool(true));
 
     vm.function("flip", &[]);
 
@@ -210,9 +215,9 @@ fn flipper() {
         hex::decode("6fc90ec500000000000000001800000000").unwrap()
     );
 
-    let returns = vm.function("get", &[]);
+    let returns = vm.function("get", &[]).unwrap();
 
-    assert_eq!(returns, vec![BorshToken::Bool(false)]);
+    assert_eq!(returns, BorshToken::Bool(false));
 }
 
 #[test]
@@ -246,22 +251,19 @@ fn incrementer() {
         }"#,
     );
 
-    vm.constructor(
-        "incrementer",
-        &[BorshToken::Uint {
-            width: 32,
-            value: BigInt::from(5u8),
-        }],
-    );
+    vm.constructor(&[BorshToken::Uint {
+        width: 32,
+        value: BigInt::from(5u8),
+    }]);
 
-    let returns = vm.function("get", &[]);
+    let returns = vm.function("get", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 32,
             value: BigInt::from(5u8),
-        }]
+        }
     );
 
     vm.function(
@@ -272,14 +274,14 @@ fn incrementer() {
         }],
     );
 
-    let returns = vm.function("get", &[]);
+    let returns = vm.function("get", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 32,
             value: BigInt::from(10u8),
-        }]
+        }
     );
 }
 
@@ -327,7 +329,7 @@ fn two_arrays() {
         }"#,
     );
 
-    vm.constructor("two_arrays", &[]);
+    vm.constructor(&[]);
 }
 
 #[test]
@@ -352,16 +354,16 @@ fn dead_storage_bug() {
         }"#,
     );
 
-    vm.constructor("deadstorage", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("v", &[]);
+    let returns = vm.function("v", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(9991u16)
-        }]
+        }
     );
 }
 
@@ -411,48 +413,52 @@ contract test3 {
     );
 
     // call constructor
-    runtime.constructor("test3", &[]);
+    runtime.constructor(&[]);
 
     for i in 0..=50 {
         let res = ((50 - i) * 100 + 5) + i * 1000;
 
-        let returns = runtime.function(
-            "foo",
-            &[BorshToken::Uint {
-                width: 32,
-                value: BigInt::from(i),
-            }],
-        );
+        let returns = runtime
+            .function(
+                "foo",
+                &[BorshToken::Uint {
+                    width: 32,
+                    value: BigInt::from(i),
+                }],
+            )
+            .unwrap();
 
         assert_eq!(
             returns,
-            vec![BorshToken::Uint {
+            BorshToken::Uint {
                 width: 32,
                 value: BigInt::from(res)
-            }]
+            }
         );
     }
 
     for i in 0..=50 {
         let res = (i + 1) * 10 + 1;
 
-        let returns = runtime.function(
-            "bar",
-            &[
-                BorshToken::Uint {
-                    width: 32,
-                    value: BigInt::from(i),
-                },
-                BorshToken::Bool(true),
-            ],
-        );
+        let returns = runtime
+            .function(
+                "bar",
+                &[
+                    BorshToken::Uint {
+                        width: 32,
+                        value: BigInt::from(i),
+                    },
+                    BorshToken::Bool(true),
+                ],
+            )
+            .unwrap();
 
         assert_eq!(
             returns,
-            vec![BorshToken::Uint {
+            BorshToken::Uint {
                 width: 32,
                 value: BigInt::from(res)
-            }]
+            }
         );
     }
 
@@ -463,23 +469,25 @@ contract test3 {
             res *= 3;
         }
 
-        let returns = runtime.function(
-            "bar",
-            &[
-                BorshToken::Uint {
-                    width: 32,
-                    value: BigInt::from(i),
-                },
-                BorshToken::Bool(false),
-            ],
-        );
+        let returns = runtime
+            .function(
+                "bar",
+                &[
+                    BorshToken::Uint {
+                        width: 32,
+                        value: BigInt::from(i),
+                    },
+                    BorshToken::Bool(false),
+                ],
+            )
+            .unwrap();
 
         assert_eq!(
             returns,
-            vec![BorshToken::Uint {
+            BorshToken::Uint {
                 width: 32,
                 value: BigInt::from(res)
-            }]
+            }
         );
     }
 
@@ -494,20 +502,22 @@ contract test3 {
             res += 1;
         }
 
-        let returns = runtime.function(
-            "baz",
-            &[BorshToken::Uint {
-                width: 32,
-                value: BigInt::from(i),
-            }],
-        );
+        let returns = runtime
+            .function(
+                "baz",
+                &[BorshToken::Uint {
+                    width: 32,
+                    value: BigInt::from(i),
+                }],
+            )
+            .unwrap();
 
         assert_eq!(
             returns,
-            vec![BorshToken::Uint {
+            BorshToken::Uint {
                 width: 32,
                 value: BigInt::from(res)
-            }]
+            }
         );
     }
 }

+ 86 - 88
tests/solana_tests/storage.rs

@@ -18,14 +18,14 @@ fn simple() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
-    let returns = vm.function("boom", &[]);
+    vm.constructor(&[]);
+    let returns = vm.function("boom", &[]).unwrap();
     assert_eq!(
         returns,
-        vec![BorshToken::Int {
+        BorshToken::Int {
             width: 256,
             value: BigInt::zero(),
-        }]
+        }
     );
 
     let mut vm = build_solidity(
@@ -48,14 +48,14 @@ fn simple() {
         }"#,
     );
 
-    vm.constructor("c", &[]);
-    let returns = vm.function("func", &[]);
+    vm.constructor(&[]);
+    let returns = vm.function("func", &[]).unwrap();
     assert_eq!(
         returns,
-        vec![BorshToken::Int {
+        BorshToken::Int {
             width: 256,
             value: BigInt::one(),
-        }]
+        }
     );
 }
 
@@ -76,16 +76,16 @@ fn string() {
         }"#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
     assert_eq!(
         vm.data()[0..20].to_vec(),
         vec![65, 177, 160, 100, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0]
     );
 
-    let returns = vm.function("get", &[]);
+    let returns = vm.function("get", &[]).unwrap();
 
-    assert_eq!(returns, vec![BorshToken::String(String::from(""))]);
+    assert_eq!(returns, BorshToken::String(String::from("")));
 
     vm.function("set", &[BorshToken::String(String::from("Hello, World!"))]);
 
@@ -96,23 +96,17 @@ fn string() {
 
     assert_eq!(vm.data()[40..53].to_vec(), b"Hello, World!");
 
-    let returns = vm.function("get", &[]);
+    let returns = vm.function("get", &[]).unwrap();
 
-    assert_eq!(
-        returns,
-        vec![BorshToken::String(String::from("Hello, World!"))]
-    );
+    assert_eq!(returns, BorshToken::String(String::from("Hello, World!")));
 
     // try replacing it with a string of the same length. This is a special
     // fast-path handling
     vm.function("set", &[BorshToken::String(String::from("Hallo, Werld!"))]);
 
-    let returns = vm.function("get", &[]);
+    let returns = vm.function("get", &[]).unwrap();
 
-    assert_eq!(
-        returns,
-        vec![BorshToken::String(String::from("Hallo, Werld!"))]
-    );
+    assert_eq!(returns, BorshToken::String(String::from("Hallo, Werld!")));
 
     assert_eq!(
         vm.data()[0..20].to_vec(),
@@ -123,9 +117,9 @@ fn string() {
     // the result should be offset 0
     vm.function("set", &[BorshToken::String(String::from(""))]);
 
-    let returns = vm.function("get", &[]);
+    let returns = vm.function("get", &[]).unwrap();
 
-    assert_eq!(returns, vec![BorshToken::String(String::from(""))]);
+    assert_eq!(returns, BorshToken::String(String::from("")));
 
     assert_eq!(
         vm.data()[0..20].to_vec(),
@@ -158,21 +152,21 @@ fn bytes() {
         }"#,
     );
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     assert_eq!(
         vm.data()[0..20].to_vec(),
         vec![11, 66, 182, 57, 0, 0, 0, 0, 0, 0, 0, 0, 24, 0, 0, 0, 0, 0, 0, 0]
     );
 
-    let returns = vm.function("foo_length", &[]);
+    let returns = vm.function("foo_length", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 32,
             value: BigInt::zero(),
-        }]
+        }
     );
 
     vm.function(
@@ -191,15 +185,17 @@ fn bytes() {
         .iter()
         .enumerate()
     {
-        let returns = vm.function(
-            "get_foo_offset",
-            &[BorshToken::Uint {
-                width: 32,
-                value: BigInt::from(i),
-            }],
-        );
+        let returns = vm
+            .function(
+                "get_foo_offset",
+                &[BorshToken::Uint {
+                    width: 32,
+                    value: BigInt::from(i),
+                }],
+            )
+            .unwrap();
 
-        assert_eq!(returns, vec![BorshToken::FixedBytes(vec![*b])]);
+        assert_eq!(returns, BorshToken::uint8_fixed_array(vec![*b]));
     }
 
     vm.function(
@@ -228,15 +224,17 @@ fn bytes() {
         .iter()
         .enumerate()
     {
-        let returns = vm.function(
-            "get_foo_offset",
-            &[BorshToken::Uint {
-                width: 32,
-                value: BigInt::from(i),
-            }],
-        );
+        let returns = vm
+            .function(
+                "get_foo_offset",
+                &[BorshToken::Uint {
+                    width: 32,
+                    value: BigInt::from(i),
+                }],
+            )
+            .unwrap();
 
-        assert_eq!(returns, vec![BorshToken::FixedBytes(vec![*b])]);
+        assert_eq!(returns, BorshToken::uint8_fixed_array(vec![*b]));
     }
 }
 
@@ -266,7 +264,7 @@ fn bytes_set_subscript_range() {
         }"#,
     );
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     vm.function(
         "set_foo_offset",
@@ -306,7 +304,7 @@ fn bytes_get_subscript_range() {
         }"#,
     );
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     vm.function(
         "set_foo",
@@ -337,7 +335,7 @@ fn storage_alignment() {
         }"#,
     );
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     assert_eq!(
         vm.data()[0..40].to_vec(),
@@ -369,33 +367,33 @@ fn bytes_push_pop() {
         }"#,
     );
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("get_bs", &[]);
+    let returns = vm.function("get_bs", &[]).unwrap();
 
-    assert_eq!(returns, vec![BorshToken::Bytes(vec!(0x0e, 0xda))]);
+    assert_eq!(returns, BorshToken::Bytes(vec!(0x0e, 0xda)));
 
-    let returns = vm.function("pop", &[]);
+    let returns = vm.function("pop", &[]).unwrap();
 
-    assert_eq!(returns, vec![BorshToken::FixedBytes(vec!(0xda))]);
+    assert_eq!(returns, BorshToken::uint8_fixed_array(vec!(0xda)));
 
-    let returns = vm.function("get_bs", &[]);
+    let returns = vm.function("get_bs", &[]).unwrap();
 
-    assert_eq!(returns, vec![BorshToken::Bytes(vec!(0x0e))]);
+    assert_eq!(returns, BorshToken::Bytes(vec!(0x0e)));
 
     vm.function("push", &[BorshToken::FixedBytes(vec![0x41])]);
 
     println!("data:{}", hex::encode(vm.data()));
 
-    let returns = vm.function("get_bs", &[]);
+    let returns = vm.function("get_bs", &[]).unwrap();
 
-    assert_eq!(returns, vec![BorshToken::Bytes(vec!(0x0e, 0x41))]);
+    assert_eq!(returns, BorshToken::Bytes(vec!(0x0e, 0x41)));
 
     vm.function("push", &[BorshToken::FixedBytes(vec![0x01])]);
 
-    let returns = vm.function("get_bs", &[]);
+    let returns = vm.function("get_bs", &[]).unwrap();
 
-    assert_eq!(returns, vec![BorshToken::Bytes(vec!(0x0e, 0x41, 0x01))]);
+    assert_eq!(returns, BorshToken::Bytes(vec!(0x0e, 0x41, 0x01)));
 }
 
 #[test]
@@ -412,7 +410,7 @@ fn bytes_empty_pop() {
         }"#,
     );
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     vm.function("pop", &[]);
 }
@@ -444,7 +442,7 @@ fn simple_struct() {
         }"#,
     );
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     vm.function("set_s2", &[]);
 
@@ -456,11 +454,11 @@ fn simple_struct() {
         ]
     );
 
-    let returns = vm.function("get_s1", &[]);
+    let returns = vm.function("get_s1", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Tuple(vec![
+        BorshToken::Tuple(vec![
             BorshToken::Uint {
                 width: 8,
                 value: BigInt::from(254u8)
@@ -469,7 +467,7 @@ fn simple_struct() {
                 width: 32,
                 value: BigInt::from(0xdeadu32)
             }
-        ])]
+        ])
     );
 
     vm.function(
@@ -486,11 +484,11 @@ fn simple_struct() {
         ])],
     );
 
-    let returns = vm.function("get_s1", &[]);
+    let returns = vm.function("get_s1", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Tuple(vec![
+        BorshToken::Tuple(vec![
             BorshToken::Uint {
                 width: 8,
                 value: BigInt::from(102u8)
@@ -499,7 +497,7 @@ fn simple_struct() {
                 width: 32,
                 value: BigInt::from(3240121u32)
             }
-        ])]
+        ])
     );
 }
 
@@ -536,7 +534,7 @@ fn struct_in_struct() {
         }"#,
     );
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     vm.function("set_s2", &[]);
 
@@ -549,11 +547,11 @@ fn struct_in_struct() {
         ]
     );
 
-    let returns = vm.function("get_s1", &[]);
+    let returns = vm.function("get_s1", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Tuple(vec![
+        BorshToken::Tuple(vec![
             BorshToken::Uint {
                 width: 8,
                 value: BigInt::from(254u8)
@@ -563,13 +561,13 @@ fn struct_in_struct() {
                     width: 32,
                     value: BigInt::from(102u8)
                 },
-                BorshToken::FixedBytes(vec![102, 111, 111, 98, 97, 114])
+                BorshToken::uint8_fixed_array(vec![102, 111, 111, 98, 97, 114])
             ]),
             BorshToken::Uint {
                 width: 64,
                 value: BigInt::from(1234567890u64)
             },
-        ])]
+        ])
     );
 
     vm.function(
@@ -593,11 +591,11 @@ fn struct_in_struct() {
         ])],
     );
 
-    let returns = vm.function("get_s1", &[]);
+    let returns = vm.function("get_s1", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Tuple(vec![
+        BorshToken::Tuple(vec![
             BorshToken::Uint {
                 width: 8,
                 value: BigInt::from(127u8)
@@ -607,13 +605,13 @@ fn struct_in_struct() {
                     width: 32,
                     value: BigInt::from(8192u32)
                 },
-                BorshToken::FixedBytes(vec![1, 2, 3, 4, 5, 6])
+                BorshToken::uint8_fixed_array(vec![1, 2, 3, 4, 5, 6])
             ]),
             BorshToken::Uint {
                 width: 64,
                 value: BigInt::from(12345678901234567890u64)
             },
-        ])]
+        ])
     );
 }
 
@@ -645,7 +643,7 @@ fn string_in_struct() {
             }"#,
     );
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     vm.function("set_s2", &[]);
 
@@ -658,11 +656,11 @@ fn string_in_struct() {
         ]
     );
 
-    let returns = vm.function("get_s1", &[]);
+    let returns = vm.function("get_s1", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Tuple(vec![
+        BorshToken::Tuple(vec![
             BorshToken::Uint {
                 width: 8,
                 value: BigInt::from(254u8)
@@ -672,7 +670,7 @@ fn string_in_struct() {
                 width: 64,
                 value: BigInt::from(1234567890u64)
             }
-        ])]
+        ])
     );
 
     vm.function(
@@ -690,11 +688,11 @@ fn string_in_struct() {
         ])],
     );
 
-    let returns = vm.function("get_s1", &[]);
+    let returns = vm.function("get_s1", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Tuple(vec![
+        BorshToken::Tuple(vec![
             BorshToken::Uint {
                 width: 8,
                 value: BigInt::from(127u8)
@@ -704,7 +702,7 @@ fn string_in_struct() {
                 width: 64,
                 value: BigInt::from(12345678901234567890u64)
             }
-        ])]
+        ])
     );
 }
 
@@ -760,11 +758,11 @@ fn complex_struct() {
         }"#,
     );
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
 
     vm.function("set_s2", &[]);
 
-    let returns = vm.function("get_s1", &[]);
+    let returns = vm.function("get_s1", &[]).unwrap().unwrap_tuple();
 
     assert_eq!(
         returns,
@@ -777,7 +775,7 @@ fn complex_struct() {
                 BorshToken::String(String::from("foobar")),
                 BorshToken::Tuple(vec!(
                     BorshToken::Bool(true),
-                    BorshToken::FixedBytes(vec!(0xed, 0xae, 0xda))
+                    BorshToken::uint8_fixed_array(vec!(0xed, 0xae, 0xda))
                 )),
                 BorshToken::Uint {
                     width: 64,
@@ -828,7 +826,7 @@ fn complex_struct() {
         ],
     );
 
-    let returns = vm.function("get_s1", &[]);
+    let returns = vm.function("get_s1", &[]).unwrap().unwrap_tuple();
 
     assert_eq!(
         returns,
@@ -841,7 +839,7 @@ fn complex_struct() {
                 BorshToken::String(String::from("foobar foobar foobar foobar foobar foobar")),
                 BorshToken::Tuple(vec!(
                     BorshToken::Bool(false),
-                    BorshToken::FixedBytes(vec!(0xc3, 0x9a, 0xfd))
+                    BorshToken::uint8_fixed_array(vec!(0xc3, 0x9a, 0xfd))
                 )),
                 BorshToken::Uint {
                     width: 64,
@@ -862,7 +860,7 @@ fn complex_struct() {
 
     vm.function("rm", &[]);
 
-    let returns = vm.function("get_s1", &[]);
+    let returns = vm.function("get_s1", &[]).unwrap().unwrap_tuple();
 
     assert_eq!(
         returns,
@@ -875,7 +873,7 @@ fn complex_struct() {
                 BorshToken::String(String::from("")),
                 BorshToken::Tuple(vec!(
                     BorshToken::Bool(false),
-                    BorshToken::FixedBytes(vec!(0, 0, 0))
+                    BorshToken::uint8_fixed_array(vec!(0, 0, 0))
                 )),
                 BorshToken::Uint {
                     width: 64,

+ 35 - 29
tests/solana_tests/strings.rs

@@ -20,16 +20,16 @@ fn storage_string_length() {
     }
     "#,
     );
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
 
     let _ = vm.function(
         "setString",
         &[BorshToken::String("coffee_tastes_good".to_string())],
     );
-    let returns = vm.function("getLength", &[]);
+    let returns = vm.function("getLength", &[]).unwrap();
 
     assert_eq!(
-        returns[0],
+        returns,
         BorshToken::Uint {
             width: 32,
             value: BigInt::from(18u8),
@@ -59,8 +59,8 @@ fn load_string_vector() {
       "#,
     );
 
-    vm.constructor("Testing", &[]);
-    let returns = vm.function("testLength", &[]);
+    vm.constructor(&[]);
+    let returns = vm.function("testLength", &[]).unwrap().unwrap_tuple();
     assert_eq!(
         returns[0],
         BorshToken::Uint {
@@ -83,30 +83,36 @@ fn load_string_vector() {
         }
     );
 
-    let returns = vm.function(
-        "getString",
-        &[BorshToken::Uint {
-            width: 32,
-            value: BigInt::zero(),
-        }],
-    );
-    assert_eq!(returns[0], BorshToken::String("tea".to_string()));
+    let returns = vm
+        .function(
+            "getString",
+            &[BorshToken::Uint {
+                width: 32,
+                value: BigInt::zero(),
+            }],
+        )
+        .unwrap();
+    assert_eq!(returns, BorshToken::String("tea".to_string()));
 
-    let returns = vm.function(
-        "getString",
-        &[BorshToken::Uint {
-            width: 32,
-            value: BigInt::one(),
-        }],
-    );
-    assert_eq!(returns[0], BorshToken::String("coffe".to_string()));
+    let returns = vm
+        .function(
+            "getString",
+            &[BorshToken::Uint {
+                width: 32,
+                value: BigInt::one(),
+            }],
+        )
+        .unwrap();
+    assert_eq!(returns, BorshToken::String("coffe".to_string()));
 
-    let returns = vm.function(
-        "getString",
-        &[BorshToken::Uint {
-            width: 32,
-            value: BigInt::from(2u8),
-        }],
-    );
-    assert_eq!(returns[0], BorshToken::String("sixsix".to_string()));
+    let returns = vm
+        .function(
+            "getString",
+            &[BorshToken::Uint {
+                width: 32,
+                value: BigInt::from(2u8),
+            }],
+        )
+        .unwrap();
+    assert_eq!(returns, BorshToken::String("sixsix".to_string()));
 }

+ 10 - 10
tests/solana_tests/unused_variable_elimination.rs

@@ -37,32 +37,32 @@ fn test_returns() {
     "#;
 
     let mut vm = build_solidity(file);
-    vm.constructor("c1", &[]);
+    vm.constructor(&[]);
     let _ = vm.function("assign", &[]);
-    let returns = vm.function("pb1", &[]);
+    let returns = vm.function("pb1", &[]).unwrap();
 
     assert_eq!(
         returns,
-        vec![BorshToken::Int {
+        BorshToken::Int {
             width: 256,
             value: BigInt::from(5u8)
-        }]
+        }
     );
 
-    let returns = vm.function("test1", &[]);
+    let returns = vm.function("test1", &[]).unwrap();
     assert_eq!(
         returns,
-        vec![BorshToken::Int {
+        BorshToken::Int {
             width: 256,
             value: BigInt::from(52u8)
-        }]
+        }
     );
-    let returns = vm.function("test2", &[]);
+    let returns = vm.function("test2", &[]).unwrap();
     assert_eq!(
         returns,
-        vec![BorshToken::Int {
+        BorshToken::Int {
             width: 256,
             value: BigInt::from(5u8)
-        }]
+        }
     );
 }

+ 2 - 2
tests/solana_tests/using.rs

@@ -29,7 +29,7 @@ fn using_for_contracts() {
         }"#,
     );
 
-    runtime.constructor("C", &[]);
+    runtime.constructor(&[]);
     runtime.function("test", &[]);
 
     assert_eq!(runtime.logs, "Hello");
@@ -72,7 +72,7 @@ fn using_for_contracts() {
         }"#,
     );
 
-    runtime.constructor("foo", &[]);
+    runtime.constructor(&[]);
     runtime.function("test", &[]);
 
     assert_eq!(runtime.logs, "X libX contractx:2");

+ 3 - 3
tests/solana_tests/vector_to_slice.rs

@@ -20,8 +20,8 @@ fn test_slice_in_phi() {
     "#;
 
     let mut vm = build_solidity(file);
-    vm.constructor("c1", &[]);
-    let returns = vm.function("test", &[]);
+    vm.constructor(&[]);
+    let returns = vm.function("test", &[]).unwrap();
 
-    assert_eq!(returns, vec![BorshToken::String(String::from("Hello!"))]);
+    assert_eq!(returns, BorshToken::String(String::from("Hello!")));
 }

+ 240 - 197
tests/solana_tests/yul.rs

@@ -60,38 +60,41 @@ contract testing  {
       "#,
     );
 
-    vm.constructor("testing", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("test_slot", &[]);
+    let returns = vm.function("test_slot", &[]).unwrap();
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(56016u16)
-        }]
+        }
     );
 
-    let returns = vm.function(
-        "call_data_array",
-        &[BorshToken::Array(vec![
-            BorshToken::Uint {
-                width: 32,
-                value: BigInt::from(3u8),
-            },
-            BorshToken::Uint {
-                width: 32,
-                value: BigInt::from(5u8),
-            },
-            BorshToken::Uint {
-                width: 32,
-                value: BigInt::from(7u8),
-            },
-            BorshToken::Uint {
-                width: 32,
-                value: BigInt::from(11u8),
-            },
-        ])],
-    );
+    let returns = vm
+        .function(
+            "call_data_array",
+            &[BorshToken::Array(vec![
+                BorshToken::Uint {
+                    width: 32,
+                    value: BigInt::from(3u8),
+                },
+                BorshToken::Uint {
+                    width: 32,
+                    value: BigInt::from(5u8),
+                },
+                BorshToken::Uint {
+                    width: 32,
+                    value: BigInt::from(7u8),
+                },
+                BorshToken::Uint {
+                    width: 32,
+                    value: BigInt::from(11u8),
+                },
+            ])],
+        )
+        .unwrap()
+        .unwrap_tuple();
 
     assert_eq!(
         returns,
@@ -108,7 +111,7 @@ contract testing  {
         ]
     );
 
-    let returns = vm.function("selector_address", &[]);
+    let returns = vm.function("selector_address", &[]).unwrap().unwrap_tuple();
     assert_eq!(
         returns,
         vec![
@@ -164,15 +167,18 @@ contract testing  {
       "#,
     );
 
-    vm.constructor("testing", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function(
-        "general_test",
-        &[BorshToken::Uint {
-            width: 64,
-            value: BigInt::from(5u8),
-        }],
-    );
+    let returns = vm
+        .function(
+            "general_test",
+            &[BorshToken::Uint {
+                width: 64,
+                value: BigInt::from(5u8),
+            }],
+        )
+        .unwrap()
+        .unwrap_tuple();
     assert_eq!(
         returns,
         vec![
@@ -187,13 +193,16 @@ contract testing  {
         ]
     );
 
-    let returns = vm.function(
-        "general_test",
-        &[BorshToken::Uint {
-            width: 64,
-            value: BigInt::from(78u8),
-        }],
-    );
+    let returns = vm
+        .function(
+            "general_test",
+            &[BorshToken::Uint {
+                width: 64,
+                value: BigInt::from(78u8),
+            }],
+        )
+        .unwrap()
+        .unwrap_tuple();
     assert_eq!(
         returns,
         vec![
@@ -208,13 +217,16 @@ contract testing  {
         ]
     );
 
-    let returns = vm.function(
-        "general_test",
-        &[BorshToken::Uint {
-            width: 64,
-            value: BigInt::from(259u16),
-        }],
-    );
+    let returns = vm
+        .function(
+            "general_test",
+            &[BorshToken::Uint {
+                width: 64,
+                value: BigInt::from(259u16),
+            }],
+        )
+        .unwrap()
+        .unwrap_tuple();
     assert_eq!(
         returns,
         vec![
@@ -260,40 +272,45 @@ contract c {
         "#,
     );
 
-    vm.constructor("c", &[]);
+    vm.constructor(&[]);
     let num: Vec<u8> = vec![
         0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
         0x11, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e,
         0x2f, 0x31,
     ];
-    let returns = vm.function(
-        "getByte",
-        &[BorshToken::Uint {
-            width: 256,
-            value: BigInt::from_bytes_be(Sign::Plus, &num),
-        }],
-    );
+    let returns = vm
+        .function(
+            "getByte",
+            &[BorshToken::Uint {
+                width: 256,
+                value: BigInt::from_bytes_be(Sign::Plus, &num),
+            }],
+        )
+        .unwrap();
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(6u8),
-        }]
+        }
     );
 
-    let returns = vm.function(
-        "divide",
-        &[
-            BorshToken::Uint {
-                width: 256,
-                value: BigInt::from(4u8),
-            },
-            BorshToken::Uint {
-                width: 256,
-                value: BigInt::from(3u8),
-            },
-        ],
-    );
+    let returns = vm
+        .function(
+            "divide",
+            &[
+                BorshToken::Uint {
+                    width: 256,
+                    value: BigInt::from(4u8),
+                },
+                BorshToken::Uint {
+                    width: 256,
+                    value: BigInt::from(3u8),
+                },
+            ],
+        )
+        .unwrap()
+        .unwrap_tuple();
     assert_eq!(
         returns,
         vec![
@@ -308,19 +325,22 @@ contract c {
         ]
     );
 
-    let returns = vm.function(
-        "divide",
-        &[
-            BorshToken::Uint {
-                width: 256,
-                value: BigInt::from(4u8),
-            },
-            BorshToken::Uint {
-                width: 256,
-                value: BigInt::zero(),
-            },
-        ],
-    );
+    let returns = vm
+        .function(
+            "divide",
+            &[
+                BorshToken::Uint {
+                    width: 256,
+                    value: BigInt::from(4u8),
+                },
+                BorshToken::Uint {
+                    width: 256,
+                    value: BigInt::zero(),
+                },
+            ],
+        )
+        .unwrap()
+        .unwrap_tuple();
     assert_eq!(
         returns,
         vec![
@@ -335,23 +355,26 @@ contract c {
         ]
     );
 
-    let returns = vm.function(
-        "mods",
-        &[
-            BorshToken::Uint {
-                width: 256,
-                value: BigInt::from(4u8),
-            },
-            BorshToken::Uint {
-                width: 256,
-                value: BigInt::from(2u8),
-            },
-            BorshToken::Uint {
-                width: 256,
-                value: BigInt::from(3u8),
-            },
-        ],
-    );
+    let returns = vm
+        .function(
+            "mods",
+            &[
+                BorshToken::Uint {
+                    width: 256,
+                    value: BigInt::from(4u8),
+                },
+                BorshToken::Uint {
+                    width: 256,
+                    value: BigInt::from(2u8),
+                },
+                BorshToken::Uint {
+                    width: 256,
+                    value: BigInt::from(3u8),
+                },
+            ],
+        )
+        .unwrap()
+        .unwrap_tuple();
     assert_eq!(
         returns,
         vec![
@@ -366,23 +389,26 @@ contract c {
         ]
     );
 
-    let returns = vm.function(
-        "mods",
-        &[
-            BorshToken::Uint {
-                width: 256,
-                value: BigInt::from(4u8),
-            },
-            BorshToken::Uint {
-                width: 256,
-                value: BigInt::from(2u8),
-            },
-            BorshToken::Uint {
-                width: 256,
-                value: BigInt::zero(),
-            },
-        ],
-    );
+    let returns = vm
+        .function(
+            "mods",
+            &[
+                BorshToken::Uint {
+                    width: 256,
+                    value: BigInt::from(4u8),
+                },
+                BorshToken::Uint {
+                    width: 256,
+                    value: BigInt::from(2u8),
+                },
+                BorshToken::Uint {
+                    width: 256,
+                    value: BigInt::zero(),
+                },
+            ],
+        )
+        .unwrap()
+        .unwrap_tuple();
     assert_eq!(
         returns,
         vec![
@@ -422,19 +448,22 @@ fn external_function() {
         "#,
     );
 
-    vm.constructor("C", &[]);
+    vm.constructor(&[]);
     let mut addr: Vec<u8> = vec![0; 32];
     addr[5] = 90;
-    let returns = vm.function(
-        "test",
-        &[
-            BorshToken::Uint {
-                width: 256,
-                value: BigInt::from_bytes_le(Sign::Plus, addr.as_slice()),
-            },
-            BorshToken::FixedBytes(vec![1, 2, 3, 4, 5, 6, 7, 8]),
-        ],
-    );
+    let returns = vm
+        .function(
+            "test",
+            &[
+                BorshToken::Uint {
+                    width: 256,
+                    value: BigInt::from_bytes_le(Sign::Plus, addr.as_slice()),
+                },
+                BorshToken::FixedBytes(vec![1, 2, 3, 4, 5, 6, 7, 8]),
+            ],
+        )
+        .unwrap()
+        .unwrap_tuple();
 
     let selector = returns[0].clone().into_fixed_bytes().unwrap();
     assert_eq!(selector, vec![1, 2, 3, 4, 5, 6, 7, 8]);
@@ -470,9 +499,9 @@ contract testing  {
 }"#,
     );
 
-    runtime.constructor("testing", &[]);
-    let returns = runtime.function("test_address", &[]);
-    let addr = returns[0].clone().into_bigint().unwrap();
+    runtime.constructor(&[]);
+    let returns = runtime.function("test_address", &[]).unwrap();
+    let addr = returns.into_bigint().unwrap();
     let b_vec = addr.to_bytes_be().1;
     assert_eq!(&b_vec, runtime.stack[0].data.as_ref());
 
@@ -481,22 +510,22 @@ contract testing  {
         .get_mut(&runtime.stack[0].data)
         .unwrap()
         .lamports = 102;
-    let returns = runtime.function("test_balance", &[]);
+    let returns = runtime.function("test_balance", &[]).unwrap();
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(102u8),
-        },]
+        }
     );
 
-    let returns = runtime.function("test_selfbalance", &[]);
+    let returns = runtime.function("test_selfbalance", &[]).unwrap();
     assert_eq!(
         returns,
-        vec![BorshToken::Uint {
+        BorshToken::Uint {
             width: 256,
             value: BigInt::from(102u8),
-        },]
+        },
     );
 }
 
@@ -520,9 +549,9 @@ fn addmod_mulmod() {
         "#,
     );
 
-    vm.constructor("foo", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function("testMod", &[]);
+    let returns = vm.function("testMod", &[]).unwrap().unwrap_tuple();
     assert_eq!(
         returns,
         vec![
@@ -598,107 +627,121 @@ contract Testing {
         "#,
     );
 
-    vm.constructor("Testing", &[]);
+    vm.constructor(&[]);
 
-    let returns = vm.function(
-        "switch_default",
-        &[BorshToken::Uint {
-            width: 256,
-            value: BigInt::one(),
-        }],
-    );
+    let returns = vm
+        .function(
+            "switch_default",
+            &[BorshToken::Uint {
+                width: 256,
+                value: BigInt::one(),
+            }],
+        )
+        .unwrap();
     assert_eq!(
-        returns[0],
+        returns,
         BorshToken::Uint {
             width: 256,
             value: BigInt::from(5u8),
         }
     );
 
-    let returns = vm.function(
-        "switch_default",
-        &[BorshToken::Uint {
-            width: 256,
-            value: BigInt::from(2u8),
-        }],
-    );
+    let returns = vm
+        .function(
+            "switch_default",
+            &[BorshToken::Uint {
+                width: 256,
+                value: BigInt::from(2u8),
+            }],
+        )
+        .unwrap();
     assert_eq!(
-        returns[0],
+        returns,
         BorshToken::Uint {
             width: 256,
             value: BigInt::from(6u8),
         },
     );
 
-    let returns = vm.function(
-        "switch_default",
-        &[BorshToken::Uint {
-            width: 256,
-            value: BigInt::from(6u8),
-        }],
-    );
+    let returns = vm
+        .function(
+            "switch_default",
+            &[BorshToken::Uint {
+                width: 256,
+                value: BigInt::from(6u8),
+            }],
+        )
+        .unwrap();
     assert_eq!(
-        returns[0],
+        returns,
         BorshToken::Uint {
             width: 256,
             value: BigInt::from(9u8),
         }
     );
 
-    let returns = vm.function(
-        "switch_no_default",
-        &[BorshToken::Uint {
-            width: 256,
-            value: BigInt::one(),
-        }],
-    );
+    let returns = vm
+        .function(
+            "switch_no_default",
+            &[BorshToken::Uint {
+                width: 256,
+                value: BigInt::one(),
+            }],
+        )
+        .unwrap();
     assert_eq!(
-        returns[0],
+        returns,
         BorshToken::Uint {
             width: 256,
             value: BigInt::from(3u8),
         },
     );
 
-    let returns = vm.function(
-        "switch_no_default",
-        &[BorshToken::Uint {
-            width: 256,
-            value: BigInt::from(2u8),
-        }],
-    );
+    let returns = vm
+        .function(
+            "switch_no_default",
+            &[BorshToken::Uint {
+                width: 256,
+                value: BigInt::from(2u8),
+            }],
+        )
+        .unwrap();
     assert_eq!(
-        returns[0],
+        returns,
         BorshToken::Uint {
             width: 256,
             value: BigInt::from(6u8),
         },
     );
 
-    let returns = vm.function(
-        "switch_no_default",
-        &[BorshToken::Uint {
-            width: 256,
-            value: BigInt::from(6u8),
-        }],
-    );
+    let returns = vm
+        .function(
+            "switch_no_default",
+            &[BorshToken::Uint {
+                width: 256,
+                value: BigInt::from(6u8),
+            }],
+        )
+        .unwrap();
     assert_eq!(
-        returns[0],
+        returns,
         BorshToken::Uint {
             width: 256,
             value: BigInt::from(4u8),
         },
     );
 
-    let returns = vm.function(
-        "switch_no_case",
-        &[BorshToken::Uint {
-            width: 256,
-            value: BigInt::from(3u8),
-        }],
-    );
+    let returns = vm
+        .function(
+            "switch_no_case",
+            &[BorshToken::Uint {
+                width: 256,
+                value: BigInt::from(3u8),
+            }],
+        )
+        .unwrap();
     assert_eq!(
-        returns[0],
+        returns,
         BorshToken::Uint {
             width: 256,
             value: BigInt::from(4u8),

Some files were not shown because too many files changed in this diff