Skip to content

Commit f90ad06

Browse files
Generate Solidity ABI compatibility metadata (#2510)
* Generate Solidity ABI compatibility metadata * Collect Solidity ABI compatibility events metadata * chore: `trybuild` wrapper license info * chore: todo for enabling ink metadata gen `cfg` gating * refactor "sol" ABI codegen * chore: Silence `cfg` warnings for ui tests * chore: Update `contract-build` version * tests: Solidity ABI events info collection integration test * Update changelog * chore: update doc
1 parent c1ae464 commit f90ad06

File tree

28 files changed

+797
-106
lines changed

28 files changed

+797
-106
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,8 @@ jobs:
559559
scripts/for_all_contracts_exec.sh --path integration-tests --ignore internal/static-buffer \
560560
--ignore internal/mapping --ignore public/debugging-strategies --ignore public/wildcard-selector \
561561
--ignore solidity-abi/sol-cross-contract --ignore solidity-abi/sol-encoding \
562-
--ignore solidity-abi/solidity-calls-flipper --partition ${{ matrix.partition }}/4 -- \
562+
--ignore solidity-abi/solidity-calls-flipper --ignore solidity-abi/events \
563+
--partition ${{ matrix.partition }}/4 -- \
563564
cargo contract test --all-features --manifest-path {}
564565
565566
examples-test-mapping:

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88

99
### Added
1010
- Support ABI `cfg` flag in codegen - [#2501](https://github.com/use-ink/ink/pull/2501)
11+
- Generate Solidity ABI compatibility metadata - [#2510](https://github.com/use-ink/ink/pull/2510)
1112

1213
### Changed
13-
1414
- Use marker trait for finding ink! storage `struct` during code analysis - [2499](https://github.com/use-ink/ink/pull/2499)
1515

1616
### Fixed

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/e2e/src/contract_build.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ use contract_build::{
3838
Features,
3939
ImageVariant,
4040
ManifestPath,
41-
MetadataSpec,
4241
Network,
4342
OutputType,
4443
UnstableFlags,
@@ -221,7 +220,7 @@ fn build_contract(
221220
extra_lints: false,
222221
output_type: OutputType::HumanReadable,
223222
image: ImageVariant::Default,
224-
metadata_spec: MetadataSpec::Ink,
223+
metadata_spec: None,
225224
};
226225

227226
match contract_build::execute(args) {

crates/ink/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,5 @@ unstable-hostfn = ["ink_env/unstable-hostfn", "ink_storage/unstable-hostfn"]
8181
level = "warn"
8282
check-cfg = [
8383
'cfg(feature, values(any()))',
84+
'cfg(ink_abi, values("ink", "sol", "all"))'
8485
]

crates/ink/codegen/Cargo.toml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,10 @@ std = [
4848
"derive_more/std"
4949
]
5050

51+
# For the ui tests, which use this `Cargo.toml`
5152
[lints.rust.unexpected_cfgs]
5253
level = "warn"
5354
check-cfg = [
54-
# For the ui tests, which use this `Cargo.toml`
5555
'cfg(feature, values(any()))',
56-
# For ABI declaration.
5756
'cfg(ink_abi, values("ink", "sol", "all"))'
5857
]

crates/ink/codegen/src/generator/as_dependency/call_builder.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use quote::{
2323
use syn::spanned::Spanned as _;
2424

2525
#[cfg(any(ink_abi = "sol", ink_abi = "all"))]
26-
use crate::generator::solidity::solidity_selector;
26+
use crate::generator::sol;
2727
use crate::{
2828
generator,
2929
GenerateCode,
@@ -436,7 +436,7 @@ impl CallBuilder<'_> {
436436
} else {
437437
message_ident.clone()
438438
};
439-
let selector_bytes = solidity_selector(&message);
439+
let selector_bytes = sol::utils::selector(&message);
440440
let arg_list = generator::generate_argument_list(
441441
input_types.iter().cloned(),
442442
quote!(::ink::reflect::SolEncoding),

crates/ink/codegen/src/generator/contract.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ impl GenerateCode for Contract<'_> {
5353
.items()
5454
.iter()
5555
.filter_map(ir::Item::map_rust_item);
56+
57+
#[cfg(not(any(ink_abi = "sol", ink_abi = "all")))]
58+
let solidity_metadata = quote!();
59+
60+
#[cfg(any(ink_abi = "sol", ink_abi = "all"))]
61+
let solidity_metadata = self.generate_code_using::<generator::SolidityMetadata>();
62+
5663
quote! {
5764
#( #attrs )*
5865
#vis mod #ident {
@@ -63,6 +70,7 @@ impl GenerateCode for Contract<'_> {
6370
#item_impls
6471
#contract_reference
6572
#metadata
73+
#solidity_metadata
6674
#( #non_ink_items )*
6775
}
6876
}

crates/ink/codegen/src/generator/dispatch.rs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,7 @@ use syn::{
3737
};
3838

3939
#[cfg(any(ink_abi = "sol", ink_abi = "all"))]
40-
use crate::generator::solidity::{
41-
solidity_call_signature,
42-
solidity_call_type_ident,
43-
solidity_selector,
44-
solidity_selector_id,
45-
};
40+
use crate::generator::sol;
4641
use crate::{
4742
generator,
4843
GenerateCode,
@@ -181,7 +176,7 @@ impl Dispatch<'_> {
181176

182177
#[cfg(any(ink_abi = "sol", ink_abi = "all"))]
183178
{
184-
let id = solidity_selector_id(&message);
179+
let id = sol::utils::selector_id(&message);
185180
message_dispatchables.push(MessageDispatchable { message, id });
186181
let _ = trait_path; // removes unused warning.
187182
}
@@ -490,8 +485,8 @@ impl Dispatch<'_> {
490485
let input_tuple_type = generator::input_types_tuple(message.inputs());
491486
let input_tuple_bindings = generator::input_bindings_tuple(message.inputs());
492487

493-
let selector_id = solidity_selector_id(message);
494-
let selector_bytes = solidity_selector(message);
488+
let selector_id = sol::utils::selector_id(message);
489+
let selector_bytes = sol::utils::selector(message);
495490

496491
let (call_prefix, label) = match trait_info {
497492
None => {
@@ -1180,8 +1175,8 @@ impl Dispatch<'_> {
11801175
let span = message.span();
11811176
let ident = message.ident();
11821177
let ident_str = ident.to_string();
1183-
let call_type_ident = solidity_call_type_ident(&message);
1184-
let signature = solidity_call_signature(ident_str, message.inputs());
1178+
let call_type_ident = sol::utils::call_info_type_ident(&message);
1179+
let signature = sol::utils::call_signature(ident_str, message.inputs());
11851180

11861181
quote_spanned!(span=>
11871182
pub struct #call_type_ident;

crates/ink/codegen/src/generator/event.rs

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,18 @@
1212
// See the License for the specific language governing permissions and
1313
// limitations under the License.
1414

15-
use crate::GenerateCode;
1615
use derive_more::From;
16+
#[cfg(all(feature = "std", any(ink_abi = "sol", ink_abi = "all")))]
17+
use ir::IsDocAttribute;
1718
use proc_macro2::TokenStream as TokenStream2;
19+
use quote::quote;
1820
use syn::spanned::Spanned;
21+
#[cfg(all(feature = "std", any(ink_abi = "sol", ink_abi = "all")))]
22+
use syn::Fields;
23+
24+
#[cfg(all(feature = "std", any(ink_abi = "sol", ink_abi = "all")))]
25+
use crate::generator::sol;
26+
use crate::GenerateCode;
1927

2028
/// Generates code for the event item.
2129
#[derive(From, Copy, Clone)]
@@ -38,6 +46,12 @@ impl GenerateCode for Event<'_> {
3846
.map(|hex_s| quote::quote! { #[ink(signature_topic = #hex_s)] });
3947
let cfg_attrs = self.item.get_cfg_attrs(item.span());
4048

49+
#[cfg(all(feature = "std", any(ink_abi = "sol", ink_abi = "all")))]
50+
let sol_event_metadata = self.solidity_event_metadata();
51+
52+
#[cfg(not(all(feature = "std", any(ink_abi = "sol", ink_abi = "all"))))]
53+
let sol_event_metadata = quote! {};
54+
4155
quote::quote! (
4256
#( #cfg_attrs )*
4357
#[cfg_attr(feature = "std", derive(::ink::EventMetadata))]
@@ -46,6 +60,82 @@ impl GenerateCode for Event<'_> {
4660
#anonymous
4761
#signature_topic
4862
#item
63+
64+
#sol_event_metadata
4965
)
5066
}
5167
}
68+
69+
impl Event<'_> {
70+
/// Generates Solidity ABI compatible metadata for ink! event.
71+
#[cfg(all(feature = "std", any(ink_abi = "sol", ink_abi = "all")))]
72+
fn solidity_event_metadata(&self) -> TokenStream2 {
73+
let item = self.item.item();
74+
let ident = &item.ident;
75+
let name = ident.to_string();
76+
let is_anonymous = self.item.anonymous();
77+
78+
let fields = match &item.fields {
79+
Fields::Named(fields) => fields,
80+
Fields::Unnamed(_) | Fields::Unit => unreachable!("Expected named fields"),
81+
};
82+
let params = fields.named.iter().map(|field| {
83+
let ty = &field.ty;
84+
let sol_ty = sol::utils::sol_type(ty);
85+
let ident = field.ident.as_ref().expect("Expected a named field");
86+
let name = ident.to_string();
87+
let is_topic = field.attrs.iter().any(|attr| {
88+
let is_topic_arg = || {
89+
attr.parse_nested_meta(|meta| {
90+
if meta.path.is_ident("topic") {
91+
Ok(())
92+
} else {
93+
Err(meta.error("Not a topic arg"))
94+
}
95+
})
96+
.is_ok()
97+
};
98+
attr.path().is_ident("ink") && is_topic_arg()
99+
});
100+
let docs = field
101+
.attrs
102+
.iter()
103+
.filter_map(|attr| attr.extract_docs())
104+
.collect::<Vec<_>>()
105+
.join("\n");
106+
107+
quote! {
108+
::ink::metadata::sol::EventParamMetadata {
109+
name: #name,
110+
ty: #sol_ty,
111+
is_topic: #is_topic,
112+
docs: #docs,
113+
}
114+
}
115+
});
116+
117+
let docs = item
118+
.attrs
119+
.iter()
120+
.filter_map(|attr| attr.extract_docs())
121+
.collect::<Vec<_>>()
122+
.join("\n");
123+
124+
quote! {
125+
const _: () = {
126+
// Register Solidity ABI compatible metadata function for event in distributed slice
127+
// for collecting all events referenced in the contract binary.
128+
#[::ink::linkme::distributed_slice(::ink::CONTRACT_EVENTS_SOL)]
129+
#[linkme(crate = ::ink::linkme)]
130+
static EVENT_METADATA_SOL: fn() -> ::ink::metadata::sol::EventMetadata = || {
131+
::ink::metadata::sol::EventMetadata {
132+
name: #name,
133+
is_anonymous: #is_anonymous,
134+
params: vec![ #( #params ),* ],
135+
docs: #docs,
136+
}
137+
};
138+
};
139+
}
140+
}
141+
}

0 commit comments

Comments
 (0)