Skip to content

Commit

Permalink
chore:foundry test for LineaWorldID
Browse files Browse the repository at this point in the history
  • Loading branch information
Jemiiah committed Aug 7, 2024
1 parent 4240a9d commit 6b41167
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 59 deletions.
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[submodule "lib/forge-std"]
path = lib/forge-std
url = https://github.com/foundry-rs/forge-std

2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"editor.defaultFormatter": "NomicFoundation.hardhat-solidity"
},
"[toml]": {
"editor.defaultFormatter": "tamasfe.even-better-toml"
"editor.defaultFormatter": "be5invis.toml"
},
"solidity.formatter": "forge",
"solidity.compileUsingRemoteVersion": "v0.8.15"
Expand Down
96 changes: 53 additions & 43 deletions foundry.toml
Original file line number Diff line number Diff line change
@@ -1,55 +1,65 @@
# Full reference https://github.com/foundry-rs/foundry/tree/master/crates/config

[profile.default]
auto_detect_solc = false
block_timestamp = 1_680_220_800 # March 31, 2023 at 00:00 GMT
bytecode_hash = "none"
evm_version = "shanghai"
fuzz = { runs = 1_000 }
gas_reports = ["*"]
optimizer = true
optimizer_runs = 10_000
out = "out"
script = "script"
solc = "0.8.19"
src = "src"
test = "test"
auto_detect_solc = false
block_timestamp = 1_680_220_800 # March 31, 2023 at 00:00 GMT
bytecode_hash = "none"
evm_version = "shanghai"
fuzz = {runs = 1_000}
gas_reports = ["*"]
optimizer = true
optimizer_runs = 10_000
out = "out"
script = "script"
solc = "0.8.19"
src = "src"
test = "test"

libs = ["node_modules", "lib"]
remappings = [
"forge-std/=lib/forge-std/src/",
"@openzeppelin/=node_modules/@openzeppelin/",
"@rari-capital/=node_modules/@rari-capital/",
"hardhat/=node_modules/hardhat/",
"linea-contracts/=node_modules/linea-contracts/contracts/",
"world-id-state-bridge/=node_modules/@worldcoin/world-id-state-bridge/src/",
]

[profile.ci]
fuzz = { runs = 10_000 }
fuzz = {runs = 10_000}
verbosity = 4

[etherscan]
arbitrum = { key = "${API_KEY_ARBISCAN}" }
avalanche = { key = "${API_KEY_SNOWTRACE}" }
base = { key = "${API_KEY_BASESCAN}" }
bnb_smart_chain = { key = "${API_KEY_BSCSCAN}" }
gnosis_chain = { key = "${API_KEY_GNOSISSCAN}" }
goerli = { key = "${API_KEY_ETHERSCAN}" }
mainnet = { key = "${API_KEY_ETHERSCAN}" }
optimism = { key = "${API_KEY_OPTIMISTIC_ETHERSCAN}" }
polygon = { key = "${API_KEY_POLYGONSCAN}" }
sepolia = { key = "${API_KEY_ETHERSCAN}" }
arbitrum = {key = "${API_KEY_ARBISCAN}"}
avalanche = {key = "${API_KEY_SNOWTRACE}"}
base = {key = "${API_KEY_BASESCAN}"}
bnb_smart_chain = {key = "${API_KEY_BSCSCAN}"}
gnosis_chain = {key = "${API_KEY_GNOSISSCAN}"}
goerli = {key = "${API_KEY_ETHERSCAN}"}
mainnet = {key = "${API_KEY_ETHERSCAN}"}
optimism = {key = "${API_KEY_OPTIMISTIC_ETHERSCAN}"}
polygon = {key = "${API_KEY_POLYGONSCAN}"}
sepolia = {key = "${API_KEY_ETHERSCAN}"}

[fmt]
bracket_spacing = true
int_types = "long"
line_length = 120
multiline_func_header = "all"
number_underscore = "thousands"
quote_style = "double"
tab_width = 4
wrap_comments = true
bracket_spacing = true
int_types = "long"
line_length = 120
multiline_func_header = "all"
number_underscore = "thousands"
quote_style = "double"
tab_width = 4
wrap_comments = true

