Skip to content

Commit 3356469

Browse files
committed
Fix intent signing for malleable payloads
1 parent c832e12 commit 3356469

File tree

2 files changed

+50
-66
lines changed

2 files changed

+50
-66
lines changed

intent_config.go

Lines changed: 22 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -260,20 +260,20 @@ func CreateIntentConfiguration(mainSigner common.Address, calls []*v3.CallsPaylo
260260
func CreateIntentConfigurationWithMalleableSapient(
261261
ctx context.Context,
262262
mainSigner common.Address,
263-
calls []*v3.CallsPayload,
263+
payloads []*v3.CallsPayload,
264264
configs []MalleableSapientConfig,
265265
) (*v3.WalletConfig, error) {
266-
if len(calls) == 0 {
266+
if len(payloads) == 0 {
267267
return nil, fmt.Errorf("calls cannot be empty")
268268
}
269269

270-
if len(configs) != len(calls) {
271-
return nil, fmt.Errorf("configs length (%d) must match calls length (%d)", len(configs), len(calls))
270+
if len(configs) != len(payloads) {
271+
return nil, fmt.Errorf("configs length (%d) must match payloads length (%d)", len(configs), len(payloads))
272272
}
273273

274274
var callsWithoutMalleableSapient []*v3.CallsPayload
275275
var sapientSignerLeaves []v3.WalletConfigTree
276-
for i, callPayload := range calls {
276+
for i, callPayload := range payloads {
277277
config := configs[i]
278278

279279
// Skip if address is zero address. Will be handled by CreateIntentConfiguration.
@@ -308,33 +308,37 @@ func CreateIntentConfigurationWithMalleableSapient(
308308
}
309309

310310
// Remaining calls go to CreateIntentConfiguration
311-
return CreateIntentConfiguration(mainSigner, callsWithoutMalleableSapient, sapientSignerTree)
311+
return createIntentConfiguration(mainSigner, callsWithoutMalleableSapient, sapientSignerTree)
312+
}
313+
314+
type SignerSignature struct {
315+
Address common.Address
316+
Signature []byte
317+
Type core.SignerSignatureType
312318
}
313319

314320
// `GetIntentConfigurationSignature` creates a signature for the intent configuration that can be used to bypass chain ID validation.
315-
// The signature is based on the transaction bundle digests only.
321+
// `SignerSignatures` can be nil when executing a preapproved static payload.
316322
func GetIntentConfigurationSignature(
317-
mainSigner common.Address,
318-
calls []*v3.CallsPayload,
323+
ctx context.Context,
324+
config *v3.WalletConfig,
325+
signerSignatures []*SignerSignature,
319326
) ([]byte, error) {
320-
// Default case without any sapient signer
321-
config, err := CreateIntentConfiguration(mainSigner, calls, nil)
322-
if err != nil {
323-
return nil, err
324-
}
325-
326327
// spew.Dump(config)
327328
// spew.Dump(config.Tree)
328329

329330
signingFunc := func(ctx context.Context, signer core.Signer, _ []core.SignerSignature) (core.SignerSignatureType, []byte, error) {
330-
// For mainSigner or other signers, we don't provide a signature here.
331-
// This will result in an AddressLeaf or NodeLeaf in the signature tree.
331+
for _, signerSignature := range signerSignatures {
332+
if signer.Address == signerSignature.Address {
333+
return signerSignature.Type, signerSignature.Signature, nil
334+
}
335+
}
332336
return 0, nil, nil
333337
}
334338

335339
// Build the signature using BuildNoChainIDSignature, which allows us to inject custom signatures via SigningFunction.
336340
// Set validateSigningPower to false, as we are not necessarily providing signatures for all parts of the config.
337-
sig, err := config.BuildRegularSignature(context.Background(), signingFunc, false)
341+
sig, err := config.BuildRegularSignature(ctx, signingFunc, false)
338342
if err != nil {
339343
return nil, fmt.Errorf("failed to build regular signature: %w", err)
340344
}
@@ -374,42 +378,3 @@ func GetIntentConfigurationSignature(
374378

375379
return data, nil
376380
}
377-
378-
// // replaceSapientSignerWithNodeInConfigTree recursively traverses the WalletConfigTree.
379-
// func replaceSapientSignerWithNodeInConfigTree(tree v3.WalletConfigTree) v3.WalletConfigTree {
380-
// if tree == nil {
381-
// return nil
382-
// }
383-
384-
// switch node := tree.(type) {
385-
// case *v3.WalletConfigTreeNode:
386-
// // Recursively call on left and right children
387-
// left := replaceSapientSignerWithNodeInConfigTree(node.Left)
388-
// right := replaceSapientSignerWithNodeInConfigTree(node.Right)
389-
390-
// if left == node.Left && right == node.Right {
391-
// return node
392-
// }
393-
// return &v3.WalletConfigTreeNode{Left: left, Right: right}
394-
395-
// case *v3.WalletConfigTreeNestedLeaf:
396-
// // Recursively call on the inner tree
397-
// innerTree := replaceSapientSignerWithNodeInConfigTree(node.Tree)
398-
399-
// if innerTree == node.Tree { // Check for pointer equality
400-
// return node // No change, return original
401-
// }
402-
// return &v3.WalletConfigTreeNestedLeaf{
403-
// Weight: node.Weight,
404-
// Threshold: node.Threshold,
405-
// Tree: innerTree,
406-
// }
407-
408-
// case *v3.WalletConfigTreeSapientSignerLeaf:
409-
// // This is the target node type to replace
410-
// return &v3.WalletConfigTreeNodeLeaf{Node: node.ImageHash()}
411-
412-
// default:
413-
// return tree
414-
// }
415-
// }

intent_config_test.go

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,7 @@ func TestCreateIntentConfigurationWithMalleableSapient_ZeroAddressSkipsLeaf(t *t
940940
}
941941

942942
func TestGetIntentConfigurationSignature(t *testing.T) {
943+
ctx := context.Background()
943944
// Create test wallets
944945
eoa1, err := ethwallet.NewWalletFromRandomEntropy()
945946
require.NoError(t, err)
@@ -967,7 +968,7 @@ func TestGetIntentConfigurationSignature(t *testing.T) {
967968
require.NoError(t, err)
968969

969970
// Create the signature
970-
signature, err := sequence.GetIntentConfigurationSignature(eoa1.Address(), []*v3.CallsPayload{&payload})
971+
signature, err := sequence.GetIntentConfigurationSignature(ctx, config, nil)
971972
require.NoError(t, err)
972973

973974
// fmt.Println("==> signature", common.Bytes2Hex(signature))
@@ -1042,10 +1043,14 @@ func TestGetIntentConfigurationSignature(t *testing.T) {
10421043
}, big.NewInt(0), big.NewInt(0))
10431044

10441045
// Create signatures for each payload as separate batches
1045-
sig1, err := sequence.GetIntentConfigurationSignature(eoa1.Address(), []*v3.CallsPayload{&payload1})
1046+
config1, err := sequence.CreateIntentConfiguration(eoa1.Address(), []*v3.CallsPayload{&payload1}, nil)
1047+
require.NoError(t, err)
1048+
sig1, err := sequence.GetIntentConfigurationSignature(ctx, config1, nil)
10461049
require.NoError(t, err)
10471050

1048-
sig2, err := sequence.GetIntentConfigurationSignature(eoa1.Address(), []*v3.CallsPayload{&payload2})
1051+
config2, err := sequence.CreateIntentConfiguration(eoa1.Address(), []*v3.CallsPayload{&payload2}, nil)
1052+
require.NoError(t, err)
1053+
sig2, err := sequence.GetIntentConfigurationSignature(ctx, config2, nil)
10491054
require.NoError(t, err)
10501055

10511056
// Verify signatures are different
@@ -1054,18 +1059,24 @@ func TestGetIntentConfigurationSignature(t *testing.T) {
10541059

10551060
t.Run("same transactions produce same signatures", func(t *testing.T) {
10561061
// Use the payload directly
1057-
sig1, err := sequence.GetIntentConfigurationSignature(eoa1.Address(), []*v3.CallsPayload{&payload})
1062+
config1, err := sequence.CreateIntentConfiguration(eoa1.Address(), []*v3.CallsPayload{&payload}, nil)
1063+
require.NoError(t, err)
1064+
sig1, err := sequence.GetIntentConfigurationSignature(ctx, config1, nil)
10581065
require.NoError(t, err)
10591066

1060-
sig2, err := sequence.GetIntentConfigurationSignature(eoa1.Address(), []*v3.CallsPayload{&payload})
1067+
config2, err := sequence.CreateIntentConfiguration(eoa1.Address(), []*v3.CallsPayload{&payload}, nil)
1068+
require.NoError(t, err)
1069+
sig2, err := sequence.GetIntentConfigurationSignature(ctx, config2, nil)
10611070
require.NoError(t, err)
10621071

1063-
// Verify signatures are the same
1072+
// Verify configs and signatures are the same
1073+
require.Equal(t, config1.Tree, config2.Tree, "same transactions should produce same configuration")
10641074
require.Equal(t, sig1, sig2, "same transactions should produce same signatures")
10651075
})
10661076
}
10671077

10681078
func TestGetIntentConfigurationSignature_MultipleTransactions(t *testing.T) {
1079+
ctx := context.Background()
10691080
// Create test wallets
10701081
eoa1, err := ethwallet.NewWalletFromRandomEntropy()
10711082
require.NoError(t, err)
@@ -1093,7 +1104,9 @@ func TestGetIntentConfigurationSignature_MultipleTransactions(t *testing.T) {
10931104
}, big.NewInt(0), big.NewInt(0))
10941105

10951106
// Create a signature
1096-
sig, err := sequence.GetIntentConfigurationSignature(eoa1.Address(), []*v3.CallsPayload{&payload1})
1107+
config, err := sequence.CreateIntentConfiguration(eoa1.Address(), []*v3.CallsPayload{&payload1}, nil)
1108+
require.NoError(t, err)
1109+
sig, err := sequence.GetIntentConfigurationSignature(ctx, config, nil)
10971110
require.NoError(t, err)
10981111

10991112
// Convert the full signature into a hex string.
@@ -1104,6 +1117,7 @@ func TestGetIntentConfigurationSignature_MultipleTransactions(t *testing.T) {
11041117
}
11051118

11061119
func TestIntentTransactionToGuestModuleDeployAndCall(t *testing.T) {
1120+
ctx := context.Background()
11071121
// Create normal txn of: callmockContract.testCall(55, 0x112255)
11081122
callmockContract := testChain.UniDeploy(t, "WALLET_CALL_RECV_MOCK", 0)
11091123
calldata1, err := callmockContract.Encode("setRevertFlag", false)
@@ -1164,7 +1178,9 @@ func TestIntentTransactionToGuestModuleDeployAndCall(t *testing.T) {
11641178
require.NotZero(t, mainSigner)
11651179

11661180
// Generate a configuration signature for the batch.
1167-
intentConfigSig, err := sequence.GetIntentConfigurationSignature(mainSigner, []*v3.CallsPayload{&payload})
1181+
config, err := sequence.CreateIntentConfiguration(mainSigner, []*v3.CallsPayload{&payload}, nil)
1182+
require.NoError(t, err)
1183+
intentConfigSig, err := sequence.GetIntentConfigurationSignature(ctx, config, nil)
11681184
require.NoError(t, err)
11691185

11701186
// fmt.Println("==> bundle.Digest", bundle.Digest().Hash)
@@ -1238,6 +1254,7 @@ func TestIntentTransactionToGuestModuleDeployAndCall(t *testing.T) {
12381254
}
12391255

12401256
func TestIntentTransactionToGuestModuleDeployAndCallMultiplePayloads(t *testing.T) {
1257+
ctx := context.Background()
12411258
// Create normal txn of: callmockContract.testCall(55, 0x112255) for first chain
12421259
callmockContract := testChain.UniDeploy(t, "WALLET_CALL_RECV_MOCK", 0)
12431260
calldata1, err := callmockContract.Encode("setRevertFlag", false)
@@ -1322,7 +1339,9 @@ func TestIntentTransactionToGuestModuleDeployAndCallMultiplePayloads(t *testing.
13221339
require.NotZero(t, mainSigner)
13231340

13241341
// Generate a configuration signature for both batches
1325-
intentConfigSig, err := sequence.GetIntentConfigurationSignature(mainSigner, payloads)
1342+
config, err := sequence.CreateIntentConfiguration(mainSigner, payloads, nil)
1343+
require.NoError(t, err)
1344+
intentConfigSig, err := sequence.GetIntentConfigurationSignature(ctx, config, nil)
13261345
require.NoError(t, err)
13271346
fmt.Printf("--- Intent Config Signature (for all payloads) ---\n%s\n", common.Bytes2Hex(intentConfigSig))
13281347

0 commit comments

Comments
 (0)