Skip to content
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

Get MagicSpend test coverage to 100% #14

Merged
merged 9 commits into from
Mar 21, 2024
Merged
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
56 changes: 50 additions & 6 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: test
name: Forge CI

on:
pull_request:
Expand All @@ -9,11 +9,8 @@ env:
FOUNDRY_PROFILE: ci

jobs:
check:
strategy:
fail-fast: true

name: Foundry project
forge-test:
name: Run Forge Tests and Checks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -40,3 +37,50 @@ jobs:
run: |
forge fmt --check
id: fmt

forge-coverage:
name: Run Coverage Reporting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive

- name: Install Foundry
uses: foundry-rs/foundry-toolchain@v1
with:
version: nightly

- name: Install forge dependencies
run: forge install

- name: Install lcov
run: |
sudo apt-get install lcov
id: lcov

- name: Run coverage
run: |
forge coverage --report summary --report lcov

- name: Prune coverage
run: |
lcov --remove ./lcov.info -o ./lcov-filtered.info 'test/*' 'script/*'

- name: Submit coverage to Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
path-to-lcov: ./lcov-filtered.info
flag-name: foundry
parallel: true

finish:
needs: forge-coverage
if: ${{ always() }}
runs-on: ubuntu-latest
steps:
- name: Coveralls Finished
uses: coverallsapp/github-action@v2
with:
parallel-finished: true
23 changes: 23 additions & 0 deletions test/GetHash.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.21;

import {MagicSpendTest} from "./MagicSpend.t.sol";
import {MagicSpend} from "../src/MagicSpend.sol";
import {MockERC20} from "solady/test/utils/mocks/MockERC20.sol";
import {SignatureCheckerLib} from "solady/src/utils/SignatureCheckerLib.sol";

contract GetHashTest is MagicSpendTest {
MockERC20 token = new MockERC20("test", "TEST", 18);

function test_returnsValidHash() public {
asset = address(token);
MagicSpend.WithdrawRequest memory request = _getRequest();
bytes32 expectedHash = SignatureCheckerLib.toEthSignedMessageHash(
abi.encode(
address(magic), withdrawer, block.chainid, address(token), request.amount, request.nonce, request.expiry
)
);
bytes32 testHash = magic.getHash(withdrawer, request);
assertEq(testHash, expectedHash);
}
}
24 changes: 24 additions & 0 deletions test/IsValidWithdrawSignature.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.21;

import "./MagicSpend.t.sol";
import {MockERC20} from "solady/test/utils/mocks/MockERC20.sol";

contract IsValidWithdrawalSignature is MagicSpendTest {
MockERC20 token = new MockERC20("test", "TEST", 18);

function test_returnsTrueWithValidSignature() public {
asset = address(token);
MagicSpend.WithdrawRequest memory request = _getRequest();
bool success = magic.isValidWithdrawSignature(withdrawer, request);
assert(success);
}

function test_returnsFalseWithInvalidSignature() public {
asset = address(token);
address invalidSender = address(0xdead);
MagicSpend.WithdrawRequest memory request = _getRequest();
bool success = magic.isValidWithdrawSignature(invalidSender, request);
assertFalse(success);
}
}
36 changes: 36 additions & 0 deletions test/OwnerWithdraw.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// SPDX-License-Identifier: MIT
pragma solidity >=0.8.21;

import {Ownable} from "./MagicSpend.t.sol";
import {MagicSpendTest} from "./Validate.t.sol";
import {MockERC20} from "solady/test/utils/mocks/MockERC20.sol";

contract OwnerWithdrawTest is MagicSpendTest {
MockERC20 token = new MockERC20("test", "TEST", 18);

function test_revertsIfNotOwner() public {
vm.startPrank(withdrawer);
vm.expectRevert(Ownable.Unauthorized.selector);
magic.ownerWithdraw(address(token), withdrawer, 1);
}

function test_transfersERC20Successfully(uint256 amount_) public {
vm.startPrank(owner);
amount = amount_;
token.mint(address(magic), amount);
asset = address(token);
assertEq(token.balanceOf(owner), 0);
magic.ownerWithdraw(asset, owner, amount);
assertEq(token.balanceOf(owner), amount);
}

function test_transfersETHSuccessfully(uint256 amount_) public {
vm.deal(address(magic), amount_);
vm.startPrank(owner);
amount = amount_;
asset = address(0);
assertEq(owner.balance, 0);
magic.ownerWithdraw(asset, owner, amount);
assertEq(owner.balance, amount);
}
}
6 changes: 6 additions & 0 deletions test/ValidatePaymasterUserOp.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@ contract ValidatePaymasterUserOpTest is PaymasterMagicSpendBaseTest, ValidateTes
magic.validatePaymasterUserOp(_getUserOp(), userOpHash, maxCost);
}

function test_revertsIfWithdrawalExceedsBalance() public {
vm.deal(address(magic), 0);
vm.expectRevert(abi.encodeWithSelector(MagicSpend.InsufficientBalance.selector, amount, 0));
magic.validatePaymasterUserOp(_getUserOp(), userOpHash, maxCost);
}

function test_returnsCorrectly() public {
(bytes memory context, uint256 validationData) =
magic.validatePaymasterUserOp(_getUserOp(), userOpHash, maxCost);
Expand Down
Loading