[rpc_endpoints]
arbitrum = "https://arbitrum-mainnet.infura.io/v3/${API_KEY_INFURA}"
avalanche = "https://avalanche-mainnet.infura.io/v3/${API_KEY_INFURA}"
base = "https://mainnet.base.org"
bnb_smart_chain = "https://bsc-dataseed.binance.org"
gnosis_chain = "https://rpc.gnosischain.com"
goerli = "https://goerli.infura.io/v3/${API_KEY_INFURA}"
localhost = "http://localhost:8545"
mainnet = "https://eth-mainnet.g.alchemy.com/v2/${API_KEY_ALCHEMY}"
optimism = "https://optimism-mainnet.infura.io/v3/${API_KEY_INFURA}"
polygon = "https://polygon-mainnet.infura.io/v3/${API_KEY_INFURA}"
sepolia = "https://sepolia.infura.io/v3/${API_KEY_INFURA}"
arbitrum = "https://arbitrum-mainnet.infura.io/v3/${API_KEY_INFURA}"
avalanche = "https://avalanche-mainnet.infura.io/v3/${API_KEY_INFURA}"
base = "https://mainnet.base.org"
bnb_smart_chain = "https://bsc-dataseed.binance.org"
gnosis_chain = "https://rpc.gnosischain.com"
goerli = "https://goerli.infura.io/v3/${API_KEY_INFURA}"
localhost = "http://localhost:8545"
mainnet = "https://eth-mainnet.g.alchemy.com/v2/${API_KEY_ALCHEMY}"
optimism = "https://optimism-mainnet.infura.io/v3/${API_KEY_INFURA}"
polygon = "https://polygon-mainnet.infura.io/v3/${API_KEY_INFURA}"
sepolia = "https://sepolia.infura.io/v3/${API_KEY_INFURA}"
13 changes: 8 additions & 5 deletions remappings.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/
@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable
forge-std/=node_modules/forge-std/
world-id-state-bridge=node_modules/@worldcoin/world-id-state-bridge/src
linea-contracts/=node_modules/linea-contracts/contracts
forge-std/=lib/forge-std/src/
@openzeppelin/=node_modules/@openzeppelin/
@rari-capital/=node_modules/@rari-capital/
hardhat/=node_modules/hardhat/
linea-contracts/=node_modules/linea-contracts/contracts/
world-id-state-bridge/=node_modules/@worldcoin/world-id-state-bridge/src/
@eth-optimism/=node_modules/@eth-optimism/
@worldcoin/=node_modules/@worldcoin/
151 changes: 151 additions & 0 deletions test/LinearWorldID.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

import "forge-std/Test.sol";
import "../src/LineaWorldID.sol";
import "../src/interfaces/IMessageService.sol";

contract MockMessageService is IMessageService {
address public senderAddress;

function setSender(address _sender) external {
senderAddress = _sender;
}

function sender() external view returns (address) {
return senderAddress;
}

function sendMessage(address, uint256, bytes calldata) external payable {}
function claimMessage(address, address, uint256, uint256, address payable, bytes calldata, uint256) external {}
}

contract LineaWorldIDTest is Test {
LineaWorldID public lineaWorldID;
MockMessageService public mockMessageService;
uint8 constant TREE_DEPTH = 30;
address constant OWNER = address(0x1234);

// Error selectors
bytes4 constant CallerIsNotOwner = bytes4(keccak256("Ownable: caller is not the owner"));
bytes4 constant NonExistentRoot = bytes4(keccak256("NonExistentRoot()"));
bytes4 constant CannotOverwriteRoot = bytes4(keccak256("CannotOverwriteRoot()"));

event RootAdded(uint256 root, uint128 timestamp);
event RootHistoryExpirySet(uint256 newExpiry);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner, bool isLocal);
event MessageServiceUpdated(address indexed oldMessageService, address indexed newMessageService);

function setUp() public {
mockMessageService = new MockMessageService();
lineaWorldID = new LineaWorldID(TREE_DEPTH, address(mockMessageService));
lineaWorldID.transferOwnership(OWNER, true);
}

