agoric 0.22.0-u18.4 → 0.22.0-u18.6
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/package.json +38 -36
- package/src/anylogger-agoric.js +2 -2
- package/src/chain-config.js +22 -3
- package/src/commands/auction.js +15 -14
- package/src/commands/gov.js +41 -28
- package/src/commands/inter.js +16 -25
- package/src/commands/oracle.js +27 -18
- package/src/commands/perf.js +5 -3
- package/src/commands/psm.js +17 -10
- package/src/commands/reserve.js +11 -3
- package/src/commands/test-upgrade.js +4 -4
- package/src/commands/vaults.js +24 -9
- package/src/commands/wallet.js +68 -18
- package/src/cosmos.js +1 -1
- package/src/helpers.js +8 -5
- package/src/install.js +8 -5
- package/src/lib/chain.js +42 -5
- package/src/lib/format.js +18 -19
- package/src/lib/index.js +7 -0
- package/src/lib/wallet.js +16 -87
- package/src/main.js +3 -1
- package/src/scripts.js +1 -1
- package/src/sdk-package-names.js +3 -2
- package/src/start.js +7 -7
- package/tools/getting-started.js +7 -0
- package/src/lib/rpc.js +0 -285
package/src/lib/wallet.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
/* eslint-env node */
|
|
3
3
|
|
|
4
|
-
import { Fail } from '@endo/errors';
|
|
5
4
|
import { iterateReverse } from '@agoric/casting';
|
|
5
|
+
import { boardSlottingMarshaller } from '@agoric/client-utils';
|
|
6
6
|
import { makeWalletStateCoalescer } from '@agoric/smart-wallet/src/utils.js';
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
7
|
+
import { Fail } from '@endo/errors';
|
|
8
|
+
import { execSwingsetTransaction, pollTx } from './chain.js';
|
|
9
9
|
|
|
10
|
-
/**
|
|
11
|
-
|
|
10
|
+
/**
|
|
11
|
+
* @import {CurrentWalletRecord} from '@agoric/smart-wallet/src/smartWallet.js';
|
|
12
|
+
* @import {AgoricNamesRemotes} from '@agoric/vats/tools/board-utils.js';
|
|
13
|
+
* @import {MinimalNetworkConfig, VstorageKit} from '@agoric/client-utils';
|
|
14
|
+
*/
|
|
12
15
|
|
|
13
16
|
const marshaller = boardSlottingMarshaller();
|
|
14
17
|
|
|
@@ -22,15 +25,15 @@ const emptyCurrentRecord = {
|
|
|
22
25
|
|
|
23
26
|
/**
|
|
24
27
|
* @param {string} addr
|
|
25
|
-
* @param {Pick<
|
|
28
|
+
* @param {Pick<VstorageKit, 'readPublished'>} io
|
|
26
29
|
* @returns {Promise<import('@agoric/smart-wallet/src/smartWallet.js').CurrentWalletRecord>}
|
|
27
30
|
*/
|
|
28
|
-
export const getCurrent = async (addr, {
|
|
31
|
+
export const getCurrent = async (addr, { readPublished }) => {
|
|
29
32
|
// Partial because older writes may not have had all properties
|
|
30
33
|
// NB: assumes changes are only additions
|
|
31
34
|
let current =
|
|
32
35
|
/** @type {Partial<import('@agoric/smart-wallet/src/smartWallet.js').CurrentWalletRecord> | undefined} */ (
|
|
33
|
-
await
|
|
36
|
+
await readPublished(`wallet.${addr}.current`)
|
|
34
37
|
);
|
|
35
38
|
if (current === undefined) {
|
|
36
39
|
throw Error(`undefined current node for ${addr}`);
|
|
@@ -57,12 +60,11 @@ export const getCurrent = async (addr, { readLatestHead }) => {
|
|
|
57
60
|
|
|
58
61
|
/**
|
|
59
62
|
* @param {string} addr
|
|
60
|
-
* @param {Pick<
|
|
63
|
+
* @param {Pick<VstorageKit, 'readPublished'>} io
|
|
61
64
|
* @returns {Promise<import('@agoric/smart-wallet/src/smartWallet.js').UpdateRecord>}
|
|
62
65
|
*/
|
|
63
|
-
export const getLastUpdate = (addr, {
|
|
64
|
-
|
|
65
|
-
return readLatestHead(`published.wallet.${addr}`);
|
|
66
|
+
export const getLastUpdate = (addr, { readPublished }) => {
|
|
67
|
+
return readPublished(`wallet.${addr}`);
|
|
66
68
|
};
|
|
67
69
|
|
|
68
70
|
/**
|
|
@@ -142,12 +144,12 @@ export const coalesceWalletState = async (follower, invitationBrand) => {
|
|
|
142
144
|
*
|
|
143
145
|
* @throws { Error & { code: number } } if transaction fails
|
|
144
146
|
* @param {import('@agoric/smart-wallet/src/smartWallet.js').BridgeAction} bridgeAction
|
|
145
|
-
* @param {
|
|
147
|
+
* @param {MinimalNetworkConfig & {
|
|
146
148
|
* from: string,
|
|
147
149
|
* fees?: string,
|
|
148
150
|
* verbose?: boolean,
|
|
149
151
|
* keyring?: {home?: string, backend: string},
|
|
150
|
-
* stdout
|
|
152
|
+
* stdout?: Pick<import('stream').Writable, 'write'>,
|
|
151
153
|
* execFileSync: typeof import('child_process').execFileSync,
|
|
152
154
|
* delay: (ms: number) => Promise<void>,
|
|
153
155
|
* dryRun?: boolean,
|
|
@@ -211,76 +213,3 @@ export const findContinuingIds = (current, agoricNames) => {
|
|
|
211
213
|
}
|
|
212
214
|
return found;
|
|
213
215
|
};
|
|
214
|
-
|
|
215
|
-
export const makeWalletUtils = async (
|
|
216
|
-
{ fetch, execFileSync, delay },
|
|
217
|
-
networkConfig,
|
|
218
|
-
) => {
|
|
219
|
-
const { agoricNames, fromBoard, readLatestHead, vstorage } =
|
|
220
|
-
await makeRpcUtils({ fetch }, networkConfig);
|
|
221
|
-
/**
|
|
222
|
-
* @param {string} from
|
|
223
|
-
* @param {number|string} [minHeight]
|
|
224
|
-
*/
|
|
225
|
-
const storedWalletState = async (from, minHeight = undefined) => {
|
|
226
|
-
const m = boardSlottingMarshaller(fromBoard.convertSlotToVal);
|
|
227
|
-
|
|
228
|
-
const history = await vstorage.readFully(
|
|
229
|
-
`published.wallet.${from}`,
|
|
230
|
-
minHeight,
|
|
231
|
-
);
|
|
232
|
-
|
|
233
|
-
/** @type {{ Invitation: Brand<'set'> }} */
|
|
234
|
-
// @ts-expect-error XXX how to narrow AssetKind to set?
|
|
235
|
-
const { Invitation } = agoricNames.brand;
|
|
236
|
-
const coalescer = makeWalletStateCoalescer(Invitation);
|
|
237
|
-
// update with oldest first
|
|
238
|
-
for (const txt of history.reverse()) {
|
|
239
|
-
const { body, slots } = JSON.parse(txt);
|
|
240
|
-
const record = m.fromCapData({ body, slots });
|
|
241
|
-
coalescer.update(record);
|
|
242
|
-
}
|
|
243
|
-
const coalesced = coalescer.state;
|
|
244
|
-
harden(coalesced);
|
|
245
|
-
return coalesced;
|
|
246
|
-
};
|
|
247
|
-
|
|
248
|
-
/**
|
|
249
|
-
* Get OfferStatus by id, polling until available.
|
|
250
|
-
*
|
|
251
|
-
* @param {string} from
|
|
252
|
-
* @param {string|number} id
|
|
253
|
-
* @param {number|string} minHeight
|
|
254
|
-
* @param {boolean} [untilNumWantsSatisfied]
|
|
255
|
-
*/
|
|
256
|
-
const pollOffer = async (
|
|
257
|
-
from,
|
|
258
|
-
id,
|
|
259
|
-
minHeight,
|
|
260
|
-
untilNumWantsSatisfied = false,
|
|
261
|
-
) => {
|
|
262
|
-
const lookup = async () => {
|
|
263
|
-
const { offerStatuses } = await storedWalletState(from, minHeight);
|
|
264
|
-
const offerStatus = [...offerStatuses.values()].find(s => s.id === id);
|
|
265
|
-
if (!offerStatus) throw Error('retry');
|
|
266
|
-
harden(offerStatus);
|
|
267
|
-
if (untilNumWantsSatisfied && !('numWantsSatisfied' in offerStatus)) {
|
|
268
|
-
throw Error('retry (no numWantsSatisfied yet)');
|
|
269
|
-
}
|
|
270
|
-
return offerStatus;
|
|
271
|
-
};
|
|
272
|
-
const retryMessage = 'offer not in wallet at block';
|
|
273
|
-
const opts = { ...networkConfig, execFileSync, delay, retryMessage };
|
|
274
|
-
return pollBlocks(opts)(lookup);
|
|
275
|
-
};
|
|
276
|
-
|
|
277
|
-
return {
|
|
278
|
-
networkConfig,
|
|
279
|
-
agoricNames,
|
|
280
|
-
fromBoard,
|
|
281
|
-
vstorage,
|
|
282
|
-
readLatestHead,
|
|
283
|
-
storedWalletState,
|
|
284
|
-
pollOffer,
|
|
285
|
-
};
|
|
286
|
-
};
|
package/src/main.js
CHANGED
|
@@ -66,7 +66,9 @@ const main = async (progname, rawArgs, powers) => {
|
|
|
66
66
|
'verbosity that can be increased',
|
|
67
67
|
(_value, _previous) => (cmdOpts.verbose += 1),
|
|
68
68
|
);
|
|
69
|
-
|
|
69
|
+
/** @type {typeof program.command} */
|
|
70
|
+
const baseCmd = (nameAndParams, ...rest) =>
|
|
71
|
+
addCmdOpts(program.command(nameAndParams, ...rest));
|
|
70
72
|
|
|
71
73
|
addCmdOpts(
|
|
72
74
|
program
|
package/src/scripts.js
CHANGED
|
@@ -56,7 +56,7 @@ export const makeLookup =
|
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
58
|
* @param {string[]} scripts
|
|
59
|
-
* @param {{ allowUnsafePlugins
|
|
59
|
+
* @param {{ allowUnsafePlugins?: boolean, progname: string, rawArgs: string[], endowments?: Record<string, any> }} opts
|
|
60
60
|
* @param {{ fs: import('fs/promises'), console: Console }} powers
|
|
61
61
|
*/
|
|
62
62
|
export const makeScriptLoader =
|
package/src/sdk-package-names.js
CHANGED
|
@@ -9,6 +9,7 @@ export default [
|
|
|
9
9
|
"@agoric/builders",
|
|
10
10
|
"@agoric/cache",
|
|
11
11
|
"@agoric/casting",
|
|
12
|
+
"@agoric/client-utils",
|
|
12
13
|
"@agoric/cosmic-proto",
|
|
13
14
|
"@agoric/cosmic-swingset",
|
|
14
15
|
"@agoric/cosmos",
|
|
@@ -17,6 +18,7 @@ export default [
|
|
|
17
18
|
"@agoric/deployment",
|
|
18
19
|
"@agoric/ertp",
|
|
19
20
|
"@agoric/eslint-config",
|
|
21
|
+
"@agoric/fast-usdc",
|
|
20
22
|
"@agoric/governance",
|
|
21
23
|
"@agoric/import-manager",
|
|
22
24
|
"@agoric/inter-protocol",
|
|
@@ -49,6 +51,5 @@ export default [
|
|
|
49
51
|
"@agoric/xsnap-lockdown",
|
|
50
52
|
"@agoric/zoe",
|
|
51
53
|
"@agoric/zone",
|
|
52
|
-
"agoric"
|
|
53
|
-
"fast-usdc"
|
|
54
|
+
"agoric"
|
|
54
55
|
];
|
package/src/start.js
CHANGED
|
@@ -276,13 +276,13 @@ export default async function startMain(progname, rawArgs, powers, opts) {
|
|
|
276
276
|
await rmVerbose(serverDir);
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
+
/** @type {(args: string[], spawnOpts?: Parameters<typeof pspawn>[2], dockerArgs?: string[]) => ReturnType<pspawn>} */
|
|
279
280
|
let chainSpawn;
|
|
280
281
|
if (!popts.dockerTag) {
|
|
281
|
-
chainSpawn = (args, spawnOpts
|
|
282
|
-
|
|
283
|
-
};
|
|
282
|
+
chainSpawn = (args, spawnOpts) =>
|
|
283
|
+
pspawn(cosmosChain, [...args, `--home=${serverDir}`], spawnOpts);
|
|
284
284
|
} else {
|
|
285
|
-
chainSpawn = (args, spawnOpts
|
|
285
|
+
chainSpawn = (args, spawnOpts, dockerArgs = []) =>
|
|
286
286
|
pspawn(
|
|
287
287
|
'docker',
|
|
288
288
|
[
|
|
@@ -482,12 +482,12 @@ export default async function startMain(progname, rawArgs, powers, opts) {
|
|
|
482
482
|
await rmVerbose(serverDir);
|
|
483
483
|
}
|
|
484
484
|
|
|
485
|
+
/** @type {(args: string[], spawnOpts?: Parameters<typeof pspawn>[2], dockerArgs?: string[]) => ReturnType<pspawn>} */
|
|
485
486
|
let soloSpawn;
|
|
486
487
|
if (!popts.dockerTag) {
|
|
487
|
-
soloSpawn = (args, spawnOpts
|
|
488
|
-
pspawn(agSolo, args, spawnOpts);
|
|
488
|
+
soloSpawn = (args, spawnOpts) => pspawn(agSolo, args, spawnOpts);
|
|
489
489
|
} else {
|
|
490
|
-
soloSpawn = (args, spawnOpts
|
|
490
|
+
soloSpawn = (args, spawnOpts, dockerArgs = []) =>
|
|
491
491
|
pspawn(
|
|
492
492
|
'docker',
|
|
493
493
|
[
|
package/tools/getting-started.js
CHANGED
|
@@ -62,6 +62,13 @@ const getLatestBlockHeight = url =>
|
|
|
62
62
|
req.end();
|
|
63
63
|
});
|
|
64
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Test the "getting started" workflow. Note that this function may be imported
|
|
67
|
+
* by external repositories.
|
|
68
|
+
*
|
|
69
|
+
* @param {import('ava').ExecutionContext} t
|
|
70
|
+
* @param {{ init?: string[], install?: string[] }} [options]
|
|
71
|
+
*/
|
|
65
72
|
export const gettingStartedWorkflowTest = async (t, options = {}) => {
|
|
66
73
|
const { init: initOptions = [], install: installOptions = [] } = options;
|
|
67
74
|
const pspawn = makePspawn({ spawn });
|
package/src/lib/rpc.js
DELETED
|
@@ -1,285 +0,0 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
/* eslint-env node */
|
|
3
|
-
|
|
4
|
-
import { NonNullish } from '@agoric/internal';
|
|
5
|
-
import {
|
|
6
|
-
boardSlottingMarshaller,
|
|
7
|
-
makeBoardRemote,
|
|
8
|
-
} from '@agoric/vats/tools/board-utils.js';
|
|
9
|
-
|
|
10
|
-
export { boardSlottingMarshaller };
|
|
11
|
-
|
|
12
|
-
export const networkConfigUrl = agoricNetSubdomain =>
|
|
13
|
-
`https://${agoricNetSubdomain}.agoric.net/network-config`;
|
|
14
|
-
export const rpcUrl = agoricNetSubdomain =>
|
|
15
|
-
`https://${agoricNetSubdomain}.rpc.agoric.net:443`;
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* @typedef {{ rpcAddrs: string[], chainName: string }} MinimalNetworkConfig
|
|
19
|
-
*/
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* @param {string} str
|
|
23
|
-
* @returns {Promise<MinimalNetworkConfig>}
|
|
24
|
-
*/
|
|
25
|
-
const fromAgoricNet = str => {
|
|
26
|
-
const [netName, chainName] = str.split(',');
|
|
27
|
-
if (chainName) {
|
|
28
|
-
return Promise.resolve({ chainName, rpcAddrs: [rpcUrl(netName)] });
|
|
29
|
-
}
|
|
30
|
-
return fetch(networkConfigUrl(netName)).then(res => res.json());
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* @param {typeof process.env} env
|
|
35
|
-
* @returns {Promise<MinimalNetworkConfig>}
|
|
36
|
-
*/
|
|
37
|
-
export const getNetworkConfig = async env => {
|
|
38
|
-
if (!('AGORIC_NET' in env) || env.AGORIC_NET === 'local') {
|
|
39
|
-
return { rpcAddrs: ['http://0.0.0.0:26657'], chainName: 'agoriclocal' };
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return fromAgoricNet(NonNullish(env.AGORIC_NET)).catch(err => {
|
|
43
|
-
throw Error(
|
|
44
|
-
`cannot get network config (${env.AGORIC_NET || 'local'}): ${
|
|
45
|
-
err.message
|
|
46
|
-
}`,
|
|
47
|
-
);
|
|
48
|
-
});
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
/** @type {MinimalNetworkConfig} */
|
|
52
|
-
const networkConfig = await getNetworkConfig(process.env);
|
|
53
|
-
export { networkConfig };
|
|
54
|
-
// console.warn('networkConfig', networkConfig);
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* @param {object} powers
|
|
58
|
-
* @param {typeof window.fetch} powers.fetch
|
|
59
|
-
* @param {MinimalNetworkConfig} config
|
|
60
|
-
*/
|
|
61
|
-
export const makeVStorage = (powers, config = networkConfig) => {
|
|
62
|
-
/** @param {string} path */
|
|
63
|
-
const getJSON = path => {
|
|
64
|
-
const url = config.rpcAddrs[0] + path;
|
|
65
|
-
// console.warn('fetching', url);
|
|
66
|
-
return powers.fetch(url, { keepalive: true }).then(res => res.json());
|
|
67
|
-
};
|
|
68
|
-
// height=0 is the same as omitting height and implies the highest block
|
|
69
|
-
const url = (path = 'published', { kind = 'children', height = 0 } = {}) =>
|
|
70
|
-
`/abci_query?path=%22/custom/vstorage/${kind}/${path}%22&height=${height}`;
|
|
71
|
-
|
|
72
|
-
const readStorage = (path = 'published', { kind = 'children', height = 0 }) =>
|
|
73
|
-
getJSON(url(path, { kind, height }))
|
|
74
|
-
.catch(err => {
|
|
75
|
-
throw Error(`cannot read ${kind} of ${path}: ${err.message}`);
|
|
76
|
-
})
|
|
77
|
-
.then(data => {
|
|
78
|
-
const {
|
|
79
|
-
result: { response },
|
|
80
|
-
} = data;
|
|
81
|
-
if (response?.code !== 0) {
|
|
82
|
-
/** @type {any} */
|
|
83
|
-
const err = Error(
|
|
84
|
-
`error code ${response?.code} reading ${kind} of ${path}: ${response.log}`,
|
|
85
|
-
);
|
|
86
|
-
err.code = response?.code;
|
|
87
|
-
err.codespace = response?.codespace;
|
|
88
|
-
throw err;
|
|
89
|
-
}
|
|
90
|
-
return data;
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
return {
|
|
94
|
-
url,
|
|
95
|
-
decode({ result: { response } }) {
|
|
96
|
-
const { code } = response;
|
|
97
|
-
if (code !== 0) {
|
|
98
|
-
throw response;
|
|
99
|
-
}
|
|
100
|
-
const { value } = response;
|
|
101
|
-
return Buffer.from(value, 'base64').toString();
|
|
102
|
-
},
|
|
103
|
-
/**
|
|
104
|
-
*
|
|
105
|
-
* @param {string} path
|
|
106
|
-
* @returns {Promise<string>} latest vstorage value at path
|
|
107
|
-
*/
|
|
108
|
-
async readLatest(path = 'published') {
|
|
109
|
-
const raw = await readStorage(path, { kind: 'data' });
|
|
110
|
-
return this.decode(raw);
|
|
111
|
-
},
|
|
112
|
-
async keys(path = 'published') {
|
|
113
|
-
const raw = await readStorage(path, { kind: 'children' });
|
|
114
|
-
return JSON.parse(this.decode(raw)).children;
|
|
115
|
-
},
|
|
116
|
-
/**
|
|
117
|
-
* @param {string} path
|
|
118
|
-
* @param {number} [height] default is highest
|
|
119
|
-
* @returns {Promise<{blockHeight: number, values: string[]}>}
|
|
120
|
-
*/
|
|
121
|
-
async readAt(path, height = undefined) {
|
|
122
|
-
const raw = await readStorage(path, { kind: 'data', height });
|
|
123
|
-
const txt = this.decode(raw);
|
|
124
|
-
/** @type {{ value: string }} */
|
|
125
|
-
const { value } = JSON.parse(txt);
|
|
126
|
-
return JSON.parse(value);
|
|
127
|
-
},
|
|
128
|
-
/**
|
|
129
|
-
* Read values going back as far as available
|
|
130
|
-
*
|
|
131
|
-
* @param {string} path
|
|
132
|
-
* @param {number | string} [minHeight]
|
|
133
|
-
* @returns {Promise<string[]>}
|
|
134
|
-
*/
|
|
135
|
-
async readFully(path, minHeight = undefined) {
|
|
136
|
-
const parts = [];
|
|
137
|
-
// undefined the first iteration, to query at the highest
|
|
138
|
-
let blockHeight;
|
|
139
|
-
await null;
|
|
140
|
-
do {
|
|
141
|
-
// console.debug('READING', { blockHeight });
|
|
142
|
-
let values;
|
|
143
|
-
try {
|
|
144
|
-
({ blockHeight, values } = await this.readAt(
|
|
145
|
-
path,
|
|
146
|
-
blockHeight && Number(blockHeight) - 1,
|
|
147
|
-
));
|
|
148
|
-
// console.debug('readAt returned', { blockHeight });
|
|
149
|
-
} catch (err) {
|
|
150
|
-
if (
|
|
151
|
-
// CosmosSDK ErrInvalidRequest with particular message text;
|
|
152
|
-
// misrepresentation of pruned data
|
|
153
|
-
// TODO replace after incorporating a fix to
|
|
154
|
-
// https://github.com/cosmos/cosmos-sdk/issues/19992
|
|
155
|
-
err.codespace === 'sdk' &&
|
|
156
|
-
err.code === 18 &&
|
|
157
|
-
err.message.match(/pruned/)
|
|
158
|
-
) {
|
|
159
|
-
// console.error(err);
|
|
160
|
-
break;
|
|
161
|
-
}
|
|
162
|
-
throw err;
|
|
163
|
-
}
|
|
164
|
-
parts.push(values);
|
|
165
|
-
// console.debug('PUSHED', values);
|
|
166
|
-
// console.debug('NEW', { blockHeight, minHeight });
|
|
167
|
-
if (minHeight && Number(blockHeight) <= Number(minHeight)) break;
|
|
168
|
-
} while (blockHeight > 0);
|
|
169
|
-
return parts.flat();
|
|
170
|
-
},
|
|
171
|
-
};
|
|
172
|
-
};
|
|
173
|
-
/** @typedef {ReturnType<typeof makeVStorage>} VStorage */
|
|
174
|
-
|
|
175
|
-
export const makeFromBoard = () => {
|
|
176
|
-
const cache = new Map();
|
|
177
|
-
const convertSlotToVal = (boardId, iface) => {
|
|
178
|
-
if (cache.has(boardId)) {
|
|
179
|
-
return cache.get(boardId);
|
|
180
|
-
}
|
|
181
|
-
const val = makeBoardRemote({ boardId, iface });
|
|
182
|
-
cache.set(boardId, val);
|
|
183
|
-
return val;
|
|
184
|
-
};
|
|
185
|
-
return harden({ convertSlotToVal });
|
|
186
|
-
};
|
|
187
|
-
/** @typedef {ReturnType<typeof makeFromBoard>} IdMap */
|
|
188
|
-
|
|
189
|
-
export const storageHelper = {
|
|
190
|
-
/** @param { string } txt */
|
|
191
|
-
parseCapData: txt => {
|
|
192
|
-
assert(typeof txt === 'string', typeof txt);
|
|
193
|
-
/** @type {{ value: string }} */
|
|
194
|
-
const { value } = JSON.parse(txt);
|
|
195
|
-
const specimen = JSON.parse(value);
|
|
196
|
-
const { blockHeight, values } = specimen;
|
|
197
|
-
assert(values, `empty values in specimen ${value}`);
|
|
198
|
-
const capDatas = storageHelper.parseMany(values);
|
|
199
|
-
return { blockHeight, capDatas };
|
|
200
|
-
},
|
|
201
|
-
/**
|
|
202
|
-
* @param {string} txt
|
|
203
|
-
* @param {IdMap} ctx
|
|
204
|
-
*/
|
|
205
|
-
unserializeTxt: (txt, ctx) => {
|
|
206
|
-
const { capDatas } = storageHelper.parseCapData(txt);
|
|
207
|
-
return capDatas.map(capData =>
|
|
208
|
-
boardSlottingMarshaller(ctx.convertSlotToVal).fromCapData(capData),
|
|
209
|
-
);
|
|
210
|
-
},
|
|
211
|
-
/** @param {string[]} capDataStrings array of stringified capData */
|
|
212
|
-
parseMany: capDataStrings => {
|
|
213
|
-
assert(capDataStrings && capDataStrings.length);
|
|
214
|
-
/** @type {{ body: string, slots: string[] }[]} */
|
|
215
|
-
const capDatas = capDataStrings.map(s => JSON.parse(s));
|
|
216
|
-
for (const capData of capDatas) {
|
|
217
|
-
assert(typeof capData === 'object' && capData !== null);
|
|
218
|
-
assert('body' in capData && 'slots' in capData);
|
|
219
|
-
assert(typeof capData.body === 'string');
|
|
220
|
-
assert(Array.isArray(capData.slots));
|
|
221
|
-
}
|
|
222
|
-
return capDatas;
|
|
223
|
-
},
|
|
224
|
-
};
|
|
225
|
-
harden(storageHelper);
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* @param {IdMap} ctx
|
|
229
|
-
* @param {VStorage} vstorage
|
|
230
|
-
* @returns {Promise<import('@agoric/vats/tools/board-utils.js').AgoricNamesRemotes>}
|
|
231
|
-
*/
|
|
232
|
-
export const makeAgoricNames = async (ctx, vstorage) => {
|
|
233
|
-
const reverse = {};
|
|
234
|
-
const entries = await Promise.all(
|
|
235
|
-
['brand', 'instance', 'vbankAsset'].map(async kind => {
|
|
236
|
-
const content = await vstorage.readLatest(
|
|
237
|
-
`published.agoricNames.${kind}`,
|
|
238
|
-
);
|
|
239
|
-
/** @type {Array<[string, import('@agoric/vats/tools/board-utils.js').BoardRemote]>} */
|
|
240
|
-
const parts = storageHelper.unserializeTxt(content, ctx).at(-1);
|
|
241
|
-
for (const [name, remote] of parts) {
|
|
242
|
-
if ('getBoardId' in remote) {
|
|
243
|
-
reverse[remote.getBoardId()] = name;
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
return [kind, Object.fromEntries(parts)];
|
|
247
|
-
}),
|
|
248
|
-
);
|
|
249
|
-
return { ...Object.fromEntries(entries), reverse };
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
/**
|
|
253
|
-
* @param {{ fetch: typeof window.fetch }} io
|
|
254
|
-
* @param {MinimalNetworkConfig} config
|
|
255
|
-
*/
|
|
256
|
-
export const makeRpcUtils = async ({ fetch }, config = networkConfig) => {
|
|
257
|
-
await null;
|
|
258
|
-
try {
|
|
259
|
-
const vstorage = makeVStorage({ fetch }, config);
|
|
260
|
-
const fromBoard = makeFromBoard();
|
|
261
|
-
const agoricNames = await makeAgoricNames(fromBoard, vstorage);
|
|
262
|
-
|
|
263
|
-
const unserializer = boardSlottingMarshaller(fromBoard.convertSlotToVal);
|
|
264
|
-
|
|
265
|
-
/** @type {(txt: string) => unknown} */
|
|
266
|
-
const unserializeHead = txt =>
|
|
267
|
-
storageHelper.unserializeTxt(txt, fromBoard).at(-1);
|
|
268
|
-
|
|
269
|
-
/** @type {(path: string) => Promise<unknown>} */
|
|
270
|
-
const readLatestHead = path =>
|
|
271
|
-
vstorage.readLatest(path).then(unserializeHead);
|
|
272
|
-
|
|
273
|
-
return {
|
|
274
|
-
agoricNames,
|
|
275
|
-
fromBoard,
|
|
276
|
-
readLatestHead,
|
|
277
|
-
unserializeHead,
|
|
278
|
-
unserializer,
|
|
279
|
-
vstorage,
|
|
280
|
-
};
|
|
281
|
-
} catch (err) {
|
|
282
|
-
throw Error(`RPC failure (${config.rpcAddrs}): ${err.message}`);
|
|
283
|
-
}
|
|
284
|
-
};
|
|
285
|
-
/** @typedef {Awaited<ReturnType<typeof makeRpcUtils>>} RpcUtils */
|