agoric 0.21.2-dev-d603b6c.0 → 0.21.2-dev-02c06c4.0
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 +21 -20
- package/src/commands/auction.js +9 -3
- package/src/commands/gov.js +17 -10
- package/src/commands/inter.js +8 -14
- package/src/commands/oracle.js +10 -9
- package/src/commands/perf.js +5 -3
- package/src/commands/psm.js +7 -4
- package/src/commands/reserve.js +6 -3
- package/src/commands/test-upgrade.js +5 -4
- package/src/commands/vaults.js +18 -6
- package/src/commands/wallet.js +16 -10
- package/src/lib/chain.js +8 -4
- package/src/lib/format.js +4 -18
- package/src/lib/network-config.js +37 -0
- package/src/lib/wallet.js +11 -81
- package/src/sdk-package-names.js +1 -0
- package/src/lib/rpc.js +0 -285
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agoric",
|
|
3
|
-
"version": "0.21.2-dev-
|
|
3
|
+
"version": "0.21.2-dev-02c06c4.0+02c06c4",
|
|
4
4
|
"description": "Manage the Agoric Javascript smart contract platform",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/main.js",
|
|
@@ -29,28 +29,29 @@
|
|
|
29
29
|
"lint:eslint": "eslint ."
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@agoric/cosmic-swingset": "0.41.4-dev-
|
|
33
|
-
"@agoric/deploy-script-support": "0.10.4-dev-
|
|
32
|
+
"@agoric/cosmic-swingset": "0.41.4-dev-02c06c4.0+02c06c4",
|
|
33
|
+
"@agoric/deploy-script-support": "0.10.4-dev-02c06c4.0+02c06c4",
|
|
34
34
|
"ava": "^5.3.0",
|
|
35
35
|
"c8": "^9.1.0",
|
|
36
36
|
"dd-trace": "^4.11.1"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@agoric/access-token": "0.4.22-dev-
|
|
40
|
-
"@agoric/cache": "0.3.3-dev-
|
|
41
|
-
"@agoric/casting": "0.4.3-dev-
|
|
42
|
-
"@agoric/
|
|
43
|
-
"@agoric/
|
|
44
|
-
"@agoric/
|
|
45
|
-
"@agoric/
|
|
46
|
-
"@agoric/
|
|
47
|
-
"@agoric/
|
|
48
|
-
"@agoric/
|
|
49
|
-
"@agoric/
|
|
50
|
-
"@agoric/
|
|
51
|
-
"@agoric/
|
|
52
|
-
"@agoric/
|
|
53
|
-
"@agoric/
|
|
39
|
+
"@agoric/access-token": "0.4.22-dev-02c06c4.0+02c06c4",
|
|
40
|
+
"@agoric/cache": "0.3.3-dev-02c06c4.0+02c06c4",
|
|
41
|
+
"@agoric/casting": "0.4.3-dev-02c06c4.0+02c06c4",
|
|
42
|
+
"@agoric/client-utils": "0.1.1-dev-02c06c4.0+02c06c4",
|
|
43
|
+
"@agoric/cosmic-proto": "0.4.1-dev-02c06c4.0+02c06c4",
|
|
44
|
+
"@agoric/ertp": "0.16.3-dev-02c06c4.0+02c06c4",
|
|
45
|
+
"@agoric/governance": "0.10.4-dev-02c06c4.0+02c06c4",
|
|
46
|
+
"@agoric/inter-protocol": "0.16.2-dev-02c06c4.0+02c06c4",
|
|
47
|
+
"@agoric/internal": "0.3.3-dev-02c06c4.0+02c06c4",
|
|
48
|
+
"@agoric/network": "0.1.1-dev-02c06c4.0+02c06c4",
|
|
49
|
+
"@agoric/smart-wallet": "0.5.4-dev-02c06c4.0+02c06c4",
|
|
50
|
+
"@agoric/store": "0.9.3-dev-02c06c4.0+02c06c4",
|
|
51
|
+
"@agoric/swingset-vat": "0.32.3-dev-02c06c4.0+02c06c4",
|
|
52
|
+
"@agoric/vats": "0.15.2-dev-02c06c4.0+02c06c4",
|
|
53
|
+
"@agoric/zoe": "0.26.3-dev-02c06c4.0+02c06c4",
|
|
54
|
+
"@agoric/zone": "0.2.3-dev-02c06c4.0+02c06c4",
|
|
54
55
|
"@confio/relayer": "^0.11.3",
|
|
55
56
|
"@cosmjs/crypto": "^0.32.3",
|
|
56
57
|
"@cosmjs/encoding": "^0.32.3",
|
|
@@ -99,7 +100,7 @@
|
|
|
99
100
|
"workerThreads": false
|
|
100
101
|
},
|
|
101
102
|
"typeCoverage": {
|
|
102
|
-
"atLeast": 77.
|
|
103
|
+
"atLeast": 77.45
|
|
103
104
|
},
|
|
104
|
-
"gitHead": "
|
|
105
|
+
"gitHead": "02c06c489677233c0daa112284d16c314aff97c6"
|
|
105
106
|
}
|
package/src/commands/auction.js
CHANGED
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
-
|
|
2
|
+
/* eslint-env node */
|
|
3
3
|
import { InvalidArgumentError } from 'commander';
|
|
4
4
|
import { Fail } from '@endo/errors';
|
|
5
|
-
import {
|
|
5
|
+
import { makeVstorageKit } from '@agoric/client-utils';
|
|
6
6
|
import { outputActionAndHint } from '../lib/wallet.js';
|
|
7
|
+
import { getNetworkConfig } from '../lib/network-config.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* @import {ParamTypesMap, ParamTypesMapFromRecord} from '@agoric/governance/src/contractGovernance/typedParamManager.js'
|
|
10
11
|
* @import {ParamValueForType} from '@agoric/governance/src/types.js'
|
|
11
12
|
*/
|
|
12
13
|
|
|
14
|
+
const networkConfig = await getNetworkConfig({ env: process.env, fetch });
|
|
15
|
+
|
|
13
16
|
/**
|
|
14
17
|
* @template {ParamTypesMap} M
|
|
15
18
|
* @typedef {{
|
|
@@ -86,7 +89,10 @@ export const makeAuctionCommand = (
|
|
|
86
89
|
* }} opts
|
|
87
90
|
*/
|
|
88
91
|
async opts => {
|
|
89
|
-
const { agoricNames, readLatestHead } = await
|
|
92
|
+
const { agoricNames, readLatestHead } = await makeVstorageKit(
|
|
93
|
+
{ fetch },
|
|
94
|
+
networkConfig,
|
|
95
|
+
);
|
|
90
96
|
|
|
91
97
|
/** @type {{ current: AuctionParamRecord }} */
|
|
92
98
|
// @ts-expect-error XXX should runtime check?
|
package/src/commands/gov.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
/* eslint-disable func-names */
|
|
3
|
-
/*
|
|
3
|
+
/* eslint-env node */
|
|
4
|
+
import { makeVstorageKit } from '@agoric/client-utils';
|
|
4
5
|
import { execFileSync as execFileSyncAmbient } from 'child_process';
|
|
5
6
|
import { Command, CommanderError } from 'commander';
|
|
6
7
|
import { normalizeAddressWithOptions, pollBlocks } from '../lib/chain.js';
|
|
7
|
-
import { getNetworkConfig
|
|
8
|
+
import { getNetworkConfig } from '../lib/network-config.js';
|
|
8
9
|
import {
|
|
9
10
|
findContinuingIds,
|
|
10
11
|
getCurrent,
|
|
@@ -25,6 +26,8 @@ const collectValues = (val, memo) => {
|
|
|
25
26
|
|
|
26
27
|
const defaultKeyring = process.env.AGORIC_KEYRING_BACKEND || 'test';
|
|
27
28
|
|
|
29
|
+
const networkConfig = await getNetworkConfig({ env: process.env, fetch });
|
|
30
|
+
|
|
28
31
|
/**
|
|
29
32
|
* @param {import('anylogger').Logger} _logger
|
|
30
33
|
* @param {{
|
|
@@ -40,10 +43,9 @@ export const makeGovCommand = (_logger, io = {}) => {
|
|
|
40
43
|
const {
|
|
41
44
|
// Allow caller to provide access explicitly, but
|
|
42
45
|
// default to conventional ambient IO facilities.
|
|
43
|
-
env = process.env,
|
|
44
46
|
stdout = process.stdout,
|
|
45
47
|
stderr = process.stderr,
|
|
46
|
-
fetch =
|
|
48
|
+
fetch = global.fetch,
|
|
47
49
|
execFileSync = execFileSyncAmbient,
|
|
48
50
|
delay = ms => new Promise(resolve => setTimeout(resolve, ms)),
|
|
49
51
|
} = io;
|
|
@@ -89,14 +91,13 @@ export const makeGovCommand = (_logger, io = {}) => {
|
|
|
89
91
|
* keyringBackend: string,
|
|
90
92
|
* instanceName?: string,
|
|
91
93
|
* }} detail
|
|
92
|
-
* @param {Awaited<ReturnType<
|
|
94
|
+
* @param {Awaited<ReturnType<makeVstorageKit>>} [optUtils]
|
|
93
95
|
*/
|
|
94
96
|
const processOffer = async function (
|
|
95
97
|
{ toOffer, sendFrom, keyringBackend },
|
|
96
98
|
optUtils,
|
|
97
99
|
) {
|
|
98
|
-
const
|
|
99
|
-
const utils = await (optUtils || makeRpcUtils({ fetch }));
|
|
100
|
+
const utils = await (optUtils || makeVstorageKit({ fetch }, networkConfig));
|
|
100
101
|
const { agoricNames, readLatestHead } = utils;
|
|
101
102
|
|
|
102
103
|
assert(keyringBackend, 'missing keyring-backend option');
|
|
@@ -264,7 +265,10 @@ export const makeGovCommand = (_logger, io = {}) => {
|
|
|
264
265
|
)
|
|
265
266
|
.requiredOption('--for <string>', 'description of the invitation')
|
|
266
267
|
.action(async opts => {
|
|
267
|
-
const { agoricNames, readLatestHead } = await
|
|
268
|
+
const { agoricNames, readLatestHead } = await makeVstorageKit(
|
|
269
|
+
{ fetch },
|
|
270
|
+
networkConfig,
|
|
271
|
+
);
|
|
268
272
|
const current = await getCurrent(opts.from, { readLatestHead });
|
|
269
273
|
|
|
270
274
|
const known = findContinuingIds(current, agoricNames);
|
|
@@ -290,7 +294,10 @@ export const makeGovCommand = (_logger, io = {}) => {
|
|
|
290
294
|
normalizeAddress,
|
|
291
295
|
)
|
|
292
296
|
.action(async opts => {
|
|
293
|
-
const { agoricNames, readLatestHead } = await
|
|
297
|
+
const { agoricNames, readLatestHead } = await makeVstorageKit(
|
|
298
|
+
{ fetch },
|
|
299
|
+
networkConfig,
|
|
300
|
+
);
|
|
294
301
|
const current = await getCurrent(opts.from, { readLatestHead });
|
|
295
302
|
|
|
296
303
|
const found = findContinuingIds(current, agoricNames);
|
|
@@ -326,7 +333,7 @@ export const makeGovCommand = (_logger, io = {}) => {
|
|
|
326
333
|
normalizeAddress,
|
|
327
334
|
)
|
|
328
335
|
.action(async function (opts, options) {
|
|
329
|
-
const utils = await
|
|
336
|
+
const utils = await makeVstorageKit({ fetch }, networkConfig);
|
|
330
337
|
const { readLatestHead } = utils;
|
|
331
338
|
|
|
332
339
|
const info = await readLatestHead(
|
package/src/commands/inter.js
CHANGED
|
@@ -4,26 +4,20 @@
|
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
6
|
// @ts-check
|
|
7
|
-
import {
|
|
8
|
-
// TODO: should get M from endo https://github.com/Agoric/agoric-sdk/issues/7090
|
|
7
|
+
import { makeWalletUtils } from '@agoric/client-utils';
|
|
9
8
|
import { makeOfferSpecShape } from '@agoric/inter-protocol/src/auction/auctionBook.js';
|
|
10
9
|
import { Offers } from '@agoric/inter-protocol/src/clientSupport.js';
|
|
11
10
|
import { objectMap } from '@agoric/internal';
|
|
12
|
-
import { M, matches } from '@
|
|
13
|
-
|
|
11
|
+
import { M, matches } from '@endo/patterns';
|
|
12
|
+
import { CommanderError, InvalidArgumentError } from 'commander';
|
|
14
13
|
import { normalizeAddressWithOptions, pollBlocks } from '../lib/chain.js';
|
|
14
|
+
import { getCurrent, outputActionAndHint, sendAction } from '../lib/wallet.js';
|
|
15
15
|
import {
|
|
16
16
|
asBoardRemote,
|
|
17
17
|
bigintReplacer,
|
|
18
18
|
makeAmountFormatter,
|
|
19
19
|
} from '../lib/format.js';
|
|
20
|
-
import { getNetworkConfig } from '../lib/
|
|
21
|
-
import {
|
|
22
|
-
getCurrent,
|
|
23
|
-
makeWalletUtils,
|
|
24
|
-
outputActionAndHint,
|
|
25
|
-
sendAction,
|
|
26
|
-
} from '../lib/wallet.js';
|
|
20
|
+
import { getNetworkConfig } from '../lib/network-config.js';
|
|
27
21
|
|
|
28
22
|
const { values } = Object;
|
|
29
23
|
|
|
@@ -238,8 +232,8 @@ export const makeInterCommand = (
|
|
|
238
232
|
try {
|
|
239
233
|
// XXX pass fetch to getNetworkConfig() explicitly
|
|
240
234
|
// await null above makes this await safe
|
|
241
|
-
const networkConfig = await getNetworkConfig(env);
|
|
242
|
-
return makeWalletUtils({ fetch,
|
|
235
|
+
const networkConfig = await getNetworkConfig({ env, fetch });
|
|
236
|
+
return makeWalletUtils({ fetch, delay }, networkConfig);
|
|
243
237
|
} catch (err) {
|
|
244
238
|
// CommanderError is a class constructor, and so
|
|
245
239
|
// must be invoked with `new`.
|
|
@@ -334,7 +328,7 @@ inter auction status
|
|
|
334
328
|
* @param {string} from
|
|
335
329
|
* @param {import('@agoric/smart-wallet/src/offers.js').OfferSpec} offer
|
|
336
330
|
* @param {Awaited<ReturnType<tryMakeUtils>>} tools
|
|
337
|
-
* @param {boolean
|
|
331
|
+
* @param {boolean | undefined} dryRun
|
|
338
332
|
*/
|
|
339
333
|
const placeBid = async (from, offer, tools, dryRun = false) => {
|
|
340
334
|
const { networkConfig, agoricNames, pollOffer } = tools;
|
package/src/commands/oracle.js
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
/* eslint-disable func-names */
|
|
3
3
|
/* eslint-env node */
|
|
4
|
+
import {
|
|
5
|
+
makeVstorageKit,
|
|
6
|
+
makeWalletUtils,
|
|
7
|
+
storageHelper,
|
|
8
|
+
} from '@agoric/client-utils';
|
|
4
9
|
import { Offers } from '@agoric/inter-protocol/src/clientSupport.js';
|
|
5
10
|
import { oracleBrandFeedName } from '@agoric/inter-protocol/src/proposals/utils.js';
|
|
6
11
|
import { Fail } from '@endo/errors';
|
|
@@ -9,15 +14,14 @@ import * as cp from 'child_process';
|
|
|
9
14
|
import { Command } from 'commander';
|
|
10
15
|
import { inspect } from 'util';
|
|
11
16
|
import { normalizeAddressWithOptions } from '../lib/chain.js';
|
|
12
|
-
import {
|
|
13
|
-
import { getNetworkConfig, makeRpcUtils, storageHelper } from '../lib/rpc.js';
|
|
17
|
+
import { getNetworkConfig } from '../lib/network-config.js';
|
|
14
18
|
import {
|
|
15
19
|
getCurrent,
|
|
16
|
-
makeWalletUtils,
|
|
17
20
|
outputAction,
|
|
18
21
|
sendAction,
|
|
19
22
|
sendHint,
|
|
20
23
|
} from '../lib/wallet.js';
|
|
24
|
+
import { bigintReplacer } from '../lib/format.js';
|
|
21
25
|
|
|
22
26
|
/** @import {PriceAuthority, PriceDescription, PriceQuote, PriceQuoteValue, PriceQuery,} from '@agoric/zoe/tools/types.js'; */
|
|
23
27
|
|
|
@@ -82,8 +86,8 @@ export const makeOracleCommand = (logger, io = {}) => {
|
|
|
82
86
|
|
|
83
87
|
const rpcTools = async () => {
|
|
84
88
|
// XXX pass fetch to getNetworkConfig() explicitly
|
|
85
|
-
const networkConfig = await getNetworkConfig(env);
|
|
86
|
-
const utils = await
|
|
89
|
+
const networkConfig = await getNetworkConfig({ env: process.env, fetch });
|
|
90
|
+
const utils = await makeVstorageKit({ fetch }, networkConfig);
|
|
87
91
|
|
|
88
92
|
const lookupPriceAggregatorInstance = ([brandIn, brandOut]) => {
|
|
89
93
|
const name = oracleBrandFeedName(brandIn, brandOut);
|
|
@@ -267,10 +271,7 @@ export const makeOracleCommand = (logger, io = {}) => {
|
|
|
267
271
|
) => {
|
|
268
272
|
const { readLatestHead, networkConfig, lookupPriceAggregatorInstance } =
|
|
269
273
|
await rpcTools();
|
|
270
|
-
const wutil = await makeWalletUtils(
|
|
271
|
-
{ fetch, execFileSync, delay },
|
|
272
|
-
networkConfig,
|
|
273
|
-
);
|
|
274
|
+
const wutil = await makeWalletUtils({ fetch, delay }, networkConfig);
|
|
274
275
|
const unitPrice = scaleDecimals(price);
|
|
275
276
|
|
|
276
277
|
const feedPath = `published.priceFeed.${pair[0]}-${pair[1]}_price_feed`;
|
package/src/commands/perf.js
CHANGED
|
@@ -7,21 +7,23 @@ import {
|
|
|
7
7
|
makeFollower,
|
|
8
8
|
makeLeaderFromRpcAddresses,
|
|
9
9
|
} from '@agoric/casting';
|
|
10
|
+
import { slotToRemotable } from '@agoric/internal/src/storage-test-utils.js';
|
|
11
|
+
import { boardSlottingMarshaller } from '@agoric/vats/tools/board-utils.js';
|
|
10
12
|
import { Command } from 'commander';
|
|
11
13
|
import fs from 'fs';
|
|
12
14
|
import { exit } from 'process';
|
|
13
|
-
import { slotToRemotable } from '@agoric/internal/src/storage-test-utils.js';
|
|
14
|
-
import { boardSlottingMarshaller } from '@agoric/vats/tools/board-utils.js';
|
|
15
15
|
import { makeLeaderOptions } from '../lib/casting.js';
|
|
16
16
|
import {
|
|
17
17
|
execSwingsetTransaction,
|
|
18
18
|
normalizeAddressWithOptions,
|
|
19
19
|
} from '../lib/chain.js';
|
|
20
|
-
import {
|
|
20
|
+
import { getNetworkConfig } from '../lib/network-config.js';
|
|
21
21
|
|
|
22
22
|
// tight for perf testing but less than this tends to hang.
|
|
23
23
|
const SLEEP_SECONDS = 0.1;
|
|
24
24
|
|
|
25
|
+
const networkConfig = await getNetworkConfig({ env: process.env, fetch });
|
|
26
|
+
|
|
25
27
|
/**
|
|
26
28
|
* @param {import('anylogger').Logger} logger
|
|
27
29
|
*/
|
package/src/commands/psm.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
/* eslint-disable func-names */
|
|
3
3
|
/* eslint-env node */
|
|
4
|
-
import {
|
|
4
|
+
import { makeVstorageKit, storageHelper } from '@agoric/client-utils';
|
|
5
5
|
import { Offers } from '@agoric/inter-protocol/src/clientSupport.js';
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
6
|
+
import { Command } from 'commander';
|
|
7
|
+
import { getNetworkConfig } from '../lib/network-config.js';
|
|
8
8
|
import { outputExecuteOfferAction } from '../lib/wallet.js';
|
|
9
|
+
import { asPercent } from '../lib/format.js';
|
|
10
|
+
|
|
11
|
+
const networkConfig = await getNetworkConfig({ env: process.env, fetch });
|
|
9
12
|
|
|
10
13
|
// Adapted from https://gist.github.com/dckc/8b5b2f16395cb4d7f2ff340e0bc6b610#file-psm-tool
|
|
11
14
|
|
|
@@ -60,7 +63,7 @@ export const makePsmCommand = logger => {
|
|
|
60
63
|
);
|
|
61
64
|
|
|
62
65
|
const rpcTools = async () => {
|
|
63
|
-
const utils = await
|
|
66
|
+
const utils = await makeVstorageKit({ fetch }, networkConfig);
|
|
64
67
|
|
|
65
68
|
const lookupPsmInstance = ([minted, anchor]) => {
|
|
66
69
|
const name = `psm-${minted}-${anchor}`;
|
package/src/commands/reserve.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
/* eslint-disable func-names */
|
|
3
3
|
/* eslint-env node */
|
|
4
|
+
import { makeVstorageKit } from '@agoric/client-utils';
|
|
4
5
|
import { Offers } from '@agoric/inter-protocol/src/clientSupport.js';
|
|
5
6
|
import { Command } from 'commander';
|
|
6
|
-
import {
|
|
7
|
+
import { getNetworkConfig } from '../lib/network-config.js';
|
|
7
8
|
import { outputActionAndHint } from '../lib/wallet.js';
|
|
8
9
|
|
|
10
|
+
const networkConfig = await getNetworkConfig({ env: process.env, fetch });
|
|
11
|
+
|
|
9
12
|
/**
|
|
10
13
|
* @param {import('anylogger').Logger} _logger
|
|
11
14
|
* @param {*} io
|
|
@@ -29,7 +32,7 @@ export const makeReserveCommand = (_logger, io = {}) => {
|
|
|
29
32
|
* }} opts
|
|
30
33
|
*/
|
|
31
34
|
async ({ collateralBrand, ...opts }) => {
|
|
32
|
-
const { agoricNames } = await
|
|
35
|
+
const { agoricNames } = await makeVstorageKit({ fetch }, networkConfig);
|
|
33
36
|
|
|
34
37
|
const offer = Offers.reserve.AddCollateral(agoricNames, {
|
|
35
38
|
collateralBrandKey: collateralBrand,
|
|
@@ -63,7 +66,7 @@ export const makeReserveCommand = (_logger, io = {}) => {
|
|
|
63
66
|
1,
|
|
64
67
|
)
|
|
65
68
|
.action(async function (opts) {
|
|
66
|
-
const { agoricNames } = await
|
|
69
|
+
const { agoricNames } = await makeVstorageKit({ fetch }, networkConfig);
|
|
67
70
|
|
|
68
71
|
const reserveInstance = agoricNames.instance.reserve;
|
|
69
72
|
assert(reserveInstance, 'missing reserve in names');
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
/* eslint-env node */
|
|
3
|
+
import { makeWalletUtils } from '@agoric/client-utils';
|
|
3
4
|
import { Fail } from '@endo/errors';
|
|
4
5
|
import { CommanderError } from 'commander';
|
|
5
6
|
import { normalizeAddressWithOptions } from '../lib/chain.js';
|
|
7
|
+
import { getNetworkConfig } from '../lib/network-config.js';
|
|
8
|
+
import { sendAction } from '../lib/wallet.js';
|
|
6
9
|
import { bigintReplacer } from '../lib/format.js';
|
|
7
|
-
import { getNetworkConfig } from '../lib/rpc.js';
|
|
8
|
-
import { makeWalletUtils, sendAction } from '../lib/wallet.js';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Make commands for testing.
|
|
@@ -38,8 +39,8 @@ export const makeTestCommand = (
|
|
|
38
39
|
try {
|
|
39
40
|
// XXX pass fetch to getNetworkConfig() explicitly
|
|
40
41
|
// await null above makes this await safe
|
|
41
|
-
const networkConfig = await getNetworkConfig(env);
|
|
42
|
-
return makeWalletUtils({ fetch,
|
|
42
|
+
const networkConfig = await getNetworkConfig({ env, fetch });
|
|
43
|
+
return makeWalletUtils({ fetch, delay }, networkConfig);
|
|
43
44
|
} catch (err) {
|
|
44
45
|
// CommanderError is a class constructor, and so
|
|
45
46
|
// must be invoked with `new`.
|
package/src/commands/vaults.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
// @ts-check
|
|
2
2
|
/* eslint-disable func-names */
|
|
3
3
|
/* eslint-env node */
|
|
4
|
-
import {
|
|
4
|
+
import { makeVstorageKit } from '@agoric/client-utils';
|
|
5
5
|
import {
|
|
6
6
|
lookupOfferIdForVault,
|
|
7
7
|
Offers,
|
|
8
8
|
} from '@agoric/inter-protocol/src/clientSupport.js';
|
|
9
|
+
import { Command } from 'commander';
|
|
9
10
|
import { normalizeAddressWithOptions } from '../lib/chain.js';
|
|
10
|
-
import { makeRpcUtils } from '../lib/rpc.js';
|
|
11
11
|
import { getCurrent, outputExecuteOfferAction } from '../lib/wallet.js';
|
|
12
|
+
import { getNetworkConfig } from '../lib/network-config.js';
|
|
13
|
+
|
|
14
|
+
const networkConfig = await getNetworkConfig({ env: process.env, fetch });
|
|
12
15
|
|
|
13
16
|
/**
|
|
14
17
|
* @param {import('anylogger').Logger} logger
|
|
@@ -36,7 +39,10 @@ export const makeVaultsCommand = logger => {
|
|
|
36
39
|
normalizeAddress,
|
|
37
40
|
)
|
|
38
41
|
.action(async function (opts) {
|
|
39
|
-
const { readLatestHead } = await
|
|
42
|
+
const { readLatestHead } = await makeVstorageKit(
|
|
43
|
+
{ fetch },
|
|
44
|
+
networkConfig,
|
|
45
|
+
);
|
|
40
46
|
|
|
41
47
|
const current = await getCurrent(opts.from, {
|
|
42
48
|
readLatestHead,
|
|
@@ -61,7 +67,7 @@ export const makeVaultsCommand = logger => {
|
|
|
61
67
|
.option('--collateralBrand <string>', 'Collateral brand key', 'ATOM')
|
|
62
68
|
.action(async function (opts) {
|
|
63
69
|
logger.warn('running with options', opts);
|
|
64
|
-
const { agoricNames } = await
|
|
70
|
+
const { agoricNames } = await makeVstorageKit({ fetch }, networkConfig);
|
|
65
71
|
|
|
66
72
|
const offer = Offers.vaults.OpenVault(agoricNames, {
|
|
67
73
|
giveCollateral: opts.giveCollateral,
|
|
@@ -96,7 +102,10 @@ export const makeVaultsCommand = logger => {
|
|
|
96
102
|
.requiredOption('--vaultId <string>', 'Key of vault (e.g. vault1)')
|
|
97
103
|
.action(async function (opts) {
|
|
98
104
|
logger.warn('running with options', opts);
|
|
99
|
-
const { agoricNames, readLatestHead } = await
|
|
105
|
+
const { agoricNames, readLatestHead } = await makeVstorageKit(
|
|
106
|
+
{ fetch },
|
|
107
|
+
networkConfig,
|
|
108
|
+
);
|
|
100
109
|
|
|
101
110
|
const previousOfferId = await lookupOfferIdForVault(
|
|
102
111
|
opts.vaultId,
|
|
@@ -137,7 +146,10 @@ export const makeVaultsCommand = logger => {
|
|
|
137
146
|
)
|
|
138
147
|
.action(async function (opts) {
|
|
139
148
|
logger.warn('running with options', opts);
|
|
140
|
-
const { agoricNames, readLatestHead } = await
|
|
149
|
+
const { agoricNames, readLatestHead } = await makeVstorageKit(
|
|
150
|
+
{ fetch },
|
|
151
|
+
networkConfig,
|
|
152
|
+
);
|
|
141
153
|
|
|
142
154
|
const previousOfferId = await lookupOfferIdForVault(
|
|
143
155
|
opts.vaultId,
|
package/src/commands/wallet.js
CHANGED
|
@@ -8,11 +8,10 @@ import {
|
|
|
8
8
|
makeLeader,
|
|
9
9
|
makeLeaderFromRpcAddresses,
|
|
10
10
|
} from '@agoric/casting';
|
|
11
|
+
import { makeVstorageKit } from '@agoric/client-utils';
|
|
12
|
+
import { execFileSync } from 'child_process';
|
|
11
13
|
import fs from 'fs';
|
|
12
14
|
import util from 'util';
|
|
13
|
-
import { execFileSync } from 'child_process';
|
|
14
|
-
import { fmtRecordOfLines, summarize } from '../lib/format.js';
|
|
15
|
-
import { makeRpcUtils, networkConfig } from '../lib/rpc.js';
|
|
16
15
|
|
|
17
16
|
import { makeLeaderOptions } from '../lib/casting.js';
|
|
18
17
|
import {
|
|
@@ -20,7 +19,11 @@ import {
|
|
|
20
19
|
fetchSwingsetParams,
|
|
21
20
|
normalizeAddressWithOptions,
|
|
22
21
|
} from '../lib/chain.js';
|
|
22
|
+
import { getNetworkConfig } from '../lib/network-config.js';
|
|
23
23
|
import { coalesceWalletState, getCurrent } from '../lib/wallet.js';
|
|
24
|
+
import { summarize, fmtRecordOfLines } from '../lib/format.js';
|
|
25
|
+
|
|
26
|
+
const networkConfig = await getNetworkConfig({ env: process.env, fetch });
|
|
24
27
|
|
|
25
28
|
const SLEEP_SECONDS = 3;
|
|
26
29
|
|
|
@@ -102,7 +105,7 @@ export const makeWalletCommand = async command => {
|
|
|
102
105
|
.action(async function (opts) {
|
|
103
106
|
const offerStr = fs.readFileSync(opts.file).toString();
|
|
104
107
|
|
|
105
|
-
const { unserializer } = await
|
|
108
|
+
const { unserializer } = await makeVstorageKit({ fetch }, networkConfig);
|
|
106
109
|
|
|
107
110
|
const offerObj = unserializer.fromCapData(JSON.parse(offerStr));
|
|
108
111
|
console.log(offerObj);
|
|
@@ -117,7 +120,7 @@ export const makeWalletCommand = async command => {
|
|
|
117
120
|
.action(async function (opts) {
|
|
118
121
|
const offerStr = fs.readFileSync(opts.offer).toString();
|
|
119
122
|
|
|
120
|
-
const { unserializer } = await
|
|
123
|
+
const { unserializer } = await makeVstorageKit({ fetch }, networkConfig);
|
|
121
124
|
|
|
122
125
|
const offerObj = unserializer.fromCapData(JSON.parse(offerStr));
|
|
123
126
|
console.log(offerObj.offer.id);
|
|
@@ -155,7 +158,7 @@ export const makeWalletCommand = async command => {
|
|
|
155
158
|
.command('list')
|
|
156
159
|
.description('list all wallets in vstorage')
|
|
157
160
|
.action(async function () {
|
|
158
|
-
const { vstorage } = await
|
|
161
|
+
const { vstorage } = await makeVstorageKit({ fetch }, networkConfig);
|
|
159
162
|
const wallets = await vstorage.keys('published.wallet');
|
|
160
163
|
process.stdout.write(wallets.join('\n'));
|
|
161
164
|
});
|
|
@@ -169,16 +172,19 @@ export const makeWalletCommand = async command => {
|
|
|
169
172
|
normalizeAddress,
|
|
170
173
|
)
|
|
171
174
|
.action(async function (opts) {
|
|
172
|
-
const { agoricNames, unserializer, readLatestHead } =
|
|
173
|
-
|
|
174
|
-
|
|
175
|
+
const { agoricNames, unserializer, readLatestHead } =
|
|
176
|
+
await makeVstorageKit(
|
|
177
|
+
{
|
|
178
|
+
fetch,
|
|
179
|
+
},
|
|
180
|
+
networkConfig,
|
|
181
|
+
);
|
|
175
182
|
|
|
176
183
|
const leader = makeLeader(networkConfig.rpcAddrs[0]);
|
|
177
184
|
const follower = await makeFollower(
|
|
178
185
|
`:published.wallet.${opts.from}`,
|
|
179
186
|
leader,
|
|
180
187
|
{
|
|
181
|
-
// @ts-expect-error xxx
|
|
182
188
|
unserializer,
|
|
183
189
|
},
|
|
184
190
|
);
|
package/src/lib/chain.js
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
import { normalizeBech32 } from '@cosmjs/encoding';
|
|
4
4
|
import { execFileSync as execFileSyncAmbient } from 'child_process';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @import {MinimalNetworkConfig} from '@agoric/client-utils';
|
|
8
|
+
*/
|
|
9
|
+
|
|
6
10
|
const agdBinary = 'agd';
|
|
7
11
|
|
|
8
12
|
/**
|
|
@@ -36,7 +40,7 @@ harden(normalizeAddressWithOptions);
|
|
|
36
40
|
|
|
37
41
|
/**
|
|
38
42
|
* @param {ReadonlyArray<string>} swingsetArgs
|
|
39
|
-
* @param {
|
|
43
|
+
* @param {MinimalNetworkConfig & {
|
|
40
44
|
* from: string,
|
|
41
45
|
* fees?: string,
|
|
42
46
|
* dryRun?: boolean,
|
|
@@ -94,7 +98,7 @@ harden(execSwingsetTransaction);
|
|
|
94
98
|
|
|
95
99
|
/**
|
|
96
100
|
*
|
|
97
|
-
* @param {
|
|
101
|
+
* @param {MinimalNetworkConfig} net
|
|
98
102
|
*/
|
|
99
103
|
// TODO fetch by HTTP instead of shelling out https://github.com/Agoric/agoric-sdk/issues/9200
|
|
100
104
|
export const fetchSwingsetParams = net => {
|
|
@@ -114,7 +118,7 @@ export const fetchSwingsetParams = net => {
|
|
|
114
118
|
harden(fetchSwingsetParams);
|
|
115
119
|
|
|
116
120
|
/**
|
|
117
|
-
* @param {
|
|
121
|
+
* @param {MinimalNetworkConfig & {
|
|
118
122
|
* execFileSync: typeof import('child_process').execFileSync,
|
|
119
123
|
* delay: (ms: number) => Promise<void>,
|
|
120
124
|
* period?: number,
|
|
@@ -154,7 +158,7 @@ export const pollBlocks = opts => async lookup => {
|
|
|
154
158
|
|
|
155
159
|
/**
|
|
156
160
|
* @param {string} txhash
|
|
157
|
-
* @param {
|
|
161
|
+
* @param {MinimalNetworkConfig & {
|
|
158
162
|
* execFileSync: typeof import('child_process').execFileSync,
|
|
159
163
|
* delay: (ms: number) => Promise<void>,
|
|
160
164
|
* period?: number,
|
package/src/lib/format.js
CHANGED
|
@@ -1,24 +1,10 @@
|
|
|
1
|
-
// @ts-check
|
|
2
|
-
|
|
3
1
|
import { Fail, q } from '@endo/errors';
|
|
4
2
|
import { makeBoardRemote } from '@agoric/vats/tools/board-utils.js';
|
|
5
3
|
|
|
6
|
-
/** @import {BoardRemote} from '@agoric/vats/tools/board-utils.js' */
|
|
7
|
-
/** @import {VBankAssetDetail} from '@agoric/vats/tools/board-utils.js'; */
|
|
8
|
-
|
|
9
4
|
/**
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* @param {string} str
|
|
13
|
-
* @returns {bigint}
|
|
5
|
+
* @import {Amount, Brand} from '@agoric/ertp'
|
|
6
|
+
* @import {AgoricNamesRemotes, BoardRemote, VBankAssetDetail} from '@agoric/vats/tools/board-utils.js';
|
|
14
7
|
*/
|
|
15
|
-
export const Natural = str => {
|
|
16
|
-
const b = BigInt(str);
|
|
17
|
-
if (b < 0) {
|
|
18
|
-
throw RangeError(`${b} is negative`);
|
|
19
|
-
}
|
|
20
|
-
return b;
|
|
21
|
-
};
|
|
22
8
|
|
|
23
9
|
/**
|
|
24
10
|
* JSON.stringify replacer to handle bigint
|
|
@@ -117,7 +103,7 @@ export const fmtRecordOfLines = record => {
|
|
|
117
103
|
* Summarize the offerStatuses of the state as user-facing informative tuples
|
|
118
104
|
*
|
|
119
105
|
* @param {import('@agoric/smart-wallet/src/utils.js').CoalescedWalletState} state
|
|
120
|
-
* @param {
|
|
106
|
+
* @param {AgoricNamesRemotes} agoricNames
|
|
121
107
|
*/
|
|
122
108
|
export const offerStatusTuples = (state, agoricNames) => {
|
|
123
109
|
const { offerStatuses } = state;
|
|
@@ -174,7 +160,7 @@ export const offerStatusTuples = (state, agoricNames) => {
|
|
|
174
160
|
/**
|
|
175
161
|
* @param {import('@agoric/smart-wallet/src/smartWallet.js').CurrentWalletRecord} current
|
|
176
162
|
* @param {ReturnType<import('@agoric/smart-wallet/src/utils.js').makeWalletStateCoalescer>['state']} coalesced
|
|
177
|
-
* @param {
|
|
163
|
+
* @param {AgoricNamesRemotes} agoricNames
|
|
178
164
|
*/
|
|
179
165
|
export const summarize = (current, coalesced, agoricNames) => {
|
|
180
166
|
return {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { NonNullish } from '@agoric/internal';
|
|
2
|
+
|
|
3
|
+
export const networkConfigUrl = agoricNetSubdomain =>
|
|
4
|
+
`https://${agoricNetSubdomain}.agoric.net/network-config`;
|
|
5
|
+
export const rpcUrl = agoricNetSubdomain =>
|
|
6
|
+
`https://${agoricNetSubdomain}.rpc.agoric.net:443`;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param {string} str
|
|
10
|
+
* @param {{ fetch: typeof fetch }} io
|
|
11
|
+
* @returns {Promise<MinimalNetworkConfig>}
|
|
12
|
+
*/
|
|
13
|
+
const fromAgoricNet = (str, { fetch }) => {
|
|
14
|
+
const [netName, chainName] = str.split(',');
|
|
15
|
+
if (chainName) {
|
|
16
|
+
return Promise.resolve({ chainName, rpcAddrs: [rpcUrl(netName)] });
|
|
17
|
+
}
|
|
18
|
+
return fetch(networkConfigUrl(netName)).then(res => res.json());
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param {{ env: typeof process.env, fetch: typeof fetch }} io
|
|
23
|
+
* @returns {Promise<MinimalNetworkConfig>}
|
|
24
|
+
*/
|
|
25
|
+
export const getNetworkConfig = async ({ env, fetch }) => {
|
|
26
|
+
if (!('AGORIC_NET' in env) || env.AGORIC_NET === 'local') {
|
|
27
|
+
return { rpcAddrs: ['http://0.0.0.0:26657'], chainName: 'agoriclocal' };
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return fromAgoricNet(NonNullish(env.AGORIC_NET), { fetch }).catch(err => {
|
|
31
|
+
throw Error(
|
|
32
|
+
`cannot get network config (${env.AGORIC_NET || 'local'}): ${
|
|
33
|
+
err.message
|
|
34
|
+
}`,
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
};
|
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, WalletUtils} from '@agoric/client-utils';
|
|
14
|
+
*/
|
|
12
15
|
|
|
13
16
|
const marshaller = boardSlottingMarshaller();
|
|
14
17
|
|
|
@@ -22,7 +25,7 @@ const emptyCurrentRecord = {
|
|
|
22
25
|
|
|
23
26
|
/**
|
|
24
27
|
* @param {string} addr
|
|
25
|
-
* @param {Pick<
|
|
28
|
+
* @param {Pick<WalletUtils, 'readLatestHead'>} io
|
|
26
29
|
* @returns {Promise<import('@agoric/smart-wallet/src/smartWallet.js').CurrentWalletRecord>}
|
|
27
30
|
*/
|
|
28
31
|
export const getCurrent = async (addr, { readLatestHead }) => {
|
|
@@ -57,7 +60,7 @@ export const getCurrent = async (addr, { readLatestHead }) => {
|
|
|
57
60
|
|
|
58
61
|
/**
|
|
59
62
|
* @param {string} addr
|
|
60
|
-
* @param {Pick<
|
|
63
|
+
* @param {Pick<WalletUtils, 'readLatestHead'>} io
|
|
61
64
|
* @returns {Promise<import('@agoric/smart-wallet/src/smartWallet.js').UpdateRecord>}
|
|
62
65
|
*/
|
|
63
66
|
export const getLastUpdate = (addr, { readLatestHead }) => {
|
|
@@ -142,7 +145,7 @@ export const coalesceWalletState = async (follower, invitationBrand) => {
|
|
|
142
145
|
*
|
|
143
146
|
* @throws { Error & { code: number } } if transaction fails
|
|
144
147
|
* @param {import('@agoric/smart-wallet/src/smartWallet.js').BridgeAction} bridgeAction
|
|
145
|
-
* @param {
|
|
148
|
+
* @param {MinimalNetworkConfig & {
|
|
146
149
|
* from: string,
|
|
147
150
|
* fees?: string,
|
|
148
151
|
* verbose?: boolean,
|
|
@@ -211,76 +214,3 @@ export const findContinuingIds = (current, agoricNames) => {
|
|
|
211
214
|
}
|
|
212
215
|
return found;
|
|
213
216
|
};
|
|
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/sdk-package-names.js
CHANGED
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 */
|