Flatten: Inherited contracts need to be defined before Derived contracts
Closed this issue · 5 comments
Using flatten on the Replica.sol contract of Nomad bridge.
sol2uml flatten 0xB92336759618F55bd0F8313bd843604592E27bd8
Attempted to compile with foundry suite:
forge build
Error:
error[2449]: src/Replica.sol:19:21: TypeError: Definition of base has to precede definition of derived contract
contract Replica is Version0, NomadBase {
^------^
contract Replica
declaration is L19
contract Version0
declaration is L341
Can there be logic inside sol2uml flatten
to rearrange contracts from {most inherited -> most derived} inside the flattened file?
you are right. I also dropped into Remix and got the same error.
In theory, it's possible. It'll be a lot more complicated than I intended. I might try simply merging the files in reverse order first.
simply reversing the order of the files as they are stored in Etherscan didn't fix the problem.
I'll need to parse thecSolidity files and come up with a way of merging the files in an order that will compile.
Yeah, there are a lot of edge cases that are hard to get right.
Especially considering that imports can also be extended to user-defined types, constants, libraries, etc, that make regex based parsers difficult to implement.
Found a good example in smart-contract-sanctuary that would be a good testing address for an implementation:
https://etherscan.io/address/0x0074F83a6a78555Cc784504358028fed2B145F4A#code
There are several top-level types and functions:
pragma solidity 0.8.13;
uint32 constant PPM_RESOLUTION = 1000000;
struct Fraction112 {
uint112 n;
uint112 d;
}
function zeroFraction() pure returns (Fraction memory) {
return Fraction({ n: 0, d: 1 });
}
function zeroFraction112() pure returns (Fraction112 memory) {
return Fraction112({ n: 0, d: 1 });
}
Constants, functions, types are later included in other contract files through import statements:
import { PPM_RESOLUTION } from "./Constants.sol";
import { Fraction, Fraction112 } from "./Fraction.sol";
After sleeping on it, I've come up with a solution.
sol2uml already parses and identifies dependencies for generating the class diagrams. I was able to reuse this and then load these dependencies into a directed acyclic graph and do a topological sort to identify the order to merge the source files.
This sounds complicated but was pretty easy as I was already using the js-graph-algorithms
package for limiting the depth of class diagrams.
I've tested for 0xB92336759618F55bd0F8313bd843604592E27bd8 and 0x0074F83a6a78555Cc784504358028fed2B145F4A.
The changes are in v2.1.2
Wow, this works incredibly well! I'll have to read up on those graph algorithms. Great job