Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,26 @@ jobs:
echo "No YAML files to lint"
fi

- name: Lint Forge files
id: lint_forge
continue-on-error: true
run: |
if [ "${{ steps.lint_mode.outputs.mode }}" = "all" ]; then
echo "Linting all Forge files..."
pnpm lint:forge
elif [ "${{ steps.changed_files.outputs.sol_count }}" -gt "0" ]; then
# Check if any changed .sol files are in Forge packages
FORGE_FILES=$(cat changed_sol.txt | grep -E '^packages/(horizon|subgraph-service)/' || true)
if [ -n "$FORGE_FILES" ]; then
echo "Found Forge-related changes, running forge lint..."
pnpm lint:forge
else
echo "No Forge-related Solidity files changed"
fi
else
echo "No Solidity files to lint with Forge"
fi

- name: Check lint results
if: always()
run: |
Expand All @@ -238,7 +258,8 @@ jobs:
[ "${{ steps.lint_ts.outcome }}" = "failure" ] || \
[ "${{ steps.lint_md.outcome }}" = "failure" ] || \
[ "${{ steps.lint_json.outcome }}" = "failure" ] || \
[ "${{ steps.lint_yaml.outcome }}" = "failure" ]; then
[ "${{ steps.lint_yaml.outcome }}" = "failure" ] || \
[ "${{ steps.lint_forge.outcome }}" = "failure" ]; then
echo "❌ One or more linters failed"
exit 1
else
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ bin/
.env
.DS_Store
.vscode
core

# Coverage and other reports
coverage/
Expand Down
3 changes: 2 additions & 1 deletion .markdownlint.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
"MD013": false,
"MD024": { "siblings_only": true },
"MD029": { "style": "ordered" },
"MD033": false
"MD033": false,
"MD040": false
}
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,14 @@ The linting configuration follows a hierarchical structure where packages inheri
- **Root Configuration**: `.markdownlint.json` - Markdown formatting and style rules
- **Direct Command**: `npx markdownlint '**/*.md' --fix`
- **Ignore Files**: `.markdownlintignore` automatically picked up by markdownlint CLI
- **Global Application**: Applied to all markdown files across the monorepo
- **Package Inheritance**: Packages that need Markdownlint must have a `.markdownlint.json` file that extends the root config
- **Example Package Config**:

```json
{
"extends": "../../.markdownlint.json"
}
```

### Linting Scripts

Expand Down Expand Up @@ -303,13 +310,14 @@ The repository enforces TODO comment resolution to maintain code quality:
| ESLint | `eslint.config.mjs` | Auto-inherited | Built into config |
| Prettier | `prettier.config.cjs` | `prettier.config.cjs` (inherits) | `.prettierignore` |
| Solhint | `.solhint.json` | `.solhint.json` (array extends) | N/A |
| Markdownlint | `.markdownlint.json` | Auto-inherited | `.markdownlintignore` |
| Markdownlint | `.markdownlint.json` | `.markdownlint.json` (extends) | `.markdownlintignore` |
| Lint-staged | `package.json` | N/A | `scripts/lint-staged-run.sh` |

### Troubleshooting

