@agoric/vats 0.15.2-dev-19b9351.0 → 0.15.2-dev-4dd330d.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/src/localchain.js CHANGED
@@ -9,18 +9,36 @@ import {
9
9
  PaymentShape,
10
10
  } from '@agoric/ertp';
11
11
  import { Shape as NetworkShape } from '@agoric/network';
12
+ import { MsgSend } from '@agoric/cosmic-proto/cosmos/bank/v1beta1/tx.js';
13
+ import { decodeAddressHook } from '@agoric/cosmic-proto/address-hooks.js';
12
14
 
13
15
  const { Vow$ } = NetworkShape;
14
16
 
15
17
  /**
18
+ * @import {MsgSendProtoMsg} from '@agoric/cosmic-proto/cosmos/bank/v1beta1/tx.js';
19
+ * @import {FungibleTokenPacketData} from '@agoric/cosmic-proto/ibc/applications/transfer/v2/packet.js';
20
+ * @import {Coin} from '@agoric/cosmic-proto/cosmos/base/v1beta1/coin.js';
16
21
  * @import {ERef, EReturn} from '@endo/far';
17
22
  * @import {Key, Pattern} from '@endo/patterns';
18
23
  * @import {TypedJson, ResponseTo, JsonSafe} from '@agoric/cosmic-proto';
19
24
  * @import {Amount, Brand, Payment} from '@agoric/ertp';
20
- * @import {PromiseVow, VowTools} from '@agoric/vow';
25
+ * @import {PromiseVow, Vow, VowTools} from '@agoric/vow';
21
26
  * @import {TargetApp, TargetRegistration} from './bridge-target.js';
22
27
  * @import {BankManager, Bank} from './vat-bank.js';
23
- * @import {ScopedBridgeManager} from './types.js';
28
+ * @import {IBCEvent, IBCPacket, ScopedBridgeManager} from './types.js';
29
+ */
30
+
31
+ /**
32
+ * @typedef {SendInfo} NotifyInfo Extend this with any additional notification
33
+ * types.
34
+ */
35
+
36
+ /**
37
+ * @typedef {{
38
+ * msgTypeUrl: MsgSendProtoMsg['typeUrl'];
39
+ * coins: Coin[];
40
+ * target: string;
41
+ * } & Omit<FungibleTokenPacketData, 'amount' | 'denom'>} SendInfo
24
42
  */
25
43
 
26
44
  /**
@@ -52,12 +70,18 @@ const { Vow$ } = NetworkShape;
52
70
  * }>}
53
71
  */
54
72
 
73
+ /**
74
+ * @template {TypedJson[]} MT
75
+ * @typedef {{
76
+ * [K in keyof MT]: JsonSafe<ResponseTo<MT[K]>>;
77
+ * }} ResponseToMany
78
+ */
79
+
55
80
  /**
56
81
  * @typedef {{
57
- * system: ScopedBridgeManager<'vlocalchain'>;
58
82
  * bank: Bank;
59
- * transfer: import('./transfer.js').TransferMiddleware;
60
- * }} AccountPowers
83
+ * lastSequence?: string;
84
+ * } & Pick<LocalChainPowers, 'system' | 'transfer'>} AccountPowers
61
85
  */
62
86
 
63
87
  /**
@@ -68,6 +92,18 @@ const { Vow$ } = NetworkShape;
68
92
  * }} LocalChainPowers
69
93
  */
70
94
 
