Skip to content

Commit

Permalink
Move type traits to separate crates.
Browse files Browse the repository at this point in the history
  • Loading branch information
g-r-a-n-t committed Jul 27, 2021
1 parent 52df65b commit 7849b1e
Show file tree
Hide file tree
Showing 48 changed files with 738 additions and 1,171 deletions.
3 changes: 1 addition & 2 deletions crates/abi/src/builder.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use crate::elements::{Component, Contract, Event, EventField, ModuleAbis};
use crate::elements::{AbiEncoding, Component, Contract, Event, EventField, ModuleAbis};
use crate::errors::AbiError;
use fe_analyzer::context::Context;
use fe_analyzer::namespace::types::AbiEncoding;
use fe_parser::ast as fe;

/// Parse a map of contract ABIs from the input `module`.
Expand Down
129 changes: 128 additions & 1 deletion crates/abi/src/elements.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::errors::AbiError;
use fe_analyzer::context::FunctionAttributes;
use fe_analyzer::namespace::types::{AbiComponent, AbiEncoding};
use fe_analyzer::namespace::types::{Array, Base, FeString, FixedSize, Integer, Struct, Tuple};
use serde::ser::SerializeSeq;
use serde::{Serialize, Serializer};
use std::collections::HashMap;
Expand Down Expand Up @@ -62,6 +62,133 @@ impl Serialize for Contract {
}
}

/// Single component of a tuple.
#[derive(Clone, Debug, PartialEq, PartialOrd, Ord, Eq)]
pub struct AbiComponent {
pub name: String,
pub typ: String,
/// The subcomponents of the component.
pub components: Vec<AbiComponent>,
}

/// Information relevant to ABI encoding.
pub trait AbiEncoding {
/// Name of the type as it appears in the Json ABI.
fn abi_json_name(&self) -> String;

/// The components of an ABI tuple.
fn abi_components(&self) -> Vec<AbiComponent>;
}

impl AbiEncoding for FixedSize {
fn abi_json_name(&self) -> String {
match self {
FixedSize::Array(array) => array.abi_json_name(),
FixedSize::Base(base) => base.abi_json_name(),
FixedSize::Tuple(tuple) => tuple.abi_json_name(),
FixedSize::String(string) => string.abi_json_name(),
FixedSize::Contract(_) => "address".to_string(),
FixedSize::Struct(val) => val.abi_json_name(),
}
}

fn abi_components(&self) -> Vec<AbiComponent> {
match self {
FixedSize::Array(array) => array.abi_components(),
FixedSize::Base(base) => base.abi_components(),
FixedSize::Tuple(tuple) => tuple.abi_components(),
FixedSize::String(string) => string.abi_components(),
FixedSize::Contract(_) => vec![],
FixedSize::Struct(val) => val.abi_components(),
}
}
}

impl AbiEncoding for Base {
fn abi_json_name(&self) -> String {
match self {
Base::Numeric(Integer::U256) => "uint256".to_string(),
Base::Numeric(Integer::U128) => "uint128".to_string(),
Base::Numeric(Integer::U64) => "uint64".to_string(),
Base::Numeric(Integer::U32) => "uint32".to_string(),
Base::Numeric(Integer::U16) => "uint16".to_string(),
Base::Numeric(Integer::U8) => "uint8".to_string(),
Base::Numeric(Integer::I256) => "int256".to_string(),
Base::Numeric(Integer::I128) => "int128".to_string(),
Base::Numeric(Integer::I64) => "int64".to_string(),
Base::Numeric(Integer::I32) => "int32".to_string(),
Base::Numeric(Integer::I16) => "int16".to_string(),
Base::Numeric(Integer::I8) => "int8".to_string(),
Base::Address => "address".to_string(),
Base::Bool => "bool".to_string(),
Base::Unit => panic!("unit type is not abi encodable"),
}
}

fn abi_components(&self) -> Vec<AbiComponent> {
vec![]
}
}

impl AbiEncoding for Array {
fn abi_json_name(&self) -> String {
if self.inner == Base::Numeric(Integer::U8) {
"bytes".to_string()
} else {
format!("{}[{}]", self.inner.abi_json_name(), self.size)
}
}

fn abi_components(&self) -> Vec<AbiComponent> {
vec![]
}
}

impl AbiEncoding for Struct {
fn abi_json_name(&self) -> String {
"tuple".to_string()
}

fn abi_components(&self) -> Vec<AbiComponent> {
self.fields
.iter()
.map(|(name, typ)| AbiComponent {
name: name.to_owned(),
typ: typ.abi_json_name(),
components: vec![],
})
.collect()
}
}

