Tutorials
Testing modules
This tutorial will walk you through testing a module. You can choose what kind of account you want to test the module on.
This tutorial uses Foundry, a toolchain to simplify and speed up smart contract development. If you are not familiar with Foundry, feel free to check out their docs.
If you do not have foundry installed, run the following command and follow the onscreen instructions: bash curl -L https://foundry.paradigm.xyz | bash
Installation
- Get started with ModuleKit by using our template or adding it into an existing foundry project:
Installation
git clone https://github.com/rhinestonewtf/module-template.git
cd module-template
forge install
Testing the module
In this section, we will walk you through testing a simple validator.
- Duplicate the file
test/validators/ValidatorTemplate.t.sol
and rename toSimpleValidator.t.sol
and the contract toSimpleValidatorTest
.
If you added the ModuleKit to an existing project, you will need to create the SimpleValidator.t.sol
file yourself
and copy the code from
here.
- Add the following import statement to the top of the file:
import { ECDSA } from "solady/utils/ECDSA.sol";
and change the following import
import { ValidatorTemplate, ERC1271_MAGICVALUE } from "../../src/validators/ValidatorTemplate.sol";
to the following:
import { SimpleValidator, ERC1271_MAGICVALUE } from "../../src/validators/SimpleValidator.sol";
and then change the code above the setup
function to the following:
contract SimpleValidatorTest is Test, RhinestoneModuleKit {
using RhinestoneModuleKitLib for RhinestoneAccount;
using ECDSA for bytes32;
RhinestoneAccount instance;
SimpleValidator simpleValidator;
...
}
- Edit the contract functions to match the following code:
setUp
function setUp() public {
// Setup account
instance = makeRhinestoneAccount("1");
vm.deal(instance.account, 10 ether);
// Setup validator
simpleValidator = new SimpleValidator();
(address owner,) = makeAddrAndKey("owner");
vm.prank(instance.account);
simpleValidator.setOwner(owner);
// Add validator to account
instance.addValidator(address(simpleValidator));
}
This function sets up the tests by creating an instance of the account, deploying and initialising the validator, and adding the validator to the account.
testSendEth
function testSendEth() public {
// Create userOperation fields
address receiver = makeAddr("receiver");
uint256 value = 10 gwei;
bytes memory callData = "";
// Create signature
(, uint256 key) = makeAddrAndKey("owner");
bytes32 hash =
instance.getUserOpHash({ target: receiver, value: value, callData: callData });
(uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash.toEthSignedMessageHash());
bytes memory signature = abi.encode(abi.encodePacked(r, s, v), address(simpleValidator));
// Create userOperation
instance.exec4337({
target: receiver,
value: value,
callData: callData,
signature: signature
});
// Validate userOperation
assertEq(receiver.balance, 10 gwei, "Receiver should have 10 gwei");
}
This function tests that the validator is setup and called correctly during the validateUserOp
function by creating a UserOperation, signing it, and then executing it.
test1271Signature
function test1271Signature() public {
// Create signature
(, uint256 key) = makeAddrAndKey("owner");
bytes32 hash = keccak256("signature");
(uint8 v, bytes32 r, bytes32 s) = vm.sign(key, hash.toEthSignedMessageHash());
bytes memory signature = abi.encodePacked(r, s, v);
// Validate signature
vm.prank(instance.account);
bytes4 returnValue = simpleValidator.isValidSignature(hash, signature);
// Validate signature success
assertEq(
returnValue,
ERC1271_MAGICVALUE, // EIP1271_MAGIC_VALUE
"Signature should be valid"
);
}
This function tests that the validator behaves correctly during the isValidSignature
function by creating a signature and then checking that the signature is validated by the validator.
- Run
forge test
to run the tests and ensure that they pass. You should see something like the following message:
response
Running 1 test for ...
[PASS] ...() (gas: ...)
Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 18.85ms
Ran 2 test suites: 5 tests passed, 0 failed, 0 skipped (5 total tests)