Skip to main content

safe_rs/contracts/
mod.rs

1//! Contract ABI definitions for Safe v1.4.1
2
3use alloy::sol;
4
5sol! {
6    /// Safe v1.4.1 interface for executing transactions
7    #[sol(rpc)]
8    interface ISafe {
9        /// Execute a transaction (requires valid signature)
10        function execTransaction(
11            address to,
12            uint256 value,
13            bytes calldata data,
14            uint8 operation,
15            uint256 safeTxGas,
16            uint256 baseGas,
17            uint256 gasPrice,
18            address gasToken,
19            address payable refundReceiver,
20            bytes memory signatures
21        ) external payable returns (bool success);
22
23        /// Returns the current nonce of the Safe
24        function nonce() external view returns (uint256 nonce);
25
26        /// Returns the threshold (number of required signatures)
27        function getThreshold() external view returns (uint256 threshold);
28
29        /// Returns array of owners
30        function getOwners() external view returns (address[] memory owners);
31
32        /// Checks if an address is an owner
33        function isOwner(address owner) external view returns (bool isOwner);
34
35        /// Returns the domain separator for EIP-712 signing
36        function domainSeparator() external view returns (bytes32);
37
38        /// Computes the hash of a Safe transaction
39        function getTransactionHash(
40            address to,
41            uint256 value,
42            bytes calldata data,
43            uint8 operation,
44            uint256 safeTxGas,
45            uint256 baseGas,
46            uint256 gasPrice,
47            address gasToken,
48            address refundReceiver,
49            uint256 _nonce
50        ) external view returns (bytes32);
51
52        /// Encodes transaction data
53        function encodeTransactionData(
54            address to,
55            uint256 value,
56            bytes calldata data,
57            uint8 operation,
58            uint256 safeTxGas,
59            uint256 baseGas,
60            uint256 gasPrice,
61            address gasToken,
62            address refundReceiver,
63            uint256 _nonce
64        ) external view returns (bytes memory);
65
66        /// Checks the signature and returns the owner address
67        function checkSignatures(
68            bytes32 dataHash,
69            bytes memory data,
70            bytes memory signatures
71        ) external view;
72
73        /// Returns the chain ID
74        function getChainId() external view returns (uint256);
75
76        /// Events
77        event ExecutionSuccess(bytes32 indexed txHash, uint256 payment);
78        event ExecutionFailure(bytes32 indexed txHash, uint256 payment);
79        event SafeReceived(address indexed sender, uint256 value);
80    }
81
82    /// MultiSend interface for batching multiple calls
83    #[sol(rpc)]
84    interface IMultiSend {
85        /// Sends multiple transactions in a single call
86        /// @param transactions Packed encoding of transactions:
87        ///        operation (1 byte) | to (20 bytes) | value (32 bytes) | data length (32 bytes) | data
88        function multiSend(bytes memory transactions) external payable;
89    }
90
91    /// MultiSendCallOnly - same as MultiSend but only allows Call operations (no DelegateCall)
92    #[sol(rpc)]
93    interface IMultiSendCallOnly {
94        /// Sends multiple transactions in a single call (Call only, no DelegateCall)
95        function multiSend(bytes memory transactions) external payable;
96    }
97
98    /// ERC20 interface for common token operations
99    #[sol(rpc)]
100    interface IERC20 {
101        function transfer(address to, uint256 amount) external returns (bool);
102        function approve(address spender, uint256 amount) external returns (bool);
103        function transferFrom(address from, address to, uint256 amount) external returns (bool);
104        function balanceOf(address account) external view returns (uint256);
105        function allowance(address owner, address spender) external view returns (uint256);
106
107        event Transfer(address indexed from, address indexed to, uint256 value);
108        event Approval(address indexed owner, address indexed spender, uint256 value);
109    }
110
111    /// SafeProxyFactory interface for deploying new Safe proxies
112    #[sol(rpc)]
113    interface ISafeProxyFactory {
114        /// Deploys a new Safe proxy with a deterministic address
115        function createProxyWithNonce(
116            address _singleton,
117            bytes memory initializer,
118            uint256 saltNonce
119        ) external returns (address proxy);
120
121        /// Returns the creation bytecode for Safe proxies
122        function proxyCreationCode() external pure returns (bytes memory);
123
124        event ProxyCreation(address indexed proxy, address singleton);
125    }
126
127    /// Safe setup interface for initialization
128    #[sol(rpc)]
129    interface ISafeSetup {
130        /// Initializes a new Safe with owners and threshold
131        function setup(
132            address[] calldata _owners,
133            uint256 _threshold,
134            address to,
135            bytes calldata data,
136            address fallbackHandler,
137            address paymentToken,
138            uint256 payment,
139            address payable paymentReceiver
140        ) external;
141    }
142}
143
144/// EIP-712 type hash for SafeTx struct
145/// keccak256("SafeTx(address to,uint256 value,bytes data,uint8 operation,uint256 safeTxGas,uint256 baseGas,uint256 gasPrice,address gasToken,address refundReceiver,uint256 nonce)")
146pub const SAFE_TX_TYPEHASH: [u8; 32] = [
147    0xbb, 0x83, 0x10, 0xd4, 0x86, 0x36, 0x8d, 0xb6, 0xbd, 0x6f, 0x84, 0x94, 0x02, 0xfd, 0xd7, 0x3a,
148    0xd5, 0x3d, 0x31, 0x6b, 0x5a, 0x4b, 0x26, 0x44, 0xad, 0x6e, 0xfe, 0x0f, 0x94, 0x12, 0x86, 0xd8,
149];
150
151/// EIP-712 domain type hash for Safe
152/// keccak256("EIP712Domain(uint256 chainId,address verifyingContract)")
153pub const DOMAIN_SEPARATOR_TYPEHASH: [u8; 32] = [
154    0x47, 0xe7, 0x95, 0x34, 0xa2, 0x45, 0x95, 0x2e, 0x8b, 0x16, 0x89, 0x3a, 0x33, 0x6b, 0x85, 0xa3,
155    0xd9, 0xea, 0x9f, 0xa8, 0xc5, 0x73, 0xf3, 0xd8, 0x03, 0xaf, 0xb9, 0x2a, 0x79, 0x46, 0x92, 0x18,
156];
157
158#[cfg(test)]
159mod tests {
160    use super::*;
161    use alloy::primitives::keccak256;
162
163    #[test]
164    fn test_safe_tx_typehash() {
165        let computed = keccak256(
166            "SafeTx(address to,uint256 value,bytes data,uint8 operation,uint256 safeTxGas,uint256 baseGas,uint256 gasPrice,address gasToken,address refundReceiver,uint256 nonce)"
167        );
168        assert_eq!(computed.as_slice(), &SAFE_TX_TYPEHASH);
169    }
170
171    #[test]
172    fn test_domain_separator_typehash() {
173        let computed = keccak256("EIP712Domain(uint256 chainId,address verifyingContract)");
174        assert_eq!(computed.as_slice(), &DOMAIN_SEPARATOR_TYPEHASH);
175    }
176}