diff --git a/.github/workflows/slither.yml b/.github/workflows/slither.yml new file mode 100644 index 00000000..6594c671 --- /dev/null +++ b/.github/workflows/slither.yml @@ -0,0 +1,56 @@ +name: Slither scanner + +on: pull_request + +jobs: + slither: + name: Slither check + runs-on: ubuntu-latest + + steps: + - name: Checkout the repository + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.11.0 + + - name: Use Node.js + uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4 + with: + node-version: lts/Iron + cache: 'pnpm' + + - name: Install dependencies + run: pnpm install -r --frozen-lockfile + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: 3.8 + + - name: Install foundry-zksync + run: | + mkdir ./foundry-zksync + curl -LO https://github.com/matter-labs/foundry-zksync/releases/download/nightly/foundry_nightly_linux_amd64.tar.gz + tar zxf foundry_nightly_linux_amd64.tar.gz -C ./foundry-zksync + chmod +x ./foundry-zksync/forge ./foundry-zksync/cast + echo "$PWD/foundry-zksync" >> $GITHUB_PATH + + - name: Foundry config file + run: | + echo "[profile.default]" > foundry.toml + echo "optimizer = true" >> foundry.toml + echo "optimizer_runs = 20_000" >> foundry.toml + echo "via_ir = true" >> foundry.toml + echo "" >> foundry.toml + + - name: Install Slither + run: | + pip install slither-analyzer + + - name: Run Slither + working-directory: ./ + run: | + slither --config ./slither.config.json . \ No newline at end of file diff --git a/slither.config.json b/slither.config.json new file mode 100644 index 00000000..a45924a5 --- /dev/null +++ b/slither.config.json @@ -0,0 +1,12 @@ +{ + "filter_paths": "(test|src/test|scripts|node_modules)", + "detectors_to_exclude": "uninitialized-local", + "exclude_dependencies": true, + "compile_force_framework": "foundry", + "foundry_ignore_compile": false, + "exclude_high": false, + "exclude_medium": false, + "exclude_low": true, + "exclude_informational": true, + "exclude_optimization": true +} diff --git a/src/AAFactory.sol b/src/AAFactory.sol index 0ea29df6..bf944e83 100644 --- a/src/AAFactory.sol +++ b/src/AAFactory.sol @@ -63,11 +63,11 @@ contract AAFactory { require(success, "Deployment failed"); (accountAddress) = abi.decode(returnData, (address)); + accountMappings[_uniqueAccountId] = accountAddress; + // Initialize the newly deployed account with validators, hooks and K1 owners. ISsoAccount(accountAddress).initialize(_initialValidators, _initialK1Owners); - accountMappings[_uniqueAccountId] = accountAddress; - emit AccountCreated(accountAddress, _uniqueAccountId); } } diff --git a/src/SsoAccount.sol b/src/SsoAccount.sol index 5102e88b..0c1b95dc 100644 --- a/src/SsoAccount.sol +++ b/src/SsoAccount.sol @@ -213,6 +213,8 @@ contract SsoAccount is Initializable, HookManager, ERC1271Handler, TokenCallback /// @dev Reverts if the Nonce Holder stores different `_nonce` value from the expected one. /// @param _expectedNonce The nonce value expected for the account to be stored in the Nonce Holder. function _incrementNonce(uint256 _expectedNonce) internal { + // Allow-listing slither finding as the call's success is checked+revert within the fn + // slither-disable-next-line unused-return SystemContractsCaller.systemCallWithPropagatedRevert( uint32(gasleft()), address(NONCE_HOLDER_SYSTEM_CONTRACT), diff --git a/src/managers/HookManager.sol b/src/managers/HookManager.sol index 1c0c8c3d..46206a87 100644 --- a/src/managers/HookManager.sol +++ b/src/managers/HookManager.sol @@ -40,6 +40,8 @@ abstract contract HookManager is IHookManager, Auth { /// @inheritdoc IHookManager function unlinkHook(address hook, bool isValidation, bytes calldata deinitData) external onlySelf { _removeHook(hook, isValidation); + // Allow-listing slither finding as we don´t want reverting calls to prevent unlinking + // slither-disable-next-line unused-return hook.excessivelySafeCall(gasleft(), 0, abi.encodeCall(IModule.onUninstall, (deinitData))); } diff --git a/src/managers/ValidatorManager.sol b/src/managers/ValidatorManager.sol index 0d6657ed..ff835ced 100644 --- a/src/managers/ValidatorManager.sol +++ b/src/managers/ValidatorManager.sol @@ -39,6 +39,8 @@ abstract contract ValidatorManager is IValidatorManager, Auth { ///@inheritdoc IValidatorManager function unlinkModuleValidator(address validator, bytes calldata deinitData) external onlySelf { _removeModuleValidator(validator); + // Allow-listing slither finding as we don´t want reverting calls to prevent unlinking + // slither-disable-next-line unused-return validator.excessivelySafeCall(gasleft(), 0, abi.encodeCall(IModule.onUninstall, (deinitData))); } diff --git a/src/validators/WebAuthValidator.sol b/src/validators/WebAuthValidator.sol index 3e4d0319..b4a51cfe 100644 --- a/src/validators/WebAuthValidator.sol +++ b/src/validators/WebAuthValidator.sol @@ -33,9 +33,6 @@ contract WebAuthValidator is VerifierCaller, IModuleValidator { mapping(string originDomain => mapping(bytes credentialId => mapping(address accountAddress => bytes32 publicKey))) public upperKeyHalf; - // allow tracking of passkey existence - mapping(string originDomain => mapping(bytes credentialId => bool keyExists)) public passkeyExists; - struct PasskeyId { string domain; bytes credentialId; @@ -70,7 +67,6 @@ contract WebAuthValidator is VerifierCaller, IModuleValidator { function _removeValidationKey(bytes memory credentialId, string memory domain) internal { lowerKeyHalf[domain][credentialId][msg.sender] = 0x0; upperKeyHalf[domain][credentialId][msg.sender] = 0x0; - passkeyExists[domain][credentialId] = false; emit PasskeyRemoved(msg.sender, domain, credentialId); } @@ -92,7 +88,6 @@ contract WebAuthValidator is VerifierCaller, IModuleValidator { lowerKeyHalf[originDomain][credentialId][msg.sender] = rawPublicKey[0]; upperKeyHalf[originDomain][credentialId][msg.sender] = rawPublicKey[1]; - passkeyExists[originDomain][credentialId] = true; emit PasskeyCreated(msg.sender, originDomain, credentialId); diff --git a/test/PasskeyModule.ts b/test/PasskeyModule.ts index febf219b..60c13e46 100644 --- a/test/PasskeyModule.ts +++ b/test/PasskeyModule.ts @@ -436,7 +436,7 @@ async function validateSignatureTest( return await passkeyValidator.validateSignature(transactionHash, fatSignature); } -describe.only("Passkey validation", function () { +describe("Passkey validation", function () { const wallet = getWallet(LOCAL_RICH_WALLETS[0].privateKey); const ethersResponse = new RecordedResponse("test/signed-challenge.json"); // this is a binary object formatted by @simplewebauthn that contains the alg type and public key