- **ESLint not finding config**: ESLint searches up parent directories automatically - no local config needed
- **Prettier not working**: Packages need a `prettier.config.cjs` that inherits from root config
- **Markdownlint not working**: Packages need a `.markdownlint.json` that extends root config
- **Solhint missing rules**: If extending a parent config, use array format: `["solhint:recommended", "./../../.solhint.json"]` to ensure all rules are loaded
- **Solhint inheritance not working**: Nested extends don't work - parent config's `solhint:recommended` won't be inherited with simple string extends
- **Solhint rule reference**: Use `npx solhint list-rules` to see all available rules and their descriptions
Expand Down
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,21 @@
"license": "GPL-2.0-or-later",
"repository": "git@github.com:graphprotocol/contracts.git",
"author": "Edge & Node",
"packageManager": "pnpm@10.17.0",
"packageManager": "pnpm@10.28.0+sha512.05df71d1421f21399e053fde567cea34d446fa02c76571441bfc1c7956e98e363088982d940465fd34480d4d90a0668bc12362f8aa88000a64e83d0b0e47be48",
"scripts": {
"postinstall": "husky",
"clean": "pnpm -r run clean",
"clean:all": "pnpm clean && rm -rf node_modules packages/*/node_modules packages/*/*/node_modules",
"build": "pnpm -r run build:self",
"todo": "node scripts/check-todos.mjs",
"lint": "pnpm lint:ts; pnpm lint:sol; pnpm lint:md; pnpm lint:json; pnpm lint:yaml",
"lint": "pnpm lint:ts; pnpm lint:sol; pnpm lint:forge; pnpm lint:md; pnpm lint:json; pnpm lint:yaml",
"lint:staged": "lint-staged; pnpm todo",
"lint:ts": "eslint --fix --cache '**/*.{js,ts,cjs,mjs,jsx,tsx}'; prettier -w --cache --log-level warn '**/*.{js,ts,cjs,mjs,jsx,tsx}'",
"lint:sol": "pnpm -r run lint:sol; prettier -w --cache --log-level warn '**/*.sol'; pnpm todo",
"lint:md": "markdownlint --fix --ignore-path .gitignore --ignore-path .markdownlintignore '**/*.md'; prettier -w --cache --log-level warn '**/*.md'",
"lint:json": "prettier -w --cache --log-level warn '**/*.json'",
"lint:yaml": "npx yaml-lint .github/**/*.{yml,yaml} packages/contracts/task/config/*.yml; prettier -w --cache --log-level warn '**/*.{yml,yaml}'",
"format": "prettier -w --cache --log-level warn '**/*.{js,ts,cjs,mjs,jsx,tsx,json,md,yaml,yml}'",
"lint:ts": "eslint --fix --cache 'packages/**/*.{js,ts,cjs,mjs,jsx,tsx}' 'scripts/**/*.{js,ts,cjs,mjs}' '*.{js,ts,cjs,mjs}'; prettier -w --cache --log-level warn 'packages/**/*.{js,ts,cjs,mjs,jsx,tsx}' 'scripts/**/*.{js,ts,cjs,mjs}' '*.{js,ts,cjs,mjs}'",
"lint:sol": "pnpm -r run lint:sol; prettier -w --cache --log-level warn 'packages/**/*.sol'; pnpm todo",
"lint:forge": "pnpm -r run lint:forge",
"lint:md": "markdownlint --fix --ignore-path .gitignore 'packages/**/*.md' '*.md'; prettier -w --cache --log-level warn 'packages/**/*.md' '*.md'",
"lint:json": "prettier -w --cache --log-level warn 'packages/**/*.json' '.changeset/**/*.json' '*.json'",
"lint:yaml": "npx yaml-lint .github/**/*.{yml,yaml} packages/contracts/task/config/*.yml; prettier -w --cache --log-level warn 'packages/**/*.{yml,yaml}' '.github/**/*.{yml,yaml}'",
"test": "pnpm build && pnpm -r run test:self",
"test:coverage": "pnpm build && pnpm -r run build:self:coverage && pnpm -r run test:coverage:self"
},
Expand Down
2 changes: 2 additions & 0 deletions packages/horizon/contracts/data-service/DataService.sol
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ abstract contract DataService is GraphDirectory, ProvisionManager, DataServiceV1
return _getDelegationRatio();
}

// forge-lint: disable-next-item(mixed-case-function)
/**
* @notice Initializes the contract and any parent contracts.
*/
Expand All @@ -67,6 +68,7 @@ abstract contract DataService is GraphDirectory, ProvisionManager, DataServiceV1
__DataService_init_unchained();
}

