Skip to content

Commit 3e722aa

Browse files
committed
Add Cross Chain Replay Protection
1 parent 0d34ed9 commit 3e722aa

File tree

3 files changed

+6
-4
lines changed

3 files changed

+6
-4
lines changed

script/BatchCallAndSponsor.s.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ contract BatchCallAndSponsorScript is Script {
9797
for (uint256 i = 0; i < calls.length; i++) {
9898
encodedCalls = abi.encodePacked(encodedCalls, calls[i].to, calls[i].value, calls[i].data);
9999
}
100-
bytes32 digest = keccak256(abi.encodePacked(BatchCallAndSponsor(ALICE_ADDRESS).nonce(), encodedCalls));
100+
bytes32 digest = keccak256(abi.encodePacked(block.chainid, BatchCallAndSponsor(ALICE_ADDRESS).nonce(), encodedCalls));
101101
(uint8 v, bytes32 r, bytes32 s) = vm.sign(ALICE_PK, MessageHashUtils.toEthSignedMessageHash(digest));
102102
bytes memory signature = abi.encodePacked(r, s, v);
103103

src/BatchCallAndSponsor.sol

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol";
1818
* 2. Directly by the smart account: When the account itself (i.e. address(this)) calls the function, no signature is required.
1919
*
2020
* Replay protection is achieved by using a nonce that is included in the signed message.
21+
* Cross chain replay protection is achieved by using the chainid in the signed message.
2122
*/
2223
contract BatchCallAndSponsor {
2324
using ECDSA for bytes32;
@@ -51,7 +52,7 @@ contract BatchCallAndSponsor {
5152
for (uint256 i = 0; i < calls.length; i++) {
5253
encodedCalls = abi.encodePacked(encodedCalls, calls[i].to, calls[i].value, calls[i].data);
5354
}
54-
bytes32 digest = keccak256(abi.encodePacked(nonce, encodedCalls));
55+
bytes32 digest = keccak256(abi.encodePacked(block.chainid, nonce, encodedCalls));
5556

5657
bytes32 ethSignedMessageHash = MessageHashUtils.toEthSignedMessageHash(digest);
5758

test/BatchCallAndSponsor.t.sol

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@ contract BatchCallAndSponsorTest is Test {
9797
encodedCalls = abi.encodePacked(encodedCalls, calls[i].to, calls[i].value, calls[i].data);
9898
}
9999

100-
bytes32 digest = keccak256(abi.encodePacked(BatchCallAndSponsor(ALICE_ADDRESS).nonce(), encodedCalls));
100+
bytes32 digest =
101+
keccak256(abi.encodePacked(block.chainid, BatchCallAndSponsor(ALICE_ADDRESS).nonce(), encodedCalls));
101102

102103
(uint8 v, bytes32 r, bytes32 s) = vm.sign(ALICE_PK, MessageHashUtils.toEthSignedMessageHash(digest));
103104
bytes memory signature = abi.encodePacked(r, s, v);
@@ -171,7 +172,7 @@ contract BatchCallAndSponsorTest is Test {
171172
vm.attachDelegation(signedDelegation);
172173

173174
uint256 nonceBefore = BatchCallAndSponsor(ALICE_ADDRESS).nonce();
174-
bytes32 digest = keccak256(abi.encodePacked(nonceBefore, encodedCalls));
175+
bytes32 digest = keccak256(abi.encodePacked(block.chainid, nonceBefore, encodedCalls));
175176
(uint8 v, bytes32 r, bytes32 s) = vm.sign(ALICE_PK, MessageHashUtils.toEthSignedMessageHash(digest));
176177
bytes memory signature = abi.encodePacked(r, s, v);
177178

0 commit comments

Comments
 (0)