The home for Hyperlane core contracts, sdk packages, and other infrastructure
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.
hyperlane-monorepo/solidity/test/AttributeCheckpointFraud.t.sol

203 lines
6.1 KiB

// 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);
}
}