Skip to content

Implement JSON ABI generation for contracts#1346

Merged
sbillig merged 1 commit intoargotorg:masterfrom
cburgdorf:json_abi
Mar 23, 2026
Merged

Implement JSON ABI generation for contracts#1346
sbillig merged 1 commit intoargotorg:masterfrom
cburgdorf:json_abi

Conversation

@cburgdorf
Copy link
Collaborator

@cburgdorf cburgdorf commented Mar 21, 2026

Summary

Adds Ethereum-compatible JSON ABI generation to the Fe compiler. ABI files (<contract>.abi.json) are now emitted by default alongside bytecode artifacts. The ABI is derived from the contract's semantic types,
ensuring correctness even for generic msg variants.

What it does

ABI entries are generated from:

  • recv arms → "function" entries (name, inputs, outputs, stateMutability)
  • init blocks → "constructor" entries (inputs, stateMutability)
  • #[event] structs reachable from the contract → "event" entries (inputs with indexed flags)

Type mapping uses the semantic type system (not HIR), so generic msg variants like GenericMsg<u8> correctly emit uint8 rather than an unresolved type parameter.

Selector validation ensures the ABI is consistent with on-chain behavior:

  • The function name and argument types are extracted from the sol("name(types)") selector signature
  • The canonical Keccak-256 selector is recomputed and verified against the declared selector value
  • Arity and type mismatches between the selector signature and semantic types are hard errors

