diff --git a/packages/snap/CHANGELOG.md b/packages/snap/CHANGELOG.md index 3025bde4..f912f95b 100644 --- a/packages/snap/CHANGELOG.md +++ b/packages/snap/CHANGELOG.md @@ -11,6 +11,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Validate that account IDs passed to `keyring_setSelectedAccounts` belong to the snap, rejecting unknown IDs with `InvalidParamsError` ([#604](https://github.com/MetaMask/snap-solana-wallet/pull/604)) +### Fixed + +- **BREAKING:** `signTransaction` and `signAllTransactions` now preserve the original `messageBytes` of a compiled `VersionedTransaction` verbatim and only append the account's signature (#[0000](https://github.com/MetaMask/snap-solana-wallet/pull/0000)) + - Previously, an unsigned compiled transaction was silently decompiled and recompiled, which canonicalised the account order and remapped instruction account indices — breaking multi-party signing flows. + ## [2.8.0] ### Added diff --git a/packages/snap/snap.manifest.json b/packages/snap/snap.manifest.json index 26c0286f..d910258e 100644 --- a/packages/snap/snap.manifest.json +++ b/packages/snap/snap.manifest.json @@ -7,7 +7,7 @@ "url": "https://github.com/MetaMask/snap-solana-wallet.git" }, "source": { - "shasum": "AzXzPnYm37l2ijVy4ZM6GRu3DouI8hs75QHbfXJ/sBQ=", + "shasum": "2hll3bYQPDYuEYTjkPO0FSfFD9j7c/++LaL9SHU1BrI=", "location": { "npm": { "filePath": "dist/bundle.js", diff --git a/packages/snap/src/core/services/signer/Signer.ts b/packages/snap/src/core/services/signer/Signer.ts index 51211f2e..e2bc8623 100644 --- a/packages/snap/src/core/services/signer/Signer.ts +++ b/packages/snap/src/core/services/signer/Signer.ts @@ -95,29 +95,14 @@ export class Signer { ); } - const isUnsigned = Object.values( - transactionMessageOrTransaction.signatures, - ).every((signature) => !signature); - - // It's an unsigned transaction, grab the message from the transaction and apply the same logic as above. - if (isUnsigned) { - const { messageBytes } = transactionMessageOrTransaction; - - const transactionMessageFromUnsignedTransaction = - await fromBytesToCompilableTransactionMessage( - messageBytes, - rpc, - config, - ); - - return this.#prepareAndPartiallySignTransactionMessage( - transactionMessageFromUnsignedTransaction, - account, - network, - ); - } - - // It's a partially signed transaction, so we cannot alter its content, and we add the account's signature. + // It's a compiled transaction (either unsigned or partially signed). + // Per the Wallet Standard `signTransaction` contract, we MUST NOT mutate + // the message bytes — only append the account's signature. Decompiling and + // recompiling here would canonicalise the account ordering and remap + // instruction account indices, breaking multi-party signing flows where + // a counterparty has already signed the original bytes + // + // See: https://consensyssoftware.atlassian.net/browse/WPN-1035 return this.#partiallySignTransaction( transactionMessageOrTransaction, account,