Skip to content

fix(protocol-kit): handle CONTRACT_SIGNATURE in toSafeTransactionType - #1301

Open
indexedfit wants to merge 1 commit into
safe-global:mainfrom
indexedfit:fix/contract-signature-toSafeTransactionType
Open

fix(protocol-kit): handle CONTRACT_SIGNATURE in toSafeTransactionType#1301
indexedfit wants to merge 1 commit into
safe-global:mainfrom
indexedfit:fix/contract-signature-toSafeTransactionType

Conversation

@indexedfit

Copy link
Copy Markdown

Summary

  • Fix toSafeTransactionType in Safe.ts to correctly handle CONTRACT_SIGNATURE confirmations from the Safe Transaction Service
  • When signatureType === 'CONTRACT_SIGNATURE', extract the inner signature data from the stored format and create EthSafeSignature with isContractSignature=true
  • Without this fix, buildSignatureBytes treats contract signatures as EOA signatures and dumps the full stored blob (header + data) as a flat 65-byte signature, which corrupts the combined signature layout and causes GS021 errors during on-chain execution

Closes #1300

Problem

The Safe Transaction Service stores contract signatures in a specific format:

r(32 bytes) + s(32 bytes) + v(1 byte) + dataLength(32 bytes) + data(N bytes)

When toSafeTransactionType reconstructs a SafeTransaction from TX Service confirmations, it creates EthSafeSignature(owner, signature) for ALL confirmation types — including CONTRACT_SIGNATURE. Since isContractSignature defaults to false, buildSignatureBytes later treats these as EOA signatures and emits the entire stored blob as flat data in the constant part, instead of splitting it into a constant part (with a dynamic offset) and a dynamic part.

This breaks checkNSignatures on-chain when there are multiple signers, because the second signer's 65-byte chunk overlaps with the first signer's oversized blob.

Fix

For CONTRACT_SIGNATURE confirmations:

  1. Read the s value (bytes 32–63) from the stored signature to find the offset to the length-prefixed inner data
  2. Read the data length at that offset
  3. Extract just the inner signature data
  4. Create EthSafeSignature(owner, innerData, true) so buildSignatureBytes correctly handles the static/dynamic split

Test plan

  • Existing protocol-kit tests pass
  • Manual test: execute a multi-signer Safe transaction where one signer is a smart contract (e.g., passkey signer proxy) — the Safe web UI should no longer produce GS021

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Feb 14, 2026

Copy link
Copy Markdown

CLA Assistant Lite bot All contributors have signed the CLA ✍️ ✅

@indexedfit

Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

@indexedfit
indexedfit force-pushed the fix/contract-signature-toSafeTransactionType branch from d754891 to d7a40be Compare February 14, 2026 11:24
`toSafeTransactionType` creates `EthSafeSignature` with
`isContractSignature=false` for all confirmations, including
CONTRACT_SIGNATURE types from the Safe Transaction Service.

This causes `buildSignatureBytes` to concatenate the full stored
signature blob (r+s+v+dynamic data) as-is instead of properly
splitting it into static part (r, s=offset, v=0) and dynamic part
(length + inner data). For multi-owner Safes, this breaks the
combined signatures layout — the second signer's 65-byte constant
part overlaps with the first signer's dynamic data, causing
GS021 ("Invalid contract signature provided") on execution.

The fix detects CONTRACT_SIGNATURE confirmations and:
1. Extracts the inner signature data from the stored format
   using the s offset (which points to the length-prefixed data)
2. Creates EthSafeSignature with isContractSignature=true
3. This lets buildSignatureBytes properly compute dynamic offsets

Affects any Safe with EIP-1271 contract signature owners (passkey
signers via SafeWebAuthnSignerProxy, nested Safes, etc.) when
executing transactions that include contract signature confirmations
fetched from the Safe Transaction Service.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@indexedfit
indexedfit force-pushed the fix/contract-signature-toSafeTransactionType branch from d7a40be to 77fdb61 Compare February 14, 2026 11:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

protocol-kit: toSafeTransactionType doesn't handle CONTRACT_SIGNATURE confirmations correctly

1 participant