Skip to content

Commit

Permalink
WarpISM testing
Browse files Browse the repository at this point in the history
  • Loading branch information
St4rgarden committed Jun 17, 2024
1 parent 36d68ba commit 04a0e58
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 57 deletions.
3 changes: 1 addition & 2 deletions script/Deploy.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -111,11 +111,10 @@ contract DeployScript is Script {

_warpISM.setSignerThreshold(_config.signerThreshold);


console2.log("Deploying AccountFactory");
_accountFactory = new AccountFactory();
console2.log("Deployed AccountFactory at: ", address(_accountFactory));

vm.stopBroadcast();
}
}
}
4 changes: 2 additions & 2 deletions src/Account.sol
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

contract Account {
contract Account {
uint256 public state;
address public owner;

Expand Down Expand Up @@ -62,4 +62,4 @@ contract AccountFactory {
emit AccountCreated(account);
}
}
}
}
3 changes: 3 additions & 0 deletions src/WarpMintController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ abstract contract WarpMintController is AccessControl, IWarpController {
virtual
{
(, uint256 amount, address sender) = abi.decode(messageBody, (address, uint256, address));
if (sender != msg.sender) {
revert SenderMustBeCaller();
}
_token.burnFrom(sender, amount);
// Initiate the order through the mailbox
// The backend consumes the dispatch event emitted by the mailbox
Expand Down
2 changes: 1 addition & 1 deletion src/hyperlane/PausableIsm.sol
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,4 @@ contract PausableIsm is IInterchainSecurityModule, Ownable, Pausable {
function unpause() external onlyOwner {
_unpause();
}
}
}
2 changes: 2 additions & 0 deletions src/interfaces/IWarpController.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
pragma solidity >=0.8.20;

interface IWarpController {
error SenderMustBeCaller();

event Fulfillment(bytes32 indexed orderId, bytes message);
event WarpMint(address indexed recipient, uint256 amount, address indexed sender);
}
7 changes: 1 addition & 6 deletions src/interfaces/IWarpISM.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@
pragma solidity >=0.8.20;

interface IWarpISM {
// Data object for signing and digest construction
struct MintData {
address recipient;
uint256 amount;
uint256 nonce;
}

error InvalidSignatureRatio();
error InvalidSignatures();
Expand All @@ -16,6 +10,7 @@ interface IWarpISM {
error InvalidSignatureLength();
error BelowMinThreshold();
error NonZero();
error InvalidDestination();

event NewValidator(address indexed validator);
event RemovedValidator(address indexed validator);
Expand Down
30 changes: 10 additions & 20 deletions test/Base.t.sol → test/BaseTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import {wPOKTMintController} from "@src/wPOKTMintController.sol";
import {Mailbox} from "@hyperlane/Mailbox.sol";
import {OmniToken} from "@src/OmniToken.sol";
import {WarpISM, ECDSA} from "@src/WarpISM.sol";
import {IWarpISM} from "@interfaces/IWarpISM.sol";
import {IInterchainSecurityModule} from "@hyperlane/interfaces/IInterchainSecurityModule.sol";
import "@hyperlane/test/TestPostDispatchHook.sol";
import "@hyperlane/test/TestRecipient.sol";

contract ContractTest is Test {
contract BaseTest is Test {
using Message for bytes;
using TypeCasts for bytes32;
using TypeCasts for address;
Expand Down Expand Up @@ -133,7 +135,7 @@ contract ContractTest is Test {
}
}

function getDigest(bytes memory message) public returns (bytes32 digest) {
function getDigest(bytes memory message) public view returns (bytes32 digest) {
digest = warpISM.getDigest(message);
}

Expand All @@ -158,7 +160,6 @@ contract ContractTest is Test {
}

function buildSignatureAsc(bytes memory message, uint256 signerIndex) public view returns (bytes memory) {
console2.log("Hashing digest:");
bytes32 digest = warpISM.getDigest(message);

(uint8 v, bytes32 r, bytes32 s) = vm.sign(privKeyAsc[signerIndex], digest);
Expand All @@ -167,53 +168,43 @@ contract ContractTest is Test {
}

function buildSignatureDesc(bytes memory message, uint256 signerIndex) public view returns (bytes memory) {

bytes32 digest = warpISM.getDigest(message);

(uint8 v, bytes32 r, bytes32 s) = vm.sign(privKeyDesc[signerIndex], digest);
bytes memory signature = abi.encodePacked(r, s, v);
return signature;
}

function buildSignaturesAsc(bytes memory data) public returns (bytes[] memory) {
console2.log("Building Ascending Signatures");
function buildSignaturesAsc(bytes memory data) public view returns (bytes[] memory) {
bytes[] memory signatures = new bytes[](privKeyAsc.length);
for (uint256 i = 0; i < signatures.length; i++) {
console2.log("Building Signature with bytes:");
bytes memory signature = buildSignatureAsc(data, i);
console2.log(signature.length);
signatures[i] = signature;
}
console2.log("Signature array length:");
console2.log(signatures.length);
console2.log("Signature Length:");
console2.log(signatures[0].length);
console2.log("Bytes of all signatures:");
console2.log(abi.encode(signatures).length);
return signatures;
}

function encodeSignatures(bytes[] memory signatures) public pure returns (bytes memory) {
require(signatures.length == 10, "There must be exactly 10 signatures");

bytes memory concatenatedSignatures;
for (uint i = 0; i < signatures.length; i++) {
for (uint256 i = 0; i < signatures.length; i++) {
require(signatures[i].length == 65, "Each signature must be 65 bytes long");
concatenatedSignatures = abi.encodePacked(concatenatedSignatures, signatures[i]);
}

return concatenatedSignatures;
}

function buildSignaturesDesc(bytes memory data) public returns (bytes[] memory) {
function buildSignaturesDesc(bytes memory data) public view returns (bytes[] memory) {
bytes[] memory signatures = new bytes[](privKeyDesc.length);
for (uint256 i = 0; i < signatures.length; i++) {
signatures[i] = buildSignatureDesc(data, i);
}
return signatures;
}

function setUp() public {
function setUp() public virtual {
uint256 chainId = block.chainid;
feeRecipient = new TestRecipient();
defaultHook = new TestPostDispatchHook();
Expand Down Expand Up @@ -252,11 +243,10 @@ contract ContractTest is Test {
function testMint() public {
uint8 version = mailbox.VERSION();
bytes memory messageBody = buildMessageBody(address(1000), 1000 ether, address(1000));
bytes memory message = buildMintData(version, 1, 1, address(1000), mailbox.localDomain(), address(mintController), messageBody);
bytes memory message =
buildMintData(version, 1, 1, address(1000), mailbox.localDomain(), address(mintController), messageBody);
bytes[] memory signatureArray = buildSignaturesAsc(message);
bytes memory concatenatedSignatures = encodeSignatures(signatureArray);
console2.log("Concatenated Signatures Length:");
console2.log(concatenatedSignatures.length);
mintController.fulfillOrder(concatenatedSignatures, message);
}
}
126 changes: 126 additions & 0 deletions test/WarpIsmTest.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
pragma solidity ^0.8.20;

import {BaseTest} from "./BaseTest.t.sol";
import {IInterchainSecurityModule} from "@hyperlane/interfaces/IInterchainSecurityModule.sol";

contract WarpIsmTest is BaseTest {

error InvalidSignatureRatio();
error InvalidSignatures();
error InvalidRemoveValidator();
error InvalidAddValidator();
error InvalidSignatureLength();
error BelowMinThreshold();
error NonZero();
error InvalidDestination();

function setUp() public virtual override {
super.setUp();
}

function testGetISM() public view {
IInterchainSecurityModule ism = mintController.interchainSecurityModule();
assertEq(address(ism), address(warpISM));
}

function testSetValidator() public {
address newValidator = address(0x123);
vm.prank(admin);
warpISM.addValidator(newValidator);
bool expected = true;
bool actual = warpISM.validators(newValidator);
assertEq(expected, actual);
}

function testRemoveValidator() public {
address newValidator = address(0x123);
vm.prank(admin);
warpISM.addValidator(newValidator);
bool expected = true;
bool actual = warpISM.validators(newValidator);
assertEq(expected, actual);
vm.prank(admin);
warpISM.removeValidator(newValidator);
expected = false;
actual = warpISM.validators(newValidator);
assertEq(expected, actual);
}

function testValidatorCount() public {
uint256 count = warpISM.validatorCount();
assertEq(count, 10);
}

function testSignerThreshold() public {
uint256 threshold = warpISM.signerThreshold();
assertEq(threshold, 7);
}

function testSignatureSize() public {
uint256 size = warpISM.SIGNATURE_SIZE();
assertEq(size, 65);
}

function testDigestTypeHash() public {
bytes32 expected = keccak256(
"Message(uint8 version,uint32 nonce,uint32 originDomain,bytes32 sender,uint32 destinationDomain,bytes32 recipient,bytes messageBody)"
);

bytes32 actual = warpISM.DIGEST_TYPE_HASH();
assertEq(expected, actual);
}

function testSetSignerThreshold() public {
uint256 newThreshold = 5;
vm.prank(admin);
warpISM.setSignerThreshold(newThreshold);
uint256 actual = warpISM.signerThreshold();
assertEq(newThreshold, actual);
}

function testAddValidatorRevertIfZeroAddress() public {
address zeroAddress = address(0);
vm.prank(admin);
vm.expectRevert(NonZero.selector);
warpISM.addValidator(zeroAddress);
}

function testAddValidatorRevertIfAlreadyAdded() public {
address validator = address(0x999);
vm.startPrank(admin);
warpISM.addValidator(validator); // Adding first time should succeed
vm.expectRevert(InvalidAddValidator.selector);
warpISM.addValidator(validator); // Adding second time should revert
vm.stopPrank();
}

function testInvalidSignatureRatio() public {
// Set the signerThreshold to 2
vm.prank(admin);
vm.expectRevert(InvalidSignatureRatio.selector);
warpISM.setSignerThreshold(2);
}

function testRemoveValidatorRevertIfZeroAddress() public {
vm.expectRevert(NonZero.selector);
vm.prank(admin);
warpISM.removeValidator(address(0));
}

function testRemoveValidatorRevertIfNotAdded() public {
vm.prank(admin);
address nonValidator = address(3);
vm.expectRevert(InvalidRemoveValidator.selector);
warpISM.removeValidator(nonValidator);
}

function testRemoveValidatorsBelowThreshold() public {
// Set the signerThreshold to 10
vm.prank(admin);
warpISM.setSignerThreshold(10);
vm.expectRevert(BelowMinThreshold.selector);
vm.prank(admin);
warpISM.removeValidator(validAddressAsc[0]);
}

}
34 changes: 8 additions & 26 deletions test/mocks/MessageMock.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {TypeCasts} from "@hyperlane/libs/TypeCasts.sol";
/**
* @title Hyperlane Message Library
* @notice Library for formatted messages used by Mailbox
**/
*
*/
contract MessageMock {
using TypeCasts for bytes32;

Expand Down Expand Up @@ -39,16 +40,7 @@ contract MessageMock {
bytes32 _recipient,
bytes calldata _messageBody
) public pure returns (bytes memory) {
return
abi.encodePacked(
_version,
_nonce,
_originDomain,
_sender,
_destinationDomain,
_recipient,
_messageBody
);
return abi.encodePacked(_version, _nonce, _originDomain, _sender, _destinationDomain, _recipient, _messageBody);
}

/**
Expand Down Expand Up @@ -101,9 +93,7 @@ contract MessageMock {
* @param _message ABI encoded Hyperlane message.
* @return Sender of `_message` as address
*/
function senderAddress(
bytes calldata _message
) public pure returns (address) {
function senderAddress(bytes calldata _message) public pure returns (address) {
return sender(_message).bytes32ToAddress();
}

Expand All @@ -112,9 +102,7 @@ contract MessageMock {
* @param _message ABI encoded Hyperlane message.
* @return Destination domain of `_message`
*/
function destination(
bytes calldata _message
) public pure returns (uint32) {
function destination(bytes calldata _message) public pure returns (uint32) {
return uint32(bytes4(_message[DESTINATION_OFFSET:RECIPIENT_OFFSET]));
}

Expand All @@ -123,9 +111,7 @@ contract MessageMock {
* @param _message ABI encoded Hyperlane message.
* @return Recipient of `_message` as bytes32
*/
function recipient(
bytes calldata _message
) public pure returns (bytes32) {
function recipient(bytes calldata _message) public pure returns (bytes32) {
return bytes32(_message[RECIPIENT_OFFSET:BODY_OFFSET]);
}

Expand All @@ -134,9 +120,7 @@ contract MessageMock {
* @param _message ABI encoded Hyperlane message.
* @return Recipient of `_message` as address
*/
function recipientAddress(
bytes calldata _message
) public pure returns (address) {
function recipientAddress(bytes calldata _message) public pure returns (address) {
return recipient(_message).bytes32ToAddress();
}

Expand All @@ -145,9 +129,7 @@ contract MessageMock {
* @param _message ABI encoded Hyperlane message.
* @return Body of `_message`
*/
function body(
bytes calldata _message
) public pure returns (bytes calldata) {
function body(bytes calldata _message) public pure returns (bytes calldata) {
return bytes(_message[BODY_OFFSET:]);
}
}

0 comments on commit 04a0e58

Please sign in to comment.