Skip to content

Commit 4e3924f

Browse files
authored
fix: add a derive for generate contract (#58)
* feat: add derives specific to contract * fix: add examples for contract derives * docs: add example for derives in README
1 parent 9f7cd5c commit 4e3924f

File tree

12 files changed

+81
-6
lines changed

12 files changed

+81
-6
lines changed

crates/rs-macro/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ The `abigen!` macro takes 2 or 3 inputs:
4646
3. Optional parameters:
4747
- `output_path`: if provided, the content will be generated in the given file instead of being expanded at the location of the macro invocation.
4848
- `type_aliases`: to avoid type name conflicts between components / contracts, you can rename some type by providing an alias for the full type path. It is important to give the **full** type path to ensure aliases are applied correctly.
49+
- `derive`: to specify the derive for the generated structs/enums.
50+
- `contract_derives`: to specify the derive for the generated contract type.
4951

5052
```rust
5153
use cainome::rs::abigen;
@@ -66,6 +68,14 @@ abigen!(
6668
},
6769
);
6870

71+
// Example with custom derives:
72+
abigen!(
73+
MyContract,
74+
"./contracts/abi/components.abi.json",
75+
derive(Debug, Clone),
76+
contract_derives(Debug, Clone)
77+
);
78+
6979
fn main() {
7080
// ... use the generated types here, which all of them
7181
// implement CairoSerde trait.

crates/rs-macro/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ fn abigen_internal(input: TokenStream) -> TokenStream {
3737
&abi_tokens,
3838
contract_abi.execution_version,
3939
&contract_abi.derives,
40+
&contract_abi.contract_derives,
4041
);
4142

4243
if let Some(out_path) = contract_abi.output_path {
@@ -66,6 +67,7 @@ fn abigen_internal_legacy(input: TokenStream) -> TokenStream {
6667
&abi_tokens,
6768
cainome_rs::ExecutionVersion::V1,
6869
&contract_abi.derives,
70+
&contract_abi.contract_derives,
6971
);
7072

7173
if let Some(out_path) = contract_abi.output_path {

crates/rs-macro/src/macro_inputs.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ pub(crate) struct ContractAbi {
3939
pub type_aliases: HashMap<String, String>,
4040
pub execution_version: ExecutionVersion,
4141
pub derives: Vec<String>,
42+
pub contract_derives: Vec<String>,
4243
}
4344

4445
impl Parse for ContractAbi {
@@ -92,6 +93,7 @@ impl Parse for ContractAbi {
9293
let mut execution_version = ExecutionVersion::V1;
9394
let mut type_aliases = HashMap::new();
9495
let mut derives = Vec::new();
96+
let mut contract_derives = Vec::new();
9597

9698
loop {
9799
if input.parse::<Token![,]>().is_err() {
@@ -153,6 +155,15 @@ impl Parse for ContractAbi {
153155
derives.push(derive.to_token_stream().to_string());
154156
}
155157
}
158+
"contract_derives" => {
159+
let content;
160+
parenthesized!(content in input);
161+
let parsed = content.parse_terminated(Spanned::<Type>::parse, Token![,])?;
162+
163+
for derive in parsed {
164+
contract_derives.push(derive.to_token_stream().to_string());
165+
}
166+
}
156167
_ => emit_error!(name.span(), format!("unexpected named parameter `{name}`")),
157168
}
158169
}
@@ -164,6 +175,7 @@ impl Parse for ContractAbi {
164175
type_aliases,
165176
execution_version,
166177
derives,
178+
contract_derives,
167179
})
168180
}
169181
}

crates/rs-macro/src/macro_inputs_legacy.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ pub(crate) struct ContractAbiLegacy {
3636
pub output_path: Option<String>,
3737
pub type_aliases: HashMap<String, String>,
3838
pub derives: Vec<String>,
39+
pub contract_derives: Vec<String>,
3940
}
4041

4142
impl Parse for ContractAbiLegacy {
@@ -89,6 +90,7 @@ impl Parse for ContractAbiLegacy {
8990
let mut output_path: Option<String> = None;
9091
let mut type_aliases = HashMap::new();
9192
let mut derives = Vec::new();
93+
let mut contract_derives = Vec::new();
9294

9395
loop {
9496
if input.parse::<Token![,]>().is_err() {
@@ -142,6 +144,15 @@ impl Parse for ContractAbiLegacy {
142144
derives.push(derive.to_token_stream().to_string());
143145
}
144146
}
147+
"contract_derives" => {
148+
let content;
149+
parenthesized!(content in input);
150+
let parsed = content.parse_terminated(Spanned::<Type>::parse, Token![,])?;
151+
152+
for derive in parsed {
153+
contract_derives.push(derive.to_token_stream().to_string());
154+
}
155+
}
145156
_ => emit_error!(name.span(), format!("unexpected named parameter `{name}`")),
146157
}
147158
}
@@ -152,6 +163,7 @@ impl Parse for ContractAbiLegacy {
152163
output_path,
153164
type_aliases,
154165
derives,
166+
contract_derives,
155167
})
156168
}
157169
}

crates/rs/src/expand/contract.rs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,22 @@ use super::utils;
77
pub struct CairoContract;
88

99
impl CairoContract {
10-
pub fn expand(contract_name: Ident) -> TokenStream2 {
10+
pub fn expand(contract_name: Ident, contract_derives: &[String]) -> TokenStream2 {
1111
let reader = utils::str_to_ident(format!("{}Reader", contract_name).as_str());
1212

1313
let snrs_types = utils::snrs_types();
1414
let snrs_accounts = utils::snrs_accounts();
1515
let snrs_providers = utils::snrs_providers();
1616

17+
let mut internal_derives = vec![];
18+
19+
for d in contract_derives {
20+
internal_derives.push(utils::str_to_type(d));
21+
}
22+
1723
let q = quote! {
1824

19-
#[derive(Debug)]
25+
#[derive(#(#internal_derives,)*)]
2026
pub struct #contract_name<A: #snrs_accounts::ConnectedAccount + Sync> {
2127
pub address: #snrs_types::Felt,
2228
pub account: A,
@@ -45,7 +51,7 @@ impl CairoContract {
4551
}
4652
}
4753

48-
#[derive(Debug)]
54+
#[derive(#(#internal_derives,)*)]
4955
pub struct #reader<P: #snrs_providers::Provider + Sync> {
5056
pub address: #snrs_types::Felt,
5157
pub provider: P,

crates/rs/src/lib.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,8 @@ pub struct Abigen {
7373
pub execution_version: ExecutionVersion,
7474
/// Derives to be added to the generated types.
7575
pub derives: Vec<String>,
76+
/// Derives to be added to the generated contract.
77+
pub contract_derives: Vec<String>,
7678
}
7779

7880
impl Abigen {
@@ -90,6 +92,7 @@ impl Abigen {
9092
types_aliases: HashMap::new(),
9193
execution_version: ExecutionVersion::V1,
9294
derives: vec![],
95+
contract_derives: vec![],
9396
}
9497
}
9598

@@ -123,6 +126,16 @@ impl Abigen {
123126
self
124127
}
125128

129+
/// Sets the derives to be added to the generated contract.
130+
///
131+
/// # Arguments
132+
///
133+
/// * `derives` - Derives to be added to the generated contract.
134+
pub fn with_contract_derives(mut self, derives: Vec<String>) -> Self {
135+
self.contract_derives = derives;
136+
self
137+
}
138+
126139
/// Generates the contract bindings.
127140
pub fn generate(&self) -> Result<ContractBindings> {
128141
let file_content = std::fs::read_to_string(&self.abi_source)?;
@@ -134,6 +147,7 @@ impl Abigen {
134147
&tokens,
135148
self.execution_version,
136149
&self.derives,
150+
&self.contract_derives,
137151
);
138152

139153
Ok(ContractBindings {
@@ -157,17 +171,24 @@ impl Abigen {
157171
///
158172
/// * `contract_name` - Name of the contract.
159173
/// * `abi_tokens` - Tokenized ABI.
174+
/// * `execution_version` - The version of transaction to be executed.
175+
/// * `derives` - Derives to be added to the generated types.
176+
/// * `contract_derives` - Derives to be added to the generated contract.
160177
pub fn abi_to_tokenstream(
161178
contract_name: &str,
162179
abi_tokens: &TokenizedAbi,
163180
execution_version: ExecutionVersion,
164181
derives: &[String],
182+
contract_derives: &[String],
165183
) -> TokenStream2 {
166184
let contract_name = utils::str_to_ident(contract_name);
167185

168186
let mut tokens: Vec<TokenStream2> = vec![];
169187

170-
tokens.push(CairoContract::expand(contract_name.clone()));
188+
tokens.push(CairoContract::expand(
189+
contract_name.clone(),
190+
contract_derives,
191+
));
171192

172193
let mut sorted_structs = abi_tokens.structs.clone();
173194
sorted_structs.sort_by(|a, b| {

examples/abigen_generate.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@ async fn main() {
1010
"MyContract",
1111
"./contracts/target/dev/contracts_simple_get_set.contract_class.json",
1212
)
13-
.with_types_aliases(aliases);
13+
.with_types_aliases(aliases)
14+
.with_derives(vec!["Debug".to_string(), "PartialEq".to_string()])
15+
.with_contract_derives(vec!["Debug".to_string(), "Clone".to_string()]);
1416

1517
abigen
1618
.generate()

examples/simple_get_set.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ const KATANA_CHAIN_ID: &str = "0x4b4154414e41";
2020
// Or you can use the extracted abi entries with jq in contracts/abi/.
2121
abigen!(
2222
MyContract,
23-
"./contracts/target/dev/contracts_simple_get_set.contract_class.json"
23+
"./contracts/target/dev/contracts_simple_get_set.contract_class.json",
24+
derives(Debug, PartialEq),
25+
contract_derives(Debug, Clone)
2426
);
2527
//abigen!(MyContract, "./contracts/abi/simple_get_set.abi.json");
2628

src/bin/cli/args.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ pub struct CainomeArgs {
6767
#[arg(value_name = "DERIVES")]
6868
#[arg(help = "Derives to be added to the generated types.")]
6969
pub derives: Option<Vec<String>>,
70+
71+
#[arg(long)]
72+
#[arg(value_name = "CONTRACT_DERIVES")]
73+
#[arg(help = "Derives to be added to the generated contract.")]
74+
pub contract_derives: Option<Vec<String>>,
7075
}
7176

7277
#[derive(Debug, Args, Clone)]

src/bin/cli/main.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ async fn main() -> CainomeCliResult<()> {
5353
contracts,
5454
execution_version: args.execution_version,
5555
derives: args.derives.unwrap_or_default(),
56+
contract_derives: args.contract_derives.unwrap_or_default(),
5657
})
5758
.await?;
5859

0 commit comments

Comments
 (0)