diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9be84f9..b6ea9ff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,7 +14,7 @@ on: jobs: check: - uses: "sablier-labs/gha-utils/.github/workflows/full-check.yml@main" + uses: "sablier-labs/gha-utils/.github/workflows/evm-lint.yml@main" build: uses: "sablier-labs/gha-utils/.github/workflows/forge-build.yml@main" diff --git a/package.json b/package.json index 648619e..e70c5eb 100644 --- a/package.json +++ b/package.json @@ -43,8 +43,9 @@ "clean": "rm -rf broadcast cache out out-*", "forge:check": "forge fmt --check", "forge:write": "forge fmt", - "full-check": "bun run solhint:check && bun run forge:write && bun run prettier:check", - "full-write": "bun run solhint:write && bun run forge:write && bun run prettier:write", + "full:check": "bun run solhint:check && bun run forge:write && bun run prettier:check", + "full:write": "bun run solhint:write && bun run forge:write && bun run prettier:write", + "lint": "bun run full:check", "solhint:check": "solhint \"{precompiles,script,src,tests}/**/*.sol\"", "solhint:write": "solhint --fix --noPrompt \"{precompiles,script,src,tests}/**/*.sol\"", "prepack": "bun install", diff --git a/src/mocks/AdminableMock.sol b/src/mocks/AdminableMock.sol index 06179e5..d04dc5f 100644 --- a/src/mocks/AdminableMock.sol +++ b/src/mocks/AdminableMock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22; -import { Adminable } from "src/Adminable.sol"; +import { Adminable } from "../../src/Adminable.sol"; contract AdminableMock is Adminable { constructor(address initialAdmin) Adminable(initialAdmin) { } diff --git a/src/mocks/BatchMock.sol b/src/mocks/BatchMock.sol index a3e295f..81fae31 100644 --- a/src/mocks/BatchMock.sol +++ b/src/mocks/BatchMock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22; -import { Batch } from "src/Batch.sol"; +import { Batch } from "../../src/Batch.sol"; contract BatchMock is Batch { error InvalidNumber(uint256); diff --git a/src/mocks/ERC1271WalletMock.sol b/src/mocks/ERC1271WalletMock.sol new file mode 100644 index 0000000..fc556c6 --- /dev/null +++ b/src/mocks/ERC1271WalletMock.sol @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: UNLICENSED +pragma solidity >=0.8.22; + +import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +import { Adminable } from "../../src/Adminable.sol"; + +contract ERC1271WalletMock is Adminable { + constructor(address initialAdmin) Adminable(initialAdmin) { } + + function isValidSignature(bytes32 hash, bytes memory signature) public view returns (bytes4 magicValue) { + return + ECDSA.recover(hash, signature) == admin ? bytes4(keccak256("isValidSignature(bytes32,bytes)")) : bytes4(0); + } +} diff --git a/src/mocks/NoDelegateCallMock.sol b/src/mocks/NoDelegateCallMock.sol index 2cd54d6..396b0aa 100644 --- a/src/mocks/NoDelegateCallMock.sol +++ b/src/mocks/NoDelegateCallMock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22; -import { NoDelegateCall } from "src/NoDelegateCall.sol"; +import { NoDelegateCall } from "../../src/NoDelegateCall.sol"; contract NoDelegateCallMock is NoDelegateCall { /// @dev An empty function that uses the `noDelegateCall` modifier. diff --git a/src/mocks/RoleAdminableMock.sol b/src/mocks/RoleAdminableMock.sol index 8cb202e..ebce72f 100644 --- a/src/mocks/RoleAdminableMock.sol +++ b/src/mocks/RoleAdminableMock.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity >=0.8.22; -import { RoleAdminable } from "src/RoleAdminable.sol"; +import { RoleAdminable } from "../../src/RoleAdminable.sol"; contract RoleAdminableMock is RoleAdminable { constructor(address initialAdmin) RoleAdminable(initialAdmin) { } diff --git a/src/tests/BaseTest.sol b/src/tests/BaseTest.sol index 33990e1..f2a2817 100644 --- a/src/tests/BaseTest.sol +++ b/src/tests/BaseTest.sol @@ -8,8 +8,8 @@ import { console2 } from "forge-std/src/console2.sol"; import { StdCheats } from "forge-std/src/StdCheats.sol"; import { StdStyle } from "forge-std/src/StdStyle.sol"; import { StdUtils } from "forge-std/src/StdUtils.sol"; -import { IRoleAdminable } from "src/interfaces/IRoleAdminable.sol"; +import { IRoleAdminable } from "../interfaces/IRoleAdminable.sol"; import { ERC20MissingReturn } from "../mocks/erc20/ERC20MissingReturn.sol"; import { ERC20Mock } from "../mocks/erc20/ERC20Mock.sol"; import { ContractWithoutReceive, ContractWithReceive } from "../mocks/Receive.sol"; @@ -108,12 +108,37 @@ contract BaseTest is StdBase, StdCheats, StdUtils { return new ERC20Mock(name, symbol, decimals); } - /// @dev Generates a user, label its address, funds it with test tokens and approve `spenders` contracts. - function createUser(string memory name, address[] memory spenders) internal returns (address payable) { - address payable user = payable(makeAddr(name)); + /// @dev Generates a user, labels its address, funds it with test tokens, approves `spenders` contracts and returns + /// the user's address. + function createUser(string memory name, address[] memory spenders) internal returns (address payable user) { + user = payable(makeAddr(name)); vm.label(user, name); vm.deal({ account: user, newBalance: 100 ether }); + dealAndApproveSpenders(user, spenders); + } + + /// @dev Generates a user, labels its address, funds it with test tokens, approves `spenders` contracts and returns + /// the user's address and the private key. + function createUserAndKey( + string memory name, + address[] memory spenders + ) + internal + returns (address payable user, uint256 privateKey) + { + address addr; + (addr, privateKey) = makeAddrAndKey(name); + + user = payable(addr); + vm.label(user, name); + vm.deal({ account: user, newBalance: 100 ether }); + + dealAndApproveSpenders(user, spenders); + } + + /// @dev Deals tokens to user and approve contracts from spenders list. + function dealAndApproveSpenders(address user, address[] memory spenders) internal { for (uint256 i = 0; i < spenders.length; ++i) { for (uint256 j = 0; j < tokens.length; ++j) { deal({ @@ -124,8 +149,6 @@ contract BaseTest is StdBase, StdCheats, StdUtils { approveContract(address(tokens[j]), user, spenders[i]); } } - - return user; } /// @dev Retrieves the current block timestamp as an `uint40`.