Skip to content

fix: merge-coins size/count bugs, migrate scripts to gRPC, drop Pyth SDK - #171

Merged
11felix merged 4 commits into
mainfrom
bugfix/merge-coins-tx-size-and-counts
Aug 5, 2026
Merged

fix: merge-coins size/count bugs, migrate scripts to gRPC, drop Pyth SDK#171
11felix merged 4 commits into
mainfrom
bugfix/merge-coins-tx-size-and-counts

Conversation

@11felix

@11felix 11felix commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Fixes two bugs in the merge-coins helpers, then migrates the remaining JSON-RPC usage to gRPC and drops the Pyth SDK.

Merge-coins fixes

Both found against 0xee5360…4545 (100K+ objects).

Merge transactions exceeded the transaction size limit. A 500-object merge serializes to ~39KB against a 16384-byte cap on the gasless transaction, so it failed at submission with Size limit exceeded: serialized gasless transaction size exceeded maximum of 16384. The old cap was sized against the 512-argument command limit, which is not the binding constraint — each coin is an owned-object input costing ~79 bytes. MAX_COINS_PER_TX is now 180 (~14.4KB worst case, 88% of limit).

Note simulateTransaction does not enforce this check — it returned SUCCESS for the 39KB transaction that submission rejected. Verification measures (await tx.build({client})).length instead.

getCoinObjectCounts returned 1 of 72 coin types. It listed the address's objects capped at N and grouped by type, but objects are not listed grouped by type, so an address holding 100K SUI objects filled the entire listing and every other type was missed. It now enumerates types from the node's coin index (listBalances) and counts each type separately.

Other changes

  • Reads moved from GraphQL to fullnode gRPC: 500 objects in ~1s vs 12–19s (GraphQL pages cap at 50, gRPC at 1000). gRPC-web over fetch, works in browsers.
  • address-balance output merges into one coin then makes a single send_funds call, instead of one call per coin.
  • CoinTypeCount gains hasMoreCoinObjects so callers can render "more than N" without guessing at the cap. Breaking for anyone constructing the type.
  • New optional trailing grpcUrl on both public functions, defaulting to the fullnode endpoints.
  • Bounded concurrency plus backoff retry on RESOURCE_EXHAUSTED; the public fullnode rate-limits the per-type count burst.

Verified on mainnet

  • All at-cap types (SUI, USDC, DEEP, STSUI, WAL) in both output modes: serialized size 14,187–14,455 bytes, all under 16384, all dry-run clean.
  • Census returns 71–72 types in ~8s; three consecutive runs with no rate-limit failures.
  • grpcUrl default and explicit produce identical results; a bad URL is rejected, so the parameter is not silently ignored.

JSON-RPC → gRPC migration

JSON-RPC is deprecated, so the scripts/ helpers now use SuiGrpcClient, matching what src/ already did.

  • dryRunTransactionBlockcore.simulateTransaction; devInspectTransactionBlocksimulateTransaction({ checksEnabled: false }).
  • options: { show* }include: { effects, balanceChanges, objectTypes }.
  • requestType: "WaitForLocalExecution" is gone in v2, replaced by an explicit waitForTransaction({ result }).
  • Digests move under the $kind discriminant, so updatePriceScript unwraps Transaction / FailedTransaction and reports the failure message.
  • gRPC endpoints default to the public fullnode and are overridable with SUI_GRPC_URL. This removes the hardcoded private RPC URL (which carried an API key) from source.

Pyth SDK removal

updatePrices routes through Lazer, so @pythnetwork/pyth-sui-js was no longer used and is removed from dependencies.

  • Dropped the unused public pythClient / pythConnection fields on AlphalendClient, and the internal JSON-RPC client that existed only to construct SuiPythClient. src/ now makes no JSON-RPC calls at all.
  • Removed the two uncalled Pyth helpers from src/utils/oracle.ts and deleted scripts/pythTest.ts.
  • The on-chain Pyth path (updatePriceTransactionupdate_price_from_pyth) is untouched — it is a pure Move-call builder with no SDK dependency, and its test still passes.

Breaking: pythClient and pythConnection were public fields on the exported AlphalendClient. Unused internally, but external consumers reading them will break.

Note: @pythnetwork/pyth-sui-js remains installed as a peer dependency of @7kprotocol/sdk-ts, which hard-imports it at module load. npm 7+ auto-installs peers so this resolves normally, but installs using --legacy-peer-deps, Yarn 1, or strict-peer pnpm will not get it and will fail to import the SDK.

Verification

tsc --noEmit, npm run build, and npm run lint all clean. Test results are unchanged from before these commits — the same 25 pre-existing integration-test failures (live-network dependent), verified by diffing failing test names against the base commit.

@11felix 11felix changed the title fix(coinHelpers): cap merges at 180 objects and count every coin type fix: merge-coins size/count bugs, migrate scripts to gRPC, drop Pyth SDK Aug 3, 2026
@11felix
11felix requested review from Zorag44 and removed request for rishikesh-chavan August 3, 2026 20:37

@jangid jangid left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

operate.md: clean — lint/test/build green, no unresolved security findings, no open change-requests. Walked the rewritten buildMergeCoinsTransaction branch by branch on the PR head: every path into sendCoinsToAddressBalance is guarded non-empty (SUI throws on coins.length === 0 before the useAddressBalanceGas branch; the reserved-gas-coin branch reaches it only when hasWork required rest.length > 0; the non-SUI branch throws on selected.length === 0), so the new const [target, ...rest] destructuring has no undefined-target path. Sizing the cap against serialized transaction bytes rather than the 512-argument command limit is the right binding constraint, and measuring (await tx.build({client})).length rather than trusting simulateTransaction is the correct verification given it returned SUCCESS for the 39KB transaction submission rejected.

Two intentional breaking changes worth a release note: CoinTypeCount gains hasMoreCoinObjects (breaking for constructors of the type), and coinObjectCount is now capped at MAX_COINS_PER_TX rather than being a true count — consumers rendering the number need the companion flag. AlphaFiTech/alphafi-admin#33 is the first such consumer and is currently red on both (MAX_COINS_PER_TX not exported yet, hasMoreCoinObjects missing), so it needs this merged and published.

Approvals: 2/2 — threshold met.

@11felix
11felix merged commit cecbdac into main Aug 5, 2026
3 checks passed
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.

3 participants