// forge-lint: disable-next-item(mixed-case-function)
/**
* @notice Initializes the contract.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pragma solidity 0.8.27;
* bugs. We may have an active bug bounty program.
*/
abstract contract DataServiceV1Storage {
// forge-lint: disable-next-item(mixed-case-variable)
/// @dev Gap to allow adding variables in future upgrades
/// Note that this contract is not upgradeable but might be inherited by an upgradeable contract
uint256[50] private __gap;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ abstract contract DataServiceFees is DataService, DataServiceFeesV1Storage, IDat
return claims[_claimId].nextClaim;
}

// forge-lint: disable-next-item(asm-keccak256)
/**
* @notice Builds a stake claim ID
* @param _serviceProvider The address of the service provider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ abstract contract DataServiceFeesV1Storage {
/// @notice Service providers registered in the data service
mapping(address serviceProvider => ILinkedList.List list) public claimsLists;

// forge-lint: disable-next-item(mixed-case-variable)
/// @dev Gap to allow adding variables in future upgrades
/// Note that this contract is not upgradeable but might be inherited by an upgradeable contract
uint256[50] private __gap;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ abstract contract DataServicePausable is Pausable, DataService, IDataServicePaus
/// @notice List of pause guardians and their allowed status
mapping(address pauseGuardian => bool allowed) public pauseGuardians;

// forge-lint: disable-next-item(unwrapped-modifier-logic)
/**
* @notice Checks if the caller is a pause guardian.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@ abstract contract DataServicePausableUpgradeable is PausableUpgradeable, DataSer
/// @notice List of pause guardians and their allowed status
mapping(address pauseGuardian => bool allowed) public pauseGuardians;

// forge-lint: disable-next-item(mixed-case-variable)
/// @dev Gap to allow adding variables in future upgrades
uint256[50] private __gap;

// forge-lint: disable-next-item(unwrapped-modifier-logic)
/**
* @notice Checks if the caller is a pause guardian.
*/
Expand All @@ -41,6 +43,7 @@ abstract contract DataServicePausableUpgradeable is PausableUpgradeable, DataSer
_unpause();
}

// forge-lint: disable-next-item(mixed-case-function)
/**
* @notice Initializes the contract and parent contracts
*/
Expand All @@ -49,6 +52,7 @@ abstract contract DataServicePausableUpgradeable is PausableUpgradeable, DataSer
__DataServicePausable_init_unchained();
}

// forge-lint: disable-next-item(mixed-case-function)
/**
* @notice Initializes the contract
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@ abstract contract DataServiceRescuable is DataService, IDataServiceRescuable {
/// @notice List of rescuers and their allowed status
mapping(address rescuer => bool allowed) public rescuers;

// forge-lint: disable-next-item(mixed-case-variable)
/// @dev Gap to allow adding variables in future upgrades
/// Note that this contract is not upgradeable but might be inherited by an upgradeable contract
uint256[50] private __gap;

// forge-lint: disable-next-item(unwrapped-modifier-logic)
/**
* @notice Checks if the caller is a rescuer.
*/
Expand All @@ -39,11 +41,13 @@ abstract contract DataServiceRescuable is DataService, IDataServiceRescuable {
_;
}

// forge-lint: disable-next-item(mixed-case-function)
/// @inheritdoc IDataServiceRescuable
function rescueGRT(address to, uint256 tokens) external virtual onlyRescuer {
_rescueTokens(to, address(_graphToken()), tokens);
}

