Closed guidanoli closed 8 months ago
I prefer option 3.
offchain uses cargo.
onchain uses npm.
This requires some kind of cross-framework build tool.
Something smart enough so when you do a cargo build
in the offchain it knows there is a dependency to the onchain
and trigger the onchain build.
This is a classic problem of inter-package dependency of monorepos.
There is one framework that I'd like to understand more is https://nx.dev. It supposedly supports cross-framework builds, with the cargo plugin.
In addition to option 3, we can separate off-chain and on-chain in different repositories. The on-chain repo would contain:
And generate/export:
All of these artifacts would be published with the same version (since they all describe the same set of contracts). We may also publish alpha versions for other components to run integration tests. The off-chain code would then be able to use the bindings as a Rust crate, without having to worry about generating ABIs etc.
As for contract deployment, this could also live on a repository different from the on-chain repository. This repository would contain:
I'll propose a solution: Generate the ABIs from the bytecode when needed.
We want to preserve the message calls, events, and errors from Solidity. But these can actually be recovered from the bytecode directly using abi-to-sol.
In the current Ultrachess contracts, we depend on Curve, but Curve is compiled from Vyper so all we get is the bytecode. We address that here: https://github.com/Ultrachess/contracts/blob/main/tools/depends/curve/package.sh#L125
I'll propose a solution: Generate the ABIs from the bytecode when needed.
Hey, thanks for your contribution! Could you elaborate more on why is generating ABIs from the bytecode favorable to letting solc
generate it from the source code directly?
I guess it depends on access to the source. We only use abi-to-sol for Vyper code. If solc can generate interfaces without round-tripping into bytecode then that's probably a better solution.
If solc can generate interfaces without round-tripping into bytecode then that's probably a better solution
We use Hardhat and Foundry to build/test our smart contracts, and both frameworks allow us to generate ABIs from Solidity code.
📚 Context
Anyone can interact with Solidity contracts by means of message calls. These message calls have to be formatted in a such a way that the contract can understand and act upon. Solidity specifies the format of these message calls, as well as events, and errors. What usually happens, however, is that information gets lost when these abstractions get converted into low-level EVM instructions. That is why each Solidity contract is often accompanied by a JSON file which explains their interface in high-level Solidity terms. Libraries like
ethers-rs
use these files, called ABIs, to help developers interact with Solidity contracts, through language-specific bindings.The problem is that off-chain developers must have the ABIs in order to generate the Rust bindings, and so on-chain developers must keep the ABIs up-to-date with the contracts. Additionally, since these ABIs tend to be quite large, on-chain PRs often get polluted with unnecessarily large diffs. This impacts the productivity of on-chain developers and cleanliness of on-chain PRs.
✔️ Solutions
There are several possible solutions which have been raised. IMO, the third solution seems the most sustainable.
Create a workflow that automatically updates the ABIs when necessary.
Pros:
Cons:
Create a workflow that automatically creates/updates a PR that updates the ABIs.
Pros:
Cons:
Stop committing ABIs. Let off-chain developers generate them locally. [^1]
Pros:
Cons:
[^1]: This can be made seamless for off-chain developers by altering the
offchain/contracts/build.rs
file to runyarn
andyarn prepack
in theonchain/rollups
directory every time something in theonchain/rollups/contracts
directory changes.