impl AbiEncoding for Tuple {
fn abi_json_name(&self) -> String {
"tuple".to_string()
}

fn abi_components(&self) -> Vec<AbiComponent> {
self.items
.iter()
.enumerate()
.map(|(index, item)| AbiComponent {
name: format!("item{}", index),
typ: item.abi_json_name(),
components: vec![],
})
.collect()
}
}

impl AbiEncoding for FeString {
fn abi_json_name(&self) -> String {
"string".to_string()
}

fn abi_components(&self) -> Vec<AbiComponent> {
vec![]
}
}

/// An event interface.
#[derive(Serialize, Debug, PartialEq, Clone)]
pub struct Event {
Expand Down
7 changes: 4 additions & 3 deletions crates/abi/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ use fe_common::utils::keccak;
/// Formats the name and fields and calculates the 32 byte keccak256 value of
/// the signature.
pub fn event_topic(name: &str, fields: &[String]) -> String {
sign_event_or_func(name, fields, 32)
hash_signature(name, fields, 32)
}

/// Formats the name and params and calculates the 4 byte keccak256 value of the
/// signature.
pub fn func_selector(name: &str, params: &[String]) -> String {
sign_event_or_func(name, params, 4)
hash_signature(name, params, 4)
}

fn sign_event_or_func(name: &str, params: &[String], size: usize) -> String {
fn hash_signature(name: &str, params: &[String], size: usize) -> String {
let signature = format!("{}({})", name, params.join(","));
keccak::partial(signature.as_bytes(), size)
}
57 changes: 0 additions & 57 deletions crates/analyzer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,60 +39,3 @@ pub fn analyze(module: &fe::Module, file_id: SourceFileId) -> Result<Context, An
}
}
}

#[cfg(feature = "fix-context-harness")]
pub mod test_utils {
use crate::namespace::types::FixedSize;
use crate::{Context, ExpressionAttributes};
use fe_parser::ast as fe;
use fe_parser::node::{Node, Span};

pub struct ContextHarness {
pub context: Context,
pub src: String,
}

impl ContextHarness {
pub fn new(src: &str) -> Self {
ContextHarness {
context: Context::new(),
src: src.to_string(),
}
}

fn find_span(&self, substr: &str) -> Span {
let start = self
.src
.find(substr)
.unwrap_or_else(|| panic!("unable to find '{}' in '{}'", substr, self.src));

Span {
start,
end: start + substr.len(),
}
}

pub fn add_expression(&mut self, substr: &str, attributes: ExpressionAttributes) {
let span = self.find_span(substr);
let mock_node = Node::new(fe::Expr::Name("foo"), span);
self.context.add_expression(&mock_node, attributes)
}

pub fn add_expressions(&mut self, substrs: Vec<&str>, attributes: ExpressionAttributes) {
for substr in substrs {
self.add_expression(substr, attributes.clone())
}
}

pub fn add_declaration(&mut self, substr: &str, typ: FixedSize) {
let span = self.find_span(substr);
let mock_node = Node::new(
fe::FuncStmt::Expr {
value: fe::Expr::Name("foo"),
},
span,
);
self.context.add_declaration(&mock_node, typ)
}
}
}
24 changes: 9 additions & 15 deletions crates/analyzer/src/namespace/events.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,29 @@
use crate::namespace::types::{AbiEncoding, FixedSize};
use fe_common::utils::keccak;
use crate::namespace::types::FixedSize;

#[derive(Clone, Debug, PartialEq, Hash)]
pub struct EventDef {
pub name: String,
pub topic: String,
pub fields: Vec<(String, FixedSize)>,
pub indexed_fields: Vec<usize>,
}

impl EventDef {
pub fn new(name: &str, fields: Vec<(String, FixedSize)>, indexed_fields: Vec<usize>) -> Self {
let abi_fields = fields
.iter()
.map(|(_, typ)| typ.abi_selector_name())
.collect::<Vec<String>>();
let topic = build_event_topic(name, abi_fields);

Self {
name: name.to_string(),
topic,
fields,
indexed_fields,
}
}

pub fn all_field_types(&self) -> Vec<FixedSize> {
self.fields
.to_owned()
.into_iter()
.map(|(_, typ)| typ)
.collect()
}

/// The event's indexed fields.
///
/// These should be logged as additional topics.
Expand Down Expand Up @@ -67,11 +66,6 @@ impl EventDef {
}
}

fn build_event_topic(name: &str, fields: Vec<String>) -> String {
let signature = format!("{}({})", name, fields.join(","));
keccak::full(signature.as_bytes())
}

#[cfg(test)]
mod tests {
use crate::namespace::events::EventDef;
Expand Down
Loading

0 comments on commit 7849b1e

Please sign in to comment.