95
+ /**
96
+ * @typedef {WeakMapStore<
97
+ * LocalChainPowers['transfer'],
98
+ * {
99
+ * transferBridgeManager: Pick<
100
+ * ScopedBridgeManager<'vtransfer'>,
101
+ * 'fromBridge'
102
+ * >;
103
+ * }
104
+ * >} AdditionalTransferPowers
105
+ */
106
+
71
107
  export const LocalChainAccountI = M.interface('LocalChainAccount', {
72
108
  getAddress: M.callWhen().returns(Vow$(M.string())),
73
109
  getBalance: M.callWhen(BrandShape).returns(Vow$(AmountShape)),
@@ -85,9 +121,14 @@ export const LocalChainAccountI = M.interface('LocalChainAccount', {
85
121
 
86
122
  /**
87
123
  * @param {import('@agoric/base-zone').Zone} zone
88
- * @param {VowTools} vowTools
124
+ * @param {VowTools & {
125
+ * powersForTransfer: AdditionalTransferPowers;
126
+ * }} powers
89
127
  */
90
- export const prepareLocalChainAccountKit = (zone, { watch }) =>
128
+ export const prepareLocalChainAccountKit = (
129
+ zone,
130
+ { watch, allSettled, powersForTransfer },
131
+ ) =>
91
132
  zone.exoClassKit(
92
133
  'LocalChainAccountKit',
93
134
  {
@@ -100,15 +141,23 @@ export const prepareLocalChainAccountKit = (zone, { watch }) =>
100
141
  })
101
142
  .returns(M.promise()),
102
143
  }),
144
+ notifyTransferVatWatcher: M.interface('NotifyTransferVatWatcher', {
145
+ onFulfilled: M.call(M.any(), M.record()).returns(M.any()),
146
+ }),
147
+ overrideWatcher: M.interface('OverrideWatcher', {
148
+ onFulfilled: M.call(M.any(), M.any()).returns(M.any()),
149
+ }),
103
150
  },
104
151
  /**
105
152
  * @param {import('@agoric/orchestration').Bech32Address} address
106
- * @param {AccountPowers} powers
153
+ * @param {AccountPowers} accountPowers
107
154
  */
108
- (address, powers) => ({
155
+ (address, { bank, system, transfer }) => ({
109
156
  address,
110
- ...powers,
111
- reserved: undefined,
157
+ bank,
158
+ system,
159
+ transfer,
160
+ lastSequence: 0n,
112
161
  }),
113
162
  {
114
163
  depositPaymentWatcher: {
@@ -124,6 +173,119 @@ export const prepareLocalChainAccountKit = (zone, { watch }) =>
124
173
  return E(purse).deposit(payment, optAmountShape);
125
174
  },
126
175
  },
176
+ notifyTransferVatWatcher: {
177
+ /**
178
+ * @template {TypedJson[]} MT
179
+ * @param {ResponseToMany<MT>} fulfilment
180
+ * @param {Record<number, NotifyInfo>} notifyInfos
181
+ */
182
+ onFulfilled(fulfilment, notifyInfos) {
183
+ if (Object.keys(notifyInfos).length === 0) {
184
+ // No need to notify the transfer bridge manager, so just return.
185
+ return fulfilment;
186
+ }
187
+
188
+ const { transfer } = this.state;
189
+ const transferPowers =
190
+ powersForTransfer.has(transfer) && powersForTransfer.get(transfer);
191
+ const { transferBridgeManager } = transferPowers || {};
192
+
193
+ if (!transferBridgeManager) {
194
+ // If there is no transfer bridge manager, then we can't notify it,
195
+ // so bail and just return the fulfilment.
196
+ return fulfilment;
197
+ }
198
+
199
+ // notify the transfer vat that assets have been sent.
200
+ const notifyV = allSettled(
201
+ Object.values(notifyInfos).flatMap(info => {
202
+ if (!info) {
203
+ // If there is no info, then this is not a tx message that needs
204
+ // notification.
205
+ return [];
206
+ }
207
+
208
+ // If the message is not a MsgSend, then we don't do anything.
209
+ if (info.msgTypeUrl !== MsgSend.typeUrl) {
210
+ return [];
211
+ }
212
+
213
+ const sendInfo = /** @type {SendInfo} */ (info);
214
+
215
+ const { coins, target, memo, sender, receiver } = sendInfo;
216
+ /** @type {Omit<FungibleTokenPacketData, 'amount' | 'denom'>} */
217
+ const sharedFtpData = {
218
+ sender,
219
+ receiver,
220
+ memo,
221
+ };
222
+ /** @type {Omit<IBCPacket, 'data' | 'sequence'>} */
223
+ const sharedPacket = {
224
+ source_port: 'localchain-msg',
225
+ source_channel: 'channel-0',
226
+ destination_port: 'localchain-msg',
227
+ destination_channel: 'channel-1',
228
+ };
229
+ return coins.map(({ denom, amount }) => {
230
+ // MsgSends are local to this chain, so ensure the transfer packet
231
+ // reflects that.
232
+ const transferDenom = `${sharedPacket.source_port}/${sharedPacket.source_channel}/${denom}`;
233
+
234
+ /** @type {FungibleTokenPacketData} */
235
+ const ftpData = {
236
+ ...sharedFtpData,
237
+ denom: transferDenom,
238
+ amount,
239
+ };
240
+
241
+ /** @type {bigint} */
242
+ const lastSequence = BigInt(this.state.lastSequence ?? 0) + 1n;
243
+
244
+ const sequence = String(lastSequence);
245
+ this.state.lastSequence = lastSequence;
246
+
247
+ /** @type {IBCPacket} */
248
+ const packet = {
249
+ ...sharedPacket,
250
+ data: btoa(JSON.stringify(ftpData)),
251
+ sequence,
252
+ };
253
+ /** @type {IBCEvent<'receivePacket', 'VTRANSFER_IBC_EVENT'>} */
254
+ const obj = {
255
+ type: 'VTRANSFER_IBC_EVENT',
256
+ event: 'receivePacket',
257
+ packet,
258
+ target: { onlyIfRegistered: target },
259
+ };
260
+ return E(transferBridgeManager).fromBridge(obj);
261
+ });
262
+ }),
263
+ );
264
+
265
+ const overrideV = watch(
266
+ notifyV,
267
+ this.facets.overrideWatcher,
268
+ fulfilment,
269
+ );
270
+
271
+ return /** @type {Vow<typeof fulfilment>} */ (
272
+ /** @type {unknown} */ (overrideV)
273
+ );
274
+ },
275
+ },
276
+ overrideWatcher: {
277
+ /**
278
+ * @template T
279
+ * @param {unknown} _awaited
280
+ * @param {T} override
281
+ * @returns {T}
282
+ */
283
+ onFulfilled(_awaited, override) {
284
+ // This watcher is used to wait for fulfilment, then override the
285
+ // return.
286
+ return override;
287
+ },
288
+ },
127
289
  account: {
128
290
  // Information that the account creator needs.
129
291
  getAddress() {
@@ -173,6 +335,7 @@ export const prepareLocalChainAccountKit = (zone, { watch }) =>
173
335
  const purse = E(bank).getPurse(amount.brand);
174
336
  return E(purse).withdraw(amount);
175
337
  },
338
+
176
339
  /**
177
340
  * Execute a batch of messages on the local chain. Note in particular,
178
341
  * that for IBC `MsgTransfer`, execution only queues a packet for the
@@ -186,10 +349,7 @@ export const prepareLocalChainAccountKit = (zone, { watch }) =>
186
349
  * @template {TypedJson[]} MT messages tuple (use const with multiple
187
350
  * elements or it will be a mixed array)
188
351
  * @param {MT} messages
189
- * @returns {PromiseVowOfTupleMappedToGenerics<{
190
- * [K in keyof MT]: JsonSafe<ResponseTo<MT[K]>>;
191
- * }>}
192
- *
352
+ * @returns {PromiseVowOfTupleMappedToGenerics<ResponseToMany<MT>>}
193
353
  * @see {typedJson} which can be used on arguments to get typed return
194
354
  * values.
195
355
  */
@@ -197,15 +357,82 @@ export const prepareLocalChainAccountKit = (zone, { watch }) =>
197
357
  const { address, system } = this.state;
198
358
  messages.length > 0 || Fail`need at least one message to execute`;
199
359
 
360
+ /** @type {Record<number, NotifyInfo>} */
361
+ const notifyInfos = {};
362
+
363
+ const rewrittenMsgs = messages.map((msg, i) => {
364
+ const { '@type': typeUrl, ...value } = msg;
365
+ if (typeUrl !== MsgSend.typeUrl) {
366
+ console.info(
367
+ `Skipping message ${i} of type ${typeUrl} as it is not a MsgSend`,
368
+ );
369
+ return msg;
370
+ }
371
+
372
+ const msgTypeUrl = /** @type {MsgSendProtoMsg['typeUrl']} */ (
373
+ MsgSend.typeUrl
374
+ );
375
+
376
+ // Since the message is a `MsgSend`, then we remap the receiver
377
+ // to its unhooked baseAddress.
378
+ const origSend = MsgSend.fromPartial(value);
379
+ const { baseAddress: target } = decodeAddressHook(
380
+ origSend.toAddress,
381
+ );
382
+ const newSend = MsgSend.fromPartial({
383
+ ...value,
384
+ toAddress: target,
385
+ });
386
+
387
+ const {
388
+ amount: coins,
389
+ fromAddress: sender,
390
+ // Propagate the original hooked address for the target
391
+ // distinguish.
392
+ toAddress: receiver,
393
+ } = origSend;
394
+
395
+ /** @type {NotifyInfo} */
396
+ const info = {
397
+ msgTypeUrl,
398
+ coins,
399
+ target,
400
+ sender,
401
+ receiver,
402
+ memo: JSON.stringify({
403
+ hookedTypeUrl: msgTypeUrl,
404
+ }),
405
+ };
406
+ notifyInfos[i] = info;
407
+ return harden({ '@type': msgTypeUrl, ...newSend });
408
+ });
409
+
200
410
  const obj = {
201
411
  type: 'VLOCALCHAIN_EXECUTE_TX',
202
412
  // This address is the only one that `VLOCALCHAIN_EXECUTE_TX` will
203
413
  // accept as a signer for the transaction. If the messages have other
204
414
  // addresses in signer positions, the transaction will be aborted.
205
415
  address,
206
- messages,
416
+ messages: rewrittenMsgs,
207
417
  };
208
- return E(system).toBridge(obj);
418
+
419
+ const notifiedV =
420
+ /**
421
+ * @type {PromiseVowOfTupleMappedToGenerics<
422
+ * ResponseToMany<MT>
423
+ * >}
424
+ */
425
+ (
426
+ /** @type {unknown} */ (
427
+ watch(
428
+ E(system).toBridge(obj),
429
+ this.facets.notifyTransferVatWatcher,
430
+ notifyInfos,
431
+ )
432
+ )
433
+ );
434
+
435
+ return notifiedV;
209
436
  },
210
437
  /**
211
438
  * @param {TargetApp} tap
@@ -273,7 +500,7 @@ const prepareLocalChain = (zone, makeAccountKit, { watch }) => {
273
500
  type: 'VLOCALCHAIN_ALLOCATE_ADDRESS',
274
501
  });
275
502
  const bank = await E(bankManager).getBankForAddress(address);
276
- return makeAccountKit(address, { system, bank, transfer }).account;
503
+ return makeAccountKit(address, { bank, system, transfer }).account;
277
504
  },
278
505
  /**
279
506
  * Make a single query to the local chain. Will reject with an error if
@@ -332,13 +559,18 @@ const prepareLocalChain = (zone, makeAccountKit, { watch }) => {
332
559
 
333
560
  /**
334
561
  * @param {import('@agoric/base-zone').Zone} zone
335
- * @param {VowTools} vowTools
562
+ * @param {VowTools & { powersForTransfer: AdditionalTransferPowers }} powers
336
563
  */
337
- export const prepareLocalChainTools = (zone, vowTools) => {
338
- const makeAccountKit = prepareLocalChainAccountKit(zone, vowTools);
339
- const makeLocalChain = prepareLocalChain(zone, makeAccountKit, vowTools);
564
+ export const prepareLocalChainTools = (zone, powers) => {
565
+ const { powersForTransfer: _, ...localChainPowers } = powers;
566
+ const makeLocalChainAccountKit = prepareLocalChainAccountKit(zone, powers);
567
+ const makeLocalChain = prepareLocalChain(
568
+ zone,
569
+ makeLocalChainAccountKit,
570
+ localChainPowers,
571
+ );
340
572
 
341
- return harden({ makeLocalChain });
573
+ return makeLocalChain;
342
574
  };
343
575
  harden(prepareLocalChainTools);
344
576
  /** @typedef {ReturnType<typeof prepareLocalChainTools>} LocalChainTools */
@@ -0,0 +1,26 @@
1
+ export function upgradeAndInterceptMsgSend(powers: BootstrapPowers & {
2
+ consume: {
3
+ vtransferBridgeManager: import("../types.js").ScopedBridgeManager<"vtransfer">;
4
+ transferMiddleware: import("../transfer.js").TransferMiddleware;
5
+ vatAdminSvc: VatAdminSvc;
6
+ vatStore: MapStore<string, import("@agoric/swingset-vat").CreateVatResults>;
7
+ };
8
+ }, options: object): Promise<void>;
9
+ export function getManifestForMsgSendToTransfer(powers: any, arg: any): {
10
+ options: {
11
+ bundleRefs: any;
12
+ vatOptions: any;
13
+ };
14
+ manifest: {
15
+ [upgradeAndInterceptMsgSend.name]: {
16
+ consume: {
17
+ vtransferBridgeManager: string;
18
+ transferMiddleware: string;
19
+ vatStore: string;
20
+ vatAdminSvc: string;
21
+ };
22
+ produce: {};
23
+ };
24
+ };
25
+ };
26
+ //# sourceMappingURL=localchain-hook-msg-send.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"localchain-hook-msg-send.d.ts","sourceRoot":"","sources":["localchain-hook-msg-send.js"],"names":[],"mappings":"AAqBO,mDAbI,eAAe,GAAG;IACxB,OAAO,EAAE;QACP,sBAAsB,EAAE,OAAO,aAAa,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC;QAC/E,kBAAkB,EAAE,OAAO,gBAAgB,EAAE,kBAAkB,CAAC;QAChE,WAAW,EAAE,WAAW,CAAC;QACzB,QAAQ,EAAE,QAAQ,CACxB,MAAc,EACd,OAAe,sBAAsB,EAAE,gBAAgB,CAChD,CAAC;KACH,CAAC;CACH,WACO,MAAM,iBAuBhB;AAEM;;;;;;QAaD,CAAC,0BAA0B,CAAC,IAAI,CAAC;;;;;;;;UAQhC;;EAIN"}
@@ -0,0 +1,70 @@
1
+ // @ts-check
2
+ import { E } from '@endo/far';
3
+ import {
4
+ getManifestForUpgradingVats,
5
+ upgradeVatsGeneric,
6
+ } from './upgrade-vats-generic-proposal.js';
7
+
8
+ /**
9
+ * @param {BootstrapPowers & {
10
+ * consume: {
11
+ * vtransferBridgeManager: import('../types.js').ScopedBridgeManager<'vtransfer'>;
12
+ * transferMiddleware: import('../transfer.js').TransferMiddleware;
13
+ * vatAdminSvc: VatAdminSvc;
14
+ * vatStore: MapStore<
15
+ * string,
16
+ * import('@agoric/swingset-vat').CreateVatResults
17
+ * >;
18
+ * };
19
+ * }} powers
20
+ * @param {object} options
21
+ */
22
+ export const upgradeAndInterceptMsgSend = async (powers, options) => {
23
+ const {
24
+ consume: {
25
+ vtransferBridgeManager: vtransferBridgeManagerP,
26
+ transferMiddleware: transferMiddlewareP,
27
+ },
28
+ } = powers;
29
+
30
+ // Go on to upgrade the vats and provide the transferBridgeManager.
31
+ const upgradeRoots = await upgradeVatsGeneric(powers, options);
32
+
33
+ const [transferMiddleware, transferBridgeManager] = await Promise.all([
34
+ transferMiddlewareP,
35
+ vtransferBridgeManagerP,
36
+ ]);
37
+
38
+ // Link the transferBridgeManager with the localchain vat.
39
+ await E(upgradeRoots.localchain).linkTransferMiddlewareToBridgeManager(
40
+ transferMiddleware,
41
+ transferBridgeManager,
42
+ );
43
+ };
44
+
45
+ export const getManifestForMsgSendToTransfer = (powers, arg) => {
46
+ const {
47
+ manifest: { [upgradeVatsGeneric.name]: upgradeVatsManifest, ...empty },
48
+ ...rest
49
+ } = getManifestForUpgradingVats(powers, arg);
50
+ assert.equal(
51
+ Object.keys(empty).length,
52
+ 0,
53
+ 'expected empty remaining manifest',
54
+ );
55
+
56
+ return {
57
+ manifest: {
58
+ [upgradeAndInterceptMsgSend.name]: {
59
+ ...upgradeVatsManifest,
60
+ consume: {
61
+ ...upgradeVatsManifest.consume,
62
+ vtransferBridgeManager: 'hookedMsgSend',
63
+ transferMiddleware: 'hookedMsgSend',
64
+ vatStore: 'hookedMsgSend',
65
+ },
66
+ },
67
+ },
68
+ ...rest,
69
+ };
70
+ };
@@ -1,9 +1,10 @@
1
- export function setupLocalChainVat({ consume: { loadCriticalVat, bridgeManager: bridgeManagerP, localchainBridgeManager: localchainBridgeManagerP, bankManager, transferMiddleware, }, produce: { localchainVat, localchain, localchainBridgeManager }, }: BootstrapPowers & {
1
+ export function setupLocalChainVat({ consume: { loadCriticalVat, bridgeManager: bridgeManagerP, localchainBridgeManager: localchainBridgeManagerP, bankManager: bankManagerP, transferMiddleware: transferMiddlewareP, vtransferBridgeManager: vtransferBridgeManagerP, }, produce: { localchainVat, localchain, localchainBridgeManager }, }: BootstrapPowers & {
2
2
  consume: {
3
3
  bridgeManager: import("../types").BridgeManager;
4
4
  localchainBridgeManager: import("../types").ScopedBridgeManager<"vlocalchain">;
5
5
  bankManager: Promise<import("../vat-bank.js").BankManager>;
6
6
  transferMiddleware: Promise<import("../transfer.js").TransferMiddleware>;
7
+ vtransferBridgeManager: Promise<import("../types").ScopedBridgeManager<"vtransfer">>;
7
8
  };
8
9
  produce: {
9
10
  localchain: Producer<any>;
@@ -31,6 +32,7 @@ export function getManifestForLocalChain(_powers: any, { localchainRef }: {
31
32
  localchainBridgeManager: string;
32
33
  bankManager: string;
33
34
  transferMiddleware: string;
35
+ vtransferBridgeManager: string;
34
36
  };
35
37
  produce: {
36
38
  localchain: string;
@@ -1 +1 @@
1
- {"version":3,"file":"localchain-proposal.d.ts","sourceRoot":"","sources":["localchain-proposal.js"],"names":[],"mappings":"AA0BO,2PApBI,eAAe,GAAG;IACxB,OAAO,EAAE;QACP,aAAa,EAAE,OAAO,UAAU,EAAE,aAAa,CAAC;QAChD,uBAAuB,EAAE,OAAO,UAAU,EAAE,mBAAmB,CAAC,aAAa,CAAC,CAAC;QAC/E,WAAW,EAAE,OAAO,CAAC,OAAO,gBAAgB,EAAE,WAAW,CAAC,CAAC;QAC3D,kBAAkB,EAAE,OAAO,CAAC,OAAO,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;KAC1E,CAAC;IACF,OAAO,EAAE;QACP,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC1B,aAAa,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC7B,uBAAuB,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;KACxC,CAAC;CACH,WAED;IAAiD,OAAO,EAAhD;QAAE,aAAa,EAAE,YAAY,CAAA;KAAE;CAEvC,iBA6DF;AAUM,2EAPI,eAAe,GAAG;IACxB,OAAO,EAAE;QACP,UAAU,EAAE,OAAO,kBAAkB,EAAE,UAAU,CAAC;KACnD,CAAC;CACH,YACO,MAAM,iBAOhB;AAEM;;;;QAEH,CAAC,kBAAkB,CAAC,IAAI,CAAC;;;;;;;;;;;;;UAaxB;QAED,CAAC,qBAAqB,CAAC,IAAI,CAAC;;;;;UAK3B;;;;;EAKH;6BAzGW;IACR,UAAU,EAAE,IAAI,CAAC,OAAO,sBAAsB,EAAE,aAAa,CAAC,CAAC;CAChE"}
1
+ {"version":3,"file":"localchain-proposal.d.ts","sourceRoot":"","sources":["localchain-proposal.js"],"names":[],"mappings":"AA6BO,+UAvBI,eAAe,GAAG;IACxB,OAAO,EAAE;QACP,aAAa,EAAE,OAAO,UAAU,EAAE,aAAa,CAAC;QAChD,uBAAuB,EAAE,OAAO,UAAU,EAAE,mBAAmB,CAAC,aAAa,CAAC,CAAC;QAC/E,WAAW,EAAE,OAAO,CAAC,OAAO,gBAAgB,EAAE,WAAW,CAAC,CAAC;QAC3D,kBAAkB,EAAE,OAAO,CAAC,OAAO,gBAAgB,EAAE,kBAAkB,CAAC,CAAC;QACzE,sBAAsB,EAAE,OAAO,CACrC,OAAe,UAAU,EAAE,mBAAmB,CAAC,WAAW,CAAC,CACpD,CAAC;KACH,CAAC;IACF,OAAO,EAAE;QACP,UAAU,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC1B,aAAa,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC7B,uBAAuB,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC;KACxC,CAAC;CACH,WAED;IAAiD,OAAO,EAAhD;QAAE,aAAa,EAAE,YAAY,CAAA;KAAE;CAEvC,iBA0EF;AAUM,2EAPI,eAAe,GAAG;IACxB,OAAO,EAAE;QACP,UAAU,EAAE,OAAO,kBAAkB,EAAE,UAAU,CAAC;KACnD,CAAC;CACH,YACO,MAAM,iBAOhB;AAEM;;;;QAEH,CAAC,kBAAkB,CAAC,IAAI,CAAC;;;;;;;;;;;;;;UAcxB;QAED,CAAC,qBAAqB,CAAC,IAAI,CAAC;;;;;UAK3B;;;;;EAKH;6BAvHW;IACR,UAAU,EAAE,IAAI,CAAC,OAAO,sBAAsB,EAAE,aAAa,CAAC,CAAC;CAChE"}
@@ -10,6 +10,9 @@ import { makeScopedBridge } from '../bridge.js';
10
10
  * localchainBridgeManager: import('../types').ScopedBridgeManager<'vlocalchain'>;
11
11
  * bankManager: Promise<import('../vat-bank.js').BankManager>;
12
12
  * transferMiddleware: Promise<import('../transfer.js').TransferMiddleware>;
13
+ * vtransferBridgeManager: Promise<
14
+ * import('../types').ScopedBridgeManager<'vtransfer'>
15
+ * >;
13
16
  * };
14
17
  * produce: {
15
18
  * localchain: Producer<any>;
@@ -30,8 +33,9 @@ export const setupLocalChainVat = async (
30
33
  loadCriticalVat,
31
34
  bridgeManager: bridgeManagerP,
32
35
  localchainBridgeManager: localchainBridgeManagerP,
33
- bankManager,
34
- transferMiddleware,
36
+ bankManager: bankManagerP,
37
+ transferMiddleware: transferMiddlewareP,
38
+ vtransferBridgeManager: vtransferBridgeManagerP,
35
39
  },
36
40
  produce: { localchainVat, localchain, localchainBridgeManager },
37
41
  },
@@ -73,12 +77,24 @@ export const setupLocalChainVat = async (
73
77
  );
74
78
  }
75
79
 
80
+ const [transferBridgeManager, transfer, bankManager] = await Promise.all([
81
+ vtransferBridgeManagerP,
82
+ transferMiddlewareP,
83
+ bankManagerP,
84
+ ]);
85
+
76
86
  const newLocalChain = await E(vats.localchain).makeLocalChain({
77
87
  system: scopedManager,
78
- bankManager: await bankManager,
79
- transfer: await transferMiddleware,
88
+ bankManager,
89
+ transfer,
80
90
  });
81
91
 
92
+ // Allow the localchain to obtain the bridge manager via the middleware.
93
+ await E(vats.localchain).linkTransferMiddlewareToBridgeManager(
94
+ transfer,
95
+ transferBridgeManager,
96
+ );
97
+
82
98
  localchain.reset();
83
99
  localchain.resolve(newLocalChain);
84
100
  };
@@ -107,6 +123,7 @@ export const getManifestForLocalChain = (_powers, { localchainRef }) => ({
107
123
  localchainBridgeManager: 'localchain',
108
124
  bankManager: 'bank',
109
125
  transferMiddleware: 'transfer',
126
+ vtransferBridgeManager: 'vtransfer',
110
127
  },
111
128
  produce: {
112
129
  localchain: 'localchain',
@@ -1,4 +1,4 @@
1
- export function testLocalChain({ consume: { chainStorage, localchain } }: BootstrapPowers & {
1
+ export function testLocalChain({ consume: { board, chainStorage, localchain } }: BootstrapPowers & {
2
2
  consume: {
3
3
  localchain: import("../localchain.js").LocalChain;
4
4
  };
@@ -13,9 +13,13 @@ export function getManifestForLocalChainTest(_powers: any, { testResultPath }: {
13
13
  manifest: {
14
14
  [testLocalChain.name]: {
15
15
  consume: {
16
+ board: string;
16
17
  chainStorage: string;
17
18
  localchain: string;
18
19
  };
20
+ produce: {
21
+ testLocalChain: string;
22
+ };
19
23
  };
20
24
  };
21
25
  options: {
@@ -1 +1 @@
1
- {"version":3,"file":"localchain-test.d.ts","sourceRoot":"","sources":["localchain-test.js"],"names":[],"mappings":"AAaO,0EARI,eAAe,GAAG;IACxB,OAAO,EAAE;QACP,UAAU,EAAE,OAAO,kBAAkB,EAAE,UAAU,CAAC;KACnD,CAAC;CACH,mCAED;IAA4C,OAAO,EAA3C;QAAE,cAAc,EAAE,MAAM,CAAA;KAAE;CACpC,iBA8DA;AAEM;;;;QAEH,CAAC,cAAc,CAAC,IAAI,CAAC;;;;;UAKpB;;;;;EAKH"}
1
+ {"version":3,"file":"localchain-test.d.ts","sourceRoot":"","sources":["localchain-test.js"],"names":[],"mappings":"AAcO,iFARI,eAAe,GAAG;IACxB,OAAO,EAAE;QACP,UAAU,EAAE,OAAO,kBAAkB,EAAE,UAAU,CAAC;KACnD,CAAC;CACH,mCAED;IAA4C,OAAO,EAA3C;QAAE,cAAc,EAAE,MAAM,CAAA;KAAE;CACpC,iBAmHA;AAEM;;;;QAEH,CAAC,cAAc,CAAC,IAAI,CAAC;;;;;;;;;UASpB;;;;;EAKH"}