function testInitialState() public {
assertEq(lineaWorldID.getTreeDepth(), TREE_DEPTH);
assertEq(lineaWorldID.owner(), OWNER);
assertEq(address(lineaWorldID.messageService()), address(mockMessageService));
assertEq(lineaWorldID.isLocal(), true);
}

function testReceiveRoot() public {
uint256 newRoot = 3 weeks;

vm.prank(OWNER);
vm.expectEmit(true, true, true, true);
emit RootAdded(newRoot, uint128(block.timestamp));
lineaWorldID.receiveRoot(newRoot);

assertEq(lineaWorldID.latestRoot(), newRoot);
}

function testReceiveRootNonOwner() public {
uint256 newRoot = 3 weeks;

vm.expectRevert(CallerIsNotOwner);
lineaWorldID.receiveRoot(newRoot);
}

function testSetRootHistoryExpiry() public {
uint256 newExpiry = 2 weeks;

vm.prank(OWNER);
vm.expectEmit(true, true, true, true);
emit RootHistoryExpirySet(newExpiry);
lineaWorldID.setRootHistoryExpiry(newExpiry);

assertEq(lineaWorldID.rootHistoryExpiry(), newExpiry);
}

function testSetRootHistoryExpiryNonOwner() public {
uint256 newExpiry = 2 weeks;

vm.expectRevert(CallerIsNotOwner);
lineaWorldID.setRootHistoryExpiry(newExpiry);
}

function testVerifyProof() public {
uint256 root = 2 weeks;
uint256 signalHash = 987654321;
uint256 nullifierHash = 135792468;
uint256 externalNullifierHash = 246813579;
uint256[8] memory proof;

vm.prank(OWNER);
lineaWorldID.receiveRoot(root);

vm.mockCall(
address(lineaWorldID),
abi.encodeWithSignature("verifyProof(uint256,uint256,uint256,uint256,uint256[8])", root, signalHash, nullifierHash, externalNullifierHash, proof),
abi.encode()
);

lineaWorldID.verifyProof(root, signalHash, nullifierHash, externalNullifierHash, proof);
}

function testReceiveRootOverwrite() public {
uint256 newRoot = uint256(keccak256("newRoot"));

vm.startPrank(OWNER);
lineaWorldID.receiveRoot(newRoot);
vm.expectRevert(CannotOverwriteRoot);
lineaWorldID.receiveRoot(newRoot);
vm.stopPrank();
}

function testVerifyProofInvalidRoot() public {
uint256 root = 2 weeks;
uint256 signalHash = 987654321;
uint256 nullifierHash = 135792468;
uint256 externalNullifierHash = 246813579;
uint256[8] memory proof;

vm.expectRevert(NonExistentRoot);
lineaWorldID.verifyProof(root, signalHash, nullifierHash, externalNullifierHash, proof);
}

function testTransferOwnership() public {
address newOwner = address(0x5678);
bool newIsLocal = false;

vm.prank(OWNER);
vm.expectEmit(true, true, true, true);
emit OwnershipTransferred(OWNER, newOwner, newIsLocal);
lineaWorldID.transferOwnership(newOwner, newIsLocal);

assertEq(lineaWorldID.owner(), newOwner);
assertEq(lineaWorldID.isLocal(), newIsLocal);
}

function testSetMessagingService() public {
address newMessageService = address(0x9876);

vm.prank(OWNER);
vm.expectEmit(true, true, true, true);
emit MessageServiceUpdated(address(mockMessageService), newMessageService);
lineaWorldID.setMessagingService(newMessageService);

assertEq(address(lineaWorldID.messageService()), newMessageService);
}
}
10 changes: 0 additions & 10 deletions test/placeholder.t.sol
Original file line number Diff line number Diff line change
@@ -1,10 +0,0 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.15;

// TODO: remove this placeholder test after the actual tests are implemented

contract PlaceholderTest {
function testAlwaysPasses() public pure returns (bool) {
return true;
}
}

0 comments on commit 6b41167

Please sign in to comment.