Skip to content

refactor: send transactions with the official transaction client - #123

Merged
yeboster merged 2 commits into
mainfrom
refactor/official-transaction-pipeline
Aug 29, 2026
Merged

refactor: send transactions with the official transaction client#123
yeboster merged 2 commits into
mainfrom
refactor/official-transaction-pipeline

Conversation

@yeboster

@yeboster yeboster commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Final step of the plan to drop the unmaintained partisia-blockchain-applications-* packages. #120 replaced the rpc reader, #122 replaced the signing crypto; this replaces the transaction pipeline itself.

What changed

createTransaction now builds a BlockchainTransactionClient from @partisiablockchain/blockchain-api-transaction-client and calls signAndSend / waitForSpawnedEvents, instead of driving the reader node's /blockchain endpoints by hand.

  • Chain id comes from the node. GET /chain returns "Partisia Blockchain" / "Partisia Blockchain Testnet", so the isMainnet flag and the string it built are gone.
  • Waiting is the client's condition waiter. Its spawned-event timeout defaults to ten minutes, which outlives any caller awaiting fetchResult; capped at 30s, matching the previous 30x1s poll per event.
  • Public shape unchanged. A wait that times out is reported as { hasError: true, errorMessage } rather than thrown, and eventTrace is rebuilt from the TransactionPointers of the executed tree, keeping { txHash, shardId }.
  • The broadcast retry stays. Non-interactive backends still get 3 attempts on a stale nonce; interactive ones still get 1, so a wallet never re-prompts.

What was deleted

  • src/transactions/helper.tsbuildTransactionResult, the finalization poller, getChainId. builderToBytesBe was a one-line wrapper around rpc.getBytes() and is inlined at its 9 call sites.
  • The transaction half of ShardedClient: getNonce, broadcastTransaction, getTransaction, getTransactionEventTrace and its recursive event walk, pollTransaction, shardUrl/shardUrlForAddress. It is now shard derivation plus the BYOC coin lookup.
  • putRequestOnce in the HTTP helper; nothing PUTs any more.

7 files, +86 / -255.

Endpoints

The client talks to /chain, /chain/accounts/{address}, /chain/shards/{shard}/blocks and /chain/shards/{shard}/transactions/{id}. All verified 200 on both node1.testnet.partisiablockchain.com and reader.partisiablockchain.com; an unknown account returns nonce: 1 rather than a 404, matching the old fallback.

Verification

  • tsc, eslint, yarn build clean.
  • npx jest -i: 269/269 passing against live testnet, in 44s (previous runs ~2.5min — the official waiter polls tighter than the fixed 1s/2s sleeps).

Bundle

Code-split esbuild bundle of dist/esm/index.js, versus current main:

main this PR
entry chunk 247,853 B 246,128 B
total 543,045 B 541,131 B

Small, as expected: no dependency leaves the graph here, the win is 169 fewer lines of SDK-maintained transaction plumbing. The dependency reductions were #120 and #122.

https://claude.ai/code/session_01GceWCwGXu66D1xEBDxZWBb


Follow-up commit: browser bundling

Two additions after looking at how the React app consumes this package:

  • assert is gone. It was the last node builtin in the source (one signature-length check in the MetaMask backend). esbuild/vite/webpack 5 all refuse to resolve it for a browser target without a polyfill; the SDK now bundles for --platform=browser with none.
  • privateKeyToAddress(privateKey) exported from dist/transactions, on the lazy signing path. Consumers derive an address from a private key by importing partisia-blockchain-applications-crypto directly; this is the same derivation over the official client, so that dependency can leave their package.json. Verified to return the suite's known test address.

Measured for an app-shaped entry (MetaNamesSdk, Enviroment, RecordClassEnum, getRecordValidator), minified, code-split:

eager entry chunk @metanames/sdk@6.3.1 this branch
app-shaped import 1,684,409 B 245,837 B
RecordClassEnum only 1,684,355 B 413 B

269/269 live tests still pass.

