Skip to content

feat(scripts): recover stray SUI from the stSUI CollectionFeeCap - #44

Open
Zorag44 wants to merge 1 commit into
mainfrom
bugfix/lst-receive-stray
Open

feat(scripts): recover stray SUI from the stSUI CollectionFeeCap#44
Zorag44 wants to merge 1 commit into
mainfrom
bugfix/lst-receive-stray

Conversation

@Zorag44

@Zorag44 Zorag44 commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Add scripts/receiveStray.ts to pull the 1513.878 SUI mistakenly sent to CollectionFeeCap 0x019466989a. Guards on receive_stray existing, the cap owner signing, and the coin still being unclaimed, so it no-ops until the liquid_staking upgrade lands.

Port scripts/utils.ts to SuiGrpcClient: public fullnodes no longer serve JSON-RPC, and 2.22.0 dropped SuiClient/fromB64.

Fix scripts/test.ts against current src signatures — explicit lstInfo and lstCoinType params, setValidators/updateFee renames, required typeName on event queries.

Add scripts/receiveStray.ts to pull the 1513.878 SUI mistakenly sent to
CollectionFeeCap 0x019466989a. Guards on receive_stray existing, the cap
owner signing, and the coin still being unclaimed, so it no-ops until the
liquid_staking upgrade lands.

Port scripts/utils.ts to SuiGrpcClient: public fullnodes no longer serve
JSON-RPC, and 2.22.0 dropped SuiClient/fromB64.

Fix scripts/test.ts against current src signatures — explicit lstInfo and
lstCoinType params, setValidators/updateFee renames, required typeName on
event queries.
@Zorag44
Zorag44 requested review from jangid and rg-alpha August 7, 2026 20:38
@jangid

jangid commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

operate.md review — head aa012d3. Verified against @mysten/sui@2.22.0 sources; all core-client API shapes used here check out, and the hardcoded cap id matches COLLECTION_FEE_CAP_ID. Dry-run-by-default with an explicit --execute flag is a real improvement over the comment-toggling convention. Findings, by severity:

  1. 🔴 RECIPIENT env is unvalidated and short values are silently zero-padded into a valid dead address. scripts/receiveStray.ts feeds process.env.RECIPIENT ?? signer straight into transferObjects. In @mysten/sui BCS, the address input runs fromHex(normalizeSuiAddress(val)), so a truncated paste like 0x019466989a is left-padded into a valid 32-byte address nobody owns — and the console prints the raw env value, not the normalized destination. One fat-fingered paste with --execute sends the 1513.878 SUI irrecoverably to a padded dead address. Fix: require full normalized 66-char form (isValidSuiAddress + length check) and print the normalized address in the summary.
  2. 🟡 Execution failure exits 0. executeTransactionBlock in scripts/utils.ts swallows thrown errors (console.error, no rethrow), and a MoveAbort doesn't even throw — gRPC executeTransaction returns $kind: 'FailedTransaction', which the script just stringifies. A failed recovery looks like a success to the operator/automation. Check $kind/effects.status and exit non-zero on failure.
  3. 🟡 "CI green" is vacuous for this PRci.yml lints/typechecks src/** only; tsconfig.scripts.json includes only migration-snapshot.ts and isn't run by CI. None of the three changed files are compiled by any gate, now or on future SDK bumps. Add the new scripts to tsconfig.scripts.json and a tsc --noEmit -p tsconfig.scripts.json CI step.
  4. 🟢 The bare catch around getMoveFunction conflates "function not published yet" with any transient RPC error — both print "NOT RECOVERABLE YET". Fails safe, but misdiagnoses; distinguish NOT_FOUND from transport errors.
  5. 🟢 NETWORK=testnet still queries getConf()'s production ids (fails loudly, but confusingly); CAP duplicates getConf().COLLECTION_FEE_CAP_ID — derive it to prevent drift.
  6. 🟢 Dry run requires PK_B64 because dryRunTransactionBlock calls getExecStuff(); a SENDER env fallback would make simulation possible without the key.

Deploy-order: receive_stray does not exist in the deployed package — the script self-guards and no-ops until the alpha#987 upgrade lands, and STSUI_LATEST_PACKAGE_ID must be bumped after that. So there is time to land items 1–3 before the recovery window opens. Items 1 and 2 gate approval here; the rest are advisory.

@jangid

jangid commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

@Zorag44 — two fixes requested before this can be approved (details in the operate.md comment above): (1) validate RECIPIENT as a full normalized 66-char address and print the normalized destination — right now a truncated paste is silently zero-padded into a valid dead address and --execute would send the 1513.878 SUI there irrecoverably; (2) make the execute path detect FailedTransaction/thrown errors and exit non-zero — today a failed recovery exits 0. Both are small; there's time since the script no-ops until alpha#987 deploys.

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.

2 participants