Skip to content

Commit

Permalink
feat: support multiple abis in a single contract
Browse files Browse the repository at this point in the history
  • Loading branch information
joshstevens19 committed Sep 13, 2024
1 parent 6e5d6cf commit 60ca3a6
Show file tree
Hide file tree
Showing 34 changed files with 233 additions and 672 deletions.
2 changes: 1 addition & 1 deletion cli/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ prod_build:
new_no_code:
RUSTFLAGS='-C target-cpu=native' cargo run --release --features jemalloc -- new --path $(CURDIR)/../examples no-code
new_rust:
RUSTFLAGS='-C target-cpu=native' cargo run --release --features jemalloc -- new --path $(CURDIR)/../../ rust
RUSTFLAGS='-C target-cpu=native' cargo run --release --features jemalloc -- new --path $(CURDIR)/../../rust
start_indexer:
RUSTFLAGS='-C target-cpu=native' RUST_BACKTRACE='full' cargo run --release --features jemalloc -- start --path $(CURDIR)/../examples/rindexer_demo_cli indexer
start_all:
Expand Down
4 changes: 2 additions & 2 deletions cli/src/commands/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use rindexer::{
contract::{Contract, ContractDetails},
yaml::{read_manifest_raw, write_manifest, YAML_CONFIG_NAME},
},
public_read_env_value, write_file,
public_read_env_value, write_file, StringOrArray,
};

use crate::{
Expand Down Expand Up @@ -176,7 +176,7 @@ pub async fn handle_add_contract_command(
None,
None,
)],
abi: abi_path_relative,
abi: StringOrArray::Single(abi_path_relative),
include_events: None,
index_event_in_order: None,
dependency_events: None,
Expand Down
4 changes: 2 additions & 2 deletions cli/src/commands/new.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use rindexer::{
storage::{CsvDetails, PostgresDetails, Storage},
yaml::{write_manifest, YAML_CONFIG_NAME},
},
write_file, WriteFileError,
write_file, StringOrArray, WriteFileError,
};

use crate::console::{
Expand Down Expand Up @@ -155,7 +155,7 @@ pub fn handle_new_command(
Some(U64::from(18900000)),
Some(U64::from(19000000)),
)],
abi: abi_example_path.display().to_string(),
abi: StringOrArray::Single(abi_example_path.display().to_string()),
include_events: Some(vec!["Transfer".to_string(), "Approval".to_string()]),
index_event_in_order: None,
dependency_events: None,
Expand Down
4 changes: 2 additions & 2 deletions cli/src/commands/phantom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use rindexer::{
create_dyrpc_api_key, deploy_dyrpc_contract,
shadow::deploy_shadow_contract,
},
public_read_env_value, write_file,
public_read_env_value, write_file, StringOrArray,
};

use crate::{
Expand Down Expand Up @@ -558,7 +558,7 @@ async fn handle_phantom_deploy(
serde_json::to_string_pretty(&compiled_contract.abi).unwrap().as_str(),
)?;

contract.abi = format!("./abis/{}.abi.json", name);
contract.abi = StringOrArray::Single(format!("./abis/{}.abi.json", name));
contract_network.unwrap().network = name;

write_manifest(&manifest, &rindexer_yaml_path)?;
Expand Down
11 changes: 6 additions & 5 deletions core/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use crate::{
sql_type_wrapper::{solidity_type_to_ethereum_sql_type_wrapper, EthereumSqlTypeWrapper},
},
event::contract_setup::IndexingContractSetup,
helpers::{camel_to_snake, get_full_path},
manifest::contract::Contract,
helpers::camel_to_snake,
manifest::contract::{Contract, ParseAbiError},
};

