-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
217 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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}" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} | ||