Inspiration

The original inspiration for this project was the fact we were trying to write lots of inline Yul assembly within our Solidity code. None of the Yul code in an assembly block is reusable.

Hence, we recognized a need for macros in Solidity which can generate code with string arguments.

What it does

What you can do is define something like this in your .sol file:

UNISWAP_FACTORY_ADDRESS!(mainnet)

In you macro file you would have this:

macro_rules! UNISWAP_FACTORY_ADDRESS  {
    (mainnet)  => {0xc0a47dFe034B400B47bDaD5FecDa2621de6c4d95};
    (rinkeby)   => {0xf5D915570BC477f9B8D6C0E980aA81757A3AaC36}
    (kovan)     => {0xD3E51Ef092B2845f10401a0159B2B96e8B6c3D30}
    (görli)      => {0x6Ce570d02D73d4c384b46135E87f8C592A8c86dA}
}

You could also write code blocks which themselves contain macros:

macro_rules! getWalletInList {
    ($_wallet, $_codeEndList, $_codeBlock1, $_codeBlock2, $_codeBlock3, $_lenFlag) => {
        if (wallets[$_wallet].nextWallet == address(0)) {
            $_codeEndList
        }

        defineLen!($_lenFlag)

        address buffer = $_wallet;
        // get the len of the array
        for (setLen!($_lenFlag); wallets[buffer].nextWallet != $_wallet; incrementLen!($_lenFlag)) {
            $_codeBlock1
            buffer = wallets[buffer].nextWallet;
        }

        $_codeBlock2

        handleWalletBuffer!($_codeBlock3)
    }
}

.sol file:

    function listWallets(
        address wallet
    ) external view returns (address[] memory _wallets) {
        getWalletInList!(
            wallet,
            returnBalance!(single, wallet),
            ,
            _wallets = new address[](len),
            _wallets[i] = buffer;,
            true,
        );

        return _wallets;
    }

How we built it

We built it using Typescript.

First, you have to parse both the .sol file and the .rs files which contain the macros.

Then, you must replace the macro definitions in the .sol file with the generated code.

It can get quite complex when you have nested macros!

Challenges we ran into

One of the challenges we ran into was having nested macros and having to deal with multiple possible file formats.

For example, you could have a multi-line definition of a macro which you have to parse and get all the args of.

Ultimately having small helper functions which did one very specific task was the way to get around this.

Accomplishments that we're proud of

I think it's quite impressive how far this project got in just the 2 days during the hackathon.

I really feel this is something that will be useful for Solidity developers coming from a Rust-like background.

What we learned

We learned that ultimately this is a useful project because of the ability to write generative code.

If you're writing in Yul and Solidity, you could have one code block which is in Yul and one in Solidity.

In the future we hope to be able to test small pieces of generative code so that developers can be more confident that the macros they are writing produce secure and correct output.

What's next for Solmacs

We're really proud that we followed someone's recommendation to follow the Rust-style of doing metaprogramming.

This could ultimately "red pill" a lot of developers into Solidity and we see the potential for this to be used across multiple smart contract languages.

Everyone is currently using Solidity so this will be the starting point which we will focus on to help more developers have reusable and composable pieces of code.

Built With

Share this project:

Updates