@needmoretruth/nmts-cli 0.34.4 → 0.36.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 +11 -12
- package/CHANGELOG.md +43 -0
- package/README.ko.md +33 -35
- package/README.md +21 -22
- package/dist/account.js +2 -1
- package/dist/arg-options.d.ts +169 -0
- package/dist/arg-options.js +10 -0
- package/dist/args.d.ts +2 -157
- package/dist/args.js +2 -0
- package/dist/artifact-about.d.ts +1 -1
- package/dist/autonomy.d.ts +3 -10
- package/dist/autonomy.js +15 -17
- package/dist/bytes.d.ts +15 -0
- package/dist/bytes.js +63 -0
- package/dist/collision.d.ts +5 -5
- package/dist/collision.js +19 -22
- package/dist/commands/delete-account.js +1 -1
- package/dist/commands/erase.js +1 -1
- package/dist/commands/extend.d.ts +2 -0
- package/dist/commands/extend.js +8 -1
- package/dist/commands/get.js +1 -1
- package/dist/commands/listfile.js +1 -1
- package/dist/commands/mcp.js +5 -1
- package/dist/commands/mode.js +2 -2
- package/dist/commands/on-collision.d.ts +1 -1
- package/dist/commands/on-collision.js +3 -3
- package/dist/commands/platform.d.ts +9 -0
- package/dist/commands/platform.js +124 -0
- package/dist/commands/pull.js +1 -1
- package/dist/commands/push-wallet.js +8 -1
- package/dist/commands/push.d.ts +2 -0
- package/dist/commands/push.js +6 -4
- package/dist/commands/put-payer.d.ts +8 -0
- package/dist/commands/put-payer.js +41 -0
- package/dist/commands/put-wallet.d.ts +9 -3
- package/dist/commands/put-wallet.js +108 -186
- package/dist/commands/put.d.ts +5 -7
- package/dist/commands/put.js +11 -31
- package/dist/commands/receive.js +1 -1
- package/dist/commands/settings.js +1 -1
- package/dist/commands/support.js +3 -3
- package/dist/commands/unlock.js +2 -2
- package/dist/commands/wallet-donate.d.ts +3 -0
- package/dist/commands/wallet-donate.js +6 -2
- package/dist/commands/wallet-hall.d.ts +4 -1
- package/dist/commands/wallet-hall.js +16 -8
- package/dist/commands/wallet-list.d.ts +18 -0
- package/dist/commands/wallet-list.js +116 -0
- package/dist/commands/wallet-send.d.ts +4 -0
- package/dist/commands/wallet-send.js +6 -2
- package/dist/commands/wallet-storage-ops.d.ts +4 -1
- package/dist/commands/wallet-storage-ops.js +7 -2
- package/dist/commands/wallet-swap.d.ts +3 -0
- package/dist/commands/wallet-swap.js +8 -4
- package/dist/commands/wallet-use.d.ts +7 -0
- package/dist/commands/wallet-use.js +55 -0
- package/dist/commands/wallet.d.ts +4 -0
- package/dist/commands/wallet.js +20 -8
- package/dist/crypto.d.ts +8 -5
- package/dist/crypto.js +15 -61
- package/dist/download-sink-node.d.ts +49 -0
- package/dist/download-sink-node.js +204 -0
- package/dist/download-sink.d.ts +0 -48
- package/dist/download-sink.js +6 -199
- package/dist/download.js +5 -4
- package/dist/engine-node.d.ts +19 -0
- package/dist/engine-node.js +77 -0
- package/dist/env-vars.d.ts +20 -0
- package/dist/env-vars.js +27 -0
- package/dist/extend-plan.d.ts +2 -0
- package/dist/gate.js +1 -1
- package/dist/help.js +12 -5
- package/dist/host-contract.d.ts +7 -0
- package/dist/host-contract.js +95 -0
- package/dist/host-node.d.ts +27 -0
- package/dist/host-node.js +192 -0
- package/dist/host.d.ts +99 -0
- package/dist/host.js +59 -0
- package/dist/index.d.ts +6 -40
- package/dist/index.js +20 -32
- package/dist/main.js +11 -10
- package/dist/manifest-chunk-cache.d.ts +3 -3
- package/dist/manifest-chunk-cache.js +39 -44
- package/dist/manifest-chunk-flow.js +15 -14
- package/dist/manifest-write.js +1 -1
- package/dist/manifest.d.ts +2 -2
- package/dist/manifest.js +37 -34
- package/dist/mcp-tools/tiers.js +1 -1
- package/dist/network.d.ts +1 -1
- package/dist/network.js +6 -2
- package/dist/platform-sign.d.ts +143 -0
- package/dist/platform-sign.js +220 -0
- package/dist/portable.d.ts +59 -0
- package/dist/portable.js +82 -0
- package/dist/product.d.ts +1 -1
- package/dist/product.js +1 -1
- package/dist/progress-node.d.ts +2 -0
- package/dist/progress-node.js +14 -0
- package/dist/progress.d.ts +0 -1
- package/dist/progress.js +4 -8
- package/dist/redact.js +3 -2
- package/dist/registration.js +5 -2
- package/dist/risk.d.ts +11 -0
- package/dist/risk.js +16 -0
- package/dist/run-log.d.ts +4 -4
- package/dist/run-log.js +29 -36
- package/dist/seal.js +5 -4
- package/dist/server.d.ts +1 -1
- package/dist/server.js +6 -2
- package/dist/setup-questions.js +2 -2
- package/dist/shared/lib/drive/manifest-ops.d.ts +8 -30
- package/dist/shared/lib/drive/manifest-ops.js +7 -39
- package/dist/shared/lib/drive/manifest-settings-patch.d.ts +52 -0
- package/dist/shared/lib/drive/manifest-settings-patch.js +110 -0
- package/dist/shared/lib/drive/manifest-settings.d.ts +55 -4
- package/dist/shared/lib/drive/manifest-settings.js +66 -28
- package/dist/shared/lib/wallet/discover.d.ts +54 -0
- package/dist/shared/lib/wallet/discover.js +66 -0
- package/dist/standing-tip.d.ts +3 -0
- package/dist/standing-tip.js +1 -0
- package/dist/upload-file-node.d.ts +3 -0
- package/dist/upload-file-node.js +38 -0
- package/dist/upload-file.d.ts +2 -2
- package/dist/upload-file.js +15 -45
- package/dist/upload-price-node.d.ts +8 -0
- package/dist/upload-price-node.js +37 -0
- package/dist/upload-price.d.ts +0 -8
- package/dist/upload-price.js +4 -33
- package/dist/upload-steps.js +3 -3
- package/dist/upload-store.d.ts +14 -14
- package/dist/upload-store.js +68 -75
- package/dist/upload-wallet-chain.js +3 -2
- package/dist/upload-wallet-put.d.ts +118 -0
- package/dist/upload-wallet-put.js +221 -0
- package/dist/upload-wallet.d.ts +3 -0
- package/dist/upload-wallet.js +18 -15
- package/dist/upload.js +16 -15
- package/dist/wallet-list-chain.d.ts +4 -0
- package/dist/wallet-list-chain.js +21 -0
- package/dist/wallet-pay-index.d.ts +21 -0
- package/dist/wallet-pay-index.js +68 -0
- package/dist/wallet-sign-seams.d.ts +69 -0
- package/dist/wallet-sign-seams.js +16 -0
- package/dist/wallet-sign.d.ts +3 -53
- package/dist/wallet-sign.js +22 -18
- package/dist/wallet.d.ts +13 -13
- package/dist/wallet.js +15 -15
- package/dist/walrus-write.js +3 -2
- package/dist/walrus.d.ts +1 -16
- package/dist/walrus.js +11 -22
- package/docs/commands/credits.md +1 -1
- package/docs/commands/platform.md +14 -0
- package/docs/commands/support.md +1 -1
- package/docs/commands/trash.md +1 -1
- package/docs/commands/wallet.md +26 -8
- package/package.json +13 -2
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
// `nmts put <file> --pay wallet` — one file in, sealed on this machine, its storage bought by the
|
|
2
2
|
// PERSON'S OWN WALLET on the storage network instead of by credits.
|
|
3
3
|
//
|
|
4
|
-
// ⛔
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// stops at the review and never loads the signing module.
|
|
4
|
+
// ⛔ THE UPLOAD ITSELF IS NOT HERE. `upload-wallet-put.ts` prices, refuses, signs, pushes and
|
|
5
|
+
// records; this file is the terminal around it — the arguments, the printed review, the wallet
|
|
6
|
+
// agreement this machine holds, the spending ledger and the standing gift. The split is what
|
|
7
|
+
// lets the SDK pay from a wallet without a second copy of the order that keeps money safe.
|
|
9
8
|
//
|
|
10
|
-
// ⛔ THE
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
// wallet-paid commit does (`upload-steps.ts`).
|
|
9
|
+
// ⛔ THE REVIEW IS PRINTED BEFORE ANY REFUSAL, and the agreement is asked for only after a known
|
|
10
|
+
// shortfall has already stopped the run — so a person who cannot afford it reads the numbers
|
|
11
|
+
// instead of a question. `--dry-run` stops at the review and never loads the signing module.
|
|
14
12
|
//
|
|
15
13
|
// ⛔ A HELD RESOURCE IS OFFERED, NEVER CHOSEN FOR THE PERSON — the owner's rule for storage
|
|
16
14
|
// resources: the leftover is shown in bytes and the person decides. The review names how many
|
|
@@ -20,27 +18,24 @@ import { basename, resolve } from "node:path";
|
|
|
20
18
|
import { identityOf } from "../account.js";
|
|
21
19
|
import { requireAccountCode } from "../code-access.js";
|
|
22
20
|
import { parseAsked } from "../collision.js";
|
|
23
|
-
import {
|
|
21
|
+
import { loadCrypto } from "../crypto.js";
|
|
24
22
|
import { API_KEY_ENV_VAR, readCredentialsFile, resolveApiKey } from "../credentials.js";
|
|
25
23
|
import { NmtsError } from "../errors.js";
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
24
|
+
import { payingWalletIndex } from "../wallet-pay-index.js";
|
|
25
|
+
import { activeWalletOf } from "../shared/lib/drive/manifest-settings.js";
|
|
28
26
|
import { paddingRuleOf, readFileList } from "../manifest.js";
|
|
29
27
|
import { resolveNetwork } from "../network.js";
|
|
30
28
|
import { BINARY_NAME } from "../product.js";
|
|
31
|
-
import { Progress, silentSink
|
|
32
|
-
import {
|
|
29
|
+
import { Progress, silentSink } from "../progress.js";
|
|
30
|
+
import { stderrSink } from "../progress-node.js";
|
|
33
31
|
import { resolveServer } from "../server.js";
|
|
34
|
-
import {
|
|
35
|
-
import {
|
|
36
|
-
import {
|
|
37
|
-
import {
|
|
38
|
-
import {
|
|
39
|
-
import {
|
|
40
|
-
import { chooseUploadEpochs, daysOf, describeUploadReview, parseStorageAsk, pickResource, uploadBudget, uploadShortfallNextStep, walPrice, } from "../upload-wallet-plan.js";
|
|
41
|
-
import { coinAmount, walletAddress } from "../wallet.js";
|
|
32
|
+
import { fileSource } from "../upload-file-node.js";
|
|
33
|
+
import { partSizeFor } from "../upload-price.js";
|
|
34
|
+
import { measureLocal } from "../upload-price-node.js";
|
|
35
|
+
import { describeUploadReview } from "../upload-wallet-plan.js";
|
|
36
|
+
import { walletPut } from "../upload-wallet-put.js";
|
|
37
|
+
import { coinAmount } from "../wallet.js";
|
|
42
38
|
import { recordWalletSpend, requireWalletGrant } from "../wallet-grant.js";
|
|
43
|
-
import { createBlobProtocol } from "../walrus-write.js";
|
|
44
39
|
import { folderIdFor } from "./put.js";
|
|
45
40
|
export async function putWithWallet(target, options) {
|
|
46
41
|
const say = options.write ?? ((line) => process.stdout.write(`${line}\n`));
|
|
@@ -65,6 +60,12 @@ export async function putWithWallet(target, options) {
|
|
|
65
60
|
const asked = parseAsked(options.onCollision);
|
|
66
61
|
const list = await readFileList(server, key.key, resolved.code, identity.accountId);
|
|
67
62
|
const rule = paddingRuleOf(list.manifest?.settings);
|
|
63
|
+
// ⛔ WHICH WALLET PAYS, BEFORE ANYTHING IS PRICED — out of the list that was just read, so this
|
|
64
|
+
// costs no second request and the address in the review is the address that signs.
|
|
65
|
+
const wallet = await payingWalletIndex({
|
|
66
|
+
...options,
|
|
67
|
+
readActiveWallet: async () => activeWalletOf(list.manifest?.settings),
|
|
68
|
+
});
|
|
68
69
|
const name = options.name ?? basename(localPath);
|
|
69
70
|
const destination = (options.to ?? "").replace(/^\.?\//, "").replace(/\/$/, "");
|
|
70
71
|
const parentId = folderIdFor(options.to, list.manifest?.entries ?? []);
|
|
@@ -79,6 +80,7 @@ export async function putWithWallet(target, options) {
|
|
|
79
80
|
rule,
|
|
80
81
|
onCollision: asked,
|
|
81
82
|
settings: list.manifest?.settings,
|
|
83
|
+
wallet,
|
|
82
84
|
progress: new Progress(options.json === true ? silentSink() : stderrSink(), "uploading"),
|
|
83
85
|
say,
|
|
84
86
|
json: options.json === true,
|
|
@@ -100,174 +102,75 @@ export async function putWithWallet(target, options) {
|
|
|
100
102
|
return 0;
|
|
101
103
|
}
|
|
102
104
|
/**
|
|
103
|
-
* Review, agree, upload and record ONE file. Null when `--dry-run`
|
|
105
|
+
* Review, agree, upload and record ONE file for a person who is watching. Null when `--dry-run`
|
|
106
|
+
* stopped at the review.
|
|
104
107
|
*
|
|
105
|
-
* ⛔ THE
|
|
106
|
-
*
|
|
108
|
+
* ⛔ THE AGREEMENT HANDED IN BELOW IS THIS MACHINE'S GRANT, held against the total the review
|
|
109
|
+
* names. It is the one gate between a program and somebody's wallet, and the reason it is
|
|
110
|
+
* handed to the library rather than living inside it: a library call has nobody to ask.
|
|
107
111
|
*/
|
|
108
112
|
export async function uploadOneWithWallet(ctx, file, options) {
|
|
109
113
|
const { say } = ctx;
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
114
|
+
let outcome;
|
|
115
|
+
try {
|
|
116
|
+
outcome = await walletPut({
|
|
117
|
+
code: ctx.code,
|
|
118
|
+
apiKey: ctx.apiKey,
|
|
119
|
+
server: ctx.server,
|
|
120
|
+
network: ctx.network,
|
|
121
|
+
accountId: ctx.accountId,
|
|
122
|
+
crypt: ctx.crypt,
|
|
123
|
+
wallet: ctx.wallet,
|
|
124
|
+
partSize: ctx.partSize,
|
|
125
|
+
rule: ctx.rule,
|
|
126
|
+
onCollision: ctx.onCollision,
|
|
127
|
+
}, { source: fileSource(file.localPath, file.size), name: file.name, parentId: file.parentId, destination: file.destination }, {
|
|
128
|
+
epochs: options.epochs,
|
|
129
|
+
storage: options.storage,
|
|
130
|
+
dryRun: options.dryRun,
|
|
131
|
+
readChain: options.readChain,
|
|
132
|
+
sign: options.sign,
|
|
133
|
+
protocol: options.protocol,
|
|
134
|
+
api: options.api,
|
|
135
|
+
onProgress: (sent, total) => ctx.progress.update(sent, total),
|
|
136
|
+
onStep: (step) => tell(ctx, file.size, step),
|
|
137
|
+
onReview: (review) => {
|
|
138
|
+
if (ctx.json)
|
|
139
|
+
return;
|
|
140
|
+
describeUploadReview(say, {
|
|
141
|
+
name: review.name,
|
|
142
|
+
bytes: review.bytes,
|
|
143
|
+
parts: review.parts,
|
|
144
|
+
epochs: review.epochs,
|
|
145
|
+
days: review.days,
|
|
146
|
+
endEpoch: review.endEpoch,
|
|
147
|
+
walNeeded: review.budget.walNeededFrost,
|
|
148
|
+
tipMist: review.tipMist,
|
|
149
|
+
storage: review.storage,
|
|
150
|
+
heldResources: review.heldResources,
|
|
151
|
+
}, review.budget);
|
|
152
|
+
},
|
|
153
|
+
agree: (review) => {
|
|
154
|
+
requireWalletGrant("seal", { walFrost: review.budget.walNeededFrost, suiMist: review.budget.suiNeededMist }, new Date(options.now ?? Date.now()));
|
|
155
|
+
},
|
|
156
|
+
onSpend: recordWalletSpend,
|
|
126
157
|
});
|
|
127
158
|
}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const quotes = await reads.quoteParts(sealedLens, epochs);
|
|
131
|
-
const address = await walletAddress(ctx.code);
|
|
132
|
-
let storage = { kind: "buy" };
|
|
133
|
-
let heldResources = null;
|
|
134
|
-
if (storageAsk !== null) {
|
|
135
|
-
const firstQuote = quotes[0];
|
|
136
|
-
const firstLen = sealedLens[0];
|
|
137
|
-
if (firstQuote === undefined || firstLen === undefined)
|
|
138
|
-
throw new NmtsError("unreachable: a plan with no part");
|
|
139
|
-
let resources;
|
|
140
|
-
try {
|
|
141
|
-
resources = await reads.readStorage(address);
|
|
142
|
-
}
|
|
143
|
-
catch (error) {
|
|
144
|
-
throw new NmtsError("The storage resources this wallet holds could not be read.", {
|
|
145
|
-
exitCode: 1,
|
|
146
|
-
nextStep: `Nothing was signed. That is not the same as holding none. Cause: ${error instanceof Error ? error.message : String(error)}`,
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
const encoded = await reads.encodedLength(address, firstLen);
|
|
150
|
-
storage = pickResource(storageAsk, resources, encoded, window.clock.current, endEpoch, firstQuote.writeFrost);
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
heldResources = await reads.readStorage(address).then((rows) => rows.filter((r) => statusOf(r, window.clock.current) === "usable").length, () => null);
|
|
154
|
-
}
|
|
155
|
-
const [purse, feeMist] = await Promise.all([
|
|
156
|
-
reads.readWallet(address),
|
|
157
|
-
reads.estimateRegisterGas({
|
|
158
|
-
sender: address,
|
|
159
|
-
sealedLen: Math.max(...sealedLens),
|
|
160
|
-
epochs,
|
|
161
|
-
storage: storage.kind === "buy" ? storage : { kind: "reuse", objectId: storage.objectId, cutToBytes: storage.cutToBytes, writeFrost: storage.writeFrost },
|
|
162
|
-
}),
|
|
163
|
-
]);
|
|
164
|
-
const budget = uploadBudget({ address, purse, feeMist, quotes, storage });
|
|
165
|
-
const tipMist = quotes.reduce((sum, q) => sum + q.tipMist, 0n);
|
|
166
|
-
const facts = {
|
|
167
|
-
bytes: file.size,
|
|
168
|
-
sealedBytes,
|
|
169
|
-
parts: plan.length,
|
|
170
|
-
epochs,
|
|
171
|
-
days: daysOf(window, epochs),
|
|
172
|
-
endEpoch,
|
|
173
|
-
paidFrom: "wallet",
|
|
174
|
-
priceFrost: budget.walNeededFrost.toString(),
|
|
175
|
-
priceWal: coinAmount(budget.walNeededFrost),
|
|
176
|
-
tipMist: tipMist.toString(),
|
|
177
|
-
tipSui: coinAmount(tipMist),
|
|
178
|
-
feeMist: feeMist === null ? null : feeMist.toString(),
|
|
179
|
-
feeSui: feeMist === null ? null : coinAmount(feeMist),
|
|
180
|
-
wallet: address,
|
|
181
|
-
walletWal: budget.walFrost === null ? null : coinAmount(budget.walFrost),
|
|
182
|
-
walletSui: budget.suiMist === null ? null : coinAmount(budget.suiMist),
|
|
183
|
-
storage: storage.kind === "buy"
|
|
184
|
-
? { kind: "buy" }
|
|
185
|
-
: { kind: "reuse", objectId: storage.objectId, cutToBytes: storage.cutToBytes, leftoverBytes: storage.leftoverBytes },
|
|
186
|
-
};
|
|
187
|
-
if (!ctx.json) {
|
|
188
|
-
describeUploadReview(say, { name: file.name, bytes: file.size, parts: plan.length, epochs, days: daysOf(window, epochs), endEpoch, walNeeded: walPrice(quotes, storage), tipMist, storage, heldResources }, budget);
|
|
159
|
+
finally {
|
|
160
|
+
ctx.progress.done();
|
|
189
161
|
}
|
|
190
|
-
|
|
162
|
+
const facts = factsOf(outcome.review);
|
|
163
|
+
if (outcome.kind === "review") {
|
|
191
164
|
if (ctx.json)
|
|
192
|
-
say(JSON.stringify({ dryRun: true, name:
|
|
165
|
+
say(JSON.stringify({ dryRun: true, name: outcome.review.name, ...facts, signed: false }));
|
|
193
166
|
else {
|
|
194
167
|
say(``);
|
|
195
|
-
if (budget.shortfall !== null)
|
|
196
|
-
say(` ⚠ ${budget.shortfall} As it stands, it would be refused.`);
|
|
168
|
+
if (outcome.review.budget.shortfall !== null)
|
|
169
|
+
say(` ⚠ ${outcome.review.budget.shortfall} As it stands, it would be refused.`);
|
|
197
170
|
say(` Nothing was signed and nothing was sent. Run the same command without --dry-run to upload it.`);
|
|
198
171
|
}
|
|
199
172
|
return null;
|
|
200
173
|
}
|
|
201
|
-
// ⛔ A WALLET KNOWN TO BE SHORT IS REFUSED BEFORE THE AGREEMENT IS ASKED FOR (`extend-budget.ts`).
|
|
202
|
-
if (budget.shortfall !== null) {
|
|
203
|
-
throw new NmtsError(budget.shortfall, { exitCode: 4, nextStep: uploadShortfallNextStep(budget) });
|
|
204
|
-
}
|
|
205
|
-
// ⛔ THE ONE GATE BETWEEN A PROGRAM AND SOMEBODY'S WALLET. Everything above is a read.
|
|
206
|
-
requireWalletGrant("seal", { walFrost: budget.walNeededFrost, suiMist: budget.suiNeededMist }, new Date(options.now ?? Date.now()));
|
|
207
|
-
const sign = options.sign ?? (await signers());
|
|
208
|
-
const derived = ctx.crypt.kdf_derive(ctx.crypt.account_code_parse(ctx.code));
|
|
209
|
-
const dataKey = derived.slice(DERIVED.dataKey[0], DERIVED.dataKey[1]);
|
|
210
|
-
derived.fill(0);
|
|
211
|
-
let result;
|
|
212
|
-
try {
|
|
213
|
-
result = await uploadFile({
|
|
214
|
-
api: options.api ?? createUploadApi(ctx.server, ctx.apiKey),
|
|
215
|
-
protocol,
|
|
216
|
-
crypt: ctx.crypt,
|
|
217
|
-
dataKey,
|
|
218
|
-
source: fileSource(file.localPath, file.size),
|
|
219
|
-
name: file.name,
|
|
220
|
-
parentId: file.parentId,
|
|
221
|
-
destination: file.destination,
|
|
222
|
-
relayUrl: protocol.relayUrl,
|
|
223
|
-
epochs,
|
|
224
|
-
currentEpoch: window.clock.current,
|
|
225
|
-
partSize: ctx.partSize,
|
|
226
|
-
padding: { rule: ctx.rule, unitBytes: CREDIT_BYTES },
|
|
227
|
-
onStep: (step) => tell(ctx, file.size, step),
|
|
228
|
-
buy: walletRail({
|
|
229
|
-
network: ctx.network,
|
|
230
|
-
code: ctx.code,
|
|
231
|
-
relayUrl: protocol.relayUrl,
|
|
232
|
-
epochs,
|
|
233
|
-
storage,
|
|
234
|
-
quotes,
|
|
235
|
-
feeMist,
|
|
236
|
-
signRegister: sign.register,
|
|
237
|
-
signCertify: sign.certify,
|
|
238
|
-
onSpend: recordWalletSpend,
|
|
239
|
-
}),
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
finally {
|
|
243
|
-
ctx.progress.done();
|
|
244
|
-
dataKey.fill(0);
|
|
245
|
-
}
|
|
246
|
-
const now = Date.now();
|
|
247
|
-
const added = await addEntry({
|
|
248
|
-
server: ctx.server,
|
|
249
|
-
apiKey: ctx.apiKey,
|
|
250
|
-
code: ctx.code,
|
|
251
|
-
accountId: ctx.accountId,
|
|
252
|
-
...(ctx.onCollision !== undefined ? { onCollision: ctx.onCollision } : {}),
|
|
253
|
-
entry: {
|
|
254
|
-
id: result.itemId,
|
|
255
|
-
parentId: file.parentId,
|
|
256
|
-
kind: 1,
|
|
257
|
-
name: result.entry.name,
|
|
258
|
-
size: result.entry.plaintextLen,
|
|
259
|
-
createdAt: now,
|
|
260
|
-
updatedAt: now,
|
|
261
|
-
dekWrapped: result.entry.dekWrapped,
|
|
262
|
-
contentHashCt: result.entry.contentHashCt,
|
|
263
|
-
},
|
|
264
|
-
});
|
|
265
|
-
// ⛔ ONLY NOW, AND EVERY PART — the same order `put.ts` keeps and for the same reason.
|
|
266
|
-
clearItemRecord(result.fileKey);
|
|
267
|
-
for (const record of partKeysOf(result.fileKey, result.parts))
|
|
268
|
-
clearReservation(record);
|
|
269
|
-
if (added.replaced)
|
|
270
|
-
await setTrashed(ctx.server, ctx.apiKey, added.replaced.id, true);
|
|
271
174
|
// ⛔ THE STANDING SHARE, AFTER THE PAYMENT AND NEVER INSIDE IT: a gift that fails must not fail
|
|
272
175
|
// the upload. A resumed run paid nothing now, so it owes nothing now. In --json the tip speaks
|
|
273
176
|
// on stderr — stdout carries the machine's one answer and nothing else.
|
|
@@ -276,11 +179,37 @@ export async function uploadOneWithWallet(ctx, file, options) {
|
|
|
276
179
|
network: ctx.network,
|
|
277
180
|
code: ctx.code,
|
|
278
181
|
settings: ctx.settings,
|
|
279
|
-
|
|
182
|
+
wallet: ctx.wallet,
|
|
183
|
+
paidWalFrost: outcome.resumed ? 0n : outcome.review.budget.walNeededFrost,
|
|
280
184
|
say: ctx.json ? (line) => void process.stderr.write(`${line}\n`) : say,
|
|
281
185
|
...(options.tip ?? {}),
|
|
282
186
|
});
|
|
283
|
-
return { itemId:
|
|
187
|
+
return { itemId: outcome.itemId, savedAs: outcome.savedAs, replaced: outcome.replaced, seq: outcome.fileListVersion, resumed: outcome.resumed, facts };
|
|
188
|
+
}
|
|
189
|
+
/** The review as `--json` prints it: base units as strings, with the coin amounts beside them. */
|
|
190
|
+
function factsOf(review) {
|
|
191
|
+
const { budget, storage } = review;
|
|
192
|
+
return {
|
|
193
|
+
bytes: review.bytes,
|
|
194
|
+
sealedBytes: review.sealedBytes,
|
|
195
|
+
parts: review.parts,
|
|
196
|
+
epochs: review.epochs,
|
|
197
|
+
days: review.days,
|
|
198
|
+
endEpoch: review.endEpoch,
|
|
199
|
+
paidFrom: "wallet",
|
|
200
|
+
priceFrost: budget.walNeededFrost.toString(),
|
|
201
|
+
priceWal: coinAmount(budget.walNeededFrost),
|
|
202
|
+
tipMist: review.tipMist.toString(),
|
|
203
|
+
tipSui: coinAmount(review.tipMist),
|
|
204
|
+
feeMist: budget.feeMist === null ? null : budget.feeMist.toString(),
|
|
205
|
+
feeSui: budget.feeMist === null ? null : coinAmount(budget.feeMist),
|
|
206
|
+
wallet: budget.address,
|
|
207
|
+
walletWal: budget.walFrost === null ? null : coinAmount(budget.walFrost),
|
|
208
|
+
walletSui: budget.suiMist === null ? null : coinAmount(budget.suiMist),
|
|
209
|
+
storage: storage.kind === "buy"
|
|
210
|
+
? { kind: "buy" }
|
|
211
|
+
: { kind: "reuse", objectId: storage.objectId, cutToBytes: storage.cutToBytes, leftoverBytes: storage.leftoverBytes },
|
|
212
|
+
};
|
|
284
213
|
}
|
|
285
214
|
/** Each step, for a person watching. The signatures are named as what they are. */
|
|
286
215
|
function tell(ctx, size, step) {
|
|
@@ -307,10 +236,3 @@ function tell(ctx, size, step) {
|
|
|
307
236
|
if (step.step === "committing")
|
|
308
237
|
say(` saving to the drive`);
|
|
309
238
|
}
|
|
310
|
-
async function defaultReads(network, relayUrl) {
|
|
311
|
-
return (await import("../upload-wallet-chain.js")).walletUploadReads(network, relayUrl);
|
|
312
|
-
}
|
|
313
|
-
async function signers() {
|
|
314
|
-
const signing = await import("../wallet-sign.js");
|
|
315
|
-
return { register: signing.signBlobRegister, certify: signing.signBlobCertify };
|
|
316
|
-
}
|
package/dist/commands/put.d.ts
CHANGED
|
@@ -35,16 +35,14 @@ export interface PutOptions {
|
|
|
35
35
|
epochs?: string | number | undefined;
|
|
36
36
|
/** `--pay wallet`: a held storage resource to use — `fit`, `whole`, or its object id. */
|
|
37
37
|
storage?: string | undefined;
|
|
38
|
+
/** `--pay wallet`: which of this key's wallets pays, this run only. Absent = the account's own. */
|
|
39
|
+
wallet?: string | undefined;
|
|
38
40
|
json?: boolean;
|
|
39
41
|
write?: (line: string) => void;
|
|
40
42
|
}
|
|
41
|
-
/** Who pays,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
export declare function refuseWalletOnlyOptions(options: {
|
|
45
|
-
epochs?: string | number | undefined;
|
|
46
|
-
storage?: string | undefined;
|
|
47
|
-
}): void;
|
|
43
|
+
/** Who pays, and the options that lose their meaning under that answer — the rule is in `put-payer.ts`; this is its one road. */
|
|
44
|
+
import { payerOf, refuseWalletOnlyOptions } from "./put-payer.ts";
|
|
45
|
+
export { payerOf, refuseWalletOnlyOptions };
|
|
48
46
|
/**
|
|
49
47
|
* The folder id `--to` names, or null for the root. Refuses rather than guessing.
|
|
50
48
|
*
|
package/dist/commands/put.js
CHANGED
|
@@ -19,7 +19,8 @@ import { depositDefaultOf, depositLines, parseDeposit, refuseDepositWithWallet }
|
|
|
19
19
|
import { DERIVED, loadCrypto } from "../crypto.js";
|
|
20
20
|
import { buildIndex, fullPathOf, isLive, KIND_FOLDER, normalisePath } from "../drive-paths.js";
|
|
21
21
|
import { NmtsError } from "../errors.js";
|
|
22
|
-
import { Progress, silentSink
|
|
22
|
+
import { Progress, silentSink } from "../progress.js";
|
|
23
|
+
import { stderrSink } from "../progress-node.js";
|
|
23
24
|
import { setTrashed } from "../item-trash.js";
|
|
24
25
|
import { addEntry } from "../manifest-write.js";
|
|
25
26
|
import { paddingRuleOf, readFileList } from "../manifest.js";
|
|
@@ -28,35 +29,14 @@ import { BINARY_NAME } from "../product.js";
|
|
|
28
29
|
import { resolveServer } from "../server.js";
|
|
29
30
|
import { clearItemRecord, clearReservation } from "../upload-store.js";
|
|
30
31
|
import { createUploadApi } from "../upload-api.js";
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
32
|
+
import { partKeysOf, uploadFile } from "../upload-file.js";
|
|
33
|
+
import { fileSource } from "../upload-file-node.js";
|
|
34
|
+
import { CREDIT_BYTES, creditsFor, partSizeFor, planAndPrice, UPLOAD_EPOCHS } from "../upload-price.js";
|
|
35
|
+
import { measureLocal } from "../upload-price-node.js";
|
|
33
36
|
import { createBlobProtocol, readCurrentEpoch } from "../walrus-write.js";
|
|
34
|
-
/** Who pays,
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
return "credits";
|
|
38
|
-
if (pay === "wallet")
|
|
39
|
-
return "wallet";
|
|
40
|
-
throw new NmtsError(`--pay takes credits or wallet, not "${pay}".`, {
|
|
41
|
-
exitCode: 2,
|
|
42
|
-
nextStep: `Nothing was sent. --pay wallet buys the storage from the wallet this NMTS key derives; without it credits pay.`,
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
/** The two options that only mean something when the wallet pays, refused when it does not. */
|
|
46
|
-
export function refuseWalletOnlyOptions(options) {
|
|
47
|
-
if (options.epochs !== undefined) {
|
|
48
|
-
throw new NmtsError("--epochs only applies with --pay wallet: one credit buys a fixed term.", {
|
|
49
|
-
exitCode: 2,
|
|
50
|
-
nextStep: `Nothing was sent. Add --pay wallet to choose the term, or leave --epochs off to pay with credits.`,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
if (options.storage !== undefined) {
|
|
54
|
-
throw new NmtsError("--storage only applies with --pay wallet: credits buy storage from the treasury.", {
|
|
55
|
-
exitCode: 2,
|
|
56
|
-
nextStep: `Nothing was sent. Add --pay wallet to use a storage resource this wallet holds.`,
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
}
|
|
37
|
+
/** Who pays, and the options that lose their meaning under that answer — the rule is in `put-payer.ts`; this is its one road. */
|
|
38
|
+
import { payerOf, refuseWalletOnlyOptions } from "./put-payer.js";
|
|
39
|
+
export { payerOf, refuseWalletOnlyOptions };
|
|
60
40
|
/**
|
|
61
41
|
* The folder id `--to` names, or null for the root. Refuses rather than guessing.
|
|
62
42
|
*
|
|
@@ -283,9 +263,9 @@ export async function put(target, options = {}) {
|
|
|
283
263
|
// ⛔ ONLY NOW, AND EVERY PART. Until the entry is in the list the file is paid for and invisible,
|
|
284
264
|
// and the records are the only thing that lets a second run finish the job without spending
|
|
285
265
|
// again. Clearing the file-level one first would leave a run able to commit a second time.
|
|
286
|
-
clearItemRecord(result.fileKey);
|
|
266
|
+
await clearItemRecord(result.fileKey);
|
|
287
267
|
for (const record of partKeysOf(result.fileKey, result.parts))
|
|
288
|
-
clearReservation(record);
|
|
268
|
+
await clearReservation(record);
|
|
289
269
|
// ⛔ THE DISPLACED FILE IS TOLD TO THE SERVER ONLY NOW, and only after the new one is in the
|
|
290
270
|
// list. Until this line the person still had the file they started with.
|
|
291
271
|
// ⚠ A failure here leaves it hidden in this account's trash while the server still counts it as
|
package/dist/commands/receive.js
CHANGED
|
@@ -14,7 +14,7 @@ import { resolve } from "node:path";
|
|
|
14
14
|
import { request } from "../api.js";
|
|
15
15
|
import { loadCrypto } from "../crypto.js";
|
|
16
16
|
import { fetchWithKey } from "../download.js";
|
|
17
|
-
import { fileSink, stdoutSink } from "../download-sink.js";
|
|
17
|
+
import { fileSink, stdoutSink } from "../download-sink-node.js";
|
|
18
18
|
import { NmtsError } from "../errors.js";
|
|
19
19
|
import { destinationFor } from "../safe-path.js";
|
|
20
20
|
import { resolveNetwork } from "../network.js";
|
|
@@ -39,5 +39,5 @@ export async function runSettings(command, args) {
|
|
|
39
39
|
return await mode(args.operands[0], args.operands[1], { json: args.json });
|
|
40
40
|
}
|
|
41
41
|
const { onCollision } = await import("./on-collision.js");
|
|
42
|
-
return onCollision(args.operands[0], { json: args.json });
|
|
42
|
+
return await onCollision(args.operands[0], { json: args.json });
|
|
43
43
|
}
|
package/dist/commands/support.js
CHANGED
|
@@ -57,7 +57,7 @@ async function sendReport(options) {
|
|
|
57
57
|
const clean = (text) => omitLiterals(redact(text), omit);
|
|
58
58
|
const message = clean(await readMessage(options)).trim();
|
|
59
59
|
requireLength(message, MAX_MESSAGE_CHARS, "message");
|
|
60
|
-
const attachment = packLog(options.attachLog, clean);
|
|
60
|
+
const attachment = await packLog(options.attachLog, clean);
|
|
61
61
|
const total = Buffer.byteLength(message, "utf8") + (attachment?.bytes ?? 0);
|
|
62
62
|
// ⛔ THE MACHINE-READABLE PREVIEW IS THE ONLY THING PRINTED ON THAT PATH, and it is printed
|
|
63
63
|
// INSTEAD of sending rather than before it. Two JSON objects on one stream would let a caller
|
|
@@ -169,7 +169,7 @@ function standardInput() {
|
|
|
169
169
|
});
|
|
170
170
|
}
|
|
171
171
|
/** Read the newest runs and pack them, or `null` when the option was not given. */
|
|
172
|
-
function packLog(asked, clean) {
|
|
172
|
+
async function packLog(asked, clean) {
|
|
173
173
|
if (asked === undefined)
|
|
174
174
|
return null;
|
|
175
175
|
const count = asked === "" ? DEFAULT_ATTACHED_RUNS : Number(asked);
|
|
@@ -180,7 +180,7 @@ function packLog(asked, clean) {
|
|
|
180
180
|
}
|
|
181
181
|
if (count === 0)
|
|
182
182
|
return null;
|
|
183
|
-
const runs = readRuns(count);
|
|
183
|
+
const runs = await readRuns(count);
|
|
184
184
|
if (runs.length === 0)
|
|
185
185
|
return null;
|
|
186
186
|
return buildLogAttachment(runs, clean, MAX_ATTACHMENT_BYTES);
|
package/dist/commands/unlock.js
CHANGED
|
@@ -67,7 +67,7 @@ export async function unlock(action, target, options = {}) {
|
|
|
67
67
|
}
|
|
68
68
|
if (action === "unlock") {
|
|
69
69
|
const key = keyOrFail(target);
|
|
70
|
-
if (options.readLine === undefined && !stdinIsATerminal() && currentMode() !== "skip-permissions") {
|
|
70
|
+
if (options.readLine === undefined && !stdinIsATerminal() && (await currentMode()) !== "skip-permissions") {
|
|
71
71
|
throw new NmtsError(`A person unlocks, at a terminal — stdin here is not one.`, {
|
|
72
72
|
exitCode: 5,
|
|
73
73
|
nextStep: `If you are an agent: do not unlock things. Show the person what \`${BINARY_NAME} unlock\` ` +
|
|
@@ -80,7 +80,7 @@ export async function unlock(action, target, options = {}) {
|
|
|
80
80
|
say(c.what);
|
|
81
81
|
say(` ${c.risk}`);
|
|
82
82
|
say(` ${c.limit}`);
|
|
83
|
-
if (currentMode() !== "skip-permissions") {
|
|
83
|
+
if ((await currentMode()) !== "skip-permissions") {
|
|
84
84
|
const ask = options.readLine ?? promptLine;
|
|
85
85
|
const answer = (await ask(`Unlock ${key} on this machine? [y/N] `)).trim();
|
|
86
86
|
if (answer !== "y" && answer !== "Y") {
|
|
@@ -15,7 +15,10 @@ export interface WalletDonateOptions {
|
|
|
15
15
|
yes?: boolean;
|
|
16
16
|
dryRun?: boolean;
|
|
17
17
|
feeCap?: string | undefined;
|
|
18
|
+
/** `--wallet N`: which wallet the gift comes from, this run only. Absent = the account's number. */
|
|
19
|
+
wallet?: string | undefined;
|
|
18
20
|
/** ⚠ SEAMS, NOT OPTIONS — no flag reaches them. */
|
|
21
|
+
readActiveWallet?: () => Promise<number>;
|
|
19
22
|
readDonation?: (server: string) => Promise<DonationConfig>;
|
|
20
23
|
readChain?: (network: Network) => SendReads | Promise<SendReads>;
|
|
21
24
|
sign?: SignTransfer;
|
|
@@ -25,6 +25,7 @@ import { THANKS_EN, THANKS_KO } from "../standing-tip.js";
|
|
|
25
25
|
import { explorerTxUrl } from "../shared/lib/wallet/activity.js";
|
|
26
26
|
import { clampGasBudgetMist, isValidSuiAddress, parseTokenAmountToBaseUnits, validateSendForm, } from "../shared/lib/wallet/send-rules.js";
|
|
27
27
|
import { coinAmount, walCoinType, walletAddress } from "../wallet.js";
|
|
28
|
+
import { payingWalletIndex } from "../wallet-pay-index.js";
|
|
28
29
|
/** The four facts and the promise, as the screens say them, in the order a person reads them. */
|
|
29
30
|
export const GIFT_NOTICES = [
|
|
30
31
|
"This is a voluntary gift. Nothing is provided in return, it is non-refundable, and it cannot be undone once sent.",
|
|
@@ -57,7 +58,10 @@ export async function walletDonate(operands, options = {}) {
|
|
|
57
58
|
throw new NmtsError("Say how much.", { exitCode: 2, nextStep: `\`${BINARY_NAME} wallet donate ${coin} <amount> --yes\`` });
|
|
58
59
|
}
|
|
59
60
|
const resolved = await requireAccountCode();
|
|
60
|
-
|
|
61
|
+
// ⛔ A gift leaves the same wallet storage is paid from, and it is resolved before the review is
|
|
62
|
+
// priced — so the address a person reads is the address the coins leave.
|
|
63
|
+
const wallet = await payingWalletIndex(options);
|
|
64
|
+
const address = await walletAddress(resolved.code, wallet);
|
|
61
65
|
const stored = resolved.source === "file" || resolved.source === "file-locked" ? readCredentialsFile() : null;
|
|
62
66
|
const server = resolveServer(options.server ?? stored?.server);
|
|
63
67
|
const network = resolveNetwork(server, options.network ?? stored?.network);
|
|
@@ -143,7 +147,7 @@ export async function walletDonate(operands, options = {}) {
|
|
|
143
147
|
});
|
|
144
148
|
}
|
|
145
149
|
const sign = options.sign ?? (await import("../wallet-sign.js")).signTransfer;
|
|
146
|
-
const digest = await sign({ network, code: resolved.code, shape });
|
|
150
|
+
const digest = await sign({ network, code: resolved.code, wallet, shape });
|
|
147
151
|
if (options.json) {
|
|
148
152
|
say(JSON.stringify({ ...facts, signed: true, digest, explorerUrl: explorerTxUrl(digest, network) }));
|
|
149
153
|
return 0;
|
|
@@ -6,7 +6,10 @@ export interface WalletHallOptions {
|
|
|
6
6
|
/** `--name`: be listed under this. `--remove`: go back to a shortened address. */
|
|
7
7
|
name?: string | undefined;
|
|
8
8
|
remove?: boolean;
|
|
9
|
-
/**
|
|
9
|
+
/** `--wallet N`: which wallet signs the name, this run only. Absent = the account's own number. */
|
|
10
|
+
wallet?: string | undefined;
|
|
11
|
+
/** ⚠ SEAMS, NOT OPTIONS — no flag reaches them. They exist so a test never signs for real. */
|
|
12
|
+
readActiveWallet?: () => Promise<number>;
|
|
10
13
|
sign?: SignMessage;
|
|
11
14
|
}
|
|
12
15
|
/** One row of the hall, as this tool needs it. Amounts are base units, exactly as they arrived. */
|
|
@@ -6,9 +6,12 @@
|
|
|
6
6
|
// taken off is the NAME, which puts the entry back to a shortened address.
|
|
7
7
|
//
|
|
8
8
|
// ⛔ A NAME IS PUBLISHED, AND THAT IS WHY IT IS SIGNED. The proof that an address is yours is a
|
|
9
|
-
// signature by that address, so `--name` signs a short message with the wallet this
|
|
10
|
-
//
|
|
11
|
-
//
|
|
9
|
+
// signature by that address, so `--name` signs a short message with the wallet this account
|
|
10
|
+
// pays from (`wallet-pay-index.ts`, `wallet-sign.ts`) and sends the signature. That is the
|
|
11
|
+
// wallet a gift left from, so it is the address the hall holds an entry for. Reading WHICH
|
|
12
|
+
// wallet that is opens this account's own file list, so `--name` needs an API key where
|
|
13
|
+
// reading the hall needs none; what is SENT is unchanged — no session, no API key, no account
|
|
14
|
+
// id, just an address, a name and a signature.
|
|
12
15
|
//
|
|
13
16
|
// ⛔ THE MESSAGE IS BUILT IN ONE PLACE, `hallMessage` BELOW, because the server rebuilds the same
|
|
14
17
|
// bytes from the fields it was sent and compares. A space added on either side makes every
|
|
@@ -21,6 +24,7 @@ import { isRecord } from "../guards.js";
|
|
|
21
24
|
import { BINARY_NAME, HOME_URL } from "../product.js";
|
|
22
25
|
import { resolveServer } from "../server.js";
|
|
23
26
|
import { coinAmount, walletAddress } from "../wallet.js";
|
|
27
|
+
import { payingWalletIndex } from "../wallet-pay-index.js";
|
|
24
28
|
/** How many rows a terminal gets. The page at the site carries the rest. */
|
|
25
29
|
const SHOWN = 10;
|
|
26
30
|
/**
|
|
@@ -93,7 +97,7 @@ const REFUSALS = {
|
|
|
93
97
|
signature_invalid: {
|
|
94
98
|
line: "The server did not accept the signature.",
|
|
95
99
|
exitCode: 1,
|
|
96
|
-
nextStep: `Nothing was published. \`${BINARY_NAME} wallet
|
|
100
|
+
nextStep: `Nothing was published. \`${BINARY_NAME} wallet list\` shows this key's wallets and which one this run signs as.`,
|
|
97
101
|
},
|
|
98
102
|
};
|
|
99
103
|
/** The server the sealed sign-in points at, when there is one this run can read. */
|
|
@@ -180,14 +184,17 @@ async function readHall(server) {
|
|
|
180
184
|
/** `--name` and `--remove`: sign the message, send it, and say what the hall shows now. */
|
|
181
185
|
async function setName(server, say, options) {
|
|
182
186
|
const resolved = await requireAccountCode();
|
|
183
|
-
// ⛔
|
|
184
|
-
//
|
|
185
|
-
|
|
187
|
+
// ⛔ WHICH WALLET, BEFORE THE ADDRESS — the entry belongs to the wallet the gift came from, which
|
|
188
|
+
// is the account's own number, and the address is then derived here rather than taken from a
|
|
189
|
+
// flag: a signature only proves ownership of the address it was made by, so the address, the
|
|
190
|
+
// message and the key that signs it have to be the same wallet.
|
|
191
|
+
const wallet = await payingWalletIndex({ ...options, server });
|
|
192
|
+
const address = await walletAddress(resolved.code, wallet);
|
|
186
193
|
const name = options.remove === true ? null : (options.name ?? null);
|
|
187
194
|
const issuedAt = new Date(Date.now()).toISOString();
|
|
188
195
|
const message = hallMessage(address, name, issuedAt);
|
|
189
196
|
const sign = options.sign ?? (await import("../wallet-sign.js")).signMessage;
|
|
190
|
-
const signature = await sign({ code: resolved.code, message });
|
|
197
|
+
const signature = await sign({ code: resolved.code, wallet, message });
|
|
191
198
|
let answer;
|
|
192
199
|
try {
|
|
193
200
|
answer = await request(server, "/v1/gifts/listing", {
|
|
@@ -207,6 +214,7 @@ async function setName(server, say, options) {
|
|
|
207
214
|
}
|
|
208
215
|
const label = isRecord(answer) ? text(answer["label"]) : "";
|
|
209
216
|
say(`Listed as ${label}`);
|
|
217
|
+
say(` from ${address} (wallet ${wallet})`);
|
|
210
218
|
say(``);
|
|
211
219
|
say(` The hall of fame is at ${HOME_URL}/hall. Run \`${BINARY_NAME} wallet hall --remove\` to go`);
|
|
212
220
|
say(` back to a shortened address; the gifts themselves stay on the chain either way.`);
|