Skip to content

Conversation

@0xrusowsky
Copy link
Contributor

@0xrusowsky 0xrusowsky commented Apr 27, 2025

this PR aimed to showcase the impl of a slightly more advanced set of contracts like uniswap-v2 (both pair + factory).

however, it made me realize several limitations of the compilation pipeline, such as the fact that the initial impl was limited to 1 contract per crate. Despite this limitation still holds -we can only have 1 entry point per binary + their bytecode should be independent to reduce contract size and cyclical dependency loops-, i propose a PoC for a more versatile (and complex) compilation process.

r55-compile

  • revamped so that users can define several contracts (in separate mods) which share a common project. See uniswap-v2/pair.rs and uniswap-v2/factory.rs.

  • the pipeline identifies all the necessary dependencies, including common mods like uniswap-v2/math.rs (for the time being, any module imported on lib.rs which doesn't have a contract is considered common. If we like the PoC, we would enhance AST analysis to only inject the necessary non-contracts mods for each contract). Then it generates an isolates a flattened version of each crate under target/r55-generated/ --> note that right now i only keep them for debugging purposes, but once the output bytecode is generated, they could be auto-cleared by the script itself.

  • the pipeline still accounts for compilation order based on contract dependencies, and still generates the deployable impls. However, i added more fine-grained control over contract deps based their intended usecase:

    • interface-only: informed as a regular dep, with its feature flag --> imports the interface to interact with the contract
    • deployable: since deployable impl will be generated after the temp crate (with flattening) creation, users will have to add metadata to the Cargo.toml to inform the module/crate that should be deployable.

    for instance, this toml will crate target/r55-generated/uniswap-v2/factory/deployable.rs with the bytecode of target/r55-generated/uniswap-v2/pair/lib.rs. It will also make erc20::IERC20 available to both binaries.

# uniswap-v2/Cargo.toml

[package.metadata.deployable_deps]
pair = { path = "." }

[dependencies]
erc20 = { path = "../erc20", features = ["interface-only"] }

Built-in reentrancy guard

  • added a new storage type Lock which implements a built-in reentrancy guard, UX is quite cool imo, as users only ned to:
    1. initialize the lock in the constructor when deploying the contract.
    2. aquire the guard in the re-entrancy protected fn
  • Lock automatically writes back to storage when dropped, releasing the guard

Leverage rust docs for better dev-ex

  • auto-generated doc comments for interfaces, so that the LSP shows the available methods

enhanced contract macro to support private fns

  • edgecase we hadn't considered before

Address opcode

  • added fn address(&self) -> Address to contracts, so that they can know their own address (analogous to address(this) in solidity.

extend MappingGuard

  • implemented several core utils like AddAssign to have better mapping UX:
// before
let to_balance = self.balance_of[to].read();
self.balance_of[to].write(to_balance + amount);

// now
self.balance_of[to] += amount;

Pending TODOs:

to be tackled in other PRs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant