@agoric/smart-wallet 0.5.4-dev-e68f280.0 → 0.5.4-dev-6f05870.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 +14 -13
- package/src/offers.d.ts.map +1 -1
- package/src/offers.js +5 -4
- package/src/smartWallet.d.ts +9 -4
- package/src/smartWallet.d.ts.map +1 -1
- package/src/smartWallet.js +158 -12
- package/src/walletFactory.d.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/smart-wallet",
|
|
3
|
-
"version": "0.5.4-dev-
|
|
3
|
+
"version": "0.5.4-dev-6f05870.0+6f05870",
|
|
4
4
|
"description": "Wallet contract",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -16,23 +16,24 @@
|
|
|
16
16
|
"lint:eslint": "eslint ."
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@agoric/cosmic-proto": "0.3.1-dev-
|
|
19
|
+
"@agoric/cosmic-proto": "0.3.1-dev-6f05870.0+6f05870",
|
|
20
|
+
"@endo/bundle-source": "^2.5.2",
|
|
20
21
|
"@endo/captp": "^3.1.2",
|
|
21
22
|
"@endo/init": "^0.5.57",
|
|
22
23
|
"ava": "^5.3.0",
|
|
23
24
|
"import-meta-resolve": "^2.2.1"
|
|
24
25
|
},
|
|
25
26
|
"dependencies": {
|
|
26
|
-
"@agoric/assert": "0.6.1-dev-
|
|
27
|
-
"@agoric/casting": "0.4.3-dev-
|
|
28
|
-
"@agoric/ertp": "0.16.3-dev-
|
|
29
|
-
"@agoric/internal": "0.3.3-dev-
|
|
30
|
-
"@agoric/notifier": "0.6.3-dev-
|
|
31
|
-
"@agoric/store": "0.9.3-dev-
|
|
32
|
-
"@agoric/swingset-vat": "0.32.3-dev-
|
|
33
|
-
"@agoric/vat-data": "0.5.3-dev-
|
|
34
|
-
"@agoric/vats": "0.15.2-dev-
|
|
35
|
-
"@agoric/zoe": "0.26.3-dev-
|
|
27
|
+
"@agoric/assert": "0.6.1-dev-6f05870.0+6f05870",
|
|
28
|
+
"@agoric/casting": "0.4.3-dev-6f05870.0+6f05870",
|
|
29
|
+
"@agoric/ertp": "0.16.3-dev-6f05870.0+6f05870",
|
|
30
|
+
"@agoric/internal": "0.3.3-dev-6f05870.0+6f05870",
|
|
31
|
+
"@agoric/notifier": "0.6.3-dev-6f05870.0+6f05870",
|
|
32
|
+
"@agoric/store": "0.9.3-dev-6f05870.0+6f05870",
|
|
33
|
+
"@agoric/swingset-vat": "0.32.3-dev-6f05870.0+6f05870",
|
|
34
|
+
"@agoric/vat-data": "0.5.3-dev-6f05870.0+6f05870",
|
|
35
|
+
"@agoric/vats": "0.15.2-dev-6f05870.0+6f05870",
|
|
36
|
+
"@agoric/zoe": "0.26.3-dev-6f05870.0+6f05870",
|
|
36
37
|
"@endo/eventual-send": "^0.17.3",
|
|
37
38
|
"@endo/far": "^0.2.19",
|
|
38
39
|
"@endo/marshal": "^0.8.6",
|
|
@@ -62,5 +63,5 @@
|
|
|
62
63
|
"publishConfig": {
|
|
63
64
|
"access": "public"
|
|
64
65
|
},
|
|
65
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "6f05870eef00470eb99022513e2df5ff62e81785"
|
|
66
67
|
}
|
package/src/offers.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"offers.d.ts","sourceRoot":"","sources":["offers.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"offers.d.ts","sourceRoot":"","sources":["offers.js"],"names":[],"mappings":"AAIA;;GAEG;AAEH;;;;;;;GAOG;AAEH,kEAAkE;AAClE,+CAAgD;AAwBzC;SAVI,KAAK,UAAU,CAAC;;mCACW,QAAQ,MAAM,CAAC;;sBAC1C,KAAK,OAAO,KAAK,CAAC,CAAC;;gBAEnB,KAAK,OAAO,EAAE,MAAM,GAAE,OAAO,CAAC;mCACvB,OAAO,eAAe,EAAE,cAAc,KAAK,KAAK,UAAU,CAAC;+BAC1D,KAAK,KAAK,QAAQ,KAAK,CAAC;;6BACvB,WAAW,KAAK,IAAI;oCACnB,MAAM,oBAAoB,OAAO,KAAK,CAAC,oBAAoB,OAAO,SAAS,EAAE,gBAAgB,qBAAqB,OAAO,SAAS,EAAE,iBAAiB,GAAG,OAAO,iCAAiC,EAAE,YAAY,KAAM,QAAQ,IAAI,CAAC;;IAalP;;;;;;;OAOG;4BAJQ,SAAS,2BACC,QAAQ,KAAK,IAAI,GACzB,QAAQ,IAAI,CAAC;EAyI7B;sBA9LY,MAAM,GAAG,MAAM;wBAIf;IACZ,EAAM,EAAE,OAAO,CAAC;IAChB,cAAkB,EAAE,OAAO,eAAe,EAAE,cAAc,CAAC;IAC3D,QAAY,EAAE,QAAQ,CAAC;IACvB,SAAa,CAAC,EAAE,OAAO,CAAA;CACpB;0BAOS,OAAO,aAAa,EAAE,SAAS,GAAG;IAC9C,KAAO,CAAC,EAAE,MAAM,CAAC;IACjB,iBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,MAAQ,CAAC,EAAE,OAAO,GAAG,yBAAyB,CAAC;IAC/C,OAAS,CAAC,EAAE,mBAAmB,CAAC;CAC7B"}
|
package/src/offers.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { E, passStyleOf } from '@endo/far';
|
|
2
|
+
import { deeplyFulfilledObject } from '@agoric/internal';
|
|
2
3
|
import { makePaymentsHelper } from './payments.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -80,15 +81,15 @@ export const makeOfferExecutor = ({
|
|
|
80
81
|
// 1. Prepare values and validate synchronously.
|
|
81
82
|
const { id, invitationSpec, proposal, offerArgs } = offerSpec;
|
|
82
83
|
|
|
84
|
+
/** @type {PaymentKeywordRecord | undefined} */
|
|
85
|
+
const paymentKeywordRecord = await (proposal?.give &&
|
|
86
|
+
deeplyFulfilledObject(paymentsManager.withdrawGive(proposal.give)));
|
|
87
|
+
|
|
83
88
|
const invitation = invitationFromSpec(invitationSpec);
|
|
84
89
|
const invitationAmount = await E(invitationIssuer).getAmountOf(
|
|
85
90
|
invitation,
|
|
86
91
|
);
|
|
87
92
|
|
|
88
|
-
const paymentKeywordRecord = proposal?.give
|
|
89
|
-
? paymentsManager.withdrawGive(proposal.give)
|
|
90
|
-
: undefined;
|
|
91
|
-
|
|
92
93
|
// 2. Begin executing offer
|
|
93
94
|
// No explicit signal to user that we reached here but if anything above
|
|
94
95
|
// failed they'd get an 'error' status update.
|
package/src/smartWallet.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export const BRAND_TO_PURSES_KEY: "brandToPurses";
|
|
1
2
|
export function prepareSmartWallet(baggage: MapStore<string, unknown>, shared: SharedParams): (uniqueWithoutChildNodes: Omit<UniqueParams, "currentStorageNode" | "walletStorageNode"> & {
|
|
2
3
|
walletStorageNode: ERef<StorageNode>;
|
|
3
4
|
}) => Promise<{
|
|
@@ -15,10 +16,11 @@ export function prepareSmartWallet(baggage: MapStore<string, unknown>, shared: S
|
|
|
15
16
|
*
|
|
16
17
|
* If the purse doesn't exist, we hold the payment in durable storage.
|
|
17
18
|
*
|
|
18
|
-
* @param {
|
|
19
|
-
* @returns {Promise<Amount>}
|
|
19
|
+
* @param {Payment} payment
|
|
20
|
+
* @returns {Promise<Amount>}
|
|
21
|
+
* @throws if there's not yet a purse, though the payment is held to try again when there is
|
|
20
22
|
*/
|
|
21
|
-
receive(payment:
|
|
23
|
+
receive(payment: Payment): Promise<Amount>;
|
|
22
24
|
};
|
|
23
25
|
getOffersFacet(): {
|
|
24
26
|
/**
|
|
@@ -149,7 +151,7 @@ export type SharedParams = {
|
|
|
149
151
|
*/
|
|
150
152
|
export type State = ImmutableState & MutableState;
|
|
151
153
|
export type ImmutableState = Readonly<UniqueParams & {
|
|
152
|
-
paymentQueues: MapStore<Brand, Array<
|
|
154
|
+
paymentQueues: MapStore<Brand, Array<Payment>>;
|
|
153
155
|
offerToInvitationMakers: MapStore<string, import('./types').InvitationMakers>;
|
|
154
156
|
offerToPublicSubscriberPaths: MapStore<string, Record<string, string>>;
|
|
155
157
|
offerToUsedInvitation: MapStore<string, Amount>;
|
|
@@ -159,6 +161,9 @@ export type ImmutableState = Readonly<UniqueParams & {
|
|
|
159
161
|
liveOffers: MapStore<import('./offers.js').OfferId, import('./offers.js').OfferStatus>;
|
|
160
162
|
liveOfferSeats: WeakMapStore<import('./offers.js').OfferId, UserSeat<unknown>>;
|
|
161
163
|
}>;
|
|
164
|
+
export type PurseRecord = BrandDescriptor & {
|
|
165
|
+
purse: Purse;
|
|
166
|
+
};
|
|
162
167
|
export type MutableState = {};
|
|
163
168
|
export type SmartWallet = Awaited<ReturnType<ReturnType<typeof prepareSmartWallet>>>;
|
|
164
169
|
//# sourceMappingURL=smartWallet.d.ts.map
|
package/src/smartWallet.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"smartWallet.d.ts","sourceRoot":"","sources":["smartWallet.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"smartWallet.d.ts","sourceRoot":"","sources":["smartWallet.js"],"names":[],"mappings":"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"}
|
package/src/smartWallet.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
AmountMath,
|
|
3
2
|
AmountShape,
|
|
4
3
|
BrandShape,
|
|
5
4
|
DisplayInfoShape,
|
|
@@ -7,15 +6,23 @@ import {
|
|
|
7
6
|
PaymentShape,
|
|
8
7
|
PurseShape,
|
|
9
8
|
} from '@agoric/ertp';
|
|
10
|
-
import { StorageNodeShape } from '@agoric/internal';
|
|
9
|
+
import { StorageNodeShape, makeTracer } from '@agoric/internal';
|
|
11
10
|
import { observeNotifier } from '@agoric/notifier';
|
|
12
11
|
import { M, mustMatch } from '@agoric/store';
|
|
13
|
-
import { appendToStoredArray } from '@agoric/store/src/stores/store-utils.js';
|
|
14
|
-
import { makeScalarBigMapStore, prepareExoClassKit } from '@agoric/vat-data';
|
|
15
12
|
import {
|
|
16
|
-
|
|
13
|
+
appendToStoredArray,
|
|
14
|
+
provideLazy,
|
|
15
|
+
} from '@agoric/store/src/stores/store-utils.js';
|
|
16
|
+
import {
|
|
17
|
+
makeScalarBigMapStore,
|
|
18
|
+
makeScalarBigWeakMapStore,
|
|
19
|
+
prepareExoClassKit,
|
|
20
|
+
provide,
|
|
21
|
+
} from '@agoric/vat-data';
|
|
22
|
+
import {
|
|
17
23
|
SubscriberShape,
|
|
18
24
|
TopicsRecordShape,
|
|
25
|
+
prepareRecorderKit,
|
|
19
26
|
} from '@agoric/zoe/src/contractSupport/index.js';
|
|
20
27
|
import { E } from '@endo/far';
|
|
21
28
|
import { makeInvitationsHelper } from './invitations.js';
|
|
@@ -25,6 +32,8 @@ import { objectMapStoragePath } from './utils.js';
|
|
|
25
32
|
|
|
26
33
|
const { Fail, quote: q } = assert;
|
|
27
34
|
|
|
35
|
+
const trace = makeTracer('SmrtWlt');
|
|
36
|
+
|
|
28
37
|
/**
|
|
29
38
|
* @file Smart wallet module
|
|
30
39
|
*
|
|
@@ -129,7 +138,7 @@ const { Fail, quote: q } = assert;
|
|
|
129
138
|
* - `purseBalances` is a cache of what we've received from purses. Held so we can publish all balances on change.
|
|
130
139
|
*
|
|
131
140
|
* @typedef {Readonly<UniqueParams & {
|
|
132
|
-
* paymentQueues: MapStore<Brand, Array<
|
|
141
|
+
* paymentQueues: MapStore<Brand, Array<Payment>>,
|
|
133
142
|
* offerToInvitationMakers: MapStore<string, import('./types').InvitationMakers>,
|
|
134
143
|
* offerToPublicSubscriberPaths: MapStore<string, Record<string, string>>,
|
|
135
144
|
* offerToUsedInvitation: MapStore<string, Amount>,
|
|
@@ -140,16 +149,66 @@ const { Fail, quote: q } = assert;
|
|
|
140
149
|
* liveOfferSeats: WeakMapStore<import('./offers.js').OfferId, UserSeat<unknown>>,
|
|
141
150
|
* }>} ImmutableState
|
|
142
151
|
*
|
|
152
|
+
* @typedef {BrandDescriptor & { purse: Purse }} PurseRecord
|
|
143
153
|
* @typedef {{
|
|
144
154
|
* }} MutableState
|
|
145
155
|
*/
|
|
146
156
|
|
|
157
|
+
/**
|
|
158
|
+
* NameHub reverse-lookup, finding 0 or more names for a target value
|
|
159
|
+
*
|
|
160
|
+
* TODO: consider moving to nameHub.js?
|
|
161
|
+
*
|
|
162
|
+
* @param {unknown} target - passable Key
|
|
163
|
+
* @param {ERef<NameHub>} nameHub
|
|
164
|
+
*/
|
|
165
|
+
const namesOf = async (target, nameHub) => {
|
|
166
|
+
const entries = await E(nameHub).entries();
|
|
167
|
+
const matches = [];
|
|
168
|
+
for (const [name, candidate] of entries) {
|
|
169
|
+
if (candidate === target) {
|
|
170
|
+
matches.push(name);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return harden(matches);
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Check that an issuer and its brand belong to each other.
|
|
178
|
+
*
|
|
179
|
+
* TODO: move to ERTP?
|
|
180
|
+
*
|
|
181
|
+
* @param {Issuer} issuer
|
|
182
|
+
* @param {Brand} brand
|
|
183
|
+
* @returns {Promise<boolean>} true iff the the brand and issuer match
|
|
184
|
+
*/
|
|
185
|
+
const checkMutual = (issuer, brand) =>
|
|
186
|
+
Promise.all([
|
|
187
|
+
E(issuer)
|
|
188
|
+
.getBrand()
|
|
189
|
+
.then(b => b === brand),
|
|
190
|
+
E(brand).isMyIssuer(issuer),
|
|
191
|
+
]).then(checks => checks.every(Boolean));
|
|
192
|
+
|
|
193
|
+
export const BRAND_TO_PURSES_KEY = 'brandToPurses';
|
|
194
|
+
|
|
195
|
+
const getBrandToPurses = (walletPurses, key) => {
|
|
196
|
+
const brandToPurses = provideLazy(walletPurses, key, _k => {
|
|
197
|
+
/** @type {MapStore<Brand, PurseRecord[]>} */
|
|
198
|
+
const store = makeScalarBigMapStore('purses by brand', {
|
|
199
|
+
durable: true,
|
|
200
|
+
});
|
|
201
|
+
return store;
|
|
202
|
+
});
|
|
203
|
+
return brandToPurses;
|
|
204
|
+
};
|
|
205
|
+
|
|
147
206
|
/**
|
|
148
207
|
* @param {import('@agoric/vat-data').Baggage} baggage
|
|
149
208
|
* @param {SharedParams} shared
|
|
150
209
|
*/
|
|
151
210
|
export const prepareSmartWallet = (baggage, shared) => {
|
|
152
|
-
const { registry:
|
|
211
|
+
const { registry: _r, ...passableShared } = shared;
|
|
153
212
|
mustMatch(
|
|
154
213
|
harden(passableShared),
|
|
155
214
|
harden({
|
|
@@ -164,6 +223,15 @@ export const prepareSmartWallet = (baggage, shared) => {
|
|
|
164
223
|
|
|
165
224
|
const makeRecorderKit = prepareRecorderKit(baggage, shared.publicMarshaller);
|
|
166
225
|
|
|
226
|
+
const walletPurses = provide(baggage, BRAND_TO_PURSES_KEY, () => {
|
|
227
|
+
trace('make purses by wallet and save in baggage at', BRAND_TO_PURSES_KEY);
|
|
228
|
+
/** @type {WeakMapStore<unknown, MapStore<Brand, PurseRecord[]>>} */
|
|
229
|
+
const store = makeScalarBigWeakMapStore('purses by wallet', {
|
|
230
|
+
durable: true,
|
|
231
|
+
});
|
|
232
|
+
return store;
|
|
233
|
+
});
|
|
234
|
+
|
|
167
235
|
/**
|
|
168
236
|
*
|
|
169
237
|
* @param {UniqueParams} unique
|
|
@@ -242,6 +310,9 @@ export const prepareSmartWallet = (baggage, shared) => {
|
|
|
242
310
|
helper: M.interface('helperFacetI', {
|
|
243
311
|
assertUniqueOfferId: M.call(M.string()).returns(),
|
|
244
312
|
updateBalance: M.call(PurseShape, AmountShape).optional('init').returns(),
|
|
313
|
+
getPurseIfKnownBrand: M.call(BrandShape)
|
|
314
|
+
.optional(M.eref(M.remotable()))
|
|
315
|
+
.returns(M.promise()),
|
|
245
316
|
publishCurrentState: M.call().returns(),
|
|
246
317
|
watchPurse: M.call(M.eref(PurseShape)).returns(M.promise()),
|
|
247
318
|
}),
|
|
@@ -366,6 +437,63 @@ export const prepareSmartWallet = (baggage, shared) => {
|
|
|
366
437
|
},
|
|
367
438
|
});
|
|
368
439
|
},
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Provide a purse given a NameHub of issuers and their
|
|
443
|
+
* brands.
|
|
444
|
+
*
|
|
445
|
+
* We current support only one NameHub, agoricNames, and
|
|
446
|
+
* hence one purse per brand. But we store an array of them
|
|
447
|
+
* to facilitate a transition to decentralized introductions.
|
|
448
|
+
*
|
|
449
|
+
* @param {Brand} brand
|
|
450
|
+
* @param {ERef<NameHub>} known - namehub with brand, issuer branches
|
|
451
|
+
* @returns {Promise<Purse | undefined>} undefined if brand is not known
|
|
452
|
+
*/
|
|
453
|
+
async getPurseIfKnownBrand(brand, known) {
|
|
454
|
+
const { helper, self } = this.facets;
|
|
455
|
+
const brandToPurses = getBrandToPurses(walletPurses, self);
|
|
456
|
+
|
|
457
|
+
if (brandToPurses.has(brand)) {
|
|
458
|
+
const purses = brandToPurses.get(brand);
|
|
459
|
+
if (purses.length > 0) {
|
|
460
|
+
// UNTIL https://github.com/Agoric/agoric-sdk/issues/6126
|
|
461
|
+
// multiple purses
|
|
462
|
+
return purses[0].purse;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
const found = await namesOf(brand, E(known).lookup('brand'));
|
|
467
|
+
if (found.length === 0) {
|
|
468
|
+
return undefined;
|
|
469
|
+
}
|
|
470
|
+
const [edgeName] = found;
|
|
471
|
+
const issuer = await E(known).lookup('issuer', edgeName);
|
|
472
|
+
|
|
473
|
+
// Even though we rely on this nameHub, double-check
|
|
474
|
+
// that the issuer and the brand belong to each other.
|
|
475
|
+
if (!(await checkMutual(issuer, brand))) {
|
|
476
|
+
// if they don't, it's not a "known" brand in a coherent way
|
|
477
|
+
return undefined;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// Accept the issuer; rely on it in future offers.
|
|
481
|
+
const [displayInfo, purse] = await Promise.all([
|
|
482
|
+
E(issuer).getDisplayInfo(),
|
|
483
|
+
E(issuer).makeEmptyPurse(),
|
|
484
|
+
]);
|
|
485
|
+
|
|
486
|
+
// adopt edgeName as petname
|
|
487
|
+
// NOTE: for decentralized introductions, qualify edgename by nameHub petname
|
|
488
|
+
const petname = edgeName;
|
|
489
|
+
const assetInfo = { petname, brand, issuer, purse, displayInfo };
|
|
490
|
+
appendToStoredArray(brandToPurses, brand, assetInfo);
|
|
491
|
+
// NOTE: when we decentralize introduction of issuers,
|
|
492
|
+
// process queued payments for this brand.
|
|
493
|
+
|
|
494
|
+
void helper.watchPurse(purse);
|
|
495
|
+
return purse;
|
|
496
|
+
},
|
|
369
497
|
},
|
|
370
498
|
/**
|
|
371
499
|
* Similar to {DepositFacet} but async because it has to look up the purse.
|
|
@@ -376,10 +504,12 @@ export const prepareSmartWallet = (baggage, shared) => {
|
|
|
376
504
|
*
|
|
377
505
|
* If the purse doesn't exist, we hold the payment in durable storage.
|
|
378
506
|
*
|
|
379
|
-
* @param {
|
|
380
|
-
* @returns {Promise<Amount>}
|
|
507
|
+
* @param {Payment} payment
|
|
508
|
+
* @returns {Promise<Amount>}
|
|
509
|
+
* @throws if there's not yet a purse, though the payment is held to try again when there is
|
|
381
510
|
*/
|
|
382
511
|
async receive(payment) {
|
|
512
|
+
const { helper } = this.facets;
|
|
383
513
|
const { paymentQueues: queues, bank, invitationPurse } = this.state;
|
|
384
514
|
const { registry, invitationBrand } = shared;
|
|
385
515
|
const brand = await E(payment).getAllegedBrand();
|
|
@@ -387,17 +517,24 @@ export const prepareSmartWallet = (baggage, shared) => {
|
|
|
387
517
|
// When there is a purse deposit into it
|
|
388
518
|
if (registry.has(brand)) {
|
|
389
519
|
const purse = E(bank).getPurse(brand);
|
|
390
|
-
// @ts-expect-error deposit does take a FarRef<Payment>
|
|
391
520
|
return E(purse).deposit(payment);
|
|
392
521
|
} else if (invitationBrand === brand) {
|
|
393
|
-
// @ts-expect-error
|
|
522
|
+
// @ts-expect-error narrow assetKind to 'set'
|
|
394
523
|
return E(invitationPurse).deposit(payment);
|
|
395
524
|
}
|
|
396
525
|
|
|
526
|
+
const purse = await helper.getPurseIfKnownBrand(
|
|
527
|
+
brand,
|
|
528
|
+
shared.agoricNames,
|
|
529
|
+
);
|
|
530
|
+
if (purse) {
|
|
531
|
+
return E(purse).deposit(payment);
|
|
532
|
+
}
|
|
533
|
+
|
|
397
534
|
// When there is no purse, save the payment into a queue.
|
|
398
535
|
// It's not yet ever read but a future version of the contract can
|
|
399
536
|
appendToStoredArray(queues, brand, payment);
|
|
400
|
-
|
|
537
|
+
throw Fail`cannot deposit payment with brand ${brand}: no purse`;
|
|
401
538
|
},
|
|
402
539
|
},
|
|
403
540
|
offers: {
|
|
@@ -445,12 +582,21 @@ export const prepareSmartWallet = (baggage, shared) => {
|
|
|
445
582
|
* @returns {Promise<Purse>}
|
|
446
583
|
*/
|
|
447
584
|
purseForBrand: async brand => {
|
|
585
|
+
const { helper } = facets;
|
|
448
586
|
if (registry.has(brand)) {
|
|
449
587
|
// @ts-expect-error virtual purse
|
|
450
588
|
return E(bank).getPurse(brand);
|
|
451
589
|
} else if (invitationBrand === brand) {
|
|
452
590
|
return invitationPurse;
|
|
453
591
|
}
|
|
592
|
+
|
|
593
|
+
const purse = await helper.getPurseIfKnownBrand(
|
|
594
|
+
brand,
|
|
595
|
+
shared.agoricNames,
|
|
596
|
+
);
|
|
597
|
+
if (purse) {
|
|
598
|
+
return purse;
|
|
599
|
+
}
|
|
454
600
|
throw Fail`cannot find/make purse for ${brand}`;
|
|
455
601
|
},
|
|
456
602
|
logger,
|
package/src/walletFactory.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ export function start(zcf: ZCF<SmartWalletContractTerms>, privateArgs: {
|
|
|
35
35
|
provideSmartWallet(address: string, bank: ERef<import('@agoric/vats/src/vat-bank').Bank>, namesByAddressAdmin: ERef<import('@agoric/vats/').NameAdmin>): Promise<[wallet: {
|
|
36
36
|
handleBridgeAction(actionCapData: import("@endo/marshal").CapData<string>, canSpend?: boolean | undefined): Promise<void>;
|
|
37
37
|
getDepositFacet(): {
|
|
38
|
-
receive(payment:
|
|
38
|
+
receive(payment: Payment<AssetKind>): Promise<Amount<AssetKind>>;
|
|
39
39
|
};
|
|
40
40
|
getOffersFacet(): {
|
|
41
41
|
executeOffer(offerSpec: import("./offers.js").OfferSpec): Promise<void>;
|
|
@@ -68,7 +68,7 @@ export function start(zcf: ZCF<SmartWalletContractTerms>, privateArgs: {
|
|
|
68
68
|
provideSmartWallet(address: string, bank: ERef<import('@agoric/vats/src/vat-bank').Bank>, namesByAddressAdmin: ERef<import('@agoric/vats/').NameAdmin>): Promise<[wallet: {
|
|
69
69
|
handleBridgeAction(actionCapData: import("@endo/marshal").CapData<string>, canSpend?: boolean | undefined): Promise<void>;
|
|
70
70
|
getDepositFacet(): {
|
|
71
|
-
receive(payment:
|
|
71
|
+
receive(payment: Payment<AssetKind>): Promise<Amount<AssetKind>>;
|
|
72
72
|
};
|
|
73
73
|
getOffersFacet(): {
|
|
74
74
|
executeOffer(offerSpec: import("./offers.js").OfferSpec): Promise<void>;
|