Signing, broadcasting and waiting for execution now go through
BlockchainTransactionClient from
@partisiablockchain/blockchain-api-transaction-client instead of the
hand-rolled pipeline over the reader node's /blockchain endpoints.

- the chain id is read from the node (/chain) rather than derived from
  the environment flag, so isMainnet is gone from createTransaction
- inclusion and spawned-event waiting use the client's condition waiter;
  the spawned-event timeout is capped at 30s instead of its ten-minute
  default, which no caller awaiting fetchResult would tolerate
- a wait that times out is still reported as { hasError: true } rather
  than thrown, so ITransactionResult is unchanged; eventTrace is
  rebuilt from the TransactionPointers of the executed tree and keeps
  its { txHash, shardId } shape
- the broadcast retry for non-interactive backends is kept

Deletes src/transactions/helper.ts and the transaction half of
ShardedClient (nonce, broadcast, transaction lookup, event-trace walk,
finalization poller) along with putRequestOnce; ShardedClient is now
just shard derivation and the BYOC coin lookup. builderToBytesBe was a
one-line wrapper around rpc.getBytes() and is inlined.

Net -169 lines of SDK code. All 269 live testnet tests pass.

Claude-Session: https://claude.ai/code/session_01GceWCwGXu66D1xEBDxZWBb
@github-actions

Copy link
Copy Markdown

Total Coverage: 92.00%

Coverage Report
File Branch Funcs Lines Uncovered Lines
src
   actions.ts 100% 100% 100%
   index.ts 100% 100% 100%
   interface.ts 100% 100% 100%
   meta-names-sdk.ts 75% 75% 95.65% 22, 44, 45
   partisia-name-system.ts 58% 87.50% 84.07% 106, 114, 12, 139, 152, 160, 164, 169, 170, 171, 178, 180, 188, 189, 19, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 22, 220, 221, 222, 29, 33, 42, 49, 54, 55, 7, 78, 82
   version.ts 100% 100% 100%
src/actions
   domain.ts 64.29% 100% 100% 34, 43, 55, 70, 73
   record.ts 77.78% 100% 100% 13, 47
src/models
   domain.ts 100% 83.33% 95.95% 45, 46, 47
   index.ts 100% 100% 100%
src/models/helpers
   domain.ts 100% 100% 100%
src/providers
   config.ts 66.67% 100% 98.11% 40, 49, 50
   index.ts 100% 100% 100%
   secrets.ts 45.45% 62.50% 78.57% 19, 23, 24, 25, 26, 27, 29, 30, 44, 50, 51, 52, 53, 56, 57, 58, 59, 62, 63, 64, 65
src/providers/config
   mainnet.ts 100% 100% 100%
   testnet.ts 100% 100% 100%
src/repositories
   contract-repository.ts 76.92% 100% 98.28% 101, 111, 134, 135, 137, 138, 140, 141, 143, 144, 153, 169, 191, 207, 32, 44, 45, 55, 61
   domain-repository.ts 60% 100% 100% 102, 113, 117, 118, 133, 142, 150, 176, 220, 225, 240, 256, 262, 269, 34, 53, 54, 96, 98, 99
   index.ts 100% 75% 100%
   record-repository.ts 71.43% 100% 100% 24, 34, 50, 60
src/repositories/contracts
   meta-names-contract-repository.ts 84.62% 88.89% 86.14% 57, 58, 59, 60, 61, 62, 63, 64, 78, 79, 80, 81, 82, 83, 84, 94
src/repositories/helpers
   avl-client.ts 80% 77.78% 61.62% 16, 22, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 95
   client.ts 92.31% 100% 100% 54
   contract.ts 75% 100% 92.45% 41, 42, 43, 44, 45, 50
   sharded-client.ts 66.67% 100% 100% 41, 52
src/transactions
   authentication.ts 100% 25% 40% 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 93, 94, 95, 96, 97, 98, 99
   index.ts 46.15% 42.86% 87.18% 100, 101, 102, 112, 56, 60, 69, 70, 71, 73, 73, 74, 75, 89, 92, 93, 94, 95, 96, 97, 98, 99
