fix(sdk-coin-polyx): forward caller material into v8 batch staking builder on rebuild [SI-1034]#9290
Conversation
…ilder on decode-success path getBuilder() routed the v8 batchAll(bond,nominate) decode-success path to getV8BatchStakingBuilder() without forwarding this._material, unlike every other getter. When wallet-platform's getSignedTx re-verifies a custodial v8 stake via factory.material(liveMaterial).from(serializedTxHex), the live material was silently dropped in favor of the builder's static getV8Material(), so the rebuilt signable payload used a stale specVersion and no longer matched the HSM-signed bytes, causing InvalidSignature: invalid key signature at Trust approval. SI-1034. TICKET: SI-1034
|
@claude review |
|
Claude finished @abhijit0943's task —— View job Code Review Complete ✅PR Summary: This PR fixes a critical issue in Polymesh v8 staking where custodial transactions fail with ✅ Fix Implementation ReviewProblem Analysis:
Solution Quality: ⭐⭐⭐⭐⭐ // Before (line 230)
return this.getV8BatchStakingBuilder();
// After (line 238)
return this.getV8BatchStakingBuilder().material(this._material);Strengths:
✅ Test Implementation ReviewTest Quality: ⭐⭐⭐⭐⭐ The new test in
Test Coverage: Covers the exact production scenario where wallet-platform calls ✅ Architecture & Code QualityDesign Consistency: ⭐⭐⭐⭐⭐
Code Safety: ⭐⭐⭐⭐⭐
✅ Security & PerformanceSecurity: ✅ No security concerns
Performance: ✅ Zero performance impact
🎯 Recommendations
📝 Minor Observations
✅ Overall AssessmentRating: ⭐⭐⭐⭐⭐ Excellent This is a production-critical fix implemented with exceptional care:
Recommendation: Approve and prioritize for deployment ✅ |
Summary
Custodial Polymesh v8 stake fails at Trust approval with
InvalidSignature: invalid key signatureinTPOLYX.getSignedTx, while custodial transfers on the same wallet succeed.Root cause (proven from staging Loki + payload decode): the tx is signed by the HSM against live chain material (specVersion
8000010) but re-verified against stale static material (getV8Material(), specVersion8000000). InTransactionBuilderFactory.getBuilder(), the v8batchAll(bond,nominate)decode-success path returnedgetV8BatchStakingBuilder()without forwardingthis._material— unlike every v7 getter. Sofactory.material(liveMaterial).from(serializedTxHex)(what wallet-platform'sgetSignedTxdoes) silently dropped the live material; the rebuilt signable payload used a stalespecVersionand no longer matched the signed bytes.Transfers work because their getters (
getTransferBuilder/getHexTransferBuilder) already forwardthis._material.Change
One line, on the decode-success path only:
The v8 getters and the
tryGetV8Builder()decode-failure catch path are intentionally left untouched — that path relies on the static v8 default whenthis._materialcannot decode the tx.Test
New unit test in
v8BatchStakingBuilder.ts: bumpsspecVersionby 10 on a copy oftestnetV8Material(simulating the real8000000 → 8000010chain upgrade), builds → serializes → rebuilds viafactory.material(liveMaterial).from(...), and asserts the rebuiltsignablePayloadequals the original.…00127a00…(static 8000000) vs…0a127a00…(live 8000010), rest of payload byte-identical.Notes
c22ca5c633), which is included in this branch's diff until SI-981 lands onmaster.testnetV8Material/mainnetV8MaterialspecVersion so the decode-failure catch path stays valid across future runtime upgrades.🤖 Generated with Claude Code