Repository navigation
refactor(maticjs): migrate to @polygonlabs/maticjs 4.0.0-pre.2 - #102
Merged
Merged
Conversation
The last release regenerated CHANGELOG.md with a heading directly above a list, which fails markdownlint MD022 and turns the repo's lint gate red. Claude-Session: https://claude.ai/code/session_01JRTxTYrWEMpYoCh4iv6hpv
…apter The service moves off the frozen @maticnetwork/maticjs 3.x plugin stack onto the typed 4.0 POSClient. The client cache, static providers, 10 s timeout, eRPC header and the receipt fan-out cap (now proofConcurrency) carry over unchanged. The raw RootChain headerBlocks read goes through ethers directly, so block-included keeps its historical BigNumber JSON shape byte-for-byte. Deterministic exit errors are classified on the SDK's stable POSBridgeError code instead of message text. Retry warnings log errorType/errorCode (SDK code, or the raw RPC library code). Every SDK call site that was typed `any` is now typed. Claude-Session: https://claude.ai/code/session_01JRTxTYrWEMpYoCh4iv6hpv
toDeterministicError is the contract between the SDK's POSBridgeError codes and the routes' 404 responses. Cover all three mapped codes, an unmapped code and a non-SDK error, so an SDK code rename fails here instead of silently turning deterministic 404s into retried 502s. Claude-Session: https://claude.ai/code/session_01JRTxTYrWEMpYoCh4iv6hpv
Swap the local prerelease tarball for the published 4.0.0-pre.1, pinned exactly so the dogfood runs on one known artifact. The published tarball is the one validated before publish: same sha256, battery 46/46, every proof route byte-identical to production. Claude-Session: https://claude.ai/code/session_01JRTxTYrWEMpYoCh4iv6hpv
An instanceof check fails whenever the error comes from a different copy of the SDK than the one this module imported (a duplicate install, another realm, a bundler split). A deterministic 404 would then silently become a retried 502, and the log fields would go blank. One structural guard in errors.ts (name 'POSBridgeError' plus a string code) now backs both the exit error classifier and the retry-warning log fields. Tests feed error-shaped objects that are not instances of the SDK class through both paths, with negative controls. Claude-Session: https://claude.ai/code/session_01JRTxTYrWEMpYoCh4iv6hpv
The exit-payload call sites wrapped whatever the SDK threw in `new Error(String(x))` when it was not an Error instance, before handing it to the classifier. That normalisation ran ahead of the shape guard, so an SDK error recognised only by its name and code (the case the guard exists for: another copy or realm of the SDK) lost both fields, was retried on every RPC and answered 502 instead of a deterministic 404, with blank errorType/errorCode on the retry log. The classifier now takes the thrown value as-is and attaches it as the cause only when it is an Error, which VError requires; the outer retry loop still normalises for the 502 cause. A fail-fast test feeds a plain-object SDK error through the service path. Claude-Session: https://claude.ai/code/session_01JRTxTaoqJFaPzXs5moreWN
The service has no response schema: `res.json` serialises whatever the service
returns, so the `{ type: 'BigNumber', hex }` fields consumers parse were guarded
only by an out-of-repo byte-diff against production. The SDK now returns bigint,
which JSON cannot serialise and which the raw headerBlocks read deliberately
avoids; a full-body equality on an immutable header block makes any drift in that
wire shape fail the battery instead of a consumer.
Claude-Session: https://claude.ai/code/session_01JRTxTaoqJFaPzXs5moreWN
Team test style reads object fields with .property() rather than dereferencing them, so a missing body fails with a field-level message. Claude-Session: https://claude.ai/code/session_01JRTxTYrWEMpYoCh4iv6hpv
4.0.0-pre.2 replaces the boolean checkpoint predicate with a status read, and replaces the single coded error with named condition classes that operation errors wrap. Library errors now arrive unwrapped. Checkpoint checks read getCheckpointStatus().checkpointed. Deterministic exit errors are recognised with the SDK's own name-based isMaticjsError and each condition's has(), which walk the cause chain and work across package copies and JSON. The public 404s are unchanged and every other condition is still retried. Retry warnings log the innermost condition's name as errorCode. Pinned exactly at the published 4.0.0-pre.2. Claude-Session: https://claude.ai/code/session_01JRTxTYrWEMpYoCh4iv6hpv
getCheckpointStatus answers "not yet" with a reason rather than rejecting. Pin the two not-checkpointed reasons (a pending burn and a mined burn awaiting its checkpoint): both answer at once with the 404 clients poll on, without building or retrying. Also pin a rejected lookup, which is retried on every RPC and then answers 404 "Incorrect burn transaction". The changeset now records the pending-burn response, the one answer that differs from before. Claude-Session: https://claude.ai/code/session_01JRTxTYrWEMpYoCh4iv6hpv
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The service builds every withdrawal proof and exit payload with
@maticnetwork/maticjs3.x and its ethers plugin. That line is frozen: future bridge fixes land only in its successor,@polygonlabs/maticjs4.0. The 3.x plugin model also forces costs on this service:use(Web3ClientPlugin)with CJS default-export workarounds, in the code and in the test config;any;Solution
@polygonlabs/maticjs, pinned exactly at the4.0.0-pre.2prerelease. This service is the prerelease's production dogfood before 4.0.0 is declared stable.POSClientper network from twoethersV5Adapters.requestConcurrency: 10→proofConcurrency: 10) unchanged.block-includedreadsRootChain.headerBlocksthrough ethers directly, the SDK's documented escape hatch. Its JSON keeps the historical{ "type": "BigNumber", "hex": … }fields byte-for-byte.getCheckpointStatus(...).checkpointed. The 4.0 boolean predicate is gone. Same branches, same errors when the burn isn't checkpointed.isMaticjsErrorplusLogNotFoundInReceiptError/IndexOutOfBoundsError/BurnTxNotCheckpointedError.has(). These are the SDK's own name-based recognisers: they walk the cause chain (public methods throw an operation error whose cause is the condition) and work across duplicate package copies, realms and JSON round-trips. The service never usesinstanceofon SDK errors. The public 404 messages are unchanged, and every other condition, includingReceiptsRootMismatchErrorandTransactionNotFoundError, is retried as before. The thrown value goes to the classifier as-is, never normalised to anErrorfirst. Tests cover each mapped condition bare and wrapped, JSON round-tripped errors, unmapped conditions and raw library errors, through the classifier, the log fields and the full exit-payload retry loop.errorEventis replaced byerrorType(the SDK condition's legacy 3.x type, where it has one) anderrorCode.errorCodeis the name of the innermost SDK condition (e.g.LogNotFoundInReceiptError), or, for raw RPC failures (which 4.0 rethrows unwrapped), the RPC library's own code as before.anyis now typed. No casts were introduced.Known state
404 "Burn transaction has not been checkpointed yet", the same answer as for a mined burn awaiting its checkpoint. 4.0's checkpoint status reports a pending burn as "not checkpointed, reason: pending". On 3.x the checkpoint check didn't catch it and the request failed after exhausting retries, most likely a502. A client polling until its exit is ready now gets the same 404 from submission to checkpoint. Tests pin both "not yet" reasons and the rejected-lookup path.buildExitPayloadrefuses to return a payload whose receipts don't match the block'sreceiptsRoot(ReceiptsRootMismatchError). That usually means an RPC served bad receipts, so the service retries it on the next RPC like any transient failure and answers 502 only after retries are exhausted.^4.0.0in a follow-up.err_type, against the pre-deploy baseline (about 4 per 7 days, at most 1 per 5 minutes). Any new error type is a finding.errorType/errorCode: same order of magnitude as before. AnyReceiptsRootMismatchErroris a finding, recorded per RPC origin.Invalid merkle proof created) and their 4.0 equivalents.info.versionmatches the released version.Verification
pnpm run lintgreen;pnpm test59/59 (the 40 pre-existing tests unchanged and green, plus new tests). The test run makes live RPC calls on mainnet and Amoy, including the Bor state-sync receipt regression.https://proof-generator.polygon.technology. Status codes and bodies are byte-identical on 25/25 routes: health,block-included(mainnet/Amoy/404/400s),fast-merkle-proof(200 + 5 × 400),exit-payloadERC-20 (with and without index, out-of-range index 404), ERC-1155,all-exit-payloadsERC-721, Amoy state-sync, and every validation 400.4.0.0-pre.2tarball before it was published (25/25 identical). The published tarball's sha256 matches it, and the lockfile pins its integrity.b419fa4: shape-based classification now happens before anyErrornormalisation.e451b32: a full-body test pins theblock-includedBigNumber wire shape on an immutable header block, since the service has no response schemas to guard it.POSClient.initfetches the static network index with a 1 h cache.Contractper read.TRANSACTION_NOT_FOUNDis retried across the RPC list before the 404.