src/validators
   base-validator.ts 100% 100% 100%
   domain-validator.ts 87.50% 100% 100% 29, 30, 31
   index.ts 100% 100% 100%
   record-validator.ts 100% 100% 100%
src/validators/idna
   index.ts 81.54% 100% 95.93% 108, 110, 110, 111, 118, 119, 120, 121, 122, 123, 124, 125, 136, 138, 139, 144, 151, 155, 168, 210, 46
   table.ts 100% 100% 100%
src/validators/records
   default-validator.ts 100% 100% 100%
   discord-validator.ts 100% 100% 100%
   email-validator.ts 100% 100% 100%
   main-validator.ts 100% 100% 100%
   price-validator.ts 100% 100% 100%
   regex-validator.ts 100% 100% 100%
   twitter-validator.ts 100% 100% 100%
   uri-validator.ts 100% 100% 100%
   wallet-validator.ts 100% 100% 100%
test
test/helpers
   config.ts 0% 100% 100% 7
   helper.ts 100% 60% 68% 25, 26, 27, 28, 29, 30, 31, 32, 35, 36, 37, 38, 39, 40, 41, 42
   index.ts 100% 100% 100%

Two changes aimed at consumers that bundle the SDK for a browser.

`assert` was the last node builtin left in the source; esbuild, vite and
webpack 5 all fail to resolve it for a browser target unless the consumer
wires up a polyfill. It guarded one signature-length check, which is now
a plain throw with a message.

`privateKeyToAddress` exposes the address derivation consumers were
pulling `partisia-blockchain-applications-crypto` in for. It sits on the
lazily loaded signing path, so it costs nothing to anyone who does not
call it.

Claude-Session: https://claude.ai/code/session_01GceWCwGXu66D1xEBDxZWBb
@github-actions

Copy link
Copy Markdown

Total Coverage: 91.83%

Coverage Report
File Branch Funcs Lines Uncovered Lines
src
   actions.ts 100% 100% 100%
   index.ts 100% 100% 100%
   interface.ts 100% 100% 100%
   meta-names-sdk.ts 75% 75% 95.65% 22, 44, 45
   partisia-name-system.ts 58% 87.50% 84.07% 106, 114, 12, 139, 152, 160, 164, 169, 170, 171, 178, 180, 188, 189, 19, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 22, 220, 221, 222, 29, 33, 42, 49, 54, 55, 7, 78, 82
   version.ts 100% 100% 100%
src/actions
   domain.ts 64.29% 100% 100% 34, 43, 55, 70, 73
   record.ts 77.78% 100% 100% 13, 47
src/models
   domain.ts 100% 83.33% 95.95% 45, 46, 47
   index.ts 100% 100% 100%
src/models/helpers
   domain.ts 100% 100% 100%
src/providers
   config.ts 66.67% 100% 98.11% 40, 49, 50
   index.ts 100% 100% 100%
   secrets.ts 45.45% 62.50% 78.57% 19, 23, 24, 25, 26, 27, 29, 30, 44, 50, 51, 52, 53, 56, 57, 58, 59, 62, 63, 64, 65
src/providers/config
   mainnet.ts 100% 100% 100%
   testnet.ts 100% 100% 100%
src/repositories
   contract-repository.ts 76.92% 100% 98.28% 101, 111, 134, 135, 137, 138, 140, 141, 143, 144, 153, 169, 191, 207, 32, 44, 45, 55, 61
   domain-repository.ts 60% 100% 100% 102, 113, 117, 118, 133, 142, 150, 176, 220, 225, 240, 256, 262, 269, 34, 53, 54, 96, 98, 99
   index.ts 100% 75% 100%
   record-repository.ts 71.43% 100% 100% 24, 34, 50, 60
src/repositories/contracts
   meta-names-contract-repository.ts 84.62% 88.89% 86.14% 57, 58, 59, 60, 61, 62, 63, 64, 78, 79, 80, 81, 82, 83, 84, 94
