@needmoretruth/nmts-cli 0.17.2 → 0.34.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +124 -516
- package/CHANGELOG.md +98 -0
- package/README.ko.md +374 -467
- package/README.md +384 -465
- package/dist/account-proof.d.ts +29 -0
- package/dist/account-proof.js +6 -6
- package/dist/account.d.ts +18 -0
- package/dist/account.js +5 -5
- package/dist/agent-host.d.ts +71 -0
- package/dist/agent-host.js +169 -0
- package/dist/api-advice.d.ts +2 -0
- package/dist/api-advice.js +210 -0
- package/dist/api-key.d.ts +79 -0
- package/dist/api-key.js +7 -7
- package/dist/api-refusal.d.ts +14 -0
- package/dist/api-refusal.js +8 -0
- package/dist/api.d.ts +114 -0
- package/dist/api.js +59 -162
- package/dist/args.d.ts +160 -0
- package/dist/args.js +118 -30
- package/dist/artifact-about.d.ts +49 -0
- package/dist/autonomy.d.ts +39 -0
- package/dist/autonomy.js +110 -32
- package/dist/code-access.d.ts +29 -0
- package/dist/code-access.js +3 -3
- package/dist/code-vault.d.ts +38 -0
- package/dist/code-vault.js +8 -8
- package/dist/collision.d.ts +67 -0
- package/dist/collision.js +1 -1
- package/dist/commands/accept-terms.d.ts +11 -0
- package/dist/commands/accept-terms.js +106 -0
- package/dist/commands/balance.d.ts +7 -0
- package/dist/commands/balance.js +54 -1
- package/dist/commands/create-code-file.d.ts +24 -0
- package/dist/commands/create-code-file.js +93 -0
- package/dist/commands/create-link.d.ts +10 -0
- package/dist/commands/create-link.js +232 -0
- package/dist/commands/create.d.ts +20 -0
- package/dist/commands/create.js +43 -102
- package/dist/commands/credits.d.ts +9 -0
- package/dist/commands/credits.js +110 -0
- package/dist/commands/delete-account.d.ts +11 -0
- package/dist/commands/delete-account.js +63 -0
- package/dist/commands/deposit.d.ts +7 -0
- package/dist/commands/deposit.js +85 -0
- package/dist/commands/devices.d.ts +12 -0
- package/dist/commands/devices.js +144 -0
- package/dist/commands/documents.d.ts +35 -0
- package/dist/commands/documents.js +212 -0
- package/dist/commands/env.d.ts +5 -0
- package/dist/commands/env.js +10 -2
- package/dist/commands/erase.d.ts +13 -0
- package/dist/commands/erase.js +193 -0
- package/dist/commands/expiring.d.ts +19 -0
- package/dist/commands/extend.d.ts +33 -0
- package/dist/commands/extend.js +54 -15
- package/dist/commands/get.d.ts +18 -0
- package/dist/commands/key-manage.d.ts +11 -0
- package/dist/commands/key-manage.js +162 -0
- package/dist/commands/key.d.ts +28 -0
- package/dist/commands/key.js +249 -0
- package/dist/commands/kit.d.ts +11 -0
- package/dist/commands/kit.js +7 -7
- package/dist/commands/listfile.d.ts +13 -0
- package/dist/commands/listfile.js +12 -5
- package/dist/commands/login.d.ts +18 -0
- package/dist/commands/login.js +19 -19
- package/dist/commands/logout.d.ts +1 -0
- package/dist/commands/logout.js +1 -1
- package/dist/commands/losses.d.ts +12 -0
- package/dist/commands/losses.js +180 -0
- package/dist/commands/ls.d.ts +23 -0
- package/dist/commands/marks-dispatch.d.ts +2 -0
- package/dist/commands/marks-dispatch.js +51 -0
- package/dist/commands/marks.d.ts +46 -0
- package/dist/commands/marks.js +80 -0
- package/dist/commands/mcp.d.ts +24 -0
- package/dist/commands/mcp.js +70 -5
- package/dist/commands/mode.d.ts +8 -0
- package/dist/commands/mode.js +60 -24
- package/dist/commands/on-collision.d.ts +6 -0
- package/dist/commands/organise.d.ts +46 -0
- package/dist/commands/padding.d.ts +7 -0
- package/dist/commands/padding.js +114 -0
- package/dist/commands/public-code.d.ts +9 -0
- package/dist/commands/public-code.js +8 -8
- package/dist/commands/pull.d.ts +27 -0
- package/dist/commands/push-wallet.d.ts +19 -0
- package/dist/commands/push-wallet.js +69 -0
- package/dist/commands/push.d.ts +47 -0
- package/dist/commands/push.js +37 -7
- package/dist/commands/put-wallet.d.ts +77 -0
- package/dist/commands/put-wallet.js +316 -0
- package/dist/commands/put.d.ts +56 -0
- package/dist/commands/put.js +53 -6
- package/dist/commands/rebuild.d.ts +18 -0
- package/dist/commands/rebuild.js +108 -10
- package/dist/commands/receive.d.ts +24 -0
- package/dist/commands/recovery-dispatch.d.ts +2 -0
- package/dist/commands/recovery-dispatch.js +34 -0
- package/dist/commands/recovery-list.d.ts +11 -0
- package/dist/commands/recovery-list.js +6 -6
- package/dist/commands/recovery.d.ts +25 -0
- package/dist/commands/recovery.js +2 -2
- package/dist/commands/rollback.d.ts +9 -0
- package/dist/commands/rollback.js +118 -0
- package/dist/commands/s3.d.ts +23 -0
- package/dist/commands/s3.js +6 -6
- package/dist/commands/settings.d.ts +5 -0
- package/dist/commands/settings.js +21 -6
- package/dist/commands/share-dispatch.d.ts +2 -0
- package/dist/commands/share-dispatch.js +46 -0
- package/dist/commands/share.d.ts +14 -0
- package/dist/commands/share.js +13 -3
- package/dist/commands/shares-sent.d.ts +18 -0
- package/dist/commands/shares-sent.js +95 -0
- package/dist/commands/support.d.ts +24 -0
- package/dist/commands/support.js +321 -0
- package/dist/commands/sweep.d.ts +11 -0
- package/dist/commands/tip.d.ts +11 -0
- package/dist/commands/tip.js +86 -0
- package/dist/commands/trash.d.ts +17 -0
- package/dist/commands/trash.js +1 -1
- package/dist/commands/trial.d.ts +7 -0
- package/dist/commands/trial.js +16 -18
- package/dist/commands/unlock.d.ts +16 -0
- package/dist/commands/unlock.js +159 -0
- package/dist/commands/update.d.ts +42 -0
- package/dist/commands/update.js +1 -1
- package/dist/commands/usage.d.ts +8 -0
- package/dist/commands/verify.d.ts +18 -0
- package/dist/commands/verify.js +10 -6
- package/dist/commands/wallet-activity.d.ts +26 -0
- package/dist/commands/wallet-activity.js +117 -0
- package/dist/commands/wallet-donate.d.ts +26 -0
- package/dist/commands/wallet-donate.js +163 -0
- package/dist/commands/wallet-hall.d.ts +35 -0
- package/dist/commands/wallet-hall.js +214 -0
- package/dist/commands/wallet-send.d.ts +22 -0
- package/dist/commands/wallet-send.js +153 -0
- package/dist/commands/wallet-storage-ops.d.ts +24 -0
- package/dist/commands/wallet-storage-ops.js +215 -0
- package/dist/commands/wallet-storage.d.ts +18 -0
- package/dist/commands/wallet-storage.js +95 -0
- package/dist/commands/wallet-swap.d.ts +32 -0
- package/dist/commands/wallet-swap.js +287 -0
- package/dist/commands/wallet.d.ts +36 -0
- package/dist/commands/wallet.js +57 -15
- package/dist/commands/whoami.d.ts +10 -0
- package/dist/commands/whoami.js +24 -6
- package/dist/consent.d.ts +140 -0
- package/dist/consent.js +89 -30
- package/dist/credentials.d.ts +146 -0
- package/dist/credentials.js +10 -10
- package/dist/crypto-surface.d.ts +197 -0
- package/dist/crypto.d.ts +81 -0
- package/dist/crypto.js +13 -0
- package/dist/deposit.d.ts +25 -0
- package/dist/deposit.js +78 -0
- package/dist/download-part.d.ts +40 -0
- package/dist/download-sink.d.ts +76 -0
- package/dist/download.d.ts +79 -0
- package/dist/download.js +3 -3
- package/dist/drive-paths.d.ts +73 -0
- package/dist/environment.d.ts +62 -0
- package/dist/environment.js +29 -9
- package/dist/errors.d.ts +22 -0
- package/dist/errors.js +3 -3
- package/dist/exit.d.ts +44 -0
- package/dist/expiry.d.ts +58 -0
- package/dist/extend-budget.d.ts +35 -0
- package/dist/extend-budget.js +81 -0
- package/dist/extend-chain.d.ts +43 -0
- package/dist/extend-chain.js +40 -3
- package/dist/extend-plan.d.ts +148 -0
- package/dist/extend-plan.js +1 -1
- package/dist/gate.d.ts +18 -0
- package/dist/gate.js +100 -0
- package/dist/guards.d.ts +2 -0
- package/dist/help.d.ts +20 -0
- package/dist/help.js +199 -33
- package/dist/human-check.d.ts +23 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +49 -0
- package/dist/item-trash.d.ts +1 -0
- package/dist/kit-file.d.ts +56 -0
- package/dist/kit-file.js +10 -10
- package/dist/list-file.d.ts +88 -0
- package/dist/list-file.js +90 -7
- package/dist/list-view-find.d.ts +15 -0
- package/dist/list-view-order.d.ts +32 -0
- package/dist/main.d.ts +12 -0
- package/dist/main.js +112 -113
- package/dist/manifest-chunk-cache.d.ts +14 -0
- package/dist/manifest-chunk-cache.js +103 -0
- package/dist/manifest-chunk-flow.d.ts +81 -0
- package/dist/manifest-chunk-flow.js +307 -0
- package/dist/manifest-create.d.ts +23 -0
- package/dist/manifest-create.js +26 -30
- package/dist/manifest-write.d.ts +161 -0
- package/dist/manifest-write.js +42 -33
- package/dist/manifest.d.ts +82 -0
- package/dist/manifest.js +69 -21
- package/dist/mark-render.d.ts +26 -0
- package/dist/mcp-args.d.ts +17 -0
- package/dist/mcp-ask.d.ts +43 -0
- package/dist/mcp-ask.js +100 -0
- package/dist/mcp-tools/context.d.ts +46 -0
- package/dist/mcp-tools/credits.d.ts +3 -0
- package/dist/mcp-tools/credits.js +61 -0
- package/dist/mcp-tools/files.d.ts +3 -0
- package/dist/mcp-tools/files.js +34 -0
- package/dist/mcp-tools/organise.d.ts +3 -0
- package/dist/mcp-tools/organise.js +82 -2
- package/dist/mcp-tools/reads.d.ts +3 -0
- package/dist/mcp-tools/reads.js +132 -4
- package/dist/mcp-tools/share.d.ts +3 -0
- package/dist/mcp-tools/share.js +26 -7
- package/dist/mcp-tools/support.d.ts +3 -0
- package/dist/mcp-tools/support.js +140 -0
- package/dist/mcp-tools/tiers.d.ts +31 -0
- package/dist/mcp-tools/tiers.js +147 -0
- package/dist/mcp.d.ts +80 -0
- package/dist/mcp.js +110 -9
- package/dist/net-retry.d.ts +38 -0
- package/dist/network.d.ts +10 -0
- package/dist/notice.d.ts +7 -0
- package/dist/notice.js +7 -7
- package/dist/product.d.ts +29 -0
- package/dist/product.js +1 -1
- package/dist/progress.d.ts +37 -0
- package/dist/prompt.d.ts +31 -0
- package/dist/prompt.js +1 -1
- package/dist/rebuild-key-check.d.ts +26 -0
- package/dist/rebuild-key-check.js +90 -0
- package/dist/rebuild.d.ts +87 -0
- package/dist/rebuild.js +26 -4
- package/dist/recovery-assemble.d.ts +40 -0
- package/dist/recovery-assemble.js +1 -1
- package/dist/recovery-build.d.ts +40 -0
- package/dist/recovery-map-file.d.ts +53 -0
- package/dist/recovery-map-file.js +4 -4
- package/dist/recovery-map.d.ts +197 -0
- package/dist/recovery-release.d.ts +104 -0
- package/dist/recovery-seq.d.ts +10 -0
- package/dist/recovery-source.d.ts +50 -0
- package/dist/redact.d.ts +70 -0
- package/dist/redact.js +212 -0
- package/dist/registration.d.ts +30 -0
- package/dist/registration.js +5 -5
- package/dist/risk.d.ts +380 -0
- package/dist/risk.js +206 -0
- package/dist/run-log.d.ts +78 -0
- package/dist/run-log.js +301 -0
- package/dist/s3/listing.d.ts +47 -0
- package/dist/s3/multipart.d.ts +21 -0
- package/dist/s3/response-sink.d.ts +8 -0
- package/dist/s3/same-file.d.ts +54 -0
- package/dist/s3/server.d.ts +58 -0
- package/dist/s3/server.js +2 -2
- package/dist/s3/sigv4.d.ts +46 -0
- package/dist/s3/sigv4.js +1 -1
- package/dist/s3/staging.d.ts +10 -0
- package/dist/s3/xml.d.ts +28 -0
- package/dist/safe-path.d.ts +41 -0
- package/dist/seal.d.ts +120 -0
- package/dist/secret-reader.d.ts +28 -0
- package/dist/server.d.ts +9 -0
- package/dist/session.d.ts +32 -0
- package/dist/session.js +1 -1
- package/dist/setup-questions.d.ts +7 -0
- package/dist/share.d.ts +108 -0
- package/dist/share.js +1 -1
- package/dist/shared/lib/crypto/size-padding.d.ts +55 -0
- package/dist/shared/lib/crypto/size-padding.js +5 -0
- package/dist/shared/lib/drive/manifest-chunks.d.ts +95 -0
- package/dist/shared/lib/drive/manifest-chunks.js +252 -0
- package/dist/shared/lib/drive/manifest-codec.d.ts +214 -0
- package/dist/shared/lib/drive/manifest-codec.js +7 -7
- package/dist/shared/lib/drive/manifest-index.d.ts +98 -0
- package/dist/shared/lib/drive/manifest-ops.d.ts +167 -0
- package/dist/shared/lib/drive/manifest-ops.js +9 -4
- package/dist/shared/lib/drive/manifest-pack.d.ts +65 -0
- package/dist/shared/lib/drive/manifest-pack.js +287 -0
- package/dist/shared/lib/drive/manifest-settings.d.ts +113 -0
- package/dist/shared/lib/drive/manifest-settings.js +87 -6
- package/dist/shared/lib/drive/name-conflict.d.ts +76 -0
- package/dist/shared/lib/drive/rebuild-verify.d.ts +73 -0
- package/dist/shared/lib/drive/rebuild-verify.js +112 -0
- package/dist/shared/lib/drive/unique-name.d.ts +9 -0
- package/dist/shared/lib/drive/zstd.d.ts +27 -0
- package/dist/shared/lib/drive/zstd.js +74 -0
- package/dist/shared/lib/extend/epochs.d.ts +205 -0
- package/dist/shared/lib/net/retry-budget.d.ts +79 -0
- package/dist/shared/lib/share/shared-file-info.d.ts +21 -0
- package/dist/shared/lib/storage-control/chain.d.ts +57 -0
- package/dist/shared/lib/storage-control/chain.js +82 -0
- package/dist/shared/lib/storage-control/plan.d.ts +40 -0
- package/dist/shared/lib/storage-control/plan.js +72 -0
- package/dist/shared/lib/storage-control/reuse.d.ts +72 -0
- package/dist/shared/lib/storage-control/reuse.js +95 -0
- package/dist/shared/lib/storage-network.d.ts +25 -0
- package/dist/shared/lib/upload/part-plan.d.ts +24 -0
- package/dist/shared/lib/wallet/activity.d.ts +138 -0
- package/dist/shared/lib/wallet/activity.js +208 -0
- package/dist/shared/lib/wallet/send-rules.d.ts +68 -0
- package/dist/shared/lib/wallet/send-rules.js +116 -0
- package/dist/shared/lib/wallet/swap-rules.d.ts +115 -0
- package/dist/shared/lib/wallet/swap-rules.js +199 -0
- package/dist/shared/lib/wallet/tip.d.ts +14 -0
- package/dist/shared/lib/wallet/tip.js +34 -0
- package/dist/shared/lib/wallet/venue-ids.d.ts +23 -0
- package/dist/shared/lib/wallet/venue-ids.js +53 -0
- package/dist/standing-tip.d.ts +24 -0
- package/dist/standing-tip.js +52 -0
- package/dist/stdout.d.ts +38 -0
- package/dist/storage-control-chain.d.ts +38 -0
- package/dist/storage-control-chain.js +78 -0
- package/dist/sui-rpc.d.ts +15 -0
- package/dist/sui-rpc.js +59 -0
- package/dist/support-attach.d.ts +24 -0
- package/dist/support-attach.js +72 -0
- package/dist/support-copy.d.ts +42 -0
- package/dist/support-copy.js +109 -0
- package/dist/support-wire.d.ts +49 -0
- package/dist/support-wire.js +194 -0
- package/dist/trash-sweep.d.ts +55 -0
- package/dist/units.d.ts +2 -0
- package/dist/update-check.d.ts +50 -0
- package/dist/update-source.d.ts +63 -0
- package/dist/upload-api.d.ts +3 -0
- package/dist/upload-file.d.ts +97 -0
- package/dist/upload-file.js +3 -2
- package/dist/upload-price.d.ts +50 -0
- package/dist/upload-steps.d.ts +26 -0
- package/dist/upload-steps.js +29 -9
- package/dist/upload-store.d.ts +182 -0
- package/dist/upload-wallet-chain.d.ts +54 -0
- package/dist/upload-wallet-chain.js +203 -0
- package/dist/upload-wallet-plan.d.ts +128 -0
- package/dist/upload-wallet-plan.js +184 -0
- package/dist/upload-wallet.d.ts +24 -0
- package/dist/upload-wallet.js +208 -0
- package/dist/upload-wire.d.ts +244 -0
- package/dist/upload.d.ts +18 -0
- package/dist/upload.js +10 -0
- package/dist/usage-report.d.ts +35 -0
- package/dist/wallet-activity-chain.d.ts +5 -0
- package/dist/wallet-activity-chain.js +31 -0
- package/dist/wallet-chain.d.ts +19 -0
- package/dist/wallet-chain.js +2 -2
- package/dist/wallet-grant.d.ts +50 -0
- package/dist/wallet-grant.js +218 -0
- package/dist/wallet-send-chain.d.ts +24 -0
- package/dist/wallet-send-chain.js +49 -0
- package/dist/wallet-sign.d.ts +133 -0
- package/dist/wallet-sign.js +317 -0
- package/dist/wallet-storage-chain.d.ts +3 -0
- package/dist/wallet-storage-chain.js +20 -0
- package/dist/wallet-swap-chain.d.ts +52 -0
- package/dist/wallet-swap-chain.js +186 -0
- package/dist/wallet-swap-quote.d.ts +22 -0
- package/dist/wallet-swap-quote.js +126 -0
- package/dist/wallet.d.ts +135 -0
- package/dist/wallet.js +5 -5
- package/dist/walrus-write.d.ts +56 -0
- package/dist/walrus-write.js +5 -4
- package/dist/walrus.d.ts +86 -0
- package/dist/walrus.js +48 -10
- package/dist/zstd-node.d.ts +11 -0
- package/dist/zstd-node.js +71 -0
- package/docs/commands/accept-terms.md +15 -0
- package/docs/commands/create.md +17 -0
- package/docs/commands/credits.md +34 -0
- package/docs/commands/delete-account.md +14 -0
- package/docs/commands/deposit.md +27 -0
- package/docs/commands/devices.md +9 -0
- package/docs/commands/documents.md +10 -0
- package/docs/commands/env.md +21 -0
- package/docs/commands/extend.md +27 -0
- package/docs/commands/folders.md +10 -0
- package/docs/commands/get.md +14 -0
- package/docs/commands/key.md +14 -0
- package/docs/commands/login.md +23 -0
- package/docs/commands/logout.md +11 -0
- package/docs/commands/losses.md +13 -0
- package/docs/commands/ls.md +16 -0
- package/docs/commands/marks.md +9 -0
- package/docs/commands/mcp.md +33 -0
- package/docs/commands/mode.md +29 -0
- package/docs/commands/on-collision.md +13 -0
- package/docs/commands/padding.md +13 -0
- package/docs/commands/public-code.md +9 -0
- package/docs/commands/pull.md +9 -0
- package/docs/commands/push.md +12 -0
- package/docs/commands/put.md +36 -0
- package/docs/commands/rebuild.md +13 -0
- package/docs/commands/recovery.md +18 -0
- package/docs/commands/s3.md +17 -0
- package/docs/commands/share.md +15 -0
- package/docs/commands/support.md +16 -0
- package/docs/commands/tip.md +21 -0
- package/docs/commands/trash.md +25 -0
- package/docs/commands/trial.md +12 -0
- package/docs/commands/unlock.md +25 -0
- package/docs/commands/update.md +14 -0
- package/docs/commands/usage.md +14 -0
- package/docs/commands/verify.md +18 -0
- package/docs/commands/wallet.md +67 -0
- package/docs/commands/whoami.md +12 -0
- package/package.json +67 -8
- package/server.json +28 -0
- package/vendor/nmts-crypto/nmts_crypto_wasm.d.ts +23 -2
- package/vendor/nmts-crypto/nmts_crypto_wasm.js +44 -2
- package/vendor/nmts-crypto/nmts_crypto_wasm_bg.wasm +0 -0
- package/vendor/nmts-crypto/nmts_crypto_wasm_bg.wasm.d.ts +1 -0
- package/vendor/nmts-crypto/package.json +1 -1
- package/dist/commands/consent.js +0 -77
- package/dist/extend-sign.js +0 -130
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
// A venue's answer, read from the chain: how much comes out now, what stays unused, and the fee the
|
|
2
|
+
// quote's own numbers say the venue charges. ⛔ EVERYTHING HERE IS A READ — `devInspect`, no gas,
|
|
3
|
+
// no key, no signature, and a zero address as the nominal sender so a quote needs no funded wallet.
|
|
4
|
+
//
|
|
5
|
+
// ⛔ THE ARITHMETIC IS THE BROWSER'S, copied byte-for-byte (`shared/lib/wallet/swap-rules.ts`); this
|
|
6
|
+
// file only asks the chain and hands the answers to it. DeepBook's fee has no constant: it is
|
|
7
|
+
// MEASURED by quoting the same amount with the fee taken from the input coin and again with the
|
|
8
|
+
// fee paid in DEEP, then comparing output per unit actually spent. Bluefin's quote reports its
|
|
9
|
+
// fee outright (`fee_amount` + `protocol_fee`; both parts count).
|
|
10
|
+
//
|
|
11
|
+
// ⛔ A FEE RATE THAT CANNOT BE MEASURED IS NULL, NEVER 0. A quote that cannot be read THROWS — the
|
|
12
|
+
// command says "this venue did not answer", never a number in its place. An output of 0 is an
|
|
13
|
+
// answer, not a failure: the amount is below one lot, or the book is empty.
|
|
14
|
+
import { bcs } from "@mysten/sui/bcs";
|
|
15
|
+
import { Transaction } from "@mysten/sui/transactions";
|
|
16
|
+
import { deepbookRowFrom, feeRateBpsOf, measureDeepbookFeeBps, } from "./shared/lib/wallet/swap-rules.js";
|
|
17
|
+
import { BLUEFIN_MAX_SQRT_PRICE, BLUEFIN_MIN_SQRT_PRICE, DEEPBOOK_PACKAGE_IDS, DEEPBOOK_WAL_SUI_POOLS, } from "./shared/lib/wallet/venue-ids.js";
|
|
18
|
+
import { SUI_COIN_TYPE, walCoinType } from "./wallet.js";
|
|
19
|
+
/** The zero address: a quote is a read, and a read needs no wallet. */
|
|
20
|
+
export const QUOTE_SENDER = `0x${"0".repeat(64)}`;
|
|
21
|
+
function readU64(value) {
|
|
22
|
+
return BigInt(bcs.U64.parse(Uint8Array.from(value[0])));
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The FRONT of Bluefin's `SwapResult`, in the order its `pool.move` declares them. BCS reads from
|
|
26
|
+
* the front, so the fields behind these need not be known. The first three are checked against the
|
|
27
|
+
* question asked; if they do not echo it, the rest cannot be trusted either.
|
|
28
|
+
*/
|
|
29
|
+
const BluefinSwapResultPrefix = bcs.struct("BluefinSwapResultPrefix", {
|
|
30
|
+
a2b: bcs.bool(),
|
|
31
|
+
by_amount_in: bcs.bool(),
|
|
32
|
+
amount_specified: bcs.u64(),
|
|
33
|
+
amount_specified_remaining: bcs.u64(),
|
|
34
|
+
amount_calculated: bcs.u64(),
|
|
35
|
+
fee_growth_global: bcs.u128(),
|
|
36
|
+
fee_amount: bcs.u64(),
|
|
37
|
+
protocol_fee: bcs.u64(),
|
|
38
|
+
});
|
|
39
|
+
async function quoteBluefin(client, network, direction, amountInUnits, binding) {
|
|
40
|
+
const a2b = direction === "WAL_TO_SUI";
|
|
41
|
+
const tx = new Transaction();
|
|
42
|
+
tx.moveCall({
|
|
43
|
+
target: `${binding.packageId}::pool::calculate_swap_results`,
|
|
44
|
+
typeArguments: [walCoinType(network), SUI_COIN_TYPE],
|
|
45
|
+
arguments: [
|
|
46
|
+
tx.object(binding.poolId),
|
|
47
|
+
tx.pure.bool(a2b),
|
|
48
|
+
tx.pure.bool(true),
|
|
49
|
+
tx.pure.u64(amountInUnits),
|
|
50
|
+
tx.pure.u128(a2b ? BLUEFIN_MIN_SQRT_PRICE : BLUEFIN_MAX_SQRT_PRICE),
|
|
51
|
+
],
|
|
52
|
+
});
|
|
53
|
+
const res = await client.devInspectTransactionBlock({ sender: QUOTE_SENDER, transactionBlock: tx });
|
|
54
|
+
if (res.error)
|
|
55
|
+
throw new Error(`the Bluefin quote was refused on chain: ${res.error}`);
|
|
56
|
+
const returned = res.results?.[0]?.returnValues;
|
|
57
|
+
const first = returned?.[0];
|
|
58
|
+
if (first === undefined)
|
|
59
|
+
throw new Error("the Bluefin quote came back with no value");
|
|
60
|
+
const result = BluefinSwapResultPrefix.parse(Uint8Array.from(first[0]));
|
|
61
|
+
if (result.a2b !== a2b || result.by_amount_in !== true || BigInt(result.amount_specified) !== amountInUnits) {
|
|
62
|
+
throw new Error("the Bluefin quote did not echo the question it was asked");
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
venue: "bluefin",
|
|
66
|
+
outUnits: BigInt(result.amount_calculated),
|
|
67
|
+
feeRateBps: feeRateBpsOf(BigInt(result.fee_amount) + BigInt(result.protocol_fee), amountInUnits),
|
|
68
|
+
leftoverInUnits: BigInt(result.amount_specified_remaining),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async function quoteDeepbook(client, network, direction, amountInUnits) {
|
|
72
|
+
const pkg = DEEPBOOK_PACKAGE_IDS[network];
|
|
73
|
+
const pool = DEEPBOOK_WAL_SUI_POOLS[network];
|
|
74
|
+
const types = [walCoinType(network), SUI_COIN_TYPE];
|
|
75
|
+
const inputFeeFn = direction === "SUI_TO_WAL" ? "get_base_quantity_out_input_fee" : "get_quote_quantity_out_input_fee";
|
|
76
|
+
const deepModeArgs = direction === "SUI_TO_WAL" ? [0n, amountInUnits] : [amountInUnits, 0n];
|
|
77
|
+
const build = (withDeepMode) => {
|
|
78
|
+
const tx = new Transaction();
|
|
79
|
+
tx.moveCall({
|
|
80
|
+
target: `${pkg}::pool::${inputFeeFn}`,
|
|
81
|
+
typeArguments: types,
|
|
82
|
+
arguments: [tx.object(pool), tx.pure.u64(amountInUnits), tx.object.clock()],
|
|
83
|
+
});
|
|
84
|
+
if (withDeepMode) {
|
|
85
|
+
tx.moveCall({
|
|
86
|
+
target: `${pkg}::pool::get_quantity_out`,
|
|
87
|
+
typeArguments: types,
|
|
88
|
+
arguments: [tx.object(pool), tx.pure.u64(deepModeArgs[0]), tx.pure.u64(deepModeArgs[1]), tx.object.clock()],
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return tx;
|
|
92
|
+
};
|
|
93
|
+
// Both modes in ONE inspection so they see the same book. If the DEEP-mode call is refused, the
|
|
94
|
+
// quote is asked again alone: what comes out matters more than what the fee was.
|
|
95
|
+
let res = await client.devInspectTransactionBlock({ sender: QUOTE_SENDER, transactionBlock: build(true) });
|
|
96
|
+
let deepModeAnswered = true;
|
|
97
|
+
if (res.error) {
|
|
98
|
+
deepModeAnswered = false;
|
|
99
|
+
res = await client.devInspectTransactionBlock({ sender: QUOTE_SENDER, transactionBlock: build(false) });
|
|
100
|
+
}
|
|
101
|
+
if (res.error)
|
|
102
|
+
throw new Error(`the DeepBook quote was refused on chain: ${res.error}`);
|
|
103
|
+
const rowOf = (values) => values !== undefined && values.length >= 3 && values[0] !== undefined && values[1] !== undefined
|
|
104
|
+
? deepbookRowFrom(direction, readU64(values[0]), readU64(values[1]))
|
|
105
|
+
: null;
|
|
106
|
+
const inputMode = rowOf(res.results?.[0]?.returnValues);
|
|
107
|
+
if (inputMode === null)
|
|
108
|
+
throw new Error("the DeepBook quote came back in a shape this tool does not read");
|
|
109
|
+
const deepMode = deepModeAnswered ? rowOf(res.results?.[1]?.returnValues) : null;
|
|
110
|
+
return {
|
|
111
|
+
venue: "deepbook",
|
|
112
|
+
outUnits: inputMode.outUnits,
|
|
113
|
+
feeRateBps: measureDeepbookFeeBps(amountInUnits, inputMode, deepMode),
|
|
114
|
+
leftoverInUnits: inputMode.leftoverInUnits,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/** One venue's answer now. Bluefin needs its resolved binding; DeepBook needs nothing resolved. */
|
|
118
|
+
export async function quoteVenue(client, network, venue, direction, amountInUnits, bluefin) {
|
|
119
|
+
if (amountInUnits <= 0n)
|
|
120
|
+
throw new Error("a swap quote needs an amount above zero");
|
|
121
|
+
if (venue === "deepbook")
|
|
122
|
+
return quoteDeepbook(client, network, direction, amountInUnits);
|
|
123
|
+
if (bluefin === null)
|
|
124
|
+
throw new Error("Bluefin's package was not resolved");
|
|
125
|
+
return quoteBluefin(client, network, direction, amountInUnits, bluefin);
|
|
126
|
+
}
|
package/dist/wallet.d.ts
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { type CryptoGlue } from "./crypto.ts";
|
|
2
|
+
import type { Network } from "./network.ts";
|
|
3
|
+
/**
|
|
4
|
+
* The wallet this NMTS key opens by itself.
|
|
5
|
+
*
|
|
6
|
+
* ⛔ IT IS WALLET 0 BECAUSE THAT IS THE ONE THE BROWSER OPENS. Every wallet, including this one,
|
|
7
|
+
* comes out of `wallet_seed_for` — there is no special case for the first — so the index is the
|
|
8
|
+
* whole of the difference between "the account's wallet" and somebody else's.
|
|
9
|
+
*
|
|
10
|
+
* ⛔ EXPORTED SO THE SIGNER CANNOT PICK ITS OWN. `extend-sign.ts` derives a keypair from the same
|
|
11
|
+
* root and has to reach the SAME wallet as the address printed here; a second literal `0` over
|
|
12
|
+
* there would be a second answer to a question with one right one, and the failure is silent —
|
|
13
|
+
* a signature from an address nobody funded. `extend-sign.test.ts` compares the two.
|
|
14
|
+
*/
|
|
15
|
+
export declare const BUILT_IN_WALLET_INDEX = 0;
|
|
16
|
+
/** The chain's own coin. Its type is fixed by the chain itself and takes no network. */
|
|
17
|
+
export declare const SUI_COIN_TYPE = "0x2::sui::SUI";
|
|
18
|
+
/**
|
|
19
|
+
* The storage network's coin, per chain.
|
|
20
|
+
*
|
|
21
|
+
* ⛔ A WRONG VALUE HERE READS AS AN EMPTY WALLET RATHER THAN AS A FAULT. Measured against the
|
|
22
|
+
* public mainnet node this tool reads from, 2026-08-24: asking for a coin type that does not
|
|
23
|
+
* exist answers `totalBalance: "0"` — the same answer a real empty balance gives. That
|
|
24
|
+
* measurement is why `readBalances` never reports a zero WAL balance without first asking the
|
|
25
|
+
* chain whether it has heard of the type at all; see `ChainReader.knowsCoinType`.
|
|
26
|
+
*
|
|
27
|
+
* ⚠ THIS IS A SECOND COPY. The browser app carries the same two strings for the same reason, and
|
|
28
|
+
* no machine holds the two level — this package deliberately imports nothing from that tree.
|
|
29
|
+
* What keeps them honest is the check above: a copy that went stale stops answering zero and
|
|
30
|
+
* starts saying it could not be read.
|
|
31
|
+
*/
|
|
32
|
+
export declare const WAL_COIN_TYPES: Readonly<Record<Network, string>>;
|
|
33
|
+
/** The WAL coin type for one network. */
|
|
34
|
+
export declare function walCoinType(network: Network): string;
|
|
35
|
+
/**
|
|
36
|
+
* The Sui address of one 32-byte wallet seed.
|
|
37
|
+
*
|
|
38
|
+
* ⛔ IT IS THE SDK'S COMPUTATION, NOT ONE WRITTEN HERE. An address is BLAKE2b-256 over a scheme
|
|
39
|
+
* byte and the public key; hand-rolling that would put a second answer in the world for a
|
|
40
|
+
* question that must have exactly one, and the failure would be silent — a well-formed address
|
|
41
|
+
* nobody can spend from.
|
|
42
|
+
*
|
|
43
|
+
* ⚠ THE KEYPAIR HOLDS THE SECRET AND CANNOT BE WIPED. `@mysten/sui` keeps the key inside its own
|
|
44
|
+
* object, with no method that clears it; the same is true in the browser's worker. What is
|
|
45
|
+
* controlled here is lifetime: it is built, asked one question, and dropped, and the caller's
|
|
46
|
+
* copy of the seed is zeroed. Nothing retains it.
|
|
47
|
+
*
|
|
48
|
+
* Exported because the vectors that hold this to the other implementations of the same derivation
|
|
49
|
+
* are (seed, address) pairs, and a test cannot check them through the account-code entry point.
|
|
50
|
+
*/
|
|
51
|
+
export declare function addressFromSeed(seed: Uint8Array): string;
|
|
52
|
+
/**
|
|
53
|
+
* The address of the wallet this NMTS key derives. Offline: nothing is asked of anybody.
|
|
54
|
+
*
|
|
55
|
+
* The same address on every network — an account has one wallet, and which chain it is looked up
|
|
56
|
+
* on is a separate question from what it is called.
|
|
57
|
+
*/
|
|
58
|
+
export declare function walletAddress(code: string): Promise<string>;
|
|
59
|
+
/**
|
|
60
|
+
* The engine functions this module uses. Narrowed to the one it actually calls.
|
|
61
|
+
*
|
|
62
|
+
* ⛔ NOT A SEAM FOR REPLACING THE ENGINE. Every address this tool prints comes from the real
|
|
63
|
+
* WebAssembly, and a fake derivation would only prove this file agrees with a fake. The narrow
|
|
64
|
+
* type exists so a test can WRAP the real function and watch what was handed to it — which is
|
|
65
|
+
* the only way the wiping below can be checked at all, and the wiping is the part that matters.
|
|
66
|
+
*/
|
|
67
|
+
export type WalletGlue = Pick<CryptoGlue, "wallet_seed_for">;
|
|
68
|
+
/**
|
|
69
|
+
* The NMTS key wallet's address, from a buffer the caller already holds.
|
|
70
|
+
*
|
|
71
|
+
* ⛔ IT TAKES KEY MATERIAL AND RETURNS A STRING. `derived` belongs to the caller and is left
|
|
72
|
+
* alone; the two secrets this function makes — the wallet root it slices out and the seed the
|
|
73
|
+
* engine expands from it — are wiped before it returns, on the failing path as well as the
|
|
74
|
+
* good one. Neither one leaves.
|
|
75
|
+
*/
|
|
76
|
+
export declare function addressFromDerived(glue: WalletGlue, derived: Uint8Array): string;
|
|
77
|
+
/**
|
|
78
|
+
* How much of one coin an address holds, exactly as the chain reported it — or why nobody knows.
|
|
79
|
+
*
|
|
80
|
+
* ⛔ THE TWO CASES ARE DIFFERENT TYPES ON PURPOSE. A number with a "did it work" flag beside it is
|
|
81
|
+
* a number somebody will read without checking the flag. This shape makes the check unavoidable.
|
|
82
|
+
*/
|
|
83
|
+
export type CoinBalance = {
|
|
84
|
+
readonly read: true;
|
|
85
|
+
readonly baseUnits: bigint;
|
|
86
|
+
} | {
|
|
87
|
+
readonly read: false;
|
|
88
|
+
readonly why: string;
|
|
89
|
+
};
|
|
90
|
+
/** Both balances of one wallet, each answering for itself. */
|
|
91
|
+
export interface WalletBalances {
|
|
92
|
+
readonly sui: CoinBalance;
|
|
93
|
+
readonly wal: CoinBalance;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* The chain, as this tool needs it: two questions, no writing.
|
|
97
|
+
*
|
|
98
|
+
* ⛔ A SEAM, NOT AN OPTION. There is no flag that reaches it and no way to supply one from a
|
|
99
|
+
* command line. It exists so the arithmetic and every failure branch below can be driven by
|
|
100
|
+
* `node --test` — a test that needed a live chain could not run offline, would answer
|
|
101
|
+
* differently every day, and could not produce a refusal on demand at all.
|
|
102
|
+
*/
|
|
103
|
+
export interface ChainReader {
|
|
104
|
+
/** Total held of one coin type, in base units. Throws, with the reason, when it cannot be read. */
|
|
105
|
+
totalOf(coinType: string): Promise<bigint>;
|
|
106
|
+
/**
|
|
107
|
+
* Has this chain heard of the coin type at all?
|
|
108
|
+
*
|
|
109
|
+
* ⛔ THE ONLY QUESTION THAT TELLS AN EMPTY WALLET FROM A COIN TYPE THIS BUILD HAS WRONG. Both
|
|
110
|
+
* answer "0" to the balance question — see the note on `WAL_COIN_TYPES`.
|
|
111
|
+
*/
|
|
112
|
+
knowsCoinType(coinType: string): Promise<boolean>;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Read both balances, keeping "could not be read" apart from "empty" in every branch.
|
|
116
|
+
*
|
|
117
|
+
* ⚠ THE REASON A READ FAILED IS SAFE TO PRINT, and that is worth saying because in this tool it
|
|
118
|
+
* usually is not (`errors.ts`). Nothing secret is in one of these requests: what goes out is a
|
|
119
|
+
* public address and a coin type, so what comes back cannot quote a secret.
|
|
120
|
+
*
|
|
121
|
+
* ⛔ ONE COIN'S FAILURE DOES NOT TAKE THE OTHER DOWN. They are separate requests about separate
|
|
122
|
+
* coins, and an answer for one of them is worth more than a matching pair of silences.
|
|
123
|
+
*/
|
|
124
|
+
export declare function readBalances(reader: ChainReader, walType: string): Promise<WalletBalances>;
|
|
125
|
+
/**
|
|
126
|
+
* Base units as a person reads them — the exact value, never rounded.
|
|
127
|
+
*
|
|
128
|
+
* ⛔ NOT `toFixed`, NOT A SHORTENED FORM. A wallet holding 0.000000004 SUI is not holding "0.00",
|
|
129
|
+
* and money that reads as zero when it is not is the one rounding error nobody forgives. The
|
|
130
|
+
* fractional part is trimmed of trailing zeros only, which removes nothing that was there.
|
|
131
|
+
*
|
|
132
|
+
* Callers hand it a total the chain reported; a negative one is refused where it is read, so this
|
|
133
|
+
* never sees one.
|
|
134
|
+
*/
|
|
135
|
+
export declare function coinAmount(baseUnits: bigint): string;
|
package/dist/wallet.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// The wallet an
|
|
1
|
+
// The wallet an NMTS key derives: its address, and what a chain says it holds.
|
|
2
2
|
//
|
|
3
3
|
// ⛔ NOTHING HERE SIGNS OR SPENDS, AND NOTHING HERE HANDS OUT A KEY. The only secret this module
|
|
4
4
|
// touches is the 32-byte wallet seed; it lives for the length of one address computation and is
|
|
@@ -19,7 +19,7 @@ import { assertUsableCode } from "./account.js";
|
|
|
19
19
|
import { DERIVED, loadCrypto } from "./crypto.js";
|
|
20
20
|
import { NmtsError } from "./errors.js";
|
|
21
21
|
/**
|
|
22
|
-
* The wallet this
|
|
22
|
+
* The wallet this NMTS key opens by itself.
|
|
23
23
|
*
|
|
24
24
|
* ⛔ IT IS WALLET 0 BECAUSE THAT IS THE ONE THE BROWSER OPENS. Every wallet, including this one,
|
|
25
25
|
* comes out of `wallet_seed_for` — there is no special case for the first — so the index is the
|
|
@@ -83,7 +83,7 @@ export function addressFromSeed(seed) {
|
|
|
83
83
|
return Ed25519Keypair.fromSecretKey(seed).toSuiAddress();
|
|
84
84
|
}
|
|
85
85
|
/**
|
|
86
|
-
* The address of the wallet this
|
|
86
|
+
* The address of the wallet this NMTS key derives. Offline: nothing is asked of anybody.
|
|
87
87
|
*
|
|
88
88
|
* The same address on every network — an account has one wallet, and which chain it is looked up
|
|
89
89
|
* on is a separate question from what it is called.
|
|
@@ -101,7 +101,7 @@ export async function walletAddress(code) {
|
|
|
101
101
|
// ⛔ Unreachable in practice — the same parser accepted this input a line ago. It is caught
|
|
102
102
|
// anyway because the alternative is an engine message going out verbatim, and an engine
|
|
103
103
|
// message about a code can carry the code (see `errors.ts`).
|
|
104
|
-
throw new NmtsError("The
|
|
104
|
+
throw new NmtsError("The NMTS key could not be read on this machine.", { exitCode: 1 });
|
|
105
105
|
}
|
|
106
106
|
// ⛔ THIS BUFFER IS EVERY KEY IN THE ACCOUNT, not just the wallet root: the sign-in secret, the
|
|
107
107
|
// key that opens the files, the key that opens the file list. It is wiped below along with
|
|
@@ -116,7 +116,7 @@ export async function walletAddress(code) {
|
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
/**
|
|
119
|
-
* The
|
|
119
|
+
* The NMTS key wallet's address, from a buffer the caller already holds.
|
|
120
120
|
*
|
|
121
121
|
* ⛔ IT TAKES KEY MATERIAL AND RETURNS A STRING. `derived` belongs to the caller and is left
|
|
122
122
|
* alone; the two secrets this function makes — the wallet root it slices out and the seed the
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { type EpochClock } from "./expiry.ts";
|
|
2
|
+
import type { BlobProtocol } from "./upload-wire.ts";
|
|
3
|
+
/**
|
|
4
|
+
* How long the relay gets for one blob PUT, sized to the body.
|
|
5
|
+
*
|
|
6
|
+
* The SDK's own default is 30 seconds, which a multi-megabyte body cannot finish on an ordinary
|
|
7
|
+
* connection — and a timeout here happens AFTER the storage is paid for.
|
|
8
|
+
*/
|
|
9
|
+
export declare function relayTimeoutMs(bodyBytes: number): number;
|
|
10
|
+
/**
|
|
11
|
+
* Build a protocol client bound to ONE relay, for ONE upload of a known size.
|
|
12
|
+
*
|
|
13
|
+
* `onSent` is called as the request body leaves — that is the honest measure of an upload, and it
|
|
14
|
+
* is the only phase of one that anything can report on.
|
|
15
|
+
*/
|
|
16
|
+
export declare function createBlobProtocol(network: string, bodyBytes: number, onSent?: (sent: number, total: number) => void): BlobProtocol & {
|
|
17
|
+
relayUrl: string;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* The storage network's current epoch, or `null` when it could not be read.
|
|
21
|
+
*
|
|
22
|
+
* ⚠ ADVISORY ONLY. It becomes the `expiry_epoch` the server records beside the file, which the
|
|
23
|
+
* chain — not this number — is the authority on. `null` is written as 0, meaning "not recorded",
|
|
24
|
+
* which is honest; inventing a number would put a date in the drive that nothing stands behind.
|
|
25
|
+
*/
|
|
26
|
+
export declare function readCurrentEpoch(network: string): Promise<number | null>;
|
|
27
|
+
/**
|
|
28
|
+
* The storage network's epoch clock: which epoch, how long one lasts, and when this one began.
|
|
29
|
+
*
|
|
30
|
+
* ⛔ THE EPOCH LENGTH IS READ, NEVER ASSUMED. It is one day on one network and fourteen on the
|
|
31
|
+
* other, so a constant borrowed from either would turn "fourteen days left" into "196 days
|
|
32
|
+
* left" on the wrong one — beside a sentence about a file being deleted.
|
|
33
|
+
*
|
|
34
|
+
* ⚠ `startedMs` is usually ABSENT and that is normal, not a failure: the network only carries the
|
|
35
|
+
* moment an epoch settled while it is not changing epochs. Everything downstream treats its
|
|
36
|
+
* absence as "the day count is a lower bound", which is the safe direction.
|
|
37
|
+
*
|
|
38
|
+
* `null` means the clock could not be read at all. ⛔ The caller must say so rather than draw a
|
|
39
|
+
* drive with nothing expiring — an unread clock and an account in no danger look identical from
|
|
40
|
+
* the outside and are the opposite of each other.
|
|
41
|
+
*/
|
|
42
|
+
export declare function readEpochWindow(network: string): Promise<EpochClock | null>;
|
|
43
|
+
/**
|
|
44
|
+
* When the current epoch began, or null.
|
|
45
|
+
*
|
|
46
|
+
* ⛔ THE NARROWING ITSELF IS NOT WRITTEN HERE (2026-08-25). It used to be, and it accepted a single
|
|
47
|
+
* enum case while the network sits in a different one for nearly all of every epoch — so the
|
|
48
|
+
* anchor was thrown away almost always and this tool reported "N days or more" where it could
|
|
49
|
+
* have reported a date. The browser had the same bug in its own copy of the same judgement,
|
|
50
|
+
* which is the point: two narrowings are two answers. It now lives beside the arithmetic that
|
|
51
|
+
* depends on it, in the file both programs copy from.
|
|
52
|
+
*
|
|
53
|
+
* ⛔ STILL EXPORTED FROM HERE. `extend-chain.ts` reads the same state for a different reason and
|
|
54
|
+
* imports this name; re-exporting keeps one import path for callers in this package.
|
|
55
|
+
*/
|
|
56
|
+
export { epochStartedMs } from "./shared/lib/extend/epochs.ts";
|
package/dist/walrus-write.js
CHANGED
|
@@ -16,7 +16,8 @@ import { epochClock } from "./expiry.js";
|
|
|
16
16
|
import { epochStartedMs as readEpochStart } from "./shared/lib/extend/epochs.js";
|
|
17
17
|
import { NmtsError } from "./errors.js";
|
|
18
18
|
import { countingFetch } from "./progress.js";
|
|
19
|
-
import { relayHost
|
|
19
|
+
import { relayHost } from "./walrus.js";
|
|
20
|
+
import { suiRpcTransport } from "./sui-rpc.js";
|
|
20
21
|
/**
|
|
21
22
|
* How long the relay gets for one blob PUT, sized to the body.
|
|
22
23
|
*
|
|
@@ -45,7 +46,7 @@ function extend(network, relayUrl, bodyBytes, onSent) {
|
|
|
45
46
|
// ⛔ The network name reaches the SDK as well as the URL. A mirror pointed at the wrong chain
|
|
46
47
|
// would otherwise be discovered as a blob the storage nodes refuse, after the money moved.
|
|
47
48
|
network: network === "mainnet" ? "mainnet" : "testnet",
|
|
48
|
-
|
|
49
|
+
transport: suiRpcTransport(network),
|
|
49
50
|
});
|
|
50
51
|
return base.$extend(walrus({
|
|
51
52
|
uploadRelay: {
|
|
@@ -128,7 +129,7 @@ export async function readCurrentEpoch(network) {
|
|
|
128
129
|
try {
|
|
129
130
|
const base = new SuiJsonRpcClient({
|
|
130
131
|
network: network === "mainnet" ? "mainnet" : "testnet",
|
|
131
|
-
|
|
132
|
+
transport: suiRpcTransport(network),
|
|
132
133
|
}).$extend(walrus({}));
|
|
133
134
|
// The epoch lives on the COMMITTEE, not beside it: the system state describes capacity and
|
|
134
135
|
// the deny lists as well, and only the committee is stamped with which epoch it serves.
|
|
@@ -159,7 +160,7 @@ export async function readEpochWindow(network) {
|
|
|
159
160
|
try {
|
|
160
161
|
const base = new SuiJsonRpcClient({
|
|
161
162
|
network: network === "mainnet" ? "mainnet" : "testnet",
|
|
162
|
-
|
|
163
|
+
transport: suiRpcTransport(network),
|
|
163
164
|
}).$extend(walrus({}));
|
|
164
165
|
const [system, staking] = await Promise.all([base.walrus.systemState(), base.walrus.stakingState()]);
|
|
165
166
|
// Both numbers can arrive as strings — Sui reports 64-bit values that way — so they are
|
package/dist/walrus.d.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/** Curated Walrus aggregator (read) endpoints per network, preference order. */
|
|
2
|
+
export declare const AGGREGATOR_HOSTS: Readonly<Record<string, readonly string[]>>;
|
|
3
|
+
/**
|
|
4
|
+
* Curated Walrus upload-relay (write) endpoints per network, preference order.
|
|
5
|
+
*
|
|
6
|
+
* ⛔ A RELAY IS NOT AN AGGREGATOR, and the difference is money. The relay is named inside the
|
|
7
|
+
* register transaction the server pays a tip in, so the bytes have to go to the SAME host the
|
|
8
|
+
* reservation was made for. That is why a write picks its host BEFORE the storage is bought and
|
|
9
|
+
* then never moves: failing over to a second relay would push bytes nobody paid that relay for.
|
|
10
|
+
*/
|
|
11
|
+
export declare const RELAY_HOSTS: Readonly<Record<string, readonly string[]>>;
|
|
12
|
+
/**
|
|
13
|
+
* Sui JSON-RPC endpoints per network — public mirrors, because the official full nodes retired
|
|
14
|
+
* JSON-RPC on both networks (browser measurements 2026-07-29 testnet, 2026-08-03 mainnet).
|
|
15
|
+
*
|
|
16
|
+
* ⛔ READ-ONLY, AND NOT TRUSTED WITH ANYTHING. This tool asks one question here: how many shards
|
|
17
|
+
* the storage network currently has, which the erasure coding needs. A wrong answer produces a
|
|
18
|
+
* blob id the storage network refuses, so it fails loudly at the relay rather than quietly
|
|
19
|
+
* storing something unreadable. No key is ever sent to one of these, and nothing is signed.
|
|
20
|
+
*
|
|
21
|
+
* ⭐ 2026-09-01 — a LIST per network, two operators, first-that-answers. It used to be one host,
|
|
22
|
+
* and the testnet one was measured dead that morning: `rpc-testnet.suiscan.xyz` completes the
|
|
23
|
+
* TCP handshake in 31 ms and then sends nothing for 12 seconds, three times running. It had
|
|
24
|
+
* been that way for eleven days, so every `nmts` command that needed the shard count on testnet
|
|
25
|
+
* simply stopped. Each host below answered `sui_getChainIdentifier` with the right value the
|
|
26
|
+
* same morning, 8/8 on a burst.
|
|
27
|
+
*/
|
|
28
|
+
export declare const SUI_RPC_HOSTS: Readonly<Record<string, readonly string[]>>;
|
|
29
|
+
/** How long one host gets before the next is tried. A read that stalls is a read that failed. */
|
|
30
|
+
export declare const READ_TIMEOUT_MS = 60000;
|
|
31
|
+
/**
|
|
32
|
+
* Point reads at somebody else's aggregator, or at a development stack.
|
|
33
|
+
*
|
|
34
|
+
* ⚠ It replaces the list rather than adding to it, and that is deliberate: a run should read from
|
|
35
|
+
* where it was told to read, not from there AND the public hosts. Comma-separated for more
|
|
36
|
+
* than one, tried in the order given.
|
|
37
|
+
*/
|
|
38
|
+
export declare const AGGREGATOR_ENV_VAR = "NMTS_AGGREGATOR";
|
|
39
|
+
/**
|
|
40
|
+
* Push writes through somebody else's relay, or through a development stack.
|
|
41
|
+
*
|
|
42
|
+
* ⚠ ONE host, not a list. Unlike reads there is nothing to fail over to — see `RELAY_HOSTS`.
|
|
43
|
+
*/
|
|
44
|
+
export declare const RELAY_ENV_VAR = "NMTS_RELAY";
|
|
45
|
+
/** Ask a different Sui JSON-RPC node the shard-count question. */
|
|
46
|
+
export declare const SUI_RPC_ENV_VAR = "NMTS_SUI_RPC";
|
|
47
|
+
/** The relay this run writes through: the environment's if it named one, else the network's. */
|
|
48
|
+
export declare function relayHost(network: string): string;
|
|
49
|
+
/**
|
|
50
|
+
* Every Sui JSON-RPC node this run may ask, in order.
|
|
51
|
+
*
|
|
52
|
+
* ⛔ Naming one in the environment REPLACES the list rather than adding to it — the same rule the
|
|
53
|
+
* aggregator override follows, and for the same reason: somebody who names a node is saying
|
|
54
|
+
* *that one*, and quietly reaching a public mirror instead would send their traffic somewhere
|
|
55
|
+
* they did not choose.
|
|
56
|
+
*/
|
|
57
|
+
export declare function suiRpcHosts(network: string): readonly string[];
|
|
58
|
+
/** The node whose address gets RECORDED — the first one, since that is the one normally asked. */
|
|
59
|
+
export declare function suiRpcHost(network: string): string;
|
|
60
|
+
export interface ReadOptions {
|
|
61
|
+
/** Override the host list — for a development stack, or an aggregator somebody runs themselves. */
|
|
62
|
+
hosts?: readonly string[];
|
|
63
|
+
timeoutMs?: number;
|
|
64
|
+
signal?: AbortSignal | undefined;
|
|
65
|
+
/**
|
|
66
|
+
* Read only these bytes: inclusive start, EXCLUSIVE end. Absent reads the whole object.
|
|
67
|
+
*
|
|
68
|
+
* ⛔ IT IS A REQUEST, NOT A GUARANTEE. An aggregator is free to ignore `Range` and answer 200
|
|
69
|
+
* with everything, so what comes back is cut to the asked-for length here. Without that cut
|
|
70
|
+
* the one caller that uses this — the rebuild's 72-byte key check — would quietly become a
|
|
71
|
+
* download of the whole account.
|
|
72
|
+
*/
|
|
73
|
+
range?: {
|
|
74
|
+
start: number;
|
|
75
|
+
end: number;
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
/** Whole-blob read: `GET {aggregator}/v1/blobs/{blobId}`. */
|
|
79
|
+
export declare function readBlob(network: string, blobId: string, options?: ReadOptions): Promise<Uint8Array>;
|
|
80
|
+
/**
|
|
81
|
+
* Quilt-patch read: `GET {aggregator}/v1/blobs/by-quilt-patch-id/{patchId}`.
|
|
82
|
+
*
|
|
83
|
+
* A quilt is one stored blob holding many small files; the patch id addresses one of them. Files
|
|
84
|
+
* under 64 MiB share a quilt, so this is the common path rather than the exotic one.
|
|
85
|
+
*/
|
|
86
|
+
export declare function readQuiltPatch(network: string, patchId: string, options?: ReadOptions): Promise<Uint8Array>;
|
package/dist/walrus.js
CHANGED
|
@@ -36,10 +36,17 @@ export const RELAY_HOSTS = {
|
|
|
36
36
|
* the storage network currently has, which the erasure coding needs. A wrong answer produces a
|
|
37
37
|
* blob id the storage network refuses, so it fails loudly at the relay rather than quietly
|
|
38
38
|
* storing something unreadable. No key is ever sent to one of these, and nothing is signed.
|
|
39
|
+
*
|
|
40
|
+
* ⭐ 2026-09-01 — a LIST per network, two operators, first-that-answers. It used to be one host,
|
|
41
|
+
* and the testnet one was measured dead that morning: `rpc-testnet.suiscan.xyz` completes the
|
|
42
|
+
* TCP handshake in 31 ms and then sends nothing for 12 seconds, three times running. It had
|
|
43
|
+
* been that way for eleven days, so every `nmts` command that needed the shard count on testnet
|
|
44
|
+
* simply stopped. Each host below answered `sui_getChainIdentifier` with the right value the
|
|
45
|
+
* same morning, 8/8 on a burst.
|
|
39
46
|
*/
|
|
40
47
|
export const SUI_RPC_HOSTS = {
|
|
41
|
-
testnet: "https://
|
|
42
|
-
mainnet: "https://rpc-mainnet.suiscan.xyz",
|
|
48
|
+
testnet: ["https://sui-testnet-rpc.publicnode.com", "https://testnet.suiet.app"],
|
|
49
|
+
mainnet: ["https://rpc-mainnet.suiscan.xyz", "https://sui-rpc.publicnode.com"],
|
|
43
50
|
};
|
|
44
51
|
/** How long one host gets before the next is tried. A read that stalls is a read that failed. */
|
|
45
52
|
export const READ_TIMEOUT_MS = 60_000;
|
|
@@ -72,18 +79,29 @@ export function relayHost(network) {
|
|
|
72
79
|
}
|
|
73
80
|
return host;
|
|
74
81
|
}
|
|
75
|
-
/**
|
|
76
|
-
|
|
82
|
+
/**
|
|
83
|
+
* Every Sui JSON-RPC node this run may ask, in order.
|
|
84
|
+
*
|
|
85
|
+
* ⛔ Naming one in the environment REPLACES the list rather than adding to it — the same rule the
|
|
86
|
+
* aggregator override follows, and for the same reason: somebody who names a node is saying
|
|
87
|
+
* *that one*, and quietly reaching a public mirror instead would send their traffic somewhere
|
|
88
|
+
* they did not choose.
|
|
89
|
+
*/
|
|
90
|
+
export function suiRpcHosts(network) {
|
|
77
91
|
const named = process.env[SUI_RPC_ENV_VAR]?.trim();
|
|
78
92
|
if (named)
|
|
79
|
-
return named;
|
|
80
|
-
const
|
|
81
|
-
if (
|
|
93
|
+
return [named];
|
|
94
|
+
const hosts = SUI_RPC_HOSTS[network];
|
|
95
|
+
if (hosts === undefined || hosts.length === 0) {
|
|
82
96
|
throw new NmtsError(`No Sui RPC endpoint is known for the ${network} network.`, {
|
|
83
97
|
nextStep: `Name one in ${SUI_RPC_ENV_VAR} to upload anyway.`,
|
|
84
98
|
});
|
|
85
99
|
}
|
|
86
|
-
return
|
|
100
|
+
return hosts;
|
|
101
|
+
}
|
|
102
|
+
/** The node whose address gets RECORDED — the first one, since that is the one normally asked. */
|
|
103
|
+
export function suiRpcHost(network) {
|
|
104
|
+
return suiRpcHosts(network)[0] ?? "";
|
|
87
105
|
}
|
|
88
106
|
function fromEnvironment() {
|
|
89
107
|
const raw = process.env[AGGREGATOR_ENV_VAR];
|
|
@@ -122,12 +140,24 @@ async function readFrom(network, pathOf, what, options) {
|
|
|
122
140
|
const timer = AbortSignal.timeout(options.timeoutMs ?? READ_TIMEOUT_MS);
|
|
123
141
|
const signal = options.signal === undefined ? timer : AbortSignal.any([timer, options.signal]);
|
|
124
142
|
try {
|
|
125
|
-
const response = await fetch(url, { signal, redirect: "follow" });
|
|
143
|
+
const response = await fetch(url, { signal, redirect: "follow", ...headersFor(options) });
|
|
126
144
|
if (!response.ok) {
|
|
127
145
|
tried.push(`${host} → ${response.status}`);
|
|
128
146
|
continue;
|
|
129
147
|
}
|
|
130
|
-
|
|
148
|
+
const body = new Uint8Array(await response.arrayBuffer());
|
|
149
|
+
const range = options.range;
|
|
150
|
+
if (range === undefined)
|
|
151
|
+
return body;
|
|
152
|
+
const want = range.end - range.start;
|
|
153
|
+
// A 206 already holds exactly the asked-for bytes; a 200 holds the object from byte zero.
|
|
154
|
+
if (body.length === want)
|
|
155
|
+
return body;
|
|
156
|
+
if (body.length < range.end) {
|
|
157
|
+
tried.push(`${host} → answered ${body.length} bytes for a ${want}-byte range`);
|
|
158
|
+
continue;
|
|
159
|
+
}
|
|
160
|
+
return body.subarray(range.start, range.end);
|
|
131
161
|
}
|
|
132
162
|
catch (error) {
|
|
133
163
|
// ⛔ The reason is kept, not flattened to "failed". A timeout and a refused connection mean
|
|
@@ -141,6 +171,14 @@ async function readFrom(network, pathOf, what, options) {
|
|
|
141
171
|
`this is the wrong network — the same identifier does not exist on both.`,
|
|
142
172
|
});
|
|
143
173
|
}
|
|
174
|
+
/** The `Range` header for a partial read, or nothing at all for a whole one. */
|
|
175
|
+
function headersFor(options) {
|
|
176
|
+
const range = options.range;
|
|
177
|
+
if (range === undefined)
|
|
178
|
+
return {};
|
|
179
|
+
// HTTP ranges are inclusive at both ends; this one is exclusive at the end.
|
|
180
|
+
return { headers: { Range: `bytes=${range.start}-${range.end - 1}` } };
|
|
181
|
+
}
|
|
144
182
|
/** Whole-blob read: `GET {aggregator}/v1/blobs/{blobId}`. */
|
|
145
183
|
export function readBlob(network, blobId, options = {}) {
|
|
146
184
|
return readFrom(network, (host) => `${host}/v1/blobs/${encodeURIComponent(blobId)}`, `Blob ${blobId}`, options);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Make this program able to write and read compression flag 0x02. Safe to call more than once.
|
|
3
|
+
*
|
|
4
|
+
* ⛔ CALLED FROM THE FILE-LIST FLOW RATHER THAN FROM THE ENTRY POINT, and that is deliberate: the
|
|
5
|
+
* package is a library and an MCP server as well as a command, and a list opened through any of
|
|
6
|
+
* those doors has to be able to expand a zstd frame the browser wrote. Putting it here also
|
|
7
|
+
* means `nmts --help` never loads it.
|
|
8
|
+
*/
|
|
9
|
+
export declare function registerNodeZstd(): void;
|
|
10
|
+
/** For tests that need this process to look like a build with no encoder. */
|
|
11
|
+
export declare function forgetNodeZstd(): void;
|