-
Notifications
You must be signed in to change notification settings - Fork 156
chore: move all interfaces to dedicated package #1187
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: horizon
Are you sure you want to change the base?
Conversation
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
chore: move all interfaces to dedicated package
🚨 Report Summary
For more details view the full report in OpenZeppelin Code Inspector |
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## horizon #1187 +/- ##
===========================================
- Coverage 92.56% 82.84% -9.72%
===========================================
Files 47 47
Lines 2435 2093 -342
Branches 440 620 +180
===========================================
- Hits 2254 1734 -520
- Misses 181 359 +178
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
@@ -10,7 +10,7 @@ | |||
"postinstall": "husky", | |||
"clean": "pnpm -r run clean", | |||
"clean:all": "pnpm clean && rm -rf node_modules packages/*/node_modules", | |||
"build": "chmod +x ./scripts/build && ./scripts/build", | |||
"build": "pnpm -r run build", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good for this PR, a discussion point though:
Locally I am trying splitting build
to build:dep
(build dependencies) and build:self
(only build package currently in). Then:
- In non-root packages
build
->pnpm build:dep && pnpm build:self
- In root package
build
->pnpm -r run build:self
, because this one should not be recursive, just do each in individually once in dependency order. - In other targets like
test
in (non-root) package atpnpm build &&
to existing. Bascially I don't want to have to worry about rebuilding, although might be worth making original targettest:no-build
or something so can do that. - Worth noting might be some tuning in places to make it more efficient where no rebuild in required.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you think we should keep child packages long term? I don't exactly remember at this point why we added those, I think to break the cyclic dependency? If so, perhaps with interfaces
package we can simplify it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need child packages, and/or siblings that combine dependencies across contract packages.
They are to break cyclic dependencies, I think interfaces does not by itself fully solve that. It might mean that contract packages no longer rely on toolshed? Or is that still via dynamic loading? However, deployment has cross package needs for compiled contracts. (I think there is an argument for having a single deploy sibling, that spans contract packages.)
The same scenario for tests, similar nuances to deploy, but I think not as strong a case for (just) a single test package spanning contract packages.
If we do not separate them, I think we can appear to get away with it by recompiling dependencies, which the hardhat-dependency-compiler can do, but then you end up with other issues due to that duplication and inconsistency.
I suspect contract compilation should be separate reusable step from what we do with the compilied artifacts (deployment, testing, etc). But I might be missing something; I am new to this package management system.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it. I'm not too sold on any alternative to be honest, there are things i dislike in both :p. But happy to keep iterating.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have not looked where used, however we would normally avoid creating something like this? Would an OpenZeppelin EnumerableSet or similar be an alternative?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry not sure I follow here. Avoid creating what?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A linked list implementation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah got it. So back then we looked at the available options and there was nothing that was exactly what we needed. I don't remember top of my head what exactly was missing from OZ's EnumerableSet implementation but it didn't quite fit the bill.
|
||
import { hardhatBaseConfig, isProjectBuilt, loadTasks } from '@graphprotocol/toolshed/hardhat' | ||
import type { HardhatUserConfig } from 'hardhat/types' | ||
|
||
// Skip importing hardhat-graph-protocol when building the project, it has circular dependency | ||
// Some tasks need compiled artifacts to run so we avoid loading them when building the project |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would try to change package structure to remove the dependency. I suspect runtime loading can be eliminated, and it is better to eliminate.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean with child packages?
@@ -2,4 +2,5 @@ | |||
@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/ | |||
@openzeppelin/foundry-upgrades/=node_modules/@openzeppelin/foundry-upgrades/src/ | |||
@graphprotocol/contracts/=node_modules/@graphprotocol/contracts/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI locally I have an updated natspect config that eliminates need for this file.
If you have it, remapping @graphprotocol/=node_modules/@graphprotocol/
also works and covers them all, unless you have references to the package it is in that form, which I think is generally not the case for self references. Likewise a shorter pattern for others.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it also work for forge
commands? Even if the natspec config doesnt need it forge probably does no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe, I will need to check. I think foundry.toml handles that better?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Both foundry.toml and remappings.txt should be the same, but we need to have the remappings somewhere because they are installed via node modules.
Let's revisit this when we merge with your natspec config, we can probably move any remapping definitions to foundry.toml and delete the remappings.txt file
Note that contracts in the `toolshed/` directory are not meant to be imported by Solidity code, they only exist to | ||
generate complete TypeScript types. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I noticed them. Not looked at why, I presume to resolve something it was hard to otherwise do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason is interfaces are not 1:1 with contract implementations. Storage variables, dependencies without interface files are some examples of things that add external functions to an implementation but are not usually in the interface files. The toolshed stuff (very bad name btw) is supposed to bridge that gap by adding back anything that's missing.
You should be able to include everything into the actual contract interface that gets imported and usually extended by the implementation, but I didn't want to mess with audited code at this point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
General observation, sorry if painful to implement. :) Would a suffix like Type
be better than Toolshed
? (Make it about the purpose rather than where introduced?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes to all. It would be better and slightly painful, but worth it I believe. I'll add it to my to-do list, but need to knock off some higher prio items first.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This might be a problem you inherited from the way I set things up initially, if you adopted some of my config: locally my common does not, although it did at one stage, compile locally. The local compilation causes knock-on issues. Does it also contribute to needing for Toolshed interfaces?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not following 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was at one point doing Hardhat compilation of common (equivalent to interfaces). Not 100% why anymore, many moving parts I was trying to get working, but I came full cycle and concluded it was a mistake. When elminating compilation here it appeared to help resolve subtle downstream issues and fragility. I was able to undo pushing dependencies into root package, remove remappings.txt, and get natspect working nicely. These were layering hacks on top of each other in a fragile way to work around inconsistencies caused by doing compilation in the package. I think, anyway. There were complex interdepencies I might still not have fully understood.
A key reason why it created problems is the conversation we had about the combination of Open Zeppelin contract version and compiler version. The interfaces need to be compiled with the compiler version of the consumer, at interface level there is unresolved (but necessary) ambiguity about which compiler version and which Open Zeppelin contract version is being used. Consuming packages need to resolve that ambiguity through their own settings, and compile correctly according to their own context.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will add I do not understand the implication of now creating types in interfaces, which I think you are? That might create a dependency on compilation?
If it does, I would check if actually this is the right level to create types at. If not, that in turn adds to the need to have separate child projects from the contracts. The types also might need to be specific to the context compiled in.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can consider types to be compiler agnostic. They only use the ABIs from the compiled artifacts, which shouldn't change much between different compiler versions. Even if a new compiler version added a new feature that would change the ABI significantly, the previous ABI would still be compatible and useful for typings. I think it's unlikely we hit any problems related to this so I wouldn't add extra complexity for now. Also I suspect always compiling with the latest possible compiler would produce ABIs that are universal.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds reasonable. We could generate ABIs without compilation?
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
Signed-off-by: Tomás Migone <[email protected]>
List of changes:
main
. These only surfaced with integration tests.common
tointerfaces
. I feel this represents more accurately what this package should be, but I'm happy to further discuss the name and/or use of it.horizon
,subgraph-service
,toolshed
andhardhat-graph-protocol
to useinterfaces
. Most notably this eliminates the circular dependency allowing for arbitrary building of the packages and static import ofhardhat-graph-protocol
.contracts
package.sdk
package to it's own repository at https://github.com/graphprotocol/sdk.contracts
package (actually child packages) remains the only place where it's used, it's now pinned to latest published version.hardhat-graph-protocol
now accepts a flag to specify if address book should be created or not if it doesn't exist.toolshed
toolshed
manages types and interface imports, its now much simpler.Pending:
horizon
andsubgraph-service
contracts it's worth checking with audit team wether or not they want to take a look at the changes.contracts
package still uses it's own interfaces (though they are duplicated ininterfaces
). This seemed like a big lift atm.IGraphToken
interface is widely used and for the most part being imported fromcontracts
and notinterfaces
. This is due to the usage ofTokenUtils.sol
which also imports the file. Importing it from two sources creates problems. Perhaps this warrants a common shared solidity package, not interfaces but implementations/libs?