src/repositories/helpers
   avl-client.ts 80% 77.78% 61.62% 16, 22, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 95
   client.ts 92.31% 100% 100% 54
   contract.ts 75% 100% 92.45% 41, 42, 43, 44, 45, 50
   sharded-client.ts 66.67% 100% 100% 41, 52
src/transactions
   authentication.ts 100% 25% 38.79% 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 94, 95, 96, 97, 98, 99
   index.ts 46.15% 37.50% 85.38% 102, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 125, 16, 17, 18, 19, 69, 73, 82, 83, 84, 86, 86, 87, 88
src/validators
   base-validator.ts 100% 100% 100%
   domain-validator.ts 87.50% 100% 100% 29, 30, 31
   index.ts 100% 100% 100%
   record-validator.ts 100% 100% 100%
src/validators/idna
   index.ts 81.54% 100% 95.93% 108, 110, 110, 111, 118, 119, 120, 121, 122, 123, 124, 125, 136, 138, 139, 144, 151, 155, 168, 210, 46
   table.ts 100% 100% 100%
src/validators/records
   default-validator.ts 100% 100% 100%
   discord-validator.ts 100% 100% 100%
   email-validator.ts 100% 100% 100%
   main-validator.ts 100% 100% 100%
   price-validator.ts 100% 100% 100%
   regex-validator.ts 100% 100% 100%
   twitter-validator.ts 100% 100% 100%
   uri-validator.ts 100% 100% 100%
   wallet-validator.ts 100% 100% 100%
test
test/helpers
   config.ts 0% 100% 100% 7
   helper.ts 100% 60% 68% 25, 26, 27, 28, 29, 30, 31, 32, 35, 36, 37, 38, 39, 40, 41, 42
   index.ts 100% 100% 100%

@yeboster
yeboster merged commit f4c77f0 into main Aug 29, 2026
8 checks passed
@yeboster
yeboster deleted the refactor/official-transaction-pipeline branch August 29, 2026 10:28
yeboster added a commit that referenced this pull request Aug 30, 2026
* fix: clean dist before build and retry throttled reader responses

Three release-blocking issues found while reviewing v7 end to end.

`yarn build` wrote into whatever `dist/` was already there, so files deleted
from `src` survived in the published package: 7.0.0 packed with
`dist/transactions/helper.js` (deleted in #123) and `dist/version.js` (deleted
in #124), both reachable through the `./dist/*` exports pattern. `prepublishOnly`
runs `build`, so the fix is a clean step in `build` itself.

A reader node under load answers 429 or 503. `handleFetch` only resolves a body
on HTTP 200, so those answers arrived at callers as `undefined` and surfaced as
`Error: Contract not found` -- observed against the app's `/api/domains/recent`
and `/api/domains/stats` routes while running its end-to-end suite. Retry them.
404 still falls through to `undefined`, which is how a missing AVL value is
reported.

`privateKeyToAddress` and the signing backends had no exports entry, leaving
`@metanames/sdk/dist/transactions` as the only way in. Add `./transactions`.

* fix: keep directory subpath imports resolvable

6.3.1 shipped no exports map, so `@metanames/sdk/dist/models` and its
siblings resolved through plain file lookup. The exports map added in v7
turns those into `./dist/models.js`, which does not exist, and Node does
not fall back to a directory index. Consumers on those specifiers would
break on upgrade for no reason: each directory has an `index.js`, so the
entries point at it.

Claude-Session: https://claude.ai/code/session_01GceWCwGXu66D1xEBDxZWBb

* chore: drop the scratch notes from the branch

Working notes committed by accident in the previous commit. #125 squash
merges, so main never carries them.

Claude-Session: https://claude.ai/code/session_01GceWCwGXu66D1xEBDxZWBb

* fix: drop the dist subpaths from the exports map

`./dist/*` was carried over so consumers importing the build output kept
working. That advertises the build layout as API: the paths hard-code the
CJS tree, and nothing outside it can move without breaking someone. v7 is
the major to stop. The named subpaths cover every use.

Claude-Session: https://claude.ai/code/session_01GceWCwGXu66D1xEBDxZWBb
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.

1 participant