Skip to content

Commit 761b4fa

Browse files
authored
🔒 Add Warning for Untrusted delegatecalls (#14)
### 🕓 Changelog This PR adds a warning for the user if the transaction includes an _untrusted_ delegate call (i.e. `operation` equals `1`). The set of _trusted_ `delegatecall`able contract addresses is defined by: ```bash # Set the trusted (i.e. for delegate calls) contract addresses. # See: https://github.com/safe-global/safe-transaction-service/blob/c3b42f0bebff74b99fcdd958aee54b149e27eca5/safe_transaction_service/contracts/management/commands/setup_safe_contracts.py#L10-L16. declare -A -r TRUSTED_FOR_DELEGATE_CALL=( ["MultiSend"]="${MultiSend[@]}" ["MultiSendCallOnly"]="${MultiSendCallOnly[@]}" ["SafeMigration"]="${SafeMigration[@]}" ["SafeToL2Migration"]="${SafeToL2Migration[@]}" ["SignMessageLib"]="${SignMessageLib[@]}" ) ``` where ```bash # Set the trusted (i.e. for delegate calls) `MultiSend` addresses: # MultiSend `v1.1.1` (canonical): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.1.1/multi_send.json#L7, # MultiSend `v1.3.0` (canonical): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.3.0/multi_send.json#L7, # MultiSend `v1.3.0` (eip155): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.3.0/multi_send.json#L11, # MultiSend `v1.3.0` (zksync): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.3.0/multi_send.json#L15, # Multisend `v1.4.1` (canonical): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.4.1/multi_send.json#L7. declare -a -r MultiSend=( "0x8D29bE29923b68abfDD21e541b9374737B49cdAD" # MultiSend `v1.1.1` (canonical). "0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761" # MultiSend `v1.3.0` (canonical). "0x998739BFdAAdde7C933B942a68053933098f9EDa" # MultiSend `v1.3.0` (eip155). "0x0dFcccB95225ffB03c6FBB2559B530C2B7C8A912" # MultiSend `v1.3.0` (zksync). "0x38869bf66a61cF6bDB996A6aE40D5853Fd43B526" # MultiSend `v1.4.1` (canonical). ) # Set the trusted (i.e. for delegate calls) `MultiSendCallOnly` addresses: # MultiSendCallOnly `v1.3.0` (canonical): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.3.0/multi_send_call_only.json#L7, # MultiSendCallOnly `v1.3.0` (eip155): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.3.0/multi_send_call_only.json#L11, # MultiSendCallOnly `v1.3.0` (zksync): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.3.0/multi_send_call_only.json#L15, # MultiSendCallOnly `v1.4.1` (canonical): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.4.1/multi_send_call_only.json#L7. declare -a -r MultiSendCallOnly=( "0x40A2aCCbd92BCA938b02010E17A5b8929b49130D" # MultiSendCallOnly `v1.3.0` (canonical). "0xA1dabEF33b3B82c7814B6D82A79e50F4AC44102B" # MultiSendCallOnly `v1.3.0` (eip155). "0xf220D3b4DFb23C4ade8C88E526C1353AbAcbC38F" # MultiSendCallOnly `v1.3.0` (zksync). "0x9641d764fc13c8B624c04430C7356C1C7C8102e2" # MultiSendCallOnly `v1.4.1` (canonical). ) # Set the trusted (i.e. for delegate calls) `SafeMigration` addresses: # SafeMigration `v1.4.1` (canonical): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.4.1/safe_migration.json#L7. declare -a -r SafeMigration=( "0x526643F69b81B008F46d95CD5ced5eC0edFFDaC6" # SafeMigration `v1.4.1` (canonical). ) # Set the trusted (i.e. for delegate calls) `SafeToL2Migration` addresses: # SafeToL2Migration `v1.4.1` (canonical): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.4.1/safe_to_l2_migration.json#L7. declare -a -r SafeToL2Migration=( "0xfF83F6335d8930cBad1c0D439A841f01888D9f69" # SafeToL2Migration `v1.4.1` (canonical). ) # Set the trusted (i.e. for delegate calls) `SignMessageLib` addresses: # SignMessageLib `v1.3.0` (canonical): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.3.0/sign_message_lib.json#L7, # SignMessageLib `v1.3.0` (eip155): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.3.0/sign_message_lib.json#L11, # SignMessageLib `v1.3.0` (zksync): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.3.0/sign_message_lib.json#L15, # SignMessageLib `v1.4.1` (canonical): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.4.1/sign_message_lib.json#L7. declare -a -r SignMessageLib=( "0xA65387F16B013cf2Af4605Ad8aA5ec25a2cbA3a2" # SignMessageLib `v1.3.0` (canonical). "0x98FFBBF51bb33A056B08ddf711f289936AafF717" # SignMessageLib `v1.3.0` (eip155). "0x357147caf9C0cCa67DfA0CF5369318d8193c8407" # SignMessageLib `v1.3.0` (zksync). "0xd53cd0aB83D845Ac265BE939c57F53AD838012c9" # SignMessageLib `v1.4.1` (canonical). ) ``` This PR also fixes the chain ID for X Layer, which is `196` and not `195`. We also update the reference to the user interface, as OpenZeppelin has now published it here: [`safeutils.openzeppelin.com`](https://safeutils.openzeppelin.com). Lastly, we update the brand name of BNB Smart Chain and OP (Optimism). --------- Signed-off-by: Pascal Marco Caversaccio <pascal.caversaccio@hotmail.ch>
1 parent dd4e383 commit 761b4fa

File tree

2 files changed

+90
-7
lines changed

2 files changed

+90
-7
lines changed

README.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
[![License: AGPL-3.0-only](https://img.shields.io/badge/License-AGPL--3.0--only-blue)](https://www.gnu.org/licenses/agpl-3.0)
44

5+
> [!IMPORTANT]
6+
> This [PR](https://github.com/pcaversaccio/safe-tx-hashes-util/pull/20) introduces a _temporary_ patch to use the [Safe Client Gateway API](https://safe-client.safe.global/api) since the [Safe Transaction Service API](https://docs.safe.global/core-api/transaction-service-overview) is currently unavailable. Please checkout the `feat/use-safe-client-gateway` branch until further notice.
7+
58
```console
69
|)0/\/'T TR|\_|5T, \/3R1FY! 🫡
710
```
@@ -31,20 +34,20 @@ This Bash [script](./safe_hashes.sh) calculates the Safe transaction hashes by r
3134
- Base (identifier: `base`, chain ID: `8453`)
3235
- Base Sepolia (identifier: `base-sepolia`, chain ID: `84532`)
3336
- Blast (identifier: `blast`, chain ID: `81457`)
34-
- BSC (Binance Smart Chain) (identifier: `bsc`, chain ID: `56`)
37+
- BSC (BNB Smart Chain) (identifier: `bsc`, chain ID: `56`)
3538
- Celo (identifier: `celo`, chain ID: `42220`)
3639
- Ethereum (identifier: `ethereum`, chain ID: `1`)
3740
- Gnosis (identifier: `gnosis`, chain ID: `100`)
3841
- Gnosis Chiado (identifier: `gnosis-chiado`, chain ID: `10200`)
3942
- Linea (identifier: `linea`, chain ID: `59144`)
4043
- Mantle (identifier: `mantle`, chain ID: `5000`)
41-
- Optimism (identifier: `optimism`, chain ID: `10`)
44+
- OP (Optimism) (identifier: `optimism`, chain ID: `10`)
4245
- Polygon (identifier: `polygon`, chain ID: `137`)
4346
- Polygon zkEVM (identifier: `polygon-zkevm`, chain ID: `1101`)
4447
- Scroll (identifier: `scroll`, chain ID: `534352`)
4548
- Sepolia (identifier: `sepolia`, chain ID: `11155111`)
4649
- World Chain (identifier: `worldchain`, chain ID: `480`)
47-
- X Layer (identifier: `xlayer`, chain ID: `195`)
50+
- X Layer (identifier: `xlayer`, chain ID: `196`)
4851
- ZKsync Era (identifier: `zksync`, chain ID: `324`)
4952

5053
## Usage
@@ -269,10 +272,10 @@ Safe message hash: 0x1866b559f56261ada63528391b93a1fe8e2e33baf7cace94fc6b42202d1
269272
## Community-Maintained User Interface Implementations
270273

271274
> [!IMPORTANT]
272-
> Please be aware that user interface implementations may introduce additional trust assumptions, such as relying on `npm` dependencies that have not undergone thorough review. Always verify and cross-reference with the main [script](./safe_hashes.sh).
275+
> Please be aware that user interface implementations may introduce additional trust assumptions, such as relying on `npm` dependencies that have not undergone thorough review or a deployment process that could be compromised by an attacker. Always verify and cross-reference with the main [script](./safe_hashes.sh).
273276
274-
- [`safehashpreview.com`](https://www.safehashpreview.com):
275-
- Code: [`josepchetrit12/safe-tx-hashes-util`](https://github.com/josepchetrit12/safe-tx-hashes-util)
277+
- [`safeutils.openzeppelin.com`](https://safeutils.openzeppelin.com):
278+
- Code: [`OpenZeppelin/safe-utils`](https://github.com/OpenZeppelin/safe-utils)
276279
- Authors: [`josepchetrit12`](https://github.com/josepchetrit12), [`xaler5`](https://github.com/xaler5)
277280

278281
[^1]: It is theoretically possible to query transactions prior to the first signature; however, this functionality is not incorporated into the main [script](https://github.com/pcaversaccio/safe-tx-hashes-util/blob/main/safe_hashes.sh). To do so, you would proceed through the [Safe UI](https://app.safe.global) as usual, stopping at the page where the transaction is signed or executed. At this point, the action is recorded in the [Safe Transaction Service API](https://docs.safe.global/core-api/transaction-service-overview), allowing you to retrieve the unsigned transaction by setting `trusted=false` in the [API](https://docs.safe.global/core-api/transaction-service-reference/mainnet#List-a-Safe's-Multisig-Transactions) query within your Bash script. For example, you might use a query such as: `https://safe-transaction-arbitrum.safe.global/api/v1/safes/0xB24A3AA250E209bC95A4a9afFDF10c6D099B3d34/multisig-transactions/?trusted=false&nonce=4`. This decision to not implement this feature avoids potential confusion caused by unsigned transactions in the queue, especially when multiple transactions share the same nonce, making it unclear which one to act upon. If this feature aligns with your needs, feel free to fork the [script](https://github.com/pcaversaccio/safe-tx-hashes-util/blob/main/safe_hashes.sh) and modify it as necessary.

safe_hashes.sh

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,66 @@ readonly SAFE_TX_TYPEHASH_OLD="0x14d461bc7412367e924637b363c7bf29b8f47e2f84869f4
7777
# See: https://github.com/safe-global/safe-smart-account/blob/febab5e4e859e6e65914f17efddee415e4992961/contracts/libraries/SignMessageLib.sol#L12-L13.
7878
readonly SAFE_MSG_TYPEHASH="0x60b3cbf8b4a223d68d641b3b6ddf9a298e7f33710cf3d3a9d1146b5a6150fbca"
7979

80+
# Set the trusted (i.e. for delegate calls) `MultiSend` addresses:
81+
# MultiSend `v1.1.1` (canonical): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.1.1/multi_send.json#L7,
82+
# MultiSend `v1.3.0` (canonical): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.3.0/multi_send.json#L7,
83+
# MultiSend `v1.3.0` (eip155): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.3.0/multi_send.json#L11,
84+
# MultiSend `v1.3.0` (zksync): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.3.0/multi_send.json#L15,
85+
# Multisend `v1.4.1` (canonical): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.4.1/multi_send.json#L7.
86+
declare -a -r MultiSend=(
87+
"0x8D29bE29923b68abfDD21e541b9374737B49cdAD" # MultiSend `v1.1.1` (canonical).
88+
"0xA238CBeb142c10Ef7Ad8442C6D1f9E89e07e7761" # MultiSend `v1.3.0` (canonical).
89+
"0x998739BFdAAdde7C933B942a68053933098f9EDa" # MultiSend `v1.3.0` (eip155).
90+
"0x0dFcccB95225ffB03c6FBB2559B530C2B7C8A912" # MultiSend `v1.3.0` (zksync).
91+
"0x38869bf66a61cF6bDB996A6aE40D5853Fd43B526" # MultiSend `v1.4.1` (canonical).
92+
)
93+
94+
# Set the trusted (i.e. for delegate calls) `MultiSendCallOnly` addresses:
95+
# MultiSendCallOnly `v1.3.0` (canonical): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.3.0/multi_send_call_only.json#L7,
96+
# MultiSendCallOnly `v1.3.0` (eip155): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.3.0/multi_send_call_only.json#L11,
97+
# MultiSendCallOnly `v1.3.0` (zksync): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.3.0/multi_send_call_only.json#L15,
98+
# MultiSendCallOnly `v1.4.1` (canonical): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.4.1/multi_send_call_only.json#L7.
99+
declare -a -r MultiSendCallOnly=(
100+
"0x40A2aCCbd92BCA938b02010E17A5b8929b49130D" # MultiSendCallOnly `v1.3.0` (canonical).
101+
"0xA1dabEF33b3B82c7814B6D82A79e50F4AC44102B" # MultiSendCallOnly `v1.3.0` (eip155).
102+
"0xf220D3b4DFb23C4ade8C88E526C1353AbAcbC38F" # MultiSendCallOnly `v1.3.0` (zksync).
103+
"0x9641d764fc13c8B624c04430C7356C1C7C8102e2" # MultiSendCallOnly `v1.4.1` (canonical).
104+
)
105+
106+
# Set the trusted (i.e. for delegate calls) `SafeMigration` addresses:
107+
# SafeMigration `v1.4.1` (canonical): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.4.1/safe_migration.json#L7.
108+
declare -a -r SafeMigration=(
109+
"0x526643F69b81B008F46d95CD5ced5eC0edFFDaC6" # SafeMigration `v1.4.1` (canonical).
110+
)
111+
112+
# Set the trusted (i.e. for delegate calls) `SafeToL2Migration` addresses:
113+
# SafeToL2Migration `v1.4.1` (canonical): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.4.1/safe_to_l2_migration.json#L7.
114+
declare -a -r SafeToL2Migration=(
115+
"0xfF83F6335d8930cBad1c0D439A841f01888D9f69" # SafeToL2Migration `v1.4.1` (canonical).
116+
)
117+
118+
# Set the trusted (i.e. for delegate calls) `SignMessageLib` addresses:
119+
# SignMessageLib `v1.3.0` (canonical): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.3.0/sign_message_lib.json#L7,
120+
# SignMessageLib `v1.3.0` (eip155): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.3.0/sign_message_lib.json#L11,
121+
# SignMessageLib `v1.3.0` (zksync): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.3.0/sign_message_lib.json#L15,
122+
# SignMessageLib `v1.4.1` (canonical): https://github.com/safe-global/safe-deployments/blob/4e25b09f62a4acec92b4ebe6b8ae496b3852d440/src/assets/v1.4.1/sign_message_lib.json#L7.
123+
declare -a -r SignMessageLib=(
124+
"0xA65387F16B013cf2Af4605Ad8aA5ec25a2cbA3a2" # SignMessageLib `v1.3.0` (canonical).
125+
"0x98FFBBF51bb33A056B08ddf711f289936AafF717" # SignMessageLib `v1.3.0` (eip155).
126+
"0x357147caf9C0cCa67DfA0CF5369318d8193c8407" # SignMessageLib `v1.3.0` (zksync).
127+
"0xd53cd0aB83D845Ac265BE939c57F53AD838012c9" # SignMessageLib `v1.4.1` (canonical).
128+
)
129+
130+
# Set the trusted (i.e. for delegate calls) contract addresses.
131+
# See: https://github.com/safe-global/safe-transaction-service/blob/c3b42f0bebff74b99fcdd958aee54b149e27eca5/safe_transaction_service/contracts/management/commands/setup_safe_contracts.py#L10-L16.
132+
declare -A -r TRUSTED_FOR_DELEGATE_CALL=(
133+
["MultiSend"]="${MultiSend[@]}"
134+
["MultiSendCallOnly"]="${MultiSendCallOnly[@]}"
135+
["SafeMigration"]="${SafeMigration[@]}"
136+
["SafeToL2Migration"]="${SafeToL2Migration[@]}"
137+
["SignMessageLib"]="${SignMessageLib[@]}"
138+
)
139+
80140
# Define the supported networks from the Safe transaction service.
81141
# See https://docs.safe.global/advanced/smart-account-supported-networks?service=Transaction+Service.
82142
declare -A -r API_URLS=(
@@ -124,7 +184,7 @@ declare -A -r CHAIN_IDS=(
124184
["scroll"]="534352"
125185
["sepolia"]="11155111"
126186
["worldchain"]="480"
127-
["xlayer"]="195"
187+
["xlayer"]="196"
128188
["zksync"]="324"
129189
)
130190

@@ -425,6 +485,23 @@ validate_nonce() {
425485
fi
426486
}
427487

488+
# Utility function to warn the user if the transaction includes an untrusted delegate call.
489+
warn_if_delegate_call() {
490+
local operation="$1"
491+
local to="$2"
492+
493+
# Warn the user if `operation` equals `1`, implying a `delegatecall`, and if the `to` address is untrusted.
494+
# See: https://github.com/safe-global/safe-smart-account/blob/34359e8305d618b7d74e39ed370a6b59ab14f827/contracts/libraries/Enum.sol.
495+
if [[ "$operation" -eq 1 && ! " ${TRUSTED_FOR_DELEGATE_CALL[@]} " =~ " ${to} " ]]; then
496+
echo
497+
cat <<EOF
498+
${BOLD}${RED}WARNING: The transaction includes an untrusted delegate call to address $to!
499+
This may lead to unexpected behaviour or vulnerabilities.
500+
Please review it carefully before you sign!${RESET}
501+
EOF
502+
fi
503+
}
504+
428505
# Utility function to validate the message file.
429506
validate_message_file() {
430507
local message_file="$1"
@@ -606,6 +683,9 @@ EOF
606683
local nonce=$(echo "$response" | jq -r ".results[$idx].nonce // \"0\"")
607684
local data_decoded=$(echo "$response" | jq -r ".results[$idx].dataDecoded // \"0x\"")
608685

686+
# Warn the user if the transaction includes an untrusted delegate call.
687+
warn_if_delegate_call "$operation" "$to"
688+
609689
# Calculate and display the hashes.
610690
echo "==================================="
611691
echo "= Selected Network Configurations ="

0 commit comments

Comments
 (0)