Skip to content

Commit 5465a98

Browse files
authored
Merge pull request #2489 from AmbireTech/feature/safe-delegation-warnings-improvements
Add: display a warning when a delegate call is detected during execute as well
2 parents 15b1df0 + 389a667 commit 5465a98

3 files changed

Lines changed: 74 additions & 2 deletions

File tree

src/libs/humanizer/erc7730/humanize.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,17 @@ const getCalldataFormatMatch = (
378378
return null
379379
}
380380

381+
const getSafeExecTransactionWarnings = (match: DescriptorFormatMatch): HumanizerWarning[] => {
382+
const fragment = getFunctionFragment(match.formatKey)
383+
if (fragment?.name !== 'execTransaction') return []
384+
385+
const operation = toBigIntOrNull(match.values.operation)
386+
const to = match.values.to
387+
if (operation === null || typeof to !== 'string') return []
388+
389+
return getDelegateCallWarning(operation, to)
390+
}
391+
381392
const getTypedMessageFormatMatch = (
382393
message: Message,
383394
descriptor: Erc7730Descriptor
@@ -1557,6 +1568,7 @@ export const humanizeCallWithErc7730 = (
15571568
fullVisualization: visualizationWithNativeValue,
15581569
warnings: dedupeWarnings([
15591570
...getSafeCallWarnings(call, accountAddr),
1571+
...getSafeExecTransactionWarnings(match),
15601572
...getNativeValueWarnings(visualizationWithNativeValue, nativeAssetSymbol)
15611573
])
15621574
}

src/libs/humanizer/index.test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2251,6 +2251,60 @@ describe('ERC-7730 descriptors', () => {
22512251
})
22522252
})
22532253

2254+
test('keeps the Safe delegatecall warning after ERC-7730 execTransaction humanization', () => {
2255+
const safeProxy = '0x043faB48aCC3DD066fcf33cA3e3f2E2Ba5be9018'
2256+
const recipeExecutor = '0xc91305DdE651c899EF8eE1D0C33E7dab1B5ABF0D'
2257+
const execTransactionData = new ethers.Interface(execTransactionAbi).encodeFunctionData(
2258+
'execTransaction',
2259+
[recipeExecutor, 0, '0x0c2c8750', 1, 0, 0, 0, ZeroAddress, ZeroAddress, '0x']
2260+
)
2261+
const safeExecAccountOp: AccountOp = {
2262+
...accountOp,
2263+
chainId: 8453n,
2264+
calls: [
2265+
{
2266+
to: safeProxy,
2267+
value: 0n,
2268+
data: execTransactionData
2269+
}
2270+
]
2271+
}
2272+
const irCalls = humanizeAccountOp(safeExecAccountOp, {
2273+
erc7730Descriptors: {
2274+
0: {
2275+
descriptor: {
2276+
display: {
2277+
formats: {
2278+
'execTransaction(address to,uint256 value,bytes data,uint8 operation,uint256 safeTxGas,uint256 baseGas,uint256 gasPrice,address gasToken,address refundReceiver,bytes signatures)':
2279+
{
2280+
intent: 'sign multisig operation',
2281+
fields: [
2282+
{ path: 'operation', label: 'Operation type' },
2283+
{
2284+
path: 'data',
2285+
label: 'Transaction',
2286+
format: 'calldata',
2287+
params: { calleePath: 'to' }
2288+
}
2289+
]
2290+
}
2291+
}
2292+
}
2293+
}
2294+
}
2295+
}
2296+
})
2297+
2298+
expect(irCalls[0]?.warnings).toEqual([
2299+
getWarning(
2300+
'You are about to delegate permissions to a contract not whitelisted by Safe. Proceed with caution',
2301+
'SAFE{WALLET}_DELEGATE_CALL',
2302+
undefined,
2303+
recipeExecutor
2304+
)
2305+
])
2306+
})
2307+
22542308
test('humanizes Safe setup calldata nested in a factory initializer with ERC-7730', () => {
22552309
const safeProxyFactory = '0x4e1DCf7AD4e460CfD30791CCC4F9c8a4f820ec67'
22562310
const safeSingleton = '0x41675c099f32341bf84bfc5382af534df5c7461a'

src/libs/humanizer/modules/Safe/safe.test.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { AccountOp } from '../../../accountOp/accountOp'
33
import { HumanizerMeta } from '../../interfaces'
44
import { compareHumanizerVisualizations } from '../../testHelpers'
55
import { getAction, getAddressVisualization, getLabel } from '../../utils'
6-
import SafeModule from '.'
6+
import SafeModule from './'
77

88
const transactions = [
99
{
@@ -12,6 +12,11 @@ const transactions = [
1212
data: '0x6a7612020000000000000000000000000bbbead62f7647ae8323d2cb243a0db74b7c2b800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb0000000000000000000000006969174fd72466430a46e18234d0b530c9fd5f49000000000000000000000000000000000000000000000000016345785d8a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000820000000000000000000000004206d534CD8aCF86ba0eeC5ABb3c0B98EF7728dC000000000000000000000000000000000000000000000000000000000000000001a2df9e98285798df2bc8ba5368202ed950e153dee458fa9264dabf03722203d60a6ec8fc34f6dd0c745ef498795bf6bb00f32aec006af6fc94df3ac4b8284f1c1b000000000000000000000000000000000000000000000000000000000000'
1313
}
1414
]
15+
const delegateCallTransaction = {
16+
to: '0x043faB48aCC3DD066fcf33cA3e3f2E2Ba5be9018',
17+
value: 0n,
18+
data: '0x6a761202000000000000000000000000c91305dde651c899ef8ee1d0c33e7dab1b5abf0d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000025aa0f9a42ee4ea2dc7f3c9ff02f558dcb0445a3000000000000000000000000000000000000000000000000000000000000088000000000000000000000000000000000000000000000000000000000000007040c2c8750000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000038000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000044000000000000000000000000000000000000000000000000000000000000000104161766556334f70656e5265636970650000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000572000000000000000000000000d8293ad21678c6f09da139b4b62d38e514a03b780000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e20fcbdbffc4dd138ce8b2e6fbb6cb49777ad64d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002710000000000000000000000000d8293ad21678c6f09da139b4b62d38e514a03b780000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000e20fcbdbffc4dd138ce8b2e6fbb6cb49777ad64d00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002fc33bf00000000000000000000000000000000000000000000000000000000009e9290b100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041000000000000000000000000d8293ad21678c6f09da139b4b62d38e514a03b7800000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000'
19+
}
1520
const accountOp: AccountOp = {
1621
accountAddr: '0x6969174FD72466430a46e18234D0b530c9FD5f49',
1722
chainId: 42161n,
@@ -23,7 +28,8 @@ const accountOp: AccountOp = {
2328
calls: [],
2429
gasLimit: null,
2530
signature: null,
26-
gasFeePayment: null
31+
gasFeePayment: null,
32+
id: 'testSafe'
2733
// This is fed into the humanizer to help visualize the accountOp
2834
// This can contain info like the value of specific share tokens at the time of signing,
2935
// or any other data that needs to otherwise be retrieved in an async manner and/or needs to be

0 commit comments

Comments
 (0)