#[derive(Debug, Clone, Serialize, Deserialize)]
Expand Down Expand Up @@ -168,6 +168,9 @@ pub enum ReadAbiError {

#[error("Could not read ABI JSON: {0}")]
CouldNotReadAbiJson(#[from] serde_json::Error),

#[error("{0}")]
ParseAbiError(#[from] ParseAbiError),
}

impl ABIItem {
Expand Down Expand Up @@ -197,9 +200,7 @@ impl ABIItem {
project_path: &Path,
contract: &Contract,
) -> Result<Vec<ABIItem>, ReadAbiError> {
let full_path = get_full_path(project_path, &contract.abi)
.map_err(|_| ReadAbiError::AbiPathDoesNotExist(contract.abi.clone()))?;
let abi_str = fs::read_to_string(full_path)?;
let abi_str = contract.parse_abi(project_path)?;
let abi_items: Vec<ABIItem> = serde_json::from_str(&abi_str)?;

let filtered_abi_items = match &contract.include_events {
Expand Down
1 change: 1 addition & 0 deletions core/src/database/postgres/sql_type_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,7 @@ impl ToSql for EthereumSqlTypeWrapper {
to_sql_checked!();
}

#[allow(clippy::manual_strip)]
pub fn solidity_type_to_ethereum_sql_type_wrapper(
abi_type: &str,
) -> Option<EthereumSqlTypeWrapper> {
Expand Down
3 changes: 2 additions & 1 deletion core/src/event/contract_setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::{
generate_random_id,
manifest::contract::{Contract, EventInputIndexedFilters},
provider::{CreateNetworkProvider, JsonRpcCachedProvider},
types::single_or_array::StringOrArray,
};

#[derive(Clone)]
Expand Down Expand Up @@ -39,7 +40,7 @@ impl NetworkContract {
pub struct ContractInformation {
pub name: String,
pub details: Vec<NetworkContract>,
pub abi: String,
pub abi: StringOrArray,
pub reorg_safe_distance: bool,
}

Expand Down
50 changes: 23 additions & 27 deletions core/src/generator/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@ use super::{
};
use crate::{
helpers::{
camel_to_snake, create_mod_file, format_all_files_for_project, get_full_path, write_file,
camel_to_snake, create_mod_file, format_all_files_for_project, write_file,
CreateModFileError, WriteFileError,
},
indexer::Indexer,
manifest::{
contract::ParseAbiError,
core::Manifest,
global::Global,
network::Network,
Expand Down Expand Up @@ -84,8 +85,8 @@ pub enum WriteIndexerEvents {
#[error("{0}")]
GenerateEventBindingCodeError(#[from] GenerateEventBindingsError),

#[error("Could not find ABI path: {0}")]
AbiPathDoesNotExist(String),
#[error("Could not parse ABI: {0}")]
CouldNotParseAbi(#[from] ParseAbiError),
}

fn write_indexer_events(
Expand All @@ -103,30 +104,25 @@ fn write_indexer_events(
format!("{}/events/{}", camel_to_snake(&indexer.name), camel_to_snake(&contract.name));
write_file(&generate_file_location(output, &event_path), events_code.as_str())?;

let abi_full_path = get_full_path(project_path, &contract.abi)
.map_err(|_| WriteIndexerEvents::AbiPathDoesNotExist(contract.abi.clone()))?;
match abi_full_path.to_str() {
None => return Err(WriteIndexerEvents::CouldNotCreateAbigenInstance),
Some(abi_full_path) => {
let abi_gen = Abigen::new(abigen_contract_name(&contract), abi_full_path)
.map_err(|_| WriteIndexerEvents::CouldNotCreateAbigenInstance)?
.generate()
.map_err(|_| WriteIndexerEvents::CouldNotGenerateAbi)?;

write_file(
&generate_file_location(
output,
&format!(
"{}/events/{}",
camel_to_snake(&indexer.name),
abigen_contract_file_name(&contract)
),
),
&abi_gen.to_string(),
)
.map_err(WriteIndexerEvents::CouldNotWriteAbigenCodeCode)?;
}
}
let abi_string = contract.parse_abi(project_path)?;

let abi_gen = Abigen::new(abigen_contract_name(&contract), abi_string)
.map_err(|_| WriteIndexerEvents::CouldNotCreateAbigenInstance)?
.generate()
.map_err(|_| WriteIndexerEvents::CouldNotGenerateAbi)?;

write_file(
&generate_file_location(
output,
&format!(
"{}/events/{}",
camel_to_snake(&indexer.name),
abigen_contract_file_name(&contract)
),
),
&abi_gen.to_string(),
)
.map_err(WriteIndexerEvents::CouldNotWriteAbigenCodeCode)?;
}
Ok(())
}
Expand Down
20 changes: 13 additions & 7 deletions core/src/generator/context_bindings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
network::Network,
},
types::code::Code,
StringOrArray,
};

fn generate_contract_code(
Expand All @@ -19,6 +20,7 @@ fn generate_contract_code(
if let Some(address) = contract_details.address() {
match address {
ValueOrArray::Value(address) => {
let contract_address = format!("{:?}", address);
let code = format!(
r#"
abigen!({contract_name}, "{contract_path}");
Expand All @@ -33,7 +35,7 @@ fn generate_contract_code(
"#,
contract_name = contract_name,
contract_fn_name = camel_to_snake(contract_name),
contract_address = address,
contract_address = contract_address,
network_fn_name = network_provider_fn_name(network),
contract_path = abi_location
);
Expand Down Expand Up @@ -83,12 +85,16 @@ fn generate_contracts_code(contracts: &[Contract], networks: &[Network]) -> Code
for contract in contracts {
for details in &contract.details {
if let Some(network) = networks.iter().find(|&n| n.name == details.network) {
code.push_str(&generate_contract_code(
&contract.name,
details,
&contract.abi,
network,
));
if let StringOrArray::Single(abi_path) = &contract.abi {
code.push_str(&generate_contract_code(
&contract.name,
details,
abi_path,
network,
));
} else {
panic!("Multiple ABIs not supported yet on global contracts");
}
}
}
}
Expand Down
15 changes: 7 additions & 8 deletions core/src/generator/events_bindings.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{fs, path::Path};
use std::path::Path;

use ethers::types::ValueOrArray;
use serde_json::Value;
Expand All @@ -11,9 +11,9 @@ use crate::{
database::postgres::generate::{
generate_column_names_only_with_base_properties, generate_event_table_full_name,
},
helpers::{camel_to_snake, camel_to_snake_advanced, get_full_path},
helpers::{camel_to_snake, camel_to_snake_advanced},
manifest::{
contract::{Contract, ContractDetails},
contract::{Contract, ContractDetails, ParseAbiError},
storage::{CsvDetails, Storage},
},
types::code::Code,
Expand Down Expand Up @@ -42,18 +42,17 @@ pub enum GenerateStructsError {
#[error("Invalid ABI JSON format")]
InvalidAbiJsonFormat,

#[error("Could not find ABI path: {0}")]
AbiPathDoesNotExist(String),
#[error("{0}")]
ParseAbiError(#[from] ParseAbiError),
}

fn generate_structs(
project_path: &Path,
contract: &Contract,
) -> Result<Code, GenerateStructsError> {
// TODO - this could be shared with `get_abi_items`
let full_path = get_full_path(project_path, &contract.abi)
.map_err(|_| GenerateStructsError::AbiPathDoesNotExist(contract.abi.clone()))?;
let abi_str = fs::read_to_string(full_path)?;
let abi_str = contract.parse_abi(project_path)?;

let abi_json: Value = serde_json::from_str(&abi_str)?;

let mut structs = Code::blank();
Expand Down
15 changes: 6 additions & 9 deletions core/src/indexer/no_code.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{fs, io, path::Path, sync::Arc};
use std::{io, path::Path, sync::Arc};

use colored::Colorize;
use ethers::abi::{Abi, Contract as EthersContract, Event};
Expand Down Expand Up @@ -29,9 +29,9 @@ use crate::{
EventMessage,
},
generate_random_id,
helpers::get_full_path,
indexer::log_helpers::{map_log_params_to_raw_values, parse_log},
manifest::{
contract::ParseAbiError,
core::Manifest,
yaml::{read_manifest, ReadManifestError},
},
Expand Down Expand Up @@ -423,9 +423,6 @@ fn no_code_callback(params: Arc<NoCodeCallbackParams>) -> EventCallbackType {

#[derive(thiserror::Error, Debug)]
pub enum ProcessIndexersError {
#[error("Could not find ABI path: {0}")]
AbiPathDoesNotExist(String),

#[error("Could not read ABI string: {0}")]
CouldNotReadAbiString(#[from] io::Error),

Expand All @@ -449,6 +446,9 @@ pub enum ProcessIndexersError {

#[error("Event name not found in ABI for contract: {0} - event: {1}")]
EventNameNotFoundInAbi(String, String),

#[error("{0}")]
ParseAbiError(#[from] ParseAbiError),
}

pub async fn process_events(
Expand All @@ -461,10 +461,7 @@ pub async fn process_events(

for contract in &mut manifest.contracts {
// TODO - this could be shared with `get_abi_items`
let full_path = get_full_path(project_path, &contract.abi)
.map_err(|_| ProcessIndexersError::AbiPathDoesNotExist(contract.abi.clone()))?;
let abi_str = fs::read_to_string(full_path)?;

let abi_str = contract.parse_abi(project_path)?;
let abi: Abi = serde_json::from_str(&abi_str)?;

#[allow(clippy::useless_conversion)]
Expand Down
2 changes: 1 addition & 1 deletion core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ pub mod provider;
mod start;
mod streams;
mod types;

// export 3rd party dependencies
pub use async_trait::async_trait;
pub use colored::Colorize as RindexerColorize;
Expand All @@ -45,3 +44,4 @@ pub use start::{
pub use tokio::main as rindexer_main;
pub use tokio_postgres::types::Type as PgType;
pub use tracing::{error as rindexer_error, info as rindexer_info};
pub use types::single_or_array::StringOrArray;
Loading

0 comments on commit 60ca3a6

Please sign in to comment.