@needmoretruth/nmts-cli 0.17.2 → 0.34.2
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 +125 -517
- package/CHANGELOG.md +104 -0
- package/README.ko.md +377 -469
- package/README.md +394 -474
- 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
package/dist/upload.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type Reservation } from "./upload-store.ts";
|
|
2
|
+
import { type PaidPart, type UploadInput, type UploadResult } from "./upload-wire.ts";
|
|
3
|
+
export * from "./upload-wire.ts";
|
|
4
|
+
/**
|
|
5
|
+
* Buy storage for ONE PART, put its bytes on the network, and stop there.
|
|
6
|
+
*
|
|
7
|
+
* ⛔ IT DOES NOT MAKE A FILE. Committing is one act for the whole file — `commitItem` names every
|
|
8
|
+
* part at once — and a part that returns from here is bought, filled and certified storage that
|
|
9
|
+
* nothing in the account can see yet. Splitting it this way is what lets a file be larger than
|
|
10
|
+
* memory: the parts are bought one at a time, each written down before its own money moves.
|
|
11
|
+
*
|
|
12
|
+
* ⛔ IT DOES NOT WRITE THE FILE LIST either. That is the caller's step, and it must happen before
|
|
13
|
+
* the records are cleared — a committed file the list does not name is invisible and, to the
|
|
14
|
+
* person, indistinguishable from one that never uploaded.
|
|
15
|
+
*/
|
|
16
|
+
export declare function buyAndPushPart(input: UploadInput): Promise<PaidPart>;
|
|
17
|
+
/** What the file list must record about this upload. Always from the record, never from a run. */
|
|
18
|
+
export declare function entryOf(record: Reservation): UploadResult["entry"];
|
package/dist/upload.js
CHANGED
|
@@ -59,6 +59,15 @@ export async function buyAndPushPart(input) {
|
|
|
59
59
|
// file splits some other way would file storage under the wrong position in the file. It
|
|
60
60
|
// happens for one ordinary reason — the same file put again with a different part size — so
|
|
61
61
|
// it is said plainly rather than left to fail later as an unreadable download.
|
|
62
|
+
if (existing?.paidFrom === "wallet") {
|
|
63
|
+
throw new UploadError({
|
|
64
|
+
phase: "reserve",
|
|
65
|
+
message: "This upload was started with the wallet paying, and this run would pay with credits.",
|
|
66
|
+
paid: existing.registerTxDigest !== undefined,
|
|
67
|
+
nextStep: "Run it again with --pay wallet to finish it, or move the records in the uploads directory " +
|
|
68
|
+
"aside to start over with credits. Nothing was sent.",
|
|
69
|
+
});
|
|
70
|
+
}
|
|
62
71
|
if (existing !== null) {
|
|
63
72
|
const record = existing;
|
|
64
73
|
if (record.partIndex !== input.part.index || record.partTotal !== input.part.total) {
|
|
@@ -184,6 +193,7 @@ export async function buyAndPushPart(input) {
|
|
|
184
193
|
// on are the same sealed bytes.
|
|
185
194
|
size: sealed.length,
|
|
186
195
|
epochs: input.epochs,
|
|
196
|
+
deposit_credits: input.depositCredits,
|
|
187
197
|
relay: {
|
|
188
198
|
host: input.relayUrl,
|
|
189
199
|
blob_digest_b64: Buffer.from(meta.blobDigest).toString("base64url"),
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type ManifestIndex } from "./drive-paths.ts";
|
|
2
|
+
/** How many of the largest files a report carries. */
|
|
3
|
+
export declare const BIGGEST_SHOWN = 5;
|
|
4
|
+
/** One of the largest files, with enough to go and fetch it. */
|
|
5
|
+
export interface BiggestFile {
|
|
6
|
+
id: string;
|
|
7
|
+
name: string;
|
|
8
|
+
/** The whole path, exactly as `ls` prints it and `get` accepts it. */
|
|
9
|
+
path: string;
|
|
10
|
+
size: number;
|
|
11
|
+
}
|
|
12
|
+
export interface UsageReport {
|
|
13
|
+
/** Live files. Folders hold nothing, so they are not in this. */
|
|
14
|
+
files: number;
|
|
15
|
+
/** Live folders. */
|
|
16
|
+
folders: number;
|
|
17
|
+
/** Plaintext bytes of the live files. */
|
|
18
|
+
bytes: number;
|
|
19
|
+
/** Files sitting in the trash — still stored, still paid for. */
|
|
20
|
+
trashedFiles: number;
|
|
21
|
+
/** Plaintext bytes held by those — the figure that explains "deleting did not free anything". */
|
|
22
|
+
trashedBytes: number;
|
|
23
|
+
/** The largest live files, largest first. At most `BIGGEST_SHOWN` of them. */
|
|
24
|
+
biggest: BiggestFile[];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The whole report, in one pass over the list.
|
|
28
|
+
*
|
|
29
|
+
* The counts come from the same `totalsOf` the browser's own usage figures are built on — this
|
|
30
|
+
* package carries that module as a byte-for-byte copy — so the two cannot drift into disagreeing
|
|
31
|
+
* about what "in the trash" means. Being in the trash is INHERITED: a file under a trashed folder
|
|
32
|
+
* is trashed even though nothing marked the file itself, and a count that read only the file's own
|
|
33
|
+
* mark would report bytes as live that the server has already stopped serving.
|
|
34
|
+
*/
|
|
35
|
+
export declare function computeUsage(index: ManifestIndex): UsageReport;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ActivityFetch } from "./commands/wallet-activity.ts";
|
|
2
|
+
import type { Network } from "./network.ts";
|
|
3
|
+
/** How long the two questions get together. A read that stalls is a read that failed. */
|
|
4
|
+
export declare const ACTIVITY_TIMEOUT_MS = 20000;
|
|
5
|
+
export declare function queryActivity(network: Network, address: string): Promise<ActivityFetch>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
// The live read behind `nmts wallet activity`: the chain's two lists for one address.
|
|
2
|
+
//
|
|
3
|
+
// ⛔ READ ONLY. The same JSON-RPC client `wallet-chain.ts` reads balances with; nothing here builds
|
|
4
|
+
// or signs a transaction. Imported lazily, only when no seam was supplied.
|
|
5
|
+
import { SuiJsonRpcClient } from "@mysten/sui/jsonRpc";
|
|
6
|
+
import { FETCH_PER_DIRECTION } from "./commands/wallet-activity.js";
|
|
7
|
+
import { suiRpcTransport } from "./sui-rpc.js";
|
|
8
|
+
/** How long the two questions get together. A read that stalls is a read that failed. */
|
|
9
|
+
export const ACTIVITY_TIMEOUT_MS = 20_000;
|
|
10
|
+
export async function queryActivity(network, address) {
|
|
11
|
+
const client = new SuiJsonRpcClient({ network, transport: suiRpcTransport(network) });
|
|
12
|
+
const options = { showBalanceChanges: true, showInput: true, showEffects: true };
|
|
13
|
+
const signal = AbortSignal.timeout(ACTIVITY_TIMEOUT_MS);
|
|
14
|
+
const [sent, received] = await Promise.all([
|
|
15
|
+
client.queryTransactionBlocks({
|
|
16
|
+
filter: { FromAddress: address },
|
|
17
|
+
options,
|
|
18
|
+
limit: FETCH_PER_DIRECTION,
|
|
19
|
+
order: "descending",
|
|
20
|
+
signal,
|
|
21
|
+
}),
|
|
22
|
+
client.queryTransactionBlocks({
|
|
23
|
+
filter: { ToAddress: address },
|
|
24
|
+
options,
|
|
25
|
+
limit: FETCH_PER_DIRECTION,
|
|
26
|
+
order: "descending",
|
|
27
|
+
signal,
|
|
28
|
+
}),
|
|
29
|
+
]);
|
|
30
|
+
return { sent: sent.data, received: received.data };
|
|
31
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Network } from "./network.ts";
|
|
2
|
+
import type { ChainReader } from "./wallet.ts";
|
|
3
|
+
/**
|
|
4
|
+
* How long one balance question gets.
|
|
5
|
+
*
|
|
6
|
+
* A read that stalls is a read that failed, and the caller has something honest to print either
|
|
7
|
+
* way. Long enough for a slow public node, short enough that an agent waiting on this does not
|
|
8
|
+
* conclude the tool has hung.
|
|
9
|
+
*/
|
|
10
|
+
export declare const BALANCE_TIMEOUT_MS = 20000;
|
|
11
|
+
/**
|
|
12
|
+
* Read balances for one address on one network.
|
|
13
|
+
*
|
|
14
|
+
* ⚠ THE NODE IS NOT TRUSTED WITH ANYTHING, and it does not have to be: what it answers is printed
|
|
15
|
+
* as a number and nothing is decided on it. A node that lies about a balance produces a wrong
|
|
16
|
+
* number on a screen — where its owner will see it disagree with every other wallet they own —
|
|
17
|
+
* and it cannot produce a wrong address, because the address never came from it.
|
|
18
|
+
*/
|
|
19
|
+
export declare function chainReader(network: Network, address: string): ChainReader;
|
package/dist/wallet-chain.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
// same question about the same address — so nothing about this run leaves that was not already
|
|
12
12
|
// published by the chain itself.
|
|
13
13
|
import { SuiJsonRpcClient } from "@mysten/sui/jsonRpc";
|
|
14
|
-
import {
|
|
14
|
+
import { suiRpcTransport } from "./sui-rpc.js";
|
|
15
15
|
/**
|
|
16
16
|
* How long one balance question gets.
|
|
17
17
|
*
|
|
@@ -31,7 +31,7 @@ export const BALANCE_TIMEOUT_MS = 20_000;
|
|
|
31
31
|
export function chainReader(network, address) {
|
|
32
32
|
// The network name reaches the SDK as well as the URL, which is what keeps a mirror pointed at
|
|
33
33
|
// the wrong chain from being discovered later, as an answer that quietly made no sense.
|
|
34
|
-
const client = new SuiJsonRpcClient({ network,
|
|
34
|
+
const client = new SuiJsonRpcClient({ network, transport: suiRpcTransport(network) });
|
|
35
35
|
return {
|
|
36
36
|
async totalOf(coinType) {
|
|
37
37
|
const { totalBalance } = await client.getBalance({
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export declare const WALLET_SCOPES: readonly ["storage", "all"];
|
|
2
|
+
export type WalletScope = (typeof WALLET_SCOPES)[number];
|
|
3
|
+
/** What a signature is for. `donate` is deliberately not here: no grant reaches a gift. */
|
|
4
|
+
export type WalletAction = "extend" | "seal" | "reshape" | "exchange" | "send" | "give";
|
|
5
|
+
/** The ceiling on any grant's length. The browser's standing approval has the same one. */
|
|
6
|
+
export declare const MAX_GRANT_DAYS = 30;
|
|
7
|
+
export interface WalletGrant {
|
|
8
|
+
scope: WalletScope;
|
|
9
|
+
grantedAt: string;
|
|
10
|
+
expiresAt: string;
|
|
11
|
+
byVersion: string;
|
|
12
|
+
/** Ceilings in base units, as strings (a JSON number would round them). `null` = no ceiling. */
|
|
13
|
+
capWalFrost: string | null;
|
|
14
|
+
capSuiMist: string | null;
|
|
15
|
+
/** What this tool has signed away under this grant, in base units. */
|
|
16
|
+
spentWalFrost: string;
|
|
17
|
+
spentSuiMist: string;
|
|
18
|
+
}
|
|
19
|
+
export interface Spend {
|
|
20
|
+
walFrost: bigint;
|
|
21
|
+
suiMist: bigint;
|
|
22
|
+
}
|
|
23
|
+
/** A decimal coin amount ("1.25") as base units. Nine decimals, like the chain. */
|
|
24
|
+
export declare function parseCoinAmount(text: string, what: string): bigint;
|
|
25
|
+
export declare function scopeCovers(scope: WalletScope, action: WalletAction): boolean;
|
|
26
|
+
/** Turn what was typed into a grant, or refuse with the line to correct. Nothing is written. */
|
|
27
|
+
export declare function parseWalletGrant(input: {
|
|
28
|
+
days?: string | undefined;
|
|
29
|
+
until?: string | undefined;
|
|
30
|
+
scope?: string | undefined;
|
|
31
|
+
capWal?: string | undefined;
|
|
32
|
+
capSui?: string | undefined;
|
|
33
|
+
}, now: Date, version: string): WalletGrant;
|
|
34
|
+
/** The grant on this machine, or null — an older bare-date record, or a malformed one, is null. */
|
|
35
|
+
export declare function readWalletGrant(): WalletGrant | null;
|
|
36
|
+
export declare function writeWalletGrant(grant: WalletGrant): void;
|
|
37
|
+
export type GrantState = "none" | "expired" | "active";
|
|
38
|
+
export declare function walletGrantState(grant: WalletGrant | null, now: Date): GrantState;
|
|
39
|
+
/** What is left under a ceiling, or null when there is none. */
|
|
40
|
+
export declare function roomLeft(cap: string | null, spent: string): bigint | null;
|
|
41
|
+
/**
|
|
42
|
+
* Stop unless an active grant covers this signature and its amount, and say what would.
|
|
43
|
+
*
|
|
44
|
+
* ⛔ THE MESSAGE IS THE PRODUCT HERE, as with every other agreement: what happens, what can go
|
|
45
|
+
* wrong, what is not covered, and the one command that agrees — and, new for this key, the
|
|
46
|
+
* three things the grant carries.
|
|
47
|
+
*/
|
|
48
|
+
export declare function requireWalletGrant(action: WalletAction, spend: Spend, now: Date): WalletGrant;
|
|
49
|
+
/** Add what was just signed to the grant's ledger. Called after a signature, never before. */
|
|
50
|
+
export declare function recordWalletSpend(spend: Spend): void;
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
// The `wallet` agreement with a SCOPE, an EXPIRY and, if the person wants one, a SPENDING CEILING.
|
|
2
|
+
//
|
|
3
|
+
// ⛔ WHY THE PLAIN "ONCE PER MACHINE, FOREVER" GRANT WAS NOT ENOUGH HERE. Every other agreement in
|
|
4
|
+
// this tool is about a capability whose cost is bounded by something else — credits by the
|
|
5
|
+
// server's ceilings, a share by the file it names. A wallet has no such bound: whatever is in it
|
|
6
|
+
// can leave in one signature, and an agent in `mode auto` that could grant an open-ended wallet
|
|
7
|
+
// agreement could give ITSELF unlimited, indefinite spending. So this one grant carries three
|
|
8
|
+
// things the others do not, in the same file, under the same key:
|
|
9
|
+
// · a scope — `storage` (extending a file's lease, paying for a file's storage) or `all`
|
|
10
|
+
// (also exchanging and sending). A gift is in neither: a person approves every gift.
|
|
11
|
+
// · an expiry — never more than 30 days away. The browser's standing approval has the same
|
|
12
|
+
// ceiling, for the same reason: a grant nobody remembers giving should run out on its own.
|
|
13
|
+
// · optionally a ceiling per coin. What this tool signs under the grant is added up here,
|
|
14
|
+
// and a signature that would pass the ceiling is refused BEFORE it is made.
|
|
15
|
+
//
|
|
16
|
+
// ⛔ AN OLDER RECORD WITHOUT AN EXPIRY COUNTS AS NO GRANT. Versions before this one wrote the wallet
|
|
17
|
+
// agreement as a bare date. Reading that as "agreed to everything, forever" would be the exact
|
|
18
|
+
// grant this file exists to make impossible, so it is asked for again — with the new words.
|
|
19
|
+
//
|
|
20
|
+
// ⚠ THE LEDGER IS THIS MACHINE'S. It counts what THIS tool signed under THIS grant. The wallet can
|
|
21
|
+
// be spent from elsewhere with the same NMTS key, and nothing here can see that.
|
|
22
|
+
import { NmtsError } from "./errors.js";
|
|
23
|
+
import { readConsentRecords, writeConsentRecords } from "./consent.js";
|
|
24
|
+
import { BINARY_NAME, SUPPORT_EMAIL } from "./product.js";
|
|
25
|
+
import { coinAmount } from "./wallet.js";
|
|
26
|
+
export const WALLET_SCOPES = ["storage", "all"];
|
|
27
|
+
const SCOPE_ACTIONS = {
|
|
28
|
+
storage: ["extend", "seal", "reshape"],
|
|
29
|
+
all: ["extend", "seal", "reshape", "exchange", "send", "give"],
|
|
30
|
+
};
|
|
31
|
+
/** The ceiling on any grant's length. The browser's standing approval has the same one. */
|
|
32
|
+
export const MAX_GRANT_DAYS = 30;
|
|
33
|
+
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
34
|
+
/** A decimal coin amount ("1.25") as base units. Nine decimals, like the chain. */
|
|
35
|
+
export function parseCoinAmount(text, what) {
|
|
36
|
+
const m = /^(\d+)(?:\.(\d{1,9}))?$/.exec(text.trim());
|
|
37
|
+
if (m === null || m[1] === undefined) {
|
|
38
|
+
throw new NmtsError(`${what} must be a number of coins, like 12 or 0.5.`, { exitCode: 2 });
|
|
39
|
+
}
|
|
40
|
+
return BigInt(m[1]) * 1000000000n + BigInt((m[2] ?? "").padEnd(9, "0"));
|
|
41
|
+
}
|
|
42
|
+
export function scopeCovers(scope, action) {
|
|
43
|
+
return SCOPE_ACTIONS[scope].includes(action);
|
|
44
|
+
}
|
|
45
|
+
/** Turn what was typed into a grant, or refuse with the line to correct. Nothing is written. */
|
|
46
|
+
export function parseWalletGrant(input, now, version) {
|
|
47
|
+
const scope = input.scope ?? "storage";
|
|
48
|
+
if (!WALLET_SCOPES.includes(scope)) {
|
|
49
|
+
throw new NmtsError(`--scope must be one of: ${WALLET_SCOPES.join(" · ")}.`, {
|
|
50
|
+
exitCode: 2,
|
|
51
|
+
nextStep: "storage = extending a file's lease and paying for a file's storage. all = also exchanging and sending. A gift is in neither.",
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
let expiresMs;
|
|
55
|
+
if (input.until !== undefined) {
|
|
56
|
+
const at = Date.parse(input.until);
|
|
57
|
+
if (!Number.isFinite(at)) {
|
|
58
|
+
throw new NmtsError("--until must be a date, like 2026-09-30 or 2026-09-30T12:00Z.", { exitCode: 2 });
|
|
59
|
+
}
|
|
60
|
+
expiresMs = at;
|
|
61
|
+
}
|
|
62
|
+
else if (input.days !== undefined) {
|
|
63
|
+
const days = Number(input.days);
|
|
64
|
+
if (!Number.isInteger(days) || days < 1) {
|
|
65
|
+
throw new NmtsError("--days must be a whole number of days, at least 1.", { exitCode: 2 });
|
|
66
|
+
}
|
|
67
|
+
expiresMs = now.getTime() + days * DAY_MS;
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
throw new NmtsError("A wallet agreement needs an expiry: say how long it lasts.", {
|
|
71
|
+
exitCode: 2,
|
|
72
|
+
nextStep: `\`${BINARY_NAME} unlock wallet --days 7\` (up to ${MAX_GRANT_DAYS}), or --until <date>. ` +
|
|
73
|
+
`Add --scope storage|all (default storage) and, if you want a ceiling, --cap-wal <coins> --cap-sui <coins>.`,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
const ceiling = now.getTime() + MAX_GRANT_DAYS * DAY_MS;
|
|
77
|
+
if (expiresMs <= now.getTime()) {
|
|
78
|
+
throw new NmtsError("That expiry is already in the past.", { exitCode: 2 });
|
|
79
|
+
}
|
|
80
|
+
if (expiresMs > ceiling) {
|
|
81
|
+
throw new NmtsError(`A wallet agreement lasts at most ${MAX_GRANT_DAYS} days.`, {
|
|
82
|
+
exitCode: 2,
|
|
83
|
+
nextStep: `Grant it again when it runs out. That is the point: a grant nobody remembers giving should run out on its own.`,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
return {
|
|
87
|
+
scope: scope,
|
|
88
|
+
grantedAt: now.toISOString(),
|
|
89
|
+
expiresAt: new Date(expiresMs).toISOString(),
|
|
90
|
+
byVersion: version,
|
|
91
|
+
capWalFrost: input.capWal === undefined ? null : parseCoinAmount(input.capWal, "--cap-wal").toString(),
|
|
92
|
+
capSuiMist: input.capSui === undefined ? null : parseCoinAmount(input.capSui, "--cap-sui").toString(),
|
|
93
|
+
spentWalFrost: "0",
|
|
94
|
+
spentSuiMist: "0",
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function isScope(value) {
|
|
98
|
+
return typeof value === "string" && WALLET_SCOPES.includes(value);
|
|
99
|
+
}
|
|
100
|
+
/** The grant on this machine, or null — an older bare-date record, or a malformed one, is null. */
|
|
101
|
+
export function readWalletGrant() {
|
|
102
|
+
const raw = readConsentRecords()["wallet"];
|
|
103
|
+
if (typeof raw !== "object" || raw === null)
|
|
104
|
+
return null;
|
|
105
|
+
const at = (name) => Reflect.get(raw, name);
|
|
106
|
+
const scope = at("scope");
|
|
107
|
+
const grantedAt = at("grantedAt");
|
|
108
|
+
const expiresAt = at("expiresAt");
|
|
109
|
+
const byVersion = at("byVersion");
|
|
110
|
+
if (!isScope(scope) || typeof grantedAt !== "string" || typeof expiresAt !== "string" || typeof byVersion !== "string") {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
const units = (name) => {
|
|
114
|
+
const v = at(name);
|
|
115
|
+
return typeof v === "string" && /^\d+$/.test(v) ? v : null;
|
|
116
|
+
};
|
|
117
|
+
return {
|
|
118
|
+
scope,
|
|
119
|
+
grantedAt,
|
|
120
|
+
expiresAt,
|
|
121
|
+
byVersion,
|
|
122
|
+
capWalFrost: units("capWalFrost"),
|
|
123
|
+
capSuiMist: units("capSuiMist"),
|
|
124
|
+
spentWalFrost: units("spentWalFrost") ?? "0",
|
|
125
|
+
spentSuiMist: units("spentSuiMist") ?? "0",
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
export function writeWalletGrant(grant) {
|
|
129
|
+
const all = readConsentRecords();
|
|
130
|
+
all["wallet"] = grant;
|
|
131
|
+
writeConsentRecords(all);
|
|
132
|
+
}
|
|
133
|
+
export function walletGrantState(grant, now) {
|
|
134
|
+
if (grant === null)
|
|
135
|
+
return "none";
|
|
136
|
+
return Date.parse(grant.expiresAt) > now.getTime() ? "active" : "expired";
|
|
137
|
+
}
|
|
138
|
+
/** What is left under a ceiling, or null when there is none. */
|
|
139
|
+
export function roomLeft(cap, spent) {
|
|
140
|
+
return cap === null ? null : BigInt(cap) - BigInt(spent);
|
|
141
|
+
}
|
|
142
|
+
const GRANT_COMMAND = `${BINARY_NAME} unlock wallet --days 7`;
|
|
143
|
+
/**
|
|
144
|
+
* Stop unless an active grant covers this signature and its amount, and say what would.
|
|
145
|
+
*
|
|
146
|
+
* ⛔ THE MESSAGE IS THE PRODUCT HERE, as with every other agreement: what happens, what can go
|
|
147
|
+
* wrong, what is not covered, and the one command that agrees — and, new for this key, the
|
|
148
|
+
* three things the grant carries.
|
|
149
|
+
*/
|
|
150
|
+
export function requireWalletGrant(action, spend, now) {
|
|
151
|
+
const grant = readWalletGrant();
|
|
152
|
+
const state = walletGrantState(grant, now);
|
|
153
|
+
const tail = [
|
|
154
|
+
"",
|
|
155
|
+
`NMTS is not responsible for what is done with this account by any program running on this`,
|
|
156
|
+
`machine, including an AI agent. The published Terms are what govern the service; this is a`,
|
|
157
|
+
`warning, not a substitute for them.`,
|
|
158
|
+
"",
|
|
159
|
+
`⛔ If a program is reading this on somebody's behalf: show it to them and let them decide.`,
|
|
160
|
+
` Do not run the unlock command yourself.`,
|
|
161
|
+
"",
|
|
162
|
+
`Something wrong or confusing here? ${SUPPORT_EMAIL}`,
|
|
163
|
+
];
|
|
164
|
+
const refuse = (what, why) => new NmtsError(what, { exitCode: 5, nextStep: [...why, ...tail].join("\n") });
|
|
165
|
+
if (state === "none" || grant === null) {
|
|
166
|
+
throw refuse("Use the wallet this NMTS key derives, and sign transactions with it.", [
|
|
167
|
+
"A signed transaction moves real assets and cannot be reversed by anybody, including NMTS. " +
|
|
168
|
+
"A mistake here is permanent.",
|
|
169
|
+
"",
|
|
170
|
+
"This agreement carries three things: a scope (storage = extending and paying for storage; " +
|
|
171
|
+
"all = also exchanging and sending — a gift is in neither), an expiry of at most " +
|
|
172
|
+
`${MAX_GRANT_DAYS} days, and, if you want one, a ceiling on what this tool may sign away.`,
|
|
173
|
+
"Only what this tool signs is counted. Handing the NMTS key to another program gives " +
|
|
174
|
+
"that program the same wallet, and nothing here can see that happen.",
|
|
175
|
+
"",
|
|
176
|
+
`To unlock, at a terminal, for a week: ${GRANT_COMMAND}`,
|
|
177
|
+
` add --scope all to cover exchanging and sending; --cap-wal <coins> --cap-sui <coins> for a ceiling`,
|
|
178
|
+
`To see what is unlocked: ${BINARY_NAME} unlock`,
|
|
179
|
+
]);
|
|
180
|
+
}
|
|
181
|
+
if (state === "expired") {
|
|
182
|
+
throw refuse(`The wallet agreement on this machine ran out on ${grant.expiresAt}.`, [
|
|
183
|
+
`It was given on ${grant.grantedAt} for scope "${grant.scope}". Nothing was signed.`,
|
|
184
|
+
`To agree again: ${GRANT_COMMAND}`,
|
|
185
|
+
]);
|
|
186
|
+
}
|
|
187
|
+
if (!scopeCovers(grant.scope, action)) {
|
|
188
|
+
throw refuse(`The wallet agreement on this machine covers storage only, and this would ${action}.`, [
|
|
189
|
+
`Nothing was signed. To widen it: ${BINARY_NAME} unlock wallet --days 7 --scope all`,
|
|
190
|
+
]);
|
|
191
|
+
}
|
|
192
|
+
const walRoom = roomLeft(grant.capWalFrost, grant.spentWalFrost);
|
|
193
|
+
const suiRoom = roomLeft(grant.capSuiMist, grant.spentSuiMist);
|
|
194
|
+
if (walRoom !== null && spend.walFrost > walRoom) {
|
|
195
|
+
throw refuse(`This would sign away ${coinAmount(spend.walFrost)} WAL and the agreement has ${coinAmount(walRoom < 0n ? 0n : walRoom)} WAL left under its ceiling.`, [
|
|
196
|
+
`Ceiling ${coinAmount(BigInt(grant.capWalFrost ?? "0"))} WAL, of which ${coinAmount(BigInt(grant.spentWalFrost))} WAL is already signed away since ${grant.grantedAt}. Nothing was signed.`,
|
|
197
|
+
`To raise it, agree again with a higher --cap-wal, or without one.`,
|
|
198
|
+
]);
|
|
199
|
+
}
|
|
200
|
+
if (suiRoom !== null && spend.suiMist > suiRoom) {
|
|
201
|
+
throw refuse(`This would spend about ${coinAmount(spend.suiMist)} SUI in fees and the agreement has ${coinAmount(suiRoom < 0n ? 0n : suiRoom)} SUI left under its ceiling.`, [
|
|
202
|
+
`Ceiling ${coinAmount(BigInt(grant.capSuiMist ?? "0"))} SUI, of which ${coinAmount(BigInt(grant.spentSuiMist))} SUI is already counted since ${grant.grantedAt}. Nothing was signed.`,
|
|
203
|
+
`To raise it, agree again with a higher --cap-sui, or without one.`,
|
|
204
|
+
]);
|
|
205
|
+
}
|
|
206
|
+
return grant;
|
|
207
|
+
}
|
|
208
|
+
/** Add what was just signed to the grant's ledger. Called after a signature, never before. */
|
|
209
|
+
export function recordWalletSpend(spend) {
|
|
210
|
+
const grant = readWalletGrant();
|
|
211
|
+
if (grant === null)
|
|
212
|
+
return;
|
|
213
|
+
writeWalletGrant({
|
|
214
|
+
...grant,
|
|
215
|
+
spentWalFrost: (BigInt(grant.spentWalFrost) + spend.walFrost).toString(),
|
|
216
|
+
spentSuiMist: (BigInt(grant.spentSuiMist) + spend.suiMist).toString(),
|
|
217
|
+
});
|
|
218
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Transaction } from "@mysten/sui/transactions";
|
|
2
|
+
import type { Network } from "./network.ts";
|
|
3
|
+
import type { SendCoin } from "./shared/lib/wallet/send-rules.ts";
|
|
4
|
+
import { type WalletBalances } from "./wallet.ts";
|
|
5
|
+
export interface TransferShape {
|
|
6
|
+
coin: SendCoin;
|
|
7
|
+
amountBaseUnits: bigint;
|
|
8
|
+
/** A full, validated Sui address. */
|
|
9
|
+
destination: string;
|
|
10
|
+
/** The WAL coin type of the network (unused for SUI). */
|
|
11
|
+
walType: string;
|
|
12
|
+
/** A gas ceiling, or undefined to let the SDK set one from its own dry run. */
|
|
13
|
+
gasBudgetMist?: bigint | undefined;
|
|
14
|
+
}
|
|
15
|
+
export declare function transferTransaction(input: TransferShape & {
|
|
16
|
+
sender: string;
|
|
17
|
+
}): Transaction;
|
|
18
|
+
/** What `commands/wallet-send.ts` reads before it prints a review. */
|
|
19
|
+
export interface SendReads {
|
|
20
|
+
readWallet(address: string): Promise<WalletBalances>;
|
|
21
|
+
/** The fee in MIST measured by dry-running this exact transfer, or null when it could not be. */
|
|
22
|
+
estimateFee(shape: TransferShape, sender: string): Promise<bigint | null>;
|
|
23
|
+
}
|
|
24
|
+
export declare function sendReads(network: Network): SendReads;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// The transfer transaction and its live reads: the wallet's balances and the fee a dry run measures.
|
|
2
|
+
//
|
|
3
|
+
// ⛔ ONE BUILDER FOR THE FEE AND THE SIGNATURE. `estimateTransferFee` and `wallet-sign.ts` both call
|
|
4
|
+
// `transferTransaction`, so the fee printed is the fee of the transaction that is then signed. Two
|
|
5
|
+
// builders would let a screen price one transaction and approve another.
|
|
6
|
+
//
|
|
7
|
+
// ⛔ THE TWO COINS MOVE DIFFERENTLY, and the difference is not cosmetic: SUI is split off the gas
|
|
8
|
+
// coin the transaction is already paying with; WAL is a separate coin type gathered from the
|
|
9
|
+
// wallet's own WAL coins, and the gas is still SUI. The browser's `withdrawFromEmbedded` does the
|
|
10
|
+
// same two things.
|
|
11
|
+
import { coinWithBalance, Transaction } from "@mysten/sui/transactions";
|
|
12
|
+
import { walrusClient, netGasFee } from "./extend-chain.js";
|
|
13
|
+
import { readBalances, walCoinType } from "./wallet.js";
|
|
14
|
+
import { chainReader } from "./wallet-chain.js";
|
|
15
|
+
export function transferTransaction(input) {
|
|
16
|
+
const tx = new Transaction();
|
|
17
|
+
tx.setSender(input.sender);
|
|
18
|
+
if (input.coin === "SUI") {
|
|
19
|
+
const [sui] = tx.splitCoins(tx.gas, [input.amountBaseUnits]);
|
|
20
|
+
tx.transferObjects([sui], input.destination);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
const wal = tx.add(coinWithBalance({ balance: input.amountBaseUnits, type: input.walType }));
|
|
24
|
+
tx.transferObjects([wal], input.destination);
|
|
25
|
+
}
|
|
26
|
+
if (input.gasBudgetMist !== undefined)
|
|
27
|
+
tx.setGasBudget(input.gasBudgetMist);
|
|
28
|
+
return tx;
|
|
29
|
+
}
|
|
30
|
+
export function sendReads(network) {
|
|
31
|
+
const client = walrusClient(network);
|
|
32
|
+
return {
|
|
33
|
+
async readWallet(address) {
|
|
34
|
+
return readBalances(chainReader(network, address), walCoinType(network));
|
|
35
|
+
},
|
|
36
|
+
async estimateFee(shape, sender) {
|
|
37
|
+
try {
|
|
38
|
+
const bytes = await transferTransaction({ ...shape, sender }).build({ client });
|
|
39
|
+
const { effects } = await client.dryRunTransactionBlock({ transactionBlock: bytes });
|
|
40
|
+
if (effects.status.status !== "success")
|
|
41
|
+
return null;
|
|
42
|
+
return netGasFee(effects.gasUsed);
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import type { SignExtension } from "./extend-plan.ts";
|
|
2
|
+
import { type TransferShape } from "./wallet-send-chain.ts";
|
|
3
|
+
import { type StorageOpShape } from "./storage-control-chain.ts";
|
|
4
|
+
import { type SwapShape } from "./wallet-swap-chain.ts";
|
|
5
|
+
import type { Network } from "./network.ts";
|
|
6
|
+
import type { RegisterShape } from "./upload-wallet-plan.ts";
|
|
7
|
+
import type { Certificate } from "./upload-wire.ts";
|
|
8
|
+
/**
|
|
9
|
+
* The address this tool would sign as.
|
|
10
|
+
*
|
|
11
|
+
* ⛔ IT EXISTS TO BE HELD AGAINST `walletAddress`. That function is what `nmts wallet address`
|
|
12
|
+
* prints and what somebody funds; this one is what a transaction would actually be signed by.
|
|
13
|
+
* Nothing else in this package proves the two are the same wallet, and the failure if they ever
|
|
14
|
+
* part is silent — a signature from an address with nothing in it, or worse, money sent to an
|
|
15
|
+
* address that signs nothing. A test compares them, offline, for free.
|
|
16
|
+
*/
|
|
17
|
+
export declare function signerAddress(code: string): Promise<string>;
|
|
18
|
+
/**
|
|
19
|
+
* Extend every listed blob by `epochs`, in ONE transaction, signed by the account's own wallet.
|
|
20
|
+
*
|
|
21
|
+
* ONE SIGNATURE FOR ALL OF IT: `extendBlob` returns a transaction fragment, so every blob a file
|
|
22
|
+
* sits on goes into the same transaction. A multi-part file is one payment and one gas fee, not
|
|
23
|
+
* five — and a partial extension would buy nothing, because one expired blob is enough to make the
|
|
24
|
+
* file unreadable.
|
|
25
|
+
*
|
|
26
|
+
* ⛔ THE IDS ARE DE-DUPLICATED. Naming the same blob twice pays for the same epochs twice.
|
|
27
|
+
*
|
|
28
|
+
* ⚠ A FAILURE HERE IS NOT PROOF THAT NOTHING HAPPENED. A refusal from the node, a timeout, a
|
|
29
|
+
* connection that dropped after the bytes went out — none of them say whether the transaction
|
|
30
|
+
* was executed. The caller re-reads the chain rather than offering a second attempt against
|
|
31
|
+
* numbers it read before.
|
|
32
|
+
*/
|
|
33
|
+
export declare const signExtension: SignExtension;
|
|
34
|
+
/**
|
|
35
|
+
* Send SUI or WAL to one address, in ONE transaction, signed by the account's own wallet.
|
|
36
|
+
*
|
|
37
|
+
* ⛔ THE TRANSACTION IS BUILT BY `wallet-send-chain.ts`, the same builder the fee was measured
|
|
38
|
+
* with, so what is signed is what was priced. The destination is whatever the caller validated
|
|
39
|
+
* (`send-rules.ts`) — nothing here checks it again, and nothing can take it back.
|
|
40
|
+
*
|
|
41
|
+
* ⚠ A FAILURE HERE IS NOT PROOF THAT NOTHING HAPPENED — the same words as the extension above.
|
|
42
|
+
*/
|
|
43
|
+
export declare const signTransfer: SignTransfer;
|
|
44
|
+
/**
|
|
45
|
+
* Sign one short message with the account's own wallet. NOT a transaction: nothing moves.
|
|
46
|
+
*
|
|
47
|
+
* ⛔ THE MESSAGE IS THE CALLER'S, WHOLE AND UNCHANGED — the server rebuilds the same bytes from
|
|
48
|
+
* the fields it was sent, so a byte added here would invalidate every signature this tool
|
|
49
|
+
* makes. `signPersonalMessage` and not `sign`: that intent is the domain separator which stops
|
|
50
|
+
* signed text from ever being read as a transaction this wallet authorised.
|
|
51
|
+
*/
|
|
52
|
+
export declare const signMessage: SignMessage;
|
|
53
|
+
/** The seam `commands/wallet-hall.ts` signs through. Returns the base64 signature, nothing else. */
|
|
54
|
+
export type SignMessage = (input: {
|
|
55
|
+
/** ⛔ The NMTS key. It never leaves this machine: it derives the wallet and nothing else. */
|
|
56
|
+
code: string;
|
|
57
|
+
message: string;
|
|
58
|
+
}) => Promise<string>;
|
|
59
|
+
/** The seam `commands/wallet-send.ts` signs through. Returns the transaction digest. */
|
|
60
|
+
export type SignTransfer = (input: {
|
|
61
|
+
network: string;
|
|
62
|
+
/** ⛔ The NMTS key. It never leaves this machine: it derives the wallet and nothing else. */
|
|
63
|
+
code: string;
|
|
64
|
+
shape: TransferShape;
|
|
65
|
+
}) => Promise<string>;
|
|
66
|
+
/**
|
|
67
|
+
* Swap SUI for WAL or WAL for SUI on the named venue, in ONE transaction, signed by the account's
|
|
68
|
+
* own wallet. Every output goes back to the signer — DeepBook's three coins are sent there by this
|
|
69
|
+
* transaction, Bluefin's by its own entry function — so there is no destination to get wrong.
|
|
70
|
+
*
|
|
71
|
+
* ⛔ THE TRANSACTION IS BUILT BY `wallet-swap-chain.ts`, the same builder the fee was measured with,
|
|
72
|
+
* on the same Bluefin package the quote used. The minimum-out in the shape is what protects the
|
|
73
|
+
* person: the chain refuses a swap that would give less, and the fee for that refusal is spent.
|
|
74
|
+
*
|
|
75
|
+
* ⚠ A FAILURE HERE IS NOT PROOF THAT NOTHING HAPPENED — the same words as the extension above.
|
|
76
|
+
*/
|
|
77
|
+
export declare const signSwap: SignSwap;
|
|
78
|
+
/** The seam `commands/wallet-swap.ts` signs through. Returns the transaction digest. */
|
|
79
|
+
export type SignSwap = (input: {
|
|
80
|
+
network: Network;
|
|
81
|
+
/** ⛔ The NMTS key. It never leaves this machine: it derives the wallet and nothing else. */
|
|
82
|
+
code: string;
|
|
83
|
+
shape: SwapShape;
|
|
84
|
+
}) => Promise<string>;
|
|
85
|
+
/**
|
|
86
|
+
* Register ONE part's blob, signed by the account's own wallet: the relay's tip, then the storage
|
|
87
|
+
* — bought for `epochs`, or a resource the wallet already holds, cut to fit first if asked.
|
|
88
|
+
*
|
|
89
|
+
* ⛔ THE TRANSACTION IS BUILT BY `upload-wallet-chain.ts`, the same builder the fee was measured
|
|
90
|
+
* with, so what is signed is what was priced. What comes back is what the commit and the resume
|
|
91
|
+
* need: the digest the relay checks its tip in, the blob object, and the epoch the chain says
|
|
92
|
+
* the storage ends at.
|
|
93
|
+
*
|
|
94
|
+
* ⚠ A FAILURE HERE IS NOT PROOF THAT NOTHING HAPPENED — the same words as the extension above.
|
|
95
|
+
* The caller keeps its record and re-reads it rather than registering again.
|
|
96
|
+
*/
|
|
97
|
+
export declare const signBlobRegister: SignBlobRegister;
|
|
98
|
+
/** Certify ONE registered part from the relay's certificate. Gas only; nothing else leaves the wallet. */
|
|
99
|
+
export declare const signBlobCertify: SignBlobCertify;
|
|
100
|
+
/** The seam the wallet rail registers through. */
|
|
101
|
+
export type SignBlobRegister = (input: {
|
|
102
|
+
network: Network;
|
|
103
|
+
code: string;
|
|
104
|
+
relayUrl: string;
|
|
105
|
+
} & RegisterShape) => Promise<{
|
|
106
|
+
digest: string;
|
|
107
|
+
blobObjectId: string;
|
|
108
|
+
endEpoch: number;
|
|
109
|
+
}>;
|
|
110
|
+
/** The seam the wallet rail certifies through. Returns the transaction digest. */
|
|
111
|
+
export type SignBlobCertify = (input: {
|
|
112
|
+
network: Network;
|
|
113
|
+
code: string;
|
|
114
|
+
relayUrl: string;
|
|
115
|
+
blobId: string;
|
|
116
|
+
blobObjectId: string;
|
|
117
|
+
certificate: Certificate;
|
|
118
|
+
}) => Promise<string>;
|
|
119
|
+
/** How a storage-resource operation is signed; the shape carries what the review priced. */
|
|
120
|
+
export type SignStorageOp = (input: {
|
|
121
|
+
network: Network;
|
|
122
|
+
code: string;
|
|
123
|
+
shape: StorageOpShape;
|
|
124
|
+
walrusPackageId: string;
|
|
125
|
+
}) => Promise<string>;
|
|
126
|
+
/**
|
|
127
|
+
* Cut, join or hand over a storage resource, in ONE transaction, signed by the account's own wallet.
|
|
128
|
+
*
|
|
129
|
+
* ⛔ THE TRANSACTION IS BUILT BY `storage-control-chain.ts`, the same builder the dry run priced,
|
|
130
|
+
* so what is signed is what was reviewed. A failed execution still has a digest and still
|
|
131
|
+
* spent its gas, so the status is read and a failure is said as one.
|
|
132
|
+
*/
|
|
133
|
+
export declare const signStorageOp: SignStorageOp;
|