Graceful handling of hex selectors: Recv arms with raw hex selectors (#[selector = 0x...]) are skipped with a warning rather than failing the build, so the rest of the ABI can still be generated.

Event collection is scope-aware: only event structs actually reachable from the contract's init/recv bodies (including transitively called functions) are included — unused events defined elsewhere in the
ingot are excluded.

State mutability is derived from effects: #[payable]"payable", no effects → "pure", read-only → "view", any mutation → "nonpayable".

Default emit: ABI is included in the default --emit set (bytecode,runtime-bytecode,abi), so fe build produces ABI files without extra flags.

Test plan

  • Unit tests: hex selector skipping with warning, sol() alias naming, const alias resolution, generic variant types, event/function name collisions, tuple/array type encoding
  • CLI integration tests: artifact written to output + report dir, imported events included, unused events excluded, hex selector produces warning + partial ABI
  • cargo test -p fe — all 57 tests pass
@cburgdorf cburgdorf force-pushed the json_abi branch 2 times, most recently from c2c98cc to d5797c1 Compare March 21, 2026 19:42
@cburgdorf
Copy link
Collaborator Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: eed3c8889d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@cburgdorf cburgdorf force-pushed the json_abi branch 2 times, most recently from f2a0e17 to 7cadbab Compare March 21, 2026 20:10
@cburgdorf
Copy link
Collaborator Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

fe/crates/fe/src/build.rs

Lines 622 to 624 in 7cadbab

if emit.writes_any_bytecode()
&& let Err(()) = check_workspace_artifact_name_collisions(&contract_names_by_member)
{

P2 Badge Guard ABI workspace builds against duplicate contract names

build_workspace only calls check_workspace_artifact_name_collisions when emit.writes_any_bytecode() is true. If a workspace build uses --emit abi (or --emit ir,abi) and two selected members define the same contract name, write_abi_artifacts still writes both outputs into the shared flat out_dir as <contract>.abi.json, so the later member silently overwrites the earlier ABI. The same collision guard needs to run whenever ABI artifacts are requested.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@cburgdorf
Copy link
Collaborator Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ce0a4cc535

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@cburgdorf
Copy link
Collaborator Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e0e6b81e53

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@cburgdorf cburgdorf force-pushed the json_abi branch 2 times, most recently from ea5ce0d to 64b5322 Compare March 21, 2026 22:17
@cburgdorf
Copy link
Collaborator Author

@codex review

1 similar comment
@cburgdorf
Copy link
Collaborator Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 64b5322e27

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@cburgdorf cburgdorf force-pushed the json_abi branch 3 times, most recently from ae86237 to dd74cfc Compare March 21, 2026 23:14
@cburgdorf
Copy link
Collaborator Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: dd74cfc763

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +681 to +685
if is_std_address_ty(db, ty, adt_ref) {
return Ok(AbiTypeDesc::simple("address"));
}
if let Some(sol_type) = std_sol_compat_abi_type(db, ty, adt_ref) {
return Ok(AbiTypeDesc::simple(&sol_type));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Honor SolCompat::SOL_TYPE before flattening ADTs

semantic_ty_to_abi_desc only recognizes Address and the built-in Uint*/Int* wrappers, then treats every other ADT as a tuple. That breaks user-defined types implementing std::abi::sol::SolCompat: ingots/std/src/abi/sol.fe:188-200 explicitly documents those as valid event-field types, and recv selectors can also be authored against their Solidity type names. For those contracts the emitted JSON ABI no longer matches the runtime topic/selector shape, and ensure_selector_matches_signature will reject otherwise valid sol("...") selectors during the now-default ABI build.

Useful? React with 👍 / 👎.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Acknowledged. There doesn't seem to be an easy fix for this but it's also less big of an issue than the P1 makes it sound.

@cburgdorf
Copy link
Collaborator Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1b21e109fd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@cburgdorf cburgdorf force-pushed the json_abi branch 2 times, most recently from e1d16df to cf47108 Compare March 22, 2026 11:17
@cburgdorf
Copy link
Collaborator Author

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cf47108ecd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Add `--emit abi` support to the Fe compiler, emitting Ethereum-compatible JSON ABI files (<contract>.abi.json) alongside bytecode artifacts. The ABI is derived from: - msg variant recv arms → function entries (name, inputs, outputs, stateMutability) - init blocks → constructor entries (inputs, stateMutability) - #[event] structs → event entries (inputs with indexed flags) State mutability derivation: - #[payable] → "payable" - no effects → "pure" - read-only effects → "view" - any mut effects → "nonpayable" ABI is emitted by default alongside bytecode and runtime-bytecode.
@cburgdorf cburgdorf requested a review from sbillig March 22, 2026 19:04
@cburgdorf cburgdorf marked this pull request as ready for review March 22, 2026 19:04
@cburgdorf
Copy link
Collaborator Author

@sbillig I think this one is good to go

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: cf60b4d256

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +2024 to +2028
if args.len() == 1
&& args[0].label.is_none()
&& let Partial::Present(Expr::Lit(LitKind::String(signature))) =
args[0].expr.data(db, body)
{

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Evaluate non-literal sol(...) args before omitting ABI entries

This branch only recovers a selector signature when std::abi::sol is called with a direct string literal. sol itself accepts any AsBytes constant (ingots/core/src/bytes.fe implements that for String<N>, tuples, etc.), so selectors like #[selector = sol(SIG)] or sol(("ping", "()")) still CTFE correctly. Here they fall through to None, and recv_arm_to_abi_entry later drops the function from *.abi.json, so a harmless refactor from a literal to another constant AsBytes expression silently removes public methods from the generated ABI.

Useful? React with 👍 / 👎.

Comment on lines +1176 to +1177
if emit.abi {
had_errors |= write_abi_artifacts(db, top_mod, &names_to_build, out_dir, report_dir);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid MIR-lowering the whole module for ABI-only builds

The new ABI path here still depends on build_top_mod having called collect_contract_names() first, and that helper enumerates contracts by running lower_module() over the entire file. In practice, fe build --emit abi --contract Foo will now fail if some other contract in the same file/ingot hits a MIR-lowering limitation, even though generate_contract_abi() only reads HIR for the selected contract. That makes ABI-only builds regress on unrelated lowering errors instead of remaining a frontend-only operation.

Useful? React with 👍 / 👎.

@sbillig sbillig merged commit 84fbbd7 into argotorg:master Mar 23, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants