@@ -6,6 +6,7 @@ import {console} from "forge-std/console.sol";
66import {Script} from "forge-std/Script.sol " ;
77import {IMulticall3} from "forge-std/interfaces/IMulticall3.sol " ;
88import {Vm} from "forge-std/Vm.sol " ;
9+ import {stdJson} from "forge-std/StdJson.sol " ;
910
1011import {IGnosisSafe, Enum} from "./IGnosisSafe.sol " ;
1112import {Signatures} from "./Signatures.sol " ;
@@ -332,7 +333,7 @@ abstract contract MultisigScript is Script {
332333 return safes;
333334 }
334335
335- function _transactionDatas (address [] memory _safes ) private view returns (bytes [] memory datas , uint256 value ) {
336+ function _transactionDatas (address [] memory _safes ) internal view returns (bytes [] memory datas , uint256 value ) {
336337 // Build the calls and sum the values
337338 IMulticall3.Call3Value[] memory calls = _buildCalls ();
338339 for (uint256 i = 0 ; i < calls.length ; i++ ) {
@@ -375,7 +376,8 @@ abstract contract MultisigScript is Script {
375376 }
376377
377378 function _printDataToSign (address _safe , bytes memory _data , uint256 _value ) internal {
378- bytes memory txData = _encodeTransactionData (_safe, _data, _value);
379+ bytes memory txData =
380+ _printDataHashes () ? _encodeTransactionData (_safe, _data, _value) : _encodeEIP712Json (_safe, _data, _value);
379381 bytes32 hash = _getTransactionHash (_safe, _data, _value);
380382
381383 emit DataToSign (txData);
@@ -397,6 +399,14 @@ abstract contract MultisigScript is Script {
397399 console.log ("############################### " );
398400 }
399401
402+ // Controls whether the safe tx is printed as structured EIP-712 data, or just hashes.
403+ //
404+ // If you want to print and sign hashed EIP-712 data (domain + message hash) rather than the
405+ // typed EIP-712 data struct, override this function and return `true`.
406+ function _printDataHashes () internal view virtual returns (bool ) {
407+ return false ;
408+ }
409+
400410 function _executeTransaction (
401411 address _safe ,
402412 bytes memory _data ,
@@ -566,6 +576,39 @@ abstract contract MultisigScript is Script {
566576 });
567577 }
568578
579+ function _encodeEIP712Json (address _safe , bytes memory _data , uint256 _value ) internal returns (bytes memory ) {
580+ string memory types = '{"EIP712Domain":[ ' '{"name":"chainId","type":"uint256"}, '
581+ '{"name":"verifyingContract","type":"address"}], ' '"Transaction":[ ' '{"name":"to","type":"address"}, '
582+ '{"name":"value","type":"uint256"}, ' '{"name":"data","type":"bytes"}, '
583+ '{"name":"operation","type":"uint8"}, ' '{"name":"safeTxGas","type":"uint256"}, '
584+ '{"name":"baseGas","type":"uint256"}, ' '{"name":"gasPrice","type":"uint256"}, '
585+ '{"name":"gasToken","type":"address"}, ' '{"name":"refundReceiver","type":"address"}, '
586+ '{"name":"nonce","type":"uint256"}]} ' ;
587+
588+ string memory domain = stdJson.serialize ("domain " , "chainId " , uint256 (block .chainid ));
589+ domain = stdJson.serialize ("domain " , "verifyingContract " , address (_safe));
590+
591+ string memory message = stdJson.serialize ("message " , "to " , MULTICALL3_ADDRESS);
592+ message = stdJson.serialize ("message " , "value " , _value);
593+ message = stdJson.serialize ("message " , "data " , _data);
594+ message = stdJson.serialize (
595+ "message " , "operation " , uint256 (_value == 0 ? Enum.Operation.DelegateCall : Enum.Operation.Call)
596+ );
597+ message = stdJson.serialize ("message " , "safeTxGas " , uint256 (0 ));
598+ message = stdJson.serialize ("message " , "baseGas " , uint256 (0 ));
599+ message = stdJson.serialize ("message " , "gasPrice " , uint256 (0 ));
600+ message = stdJson.serialize ("message " , "gasToken " , address (0 ));
601+ message = stdJson.serialize ("message " , "refundReceiver " , address (0 ));
602+ message = stdJson.serialize ("message " , "nonce " , _getNonce (_safe));
603+
604+ string memory json = stdJson.serialize ("" , "primaryType " , string ("Transaction " ));
605+ json = stdJson.serialize ("" , "types " , types);
606+ json = stdJson.serialize ("" , "domain " , domain);
607+ json = stdJson.serialize ("" , "message " , message);
608+
609+ return abi.encodePacked (json);
610+ }
611+
569612 function _execTransactionCalldata (address _safe , bytes memory _data , uint256 _value , bytes memory _signatures )
570613 internal
571614 pure
0 commit comments