// forge-lint: disable-next-item(mixed-case-function)
/// @inheritdoc IDataServiceRescuable
function rescueETH(address payable to, uint256 tokens) external virtual onlyRescuer {
_rescueTokens(to, Denominations.NATIVE_TOKEN, tokens);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ abstract contract ProvisionManager is Initializable, GraphDirectory, ProvisionMa
*/
error ProvisionManagerProvisionNotFound(address serviceProvider);

// forge-lint: disable-next-item(unwrapped-modifier-logic)
/**
* @notice Checks if the caller is authorized to manage the provision of a service provider.
* @param serviceProvider The address of the service provider.
Expand All @@ -123,6 +124,7 @@ abstract contract ProvisionManager is Initializable, GraphDirectory, ProvisionMa
_;
}

// forge-lint: disable-next-item(unwrapped-modifier-logic)
/**
* @notice Checks if a provision of a service provider is valid according
* to the parameter ranges established.
Expand All @@ -135,13 +137,15 @@ abstract contract ProvisionManager is Initializable, GraphDirectory, ProvisionMa
_;
}

// forge-lint: disable-next-item(mixed-case-function)
/**
* @notice Initializes the contract and any parent contracts.
*/
function __ProvisionManager_init() internal onlyInitializing {
__ProvisionManager_init_unchained();
}

// forge-lint: disable-next-item(mixed-case-function)
/**
* @notice Initializes the contract.
* @dev All parameters set to their entire range as valid.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ abstract contract ProvisionManagerV1Storage {
/// @dev Max calculated as service provider's stake * delegationRatio
uint32 internal _delegationRatio;

// forge-lint: disable-next-item(mixed-case-variable)
/// @dev Gap to allow adding variables in future upgrades
/// Note that this contract is not upgradeable but might be inherited by an upgradeable contract
uint256[50] private __gap;
Expand Down
1 change: 1 addition & 0 deletions packages/horizon/contracts/libraries/LibFixedMath.sol
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pragma solidity 0.8.27;

// TODO: Re-enable and fix issues when publishing a new version
// solhint-disable function-max-lines, gas-strict-inequalities
// forge-lint: disable-start(unsafe-typecast)

/**
* @title LibFixedMath
Expand Down
1 change: 1 addition & 0 deletions packages/horizon/contracts/libraries/PPMMath.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ pragma solidity 0.8.27;

// TODO: Re-enable and fix issues when publishing a new version
// solhint-disable gas-strict-inequalities
// forge-lint: disable-start(mixed-case-function)

/**
* @title PPMMath library
Expand Down
3 changes: 3 additions & 0 deletions packages/horizon/contracts/mocks/CurationMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

pragma solidity 0.8.27;

// TODO: Re-enable and fix issues when publishing a new version
// forge-lint: disable-start(mixed-case-variable)

/**
* @title CurationMock
* @author Edge & Node
Expand Down
3 changes: 3 additions & 0 deletions packages/horizon/contracts/mocks/RewardsManagerMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

pragma solidity 0.8.27;

// TODO: Re-enable and fix issues when publishing a new version
// forge-lint: disable-start(mixed-case-variable)

import { MockGRTToken } from "./MockGRTToken.sol";

/**
Expand Down
1 change: 1 addition & 0 deletions packages/horizon/contracts/payments/PaymentsEscrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ contract PaymentsEscrow is Initializable, MulticallUpgradeable, GraphDirectory,
mapping(address payer => mapping(address collector => mapping(address receiver => IPaymentsEscrow.EscrowAccount escrowAccount)))
public escrowAccounts;

// forge-lint: disable-next-item(unwrapped-modifier-logic)
/**
* @notice Modifier to prevent function execution when contract is paused
* @dev Reverts if the controller indicates the contract is paused
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pragma solidity 0.8.27;
// solhint-disable gas-small-strings
// solhint-disable gas-strict-inequalities
// solhint-disable function-max-lines
// forge-lint: disable-start(mixed-case-function, mixed-case-variable)

import { IGraphPayments } from "@graphprotocol/interfaces/contracts/horizon/IGraphPayments.sol";
import { IGraphTallyCollector } from "@graphprotocol/interfaces/contracts/horizon/IGraphTallyCollector.sol";
Expand Down
3 changes: 3 additions & 0 deletions packages/horizon/contracts/staking/HorizonStaking.sol
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ contract HorizonStaking is HorizonStakingBase, IHorizonStakingMain {
/// @dev Minimum amount of delegation.
uint256 private constant MIN_DELEGATION = 1e18;

// forge-lint: disable-next-item(unwrapped-modifier-logic)
/**
* @notice Checks that the caller is authorized to operate over a provision.
* @param serviceProvider The address of the service provider.
Expand All @@ -61,6 +62,7 @@ contract HorizonStaking is HorizonStakingBase, IHorizonStakingMain {
_;
}

// forge-lint: disable-next-item(unwrapped-modifier-logic)
/**
* @notice Checks that the caller is authorized to operate over a provision or it is the verifier.
* @param serviceProvider The address of the service provider.
Expand Down Expand Up @@ -1045,6 +1047,7 @@ contract HorizonStaking is HorizonStakingBase, IHorizonStakingMain {
);
require(thawRequestList.count < MAX_THAW_REQUESTS, HorizonStakingTooManyThawRequests());

// forge-lint: disable-next-item(asm-keccak256)
bytes32 thawRequestId = keccak256(abi.encodePacked(_serviceProvider, _verifier, _owner, thawRequestList.nonce));
ThawRequest storage thawRequest = _getThawRequest(_requestType, thawRequestId);
thawRequest.shares = _shares;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ pragma solidity 0.8.27;

// TODO: Re-enable and fix issues when publishing a new version
// solhint-disable function-max-lines, gas-strict-inequalities
// forge-lint: disable-start(mixed-case-variable, mixed-case-function, unwrapped-modifier-logic)

import { ICuration } from "@graphprotocol/interfaces/contracts/contracts/curation/ICuration.sol";
import { IGraphToken } from "@graphprotocol/interfaces/contracts/contracts/token/IGraphToken.sol";
Expand Down
3 changes: 3 additions & 0 deletions packages/horizon/contracts/staking/HorizonStakingStorage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

pragma solidity 0.8.27;

// TODO: Re-enable and fix issues when publishing a new version
// forge-lint: disable-start(mixed-case-variable)

import { IHorizonStakingExtension } from "@graphprotocol/interfaces/contracts/horizon/internal/IHorizonStakingExtension.sol";
import { IHorizonStakingTypes } from "@graphprotocol/interfaces/contracts/horizon/internal/IHorizonStakingTypes.sol";
import { IGraphPayments } from "@graphprotocol/interfaces/contracts/horizon/IGraphPayments.sol";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

pragma solidity 0.8.27;

// TODO: Re-enable and fix issues when publishing a new version
// forge-lint: disable-start(unsafe-typecast)

import { LibFixedMath } from "../../libraries/LibFixedMath.sol";

/**
Expand Down
5 changes: 5 additions & 0 deletions packages/horizon/contracts/staking/utilities/Managed.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ import { GraphDirectory } from "../../utilities/GraphDirectory.sol";
abstract contract Managed is GraphDirectory {
// -- State --

// forge-lint: disable-next-item(mixed-case-variable)
/// @notice Controller that manages this contract
address private __DEPRECATED_controller;

// forge-lint: disable-next-item(mixed-case-variable)
/// @dev Cache for the addresses of the contracts retrieved from the controller
mapping(bytes32 contractName => address contractAddress) private __DEPRECATED_addressCache;

// forge-lint: disable-next-item(mixed-case-variable)
/// @dev Gap for future storage variables
uint256[10] private __gap;

Expand All @@ -43,6 +46,7 @@ abstract contract Managed is GraphDirectory {
*/
error ManagedOnlyGovernor();

// forge-lint: disable-next-item(unwrapped-modifier-logic)
/**
* @dev Revert if the controller is paused
*/
Expand All @@ -51,6 +55,7 @@ abstract contract Managed is GraphDirectory {
_;
}

// forge-lint: disable-next-item(unwrapped-modifier-logic)
/**
* @dev Revert if the caller is not the governor
*/
Expand Down
Loading