You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
203 lines
6.1 KiB
203 lines
6.1 KiB
3 months ago
|
// SPDX-License-Identifier: Apache-2.0
|
||
|
pragma solidity ^0.8.13;
|
||
|
|
||
|
import "forge-std/Test.sol";
|
||
|
|
||
|
import "../contracts/libs/CheckpointLib.sol";
|
||
|
|
||
|
import "../contracts/test/TestMailbox.sol";
|
||
|
import "../contracts/test/TestMerkleTreeHook.sol";
|
||
|
|
||
|
import "../contracts/CheckpointFraudProofs.sol";
|
||
|
import "../contracts/AttributeCheckpointFraud.sol";
|
||
|
|
||
|
contract AttributeCheckpointFraudTest is Test {
|
||
|
using CheckpointLib for Checkpoint;
|
||
|
using TypeCasts for address;
|
||
|
|
||
|
uint32 domain = 1;
|
||
|
|
||
|
TestMailbox mailbox;
|
||
|
TestMerkleTreeHook merkleTreeHook;
|
||
|
|
||
|
AttributeCheckpointFraud acf;
|
||
|
|
||
|
function setUp() public {
|
||
|
acf = new AttributeCheckpointFraud();
|
||
|
mailbox = new TestMailbox(domain);
|
||
|
merkleTreeHook = new TestMerkleTreeHook(address(mailbox));
|
||
|
}
|
||
|
|
||
|
function test_whitelist() public {
|
||
|
vm.expectRevert("merkle tree must be a valid contract");
|
||
|
acf.whitelist(address(0));
|
||
|
|
||
|
vm.prank(address(0x1));
|
||
|
vm.expectRevert("Ownable: caller is not the owner");
|
||
|
acf.whitelist(address(merkleTreeHook));
|
||
|
|
||
|
acf.whitelist(address(merkleTreeHook));
|
||
|
assert(acf.merkleTreeWhitelist(address(merkleTreeHook)));
|
||
|
}
|
||
|
|
||
|
function sign(
|
||
|
Checkpoint memory checkpoint,
|
||
|
uint256 privateKey
|
||
|
) internal pure returns (bytes memory signature) {
|
||
|
vm.assume(
|
||
|
privateKey > 0 &&
|
||
|
// private key must be less than the secp256k1 curve order
|
||
|
privateKey <
|
||
|
115792089237316195423570985008687907852837564279074904382605163141518161494337
|
||
|
);
|
||
|
|
||
|
bytes32 digest = checkpoint.digest();
|
||
|
(uint8 v, bytes32 r, bytes32 s) = vm.sign(privateKey, digest);
|
||
|
return abi.encodePacked(r, s, v);
|
||
|
}
|
||
|
|
||
|
function test_attributeWhitelist(
|
||
|
Checkpoint memory checkpoint,
|
||
|
uint256 privateKey
|
||
|
) public {
|
||
|
checkpoint.origin = domain;
|
||
|
checkpoint.merkleTree = address(merkleTreeHook).addressToBytes32();
|
||
|
|
||
|
bytes memory signature = sign(checkpoint, privateKey);
|
||
|
|
||
|
acf.attributeWhitelist(checkpoint, signature);
|
||
|
assert(
|
||
|
acf.attributions(checkpoint, signature).fraudType ==
|
||
|
FraudType.Whitelist
|
||
|
);
|
||
|
|
||
|
vm.expectRevert("fraud already attributed to signer for digest");
|
||
|
acf.attributeWhitelist(checkpoint, signature);
|
||
|
|
||
|
acf.whitelist(address(merkleTreeHook));
|
||
|
vm.expectRevert("merkle tree is whitelisted");
|
||
|
acf.attributeWhitelist(checkpoint, signature);
|
||
|
|
||
|
checkpoint.origin = domain + 1;
|
||
|
vm.expectRevert("checkpoint must be local");
|
||
|
acf.attributeWhitelist(checkpoint, signature);
|
||
|
}
|
||
|
|
||
|
function test_attributePremature(
|
||
|
Checkpoint calldata checkpoint,
|
||
|
uint256 privateKey
|
||
|
) public {
|
||
|
bytes memory signature = sign(checkpoint, privateKey);
|
||
|
|
||
|
vm.mockCall(
|
||
|
address(acf.checkpointFraudProofs()),
|
||
|
abi.encodeWithSelector(
|
||
|
CheckpointFraudProofs.isPremature.selector,
|
||
|
checkpoint
|
||
|
),
|
||
|
abi.encode(false)
|
||
|
);
|
||
|
vm.expectRevert("checkpoint must be premature");
|
||
|
acf.attributePremature(checkpoint, signature);
|
||
|
|
||
|
vm.mockCall(
|
||
|
address(acf.checkpointFraudProofs()),
|
||
|
abi.encodeWithSelector(
|
||
|
CheckpointFraudProofs.isPremature.selector,
|
||
|
checkpoint
|
||
|
),
|
||
|
abi.encode(true)
|
||
|
);
|
||
|
acf.attributePremature(checkpoint, signature);
|
||
|
assert(
|
||
|
acf.attributions(checkpoint, signature).fraudType ==
|
||
|
FraudType.Premature
|
||
|
);
|
||
|
|
||
|
vm.expectRevert("fraud already attributed to signer for digest");
|
||
|
acf.attributePremature(checkpoint, signature);
|
||
|
}
|
||
|
|
||
|
function test_attributeMessageId(
|
||
|
Checkpoint memory checkpoint,
|
||
|
bytes32[TREE_DEPTH] calldata proof,
|
||
|
uint256 privateKey
|
||
|
) public {
|
||
|
bytes memory signature = sign(checkpoint, privateKey);
|
||
|
|
||
|
vm.mockCall(
|
||
|
address(acf.checkpointFraudProofs()),
|
||
|
abi.encodeWithSelector(
|
||
|
CheckpointFraudProofs.isFraudulentMessageId.selector
|
||
|
),
|
||
|
abi.encode(false)
|
||
|
);
|
||
|
vm.expectRevert("checkpoint must have fraudulent message ID");
|
||
|
acf.attributeMessageId(
|
||
|
checkpoint,
|
||
|
proof,
|
||
|
checkpoint.messageId,
|
||
|
signature
|
||
|
);
|
||
|
|
||
|
vm.mockCall(
|
||
|
address(acf.checkpointFraudProofs()),
|
||
|
abi.encodeWithSelector(
|
||
|
CheckpointFraudProofs.isFraudulentMessageId.selector
|
||
|
),
|
||
|
abi.encode(true)
|
||
|
);
|
||
|
acf.attributeMessageId(
|
||
|
checkpoint,
|
||
|
proof,
|
||
|
checkpoint.messageId,
|
||
|
signature
|
||
|
);
|
||
|
assert(
|
||
|
acf.attributions(checkpoint, signature).fraudType ==
|
||
|
FraudType.MessageId
|
||
|
);
|
||
|
|
||
|
vm.expectRevert("fraud already attributed to signer for digest");
|
||
|
acf.attributeMessageId(
|
||
|
checkpoint,
|
||
|
proof,
|
||
|
checkpoint.messageId,
|
||
|
signature
|
||
|
);
|
||
|
}
|
||
|
|
||
|
function test_attributeRoot(
|
||
|
Checkpoint memory checkpoint,
|
||
|
bytes32[TREE_DEPTH] calldata proof,
|
||
|
uint256 privateKey
|
||
|
) public {
|
||
|
bytes memory signature = sign(checkpoint, privateKey);
|
||
|
|
||
|
vm.mockCall(
|
||
|
address(acf.checkpointFraudProofs()),
|
||
|
abi.encodeWithSelector(
|
||
|
CheckpointFraudProofs.isFraudulentRoot.selector
|
||
|
),
|
||
|
abi.encode(false)
|
||
|
);
|
||
|
vm.expectRevert("checkpoint must have fraudulent root");
|
||
|
acf.attributeRoot(checkpoint, proof, signature);
|
||
|
|
||
|
vm.mockCall(
|
||
|
address(acf.checkpointFraudProofs()),
|
||
|
abi.encodeWithSelector(
|
||
|
CheckpointFraudProofs.isFraudulentRoot.selector
|
||
|
),
|
||
|
abi.encode(true)
|
||
|
);
|
||
|
acf.attributeRoot(checkpoint, proof, signature);
|
||
|
assert(
|
||
|
acf.attributions(checkpoint, signature).fraudType == FraudType.Root
|
||
|
);
|
||
|
|
||
|
vm.expectRevert("fraud already attributed to signer for digest");
|
||
|
acf.attributeRoot(checkpoint, proof, signature);
|
||
|
}
|
||
|
}
|