You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
EndorseSpendView in both token/services/ttx/multisig/spend.go and
token/services/ttx/boolpolicy/spend.go received a transaction from the
initiator and signed it without checking that the transaction actually
consumed the token referenced by the SpendRequest the co-owner
approved. The multisig variant carried an explicit
'TODO: check tx matches request' marker; the policy variant had the
same gap without a marker.
A malicious or buggy initiator could ask a co-owner to approve a
SpendRequest for one token and then deliver a transaction that consumes
a different token co-owned by the same group. The co-owner would sign
the substituted transaction with no diagnostic, breaking the consent
property that multisig and AND-policy spends rely on.
This change adds a verifySpendTxMatchesRequest helper in each package.
After ttx.ReceiveTransaction returns, the helper extracts the input
ids from the transaction's audit record and rejects the flow before
EndorseView is invoked unless every input id equals
request.Token.Id. The comparison rule is split into a pure helper
verifyInputIDsMatchExpected so it can be unit-tested without
constructing a full ttx.Transaction.
Documentation in docs/services/ttx.md gains a new 'Spend Coordination
Wire Flow' section with a Mermaid diagram describing the request,
delivery, and verification phases shared by the multisig and policy
variants.
Closes#1682
Signed-off-by: SuyashAlphaC <suyashagrawal862@gmail.com>
Co-owners run `EndorseSpendView` (via `EndorseSpend`) on their side, which ACKs the spend request and then endorses the assembled transaction.
210
210
211
+
#### Spend Coordination Wire Flow
212
+
213
+
The same coordination protocol is implemented in `token/services/ttx/multisig/spend.go` (for AND multisig) and in `token/services/ttx/boolpolicy/spend.go` (for AND policies). Both follow the shape below; the responder must verify that the assembled transaction actually consumes the token referenced by the `SpendRequest` it approved.
214
+
215
+
```mermaid
216
+
sequenceDiagram
217
+
autonumber
218
+
participant I as Initiator (RequestSpendView)
219
+
participant R as Co-owner (EndorseSpendView)
220
+
221
+
rect rgba(230, 230, 250, 0.35)
222
+
Note over I,R: Phase 1 - Spend approval request
223
+
I->>R: SpendRequest{Token: UnspentToken to spend}
224
+
R->>R: ReceiveSpendRequest, decide to approve
225
+
R-->>I: SpendResponse{}
226
+
end
227
+
228
+
rect rgba(255, 245, 238, 0.5)
229
+
Note over I,R: Phase 2 - Transaction assembly and delivery
Note over R: Phase 3 - Verification (required before signing)
236
+
R->>R: Extract input IDs from tx.Request().AuditRecord
237
+
alt every input id == SpendRequest.Token.Id
238
+
R->>R: Run EndorseView(tx) and sign
239
+
R-->>I: Signed transaction
240
+
else mismatch
241
+
R-->>I: Reject with error; no signature is produced
242
+
end
243
+
end
244
+
```
245
+
246
+
The Phase 3 check is what links the artifact a co-owner approves (the `SpendRequest`) to the artifact they sign (the assembled `tx`). Without it, a co-owner who reviews and approves a spend for token `T_a` could be made to sign a transaction consuming a different token `T_b` co-owned by the same group.
247
+
211
248
#### Wallet and Authorization
212
249
213
250
The `boolpolicy.OwnerWallet` (in `token/services/ttx/boolpolicy/wallet.go`) wraps a standard owner wallet and filters the token list to policy-type tokens. `VerifyApprover` can be used to assert that a given identity is one of the named component identities before allowing a spend.
0 commit comments