@agoric/smart-wallet 0.5.4-u13.0 → 0.5.4-upgrade-14-dev-0a0580c.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 +15 -13
- package/src/offerWatcher.d.ts +46 -0
- package/src/offerWatcher.d.ts.map +1 -0
- package/src/offerWatcher.js +248 -0
- package/src/offers.d.ts +0 -24
- package/src/offers.d.ts.map +1 -1
- package/src/offers.js +0 -174
- package/src/proposals/upgrade-wallet-factory2-proposal.d.ts +23 -0
- package/src/proposals/upgrade-wallet-factory2-proposal.d.ts.map +1 -0
- package/src/proposals/upgrade-wallet-factory2-proposal.js +59 -0
- package/src/smartWallet.d.ts +37 -14
- package/src/smartWallet.d.ts.map +1 -1
- package/src/smartWallet.js +518 -143
- package/src/walletFactory.d.ts +6 -4
- package/src/walletFactory.d.ts.map +1 -1
- package/src/walletFactory.js +35 -3
- package/src/payments.d.ts +0 -20
- package/src/payments.d.ts.map +0 -1
- package/src/payments.js +0 -89
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agoric/smart-wallet",
|
|
3
|
-
"version": "0.5.4-
|
|
3
|
+
"version": "0.5.4-upgrade-14-dev-0a0580c.0+0a0580c",
|
|
4
4
|
"description": "Wallet contract",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -16,7 +16,8 @@
|
|
|
16
16
|
"lint:eslint": "eslint ."
|
|
17
17
|
},
|
|
18
18
|
"devDependencies": {
|
|
19
|
-
"@agoric/cosmic-proto": "
|
|
19
|
+
"@agoric/cosmic-proto": "0.3.1-upgrade-14-dev-0a0580c.0+0a0580c",
|
|
20
|
+
"@agoric/vats": "^0.15.2-u13.0",
|
|
20
21
|
"@endo/bundle-source": "2.5.2-upstream-rollup",
|
|
21
22
|
"@endo/captp": "3.1.1",
|
|
22
23
|
"@endo/init": "0.5.56",
|
|
@@ -24,16 +25,17 @@
|
|
|
24
25
|
"import-meta-resolve": "^2.2.1"
|
|
25
26
|
},
|
|
26
27
|
"dependencies": {
|
|
27
|
-
"@agoric/assert": "
|
|
28
|
-
"@agoric/casting": "
|
|
29
|
-
"@agoric/
|
|
30
|
-
"@agoric/
|
|
31
|
-
"@agoric/
|
|
32
|
-
"@agoric/
|
|
33
|
-
"@agoric/
|
|
34
|
-
"@agoric/vat
|
|
35
|
-
"@agoric/
|
|
36
|
-
"@agoric/
|
|
28
|
+
"@agoric/assert": "0.6.1-upgrade-14-dev-0a0580c.0+0a0580c",
|
|
29
|
+
"@agoric/casting": "0.4.3-upgrade-14-dev-0a0580c.0+0a0580c",
|
|
30
|
+
"@agoric/deploy-script-support": "0.10.4-upgrade-14-dev-0a0580c.0+0a0580c",
|
|
31
|
+
"@agoric/ertp": "0.16.3-upgrade-14-dev-0a0580c.0+0a0580c",
|
|
32
|
+
"@agoric/internal": "0.4.0-upgrade-14-dev-0a0580c.0+0a0580c",
|
|
33
|
+
"@agoric/notifier": "0.6.3-upgrade-14-dev-0a0580c.0+0a0580c",
|
|
34
|
+
"@agoric/store": "0.9.3-upgrade-14-dev-0a0580c.0+0a0580c",
|
|
35
|
+
"@agoric/swingset-vat": "0.32.3-upgrade-14-dev-0a0580c.0+0a0580c",
|
|
36
|
+
"@agoric/vat-data": "0.5.3-upgrade-14-dev-0a0580c.0+0a0580c",
|
|
37
|
+
"@agoric/vats": "0.15.2-upgrade-14-dev-0a0580c.0+0a0580c",
|
|
38
|
+
"@agoric/zoe": "0.26.3-upgrade-14-dev-0a0580c.0+0a0580c",
|
|
37
39
|
"@endo/eventual-send": "0.17.2",
|
|
38
40
|
"@endo/far": "0.2.18",
|
|
39
41
|
"@endo/marshal": "0.8.5",
|
|
@@ -63,5 +65,5 @@
|
|
|
63
65
|
"publishConfig": {
|
|
64
66
|
"access": "public"
|
|
65
67
|
},
|
|
66
|
-
"gitHead": "
|
|
68
|
+
"gitHead": "0a0580cba9f4b41a1dc748cdd267dbcf0feed362"
|
|
67
69
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export function watchOfferOutcomes(watchers: OutcomeWatchers, seat: UserSeat): Promise<[unknown, 0 | 1, PaymentPKeywordRecord]>;
|
|
2
|
+
export function prepareOfferWatcher(baggage: any): (walletHelper?: any, deposit?: any, offerSpec?: any, address?: any, iAmount?: any, seatRef?: any) => {
|
|
3
|
+
helper: {
|
|
4
|
+
updateStatus(offerStatusUpdates: any): void;
|
|
5
|
+
onNewContinuingOffer(offerId: any, invitationAmount: any, invitationMakers: any, publicSubscribers: any): void;
|
|
6
|
+
publishResult(result: any): void;
|
|
7
|
+
};
|
|
8
|
+
/** @type {OutcomeWatchers['paymentWatcher']} */
|
|
9
|
+
paymentWatcher: OutcomeWatchers['paymentWatcher'];
|
|
10
|
+
/** @type {OutcomeWatchers['resultWatcher']} */
|
|
11
|
+
resultWatcher: OutcomeWatchers['resultWatcher'];
|
|
12
|
+
/** @type {OutcomeWatchers['numWantsWatcher']} */
|
|
13
|
+
numWantsWatcher: OutcomeWatchers['numWantsWatcher'];
|
|
14
|
+
} & import("@endo/eventual-send").RemotableBrand<{}, {
|
|
15
|
+
helper: {
|
|
16
|
+
updateStatus(offerStatusUpdates: any): void;
|
|
17
|
+
onNewContinuingOffer(offerId: any, invitationAmount: any, invitationMakers: any, publicSubscribers: any): void;
|
|
18
|
+
publishResult(result: any): void;
|
|
19
|
+
};
|
|
20
|
+
/** @type {OutcomeWatchers['paymentWatcher']} */
|
|
21
|
+
paymentWatcher: OutcomeWatchers['paymentWatcher'];
|
|
22
|
+
/** @type {OutcomeWatchers['resultWatcher']} */
|
|
23
|
+
resultWatcher: OutcomeWatchers['resultWatcher'];
|
|
24
|
+
/** @type {OutcomeWatchers['numWantsWatcher']} */
|
|
25
|
+
numWantsWatcher: OutcomeWatchers['numWantsWatcher'];
|
|
26
|
+
}>;
|
|
27
|
+
export type OfferStatus = import('./offers.js').OfferSpec & {
|
|
28
|
+
error?: string;
|
|
29
|
+
numWantsSatisfied?: number;
|
|
30
|
+
result?: unknown | typeof import('./offers.js').UNPUBLISHED_RESULT;
|
|
31
|
+
payouts?: AmountKeywordRecord;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* <T, [UserSeat]
|
|
35
|
+
*/
|
|
36
|
+
export type OfferPromiseWatcher<T extends unknown> = {
|
|
37
|
+
onFulfilled: (any: any) => any;
|
|
38
|
+
onRejected: (err: Error, seat: any) => void;
|
|
39
|
+
};
|
|
40
|
+
export type OutcomeWatchers = {
|
|
41
|
+
resultWatcher: OfferPromiseWatcher<unknown>;
|
|
42
|
+
numWantsWatcher: OfferPromiseWatcher<number>;
|
|
43
|
+
paymentWatcher: OfferPromiseWatcher<PaymentPKeywordRecord>;
|
|
44
|
+
};
|
|
45
|
+
export type MakeOfferWatcher = ReturnType<typeof prepareOfferWatcher>;
|
|
46
|
+
//# sourceMappingURL=offerWatcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"offerWatcher.d.ts","sourceRoot":"","sources":["offerWatcher.js"],"names":[],"mappings":"AAyEO,6CAHI,eAAe,QACf,QAAQ,oDAQlB;AA8BM;;;;;;IAwED,gDAAgD;oBAArC,eAAe,CAAC,gBAAgB,CAAC;IAyB5C,+CAA+C;mBAApC,eAAe,CAAC,eAAe,CAAC;IAkB3C,iDAAiD;qBAAtC,eAAe,CAAC,iBAAiB,CAAC;;;;;;;IA3C7C,gDAAgD;oBAArC,eAAe,CAAC,gBAAgB,CAAC;IAyB5C,+CAA+C;mBAApC,eAAe,CAAC,eAAe,CAAC;IAkB3C,iDAAiD;qBAAtC,eAAe,CAAC,iBAAiB,CAAC;GAoBlD;0BArOY,OAAO,aAAa,EAAE,SAAS,GAAG;IAC9C,KAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,MAAU,CAAC,EAAE,OAAO,GAAG,cAAc,aAAa,EAAE,kBAAkB,CAAC;IACvE,OAAW,CAAC,EAAE,mBAAmB,CAAC;CAC/B;;;;;+BAKiC,GAAG;sBAAoB,KAAK,QAAQ,GAAG,KAAK,IAAI;;8BAIxE;IACZ,aAAe,EAAE,oBAAoB,OAAO,CAAC,CAAC;IAC9C,eAAiB,EAAE,oBAAoB,MAAM,CAAC,CAAC;IAC/C,cAAgB,EAAE,oBAAoB,qBAAqB,CAAC,CAAC;CAC1D;+BAsNU,WAAW,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { E, passStyleOf } from '@endo/far';
|
|
2
|
+
|
|
3
|
+
import { isUpgradeDisconnection } from '@agoric/internal/src/upgrade-api.js';
|
|
4
|
+
import { prepareExoClassKit, watchPromise } from '@agoric/vat-data';
|
|
5
|
+
import { M } from '@agoric/store';
|
|
6
|
+
import {
|
|
7
|
+
PaymentPKeywordRecordShape,
|
|
8
|
+
SeatShape,
|
|
9
|
+
} from '@agoric/zoe/src/typeGuards.js';
|
|
10
|
+
import { AmountShape } from '@agoric/ertp/src/typeGuards.js';
|
|
11
|
+
import { deeplyFulfilledObject, objectMap } from '@agoric/internal';
|
|
12
|
+
|
|
13
|
+
import { UNPUBLISHED_RESULT } from './offers.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {import('./offers.js').OfferSpec & {
|
|
17
|
+
* error?: string,
|
|
18
|
+
* numWantsSatisfied?: number
|
|
19
|
+
* result?: unknown | typeof import('./offers.js').UNPUBLISHED_RESULT,
|
|
20
|
+
* payouts?: AmountKeywordRecord,
|
|
21
|
+
* }} OfferStatus
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @template {any} T
|
|
26
|
+
* @typedef {{ onFulfilled: (any) => any, onRejected: (err: Error, seat: any) => void }} OfferPromiseWatcher<T, [UserSeat]
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @typedef {{
|
|
31
|
+
* resultWatcher: OfferPromiseWatcher<unknown>,
|
|
32
|
+
* numWantsWatcher: OfferPromiseWatcher<number>,
|
|
33
|
+
* paymentWatcher: OfferPromiseWatcher<PaymentPKeywordRecord>,
|
|
34
|
+
* }} OutcomeWatchers
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {OutcomeWatchers} watchers
|
|
39
|
+
* @param {UserSeat} seat
|
|
40
|
+
*/
|
|
41
|
+
const watchForOfferResult = ({ resultWatcher }, seat) => {
|
|
42
|
+
const p = E(seat).getOfferResult();
|
|
43
|
+
// @ts-expect-error missing declarations?
|
|
44
|
+
watchPromise(p, resultWatcher, seat);
|
|
45
|
+
return p;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @param {OutcomeWatchers} watchers
|
|
50
|
+
* @param {UserSeat} seat
|
|
51
|
+
*/
|
|
52
|
+
const watchForNumWants = ({ numWantsWatcher }, seat) => {
|
|
53
|
+
const p = E(seat).numWantsSatisfied();
|
|
54
|
+
// @ts-expect-error missing declarations?
|
|
55
|
+
watchPromise(p, numWantsWatcher, seat);
|
|
56
|
+
return p;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @param {OutcomeWatchers} watchers
|
|
61
|
+
* @param {UserSeat} seat
|
|
62
|
+
*/
|
|
63
|
+
const watchForPayout = ({ paymentWatcher }, seat) => {
|
|
64
|
+
const p = E(seat).getPayouts();
|
|
65
|
+
// @ts-expect-error missing declarations?
|
|
66
|
+
watchPromise(p, paymentWatcher, seat);
|
|
67
|
+
return p;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @param {OutcomeWatchers} watchers
|
|
72
|
+
* @param {UserSeat} seat
|
|
73
|
+
*/
|
|
74
|
+
export const watchOfferOutcomes = (watchers, seat) => {
|
|
75
|
+
return Promise.all([
|
|
76
|
+
watchForOfferResult(watchers, seat),
|
|
77
|
+
watchForNumWants(watchers, seat),
|
|
78
|
+
watchForPayout(watchers, seat),
|
|
79
|
+
]);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const offerWatcherGuard = harden({
|
|
83
|
+
helper: M.interface('InstanceAdminStorage', {
|
|
84
|
+
updateStatus: M.call(M.any()).returns(),
|
|
85
|
+
onNewContinuingOffer: M.call(
|
|
86
|
+
M.or(M.number(), M.string()),
|
|
87
|
+
AmountShape,
|
|
88
|
+
M.any(),
|
|
89
|
+
)
|
|
90
|
+
.optional(M.record())
|
|
91
|
+
.returns(),
|
|
92
|
+
publishResult: M.call(M.any()).returns(),
|
|
93
|
+
}),
|
|
94
|
+
paymentWatcher: M.interface('paymentWatcher', {
|
|
95
|
+
onFulfilled: M.call(PaymentPKeywordRecordShape, SeatShape).returns(
|
|
96
|
+
M.promise(),
|
|
97
|
+
),
|
|
98
|
+
onRejected: M.call(M.any(), SeatShape).returns(),
|
|
99
|
+
}),
|
|
100
|
+
resultWatcher: M.interface('resultWatcher', {
|
|
101
|
+
onFulfilled: M.call(M.any(), SeatShape).returns(),
|
|
102
|
+
onRejected: M.call(M.any(), SeatShape).returns(),
|
|
103
|
+
}),
|
|
104
|
+
numWantsWatcher: M.interface('numWantsWatcher', {
|
|
105
|
+
onFulfilled: M.call(M.number(), SeatShape).returns(),
|
|
106
|
+
onRejected: M.call(M.any(), SeatShape).returns(),
|
|
107
|
+
}),
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
export const prepareOfferWatcher = baggage => {
|
|
111
|
+
return prepareExoClassKit(
|
|
112
|
+
baggage,
|
|
113
|
+
'OfferWatcher',
|
|
114
|
+
offerWatcherGuard,
|
|
115
|
+
(walletHelper, deposit, offerSpec, address, iAmount, seatRef) => ({
|
|
116
|
+
walletHelper,
|
|
117
|
+
deposit,
|
|
118
|
+
status: offerSpec,
|
|
119
|
+
address,
|
|
120
|
+
invitationAmount: iAmount,
|
|
121
|
+
seatRef,
|
|
122
|
+
}),
|
|
123
|
+
{
|
|
124
|
+
helper: {
|
|
125
|
+
updateStatus(offerStatusUpdates) {
|
|
126
|
+
const { state } = this;
|
|
127
|
+
state.status = harden({ ...state.status, ...offerStatusUpdates });
|
|
128
|
+
|
|
129
|
+
state.walletHelper.updateStatus(state.status);
|
|
130
|
+
},
|
|
131
|
+
onNewContinuingOffer(
|
|
132
|
+
offerId,
|
|
133
|
+
invitationAmount,
|
|
134
|
+
invitationMakers,
|
|
135
|
+
publicSubscribers,
|
|
136
|
+
) {
|
|
137
|
+
const { state } = this;
|
|
138
|
+
|
|
139
|
+
void state.walletHelper.addContinuingOffer(
|
|
140
|
+
offerId,
|
|
141
|
+
invitationAmount,
|
|
142
|
+
invitationMakers,
|
|
143
|
+
publicSubscribers,
|
|
144
|
+
);
|
|
145
|
+
},
|
|
146
|
+
|
|
147
|
+
publishResult(result) {
|
|
148
|
+
const { state, facets } = this;
|
|
149
|
+
|
|
150
|
+
const passStyle = passStyleOf(result);
|
|
151
|
+
// someday can we get TS to type narrow based on the passStyleOf result match?
|
|
152
|
+
switch (passStyle) {
|
|
153
|
+
case 'bigint':
|
|
154
|
+
case 'boolean':
|
|
155
|
+
case 'null':
|
|
156
|
+
case 'number':
|
|
157
|
+
case 'string':
|
|
158
|
+
case 'symbol':
|
|
159
|
+
case 'undefined':
|
|
160
|
+
facets.helper.updateStatus({ result });
|
|
161
|
+
break;
|
|
162
|
+
case 'copyRecord':
|
|
163
|
+
if ('invitationMakers' in result) {
|
|
164
|
+
// save for continuing invitation offer
|
|
165
|
+
|
|
166
|
+
void facets.helper.onNewContinuingOffer(
|
|
167
|
+
String(state.status.id),
|
|
168
|
+
state.invitationAmount,
|
|
169
|
+
result.invitationMakers,
|
|
170
|
+
result.publicSubscribers,
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
facets.helper.updateStatus({ result: UNPUBLISHED_RESULT });
|
|
174
|
+
break;
|
|
175
|
+
default:
|
|
176
|
+
// drop the result
|
|
177
|
+
facets.helper.updateStatus({ result: UNPUBLISHED_RESULT });
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
|
|
182
|
+
/** @type {OutcomeWatchers['paymentWatcher']} */
|
|
183
|
+
paymentWatcher: {
|
|
184
|
+
async onFulfilled(payouts) {
|
|
185
|
+
const { state, facets } = this;
|
|
186
|
+
|
|
187
|
+
// This will block until all payouts succeed, but user will be updated
|
|
188
|
+
// since each payout will trigger its corresponding purse notifier.
|
|
189
|
+
const amountPKeywordRecord = objectMap(payouts, paymentRef =>
|
|
190
|
+
E.when(paymentRef, payment => state.deposit.receive(payment)),
|
|
191
|
+
);
|
|
192
|
+
const amounts = await deeplyFulfilledObject(amountPKeywordRecord);
|
|
193
|
+
facets.helper.updateStatus({ payouts: amounts });
|
|
194
|
+
},
|
|
195
|
+
/**
|
|
196
|
+
* @param {Error} err
|
|
197
|
+
* @param {UserSeat} seat
|
|
198
|
+
*/
|
|
199
|
+
onRejected(err, seat) {
|
|
200
|
+
const { facets } = this;
|
|
201
|
+
if (isUpgradeDisconnection(err)) {
|
|
202
|
+
void watchForPayout(facets, seat);
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
},
|
|
206
|
+
|
|
207
|
+
/** @type {OutcomeWatchers['resultWatcher']} */
|
|
208
|
+
resultWatcher: {
|
|
209
|
+
onFulfilled(result) {
|
|
210
|
+
const { facets } = this;
|
|
211
|
+
facets.helper.publishResult(result);
|
|
212
|
+
},
|
|
213
|
+
/**
|
|
214
|
+
* @param {Error} err
|
|
215
|
+
* @param {UserSeat} seat
|
|
216
|
+
*/
|
|
217
|
+
onRejected(err, seat) {
|
|
218
|
+
const { facets } = this;
|
|
219
|
+
if (isUpgradeDisconnection(err)) {
|
|
220
|
+
void watchForOfferResult(facets, seat);
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
/** @type {OutcomeWatchers['numWantsWatcher']} */
|
|
226
|
+
numWantsWatcher: {
|
|
227
|
+
onFulfilled(numSatisfied) {
|
|
228
|
+
const { facets } = this;
|
|
229
|
+
|
|
230
|
+
facets.helper.updateStatus({ numWantsSatisfied: numSatisfied });
|
|
231
|
+
},
|
|
232
|
+
/**
|
|
233
|
+
* @param {Error} err
|
|
234
|
+
* @param {UserSeat} seat
|
|
235
|
+
*/
|
|
236
|
+
onRejected(err, seat) {
|
|
237
|
+
const { facets } = this;
|
|
238
|
+
if (isUpgradeDisconnection(err)) {
|
|
239
|
+
void watchForNumWants(facets, seat);
|
|
240
|
+
}
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
);
|
|
245
|
+
};
|
|
246
|
+
harden(prepareOfferWatcher);
|
|
247
|
+
|
|
248
|
+
/** @typedef {ReturnType<typeof prepareOfferWatcher>} MakeOfferWatcher */
|
package/src/offers.d.ts
CHANGED
|
@@ -11,30 +11,6 @@
|
|
|
11
11
|
*/
|
|
12
12
|
/** Value for "result" field when the result can't be published */
|
|
13
13
|
export const UNPUBLISHED_RESULT: "UNPUBLISHED";
|
|
14
|
-
export function makeOfferExecutor({ zoe, depositFacet, invitationIssuer, powers, onStatusChange, onNewContinuingOffer, }: {
|
|
15
|
-
zoe: ERef<ZoeService>;
|
|
16
|
-
depositFacet: {
|
|
17
|
-
receive: (payment: any) => Promise<Amount>;
|
|
18
|
-
};
|
|
19
|
-
invitationIssuer: ERef<Issuer<'set'>>;
|
|
20
|
-
powers: {
|
|
21
|
-
logger: Pick<Console, 'info' | 'error'>;
|
|
22
|
-
invitationFromSpec: (spec: import('./invitations').InvitationSpec) => ERef<Invitation>;
|
|
23
|
-
purseForBrand: (brand: Brand) => Promise<import('./types').RemotePurse>;
|
|
24
|
-
};
|
|
25
|
-
onStatusChange: (status: OfferStatus) => void;
|
|
26
|
-
onNewContinuingOffer: (offerId: string, invitationAmount: Amount<'set'>, invitationMakers: import('./types').RemoteInvitationMakers, publicSubscribers: import('./types').PublicSubscribers | import('@agoric/zoe/src/contractSupport').TopicsRecord) => Promise<void>;
|
|
27
|
-
}): {
|
|
28
|
-
/**
|
|
29
|
-
* Take an offer description provided in capData, augment it with payments and call zoe.offer()
|
|
30
|
-
*
|
|
31
|
-
* @param {OfferSpec} offerSpec
|
|
32
|
-
* @param {(seatRef: UserSeat) => void} onSeatCreated
|
|
33
|
-
* @returns {Promise<void>} when the offer has been sent to Zoe; payouts go into this wallet's purses
|
|
34
|
-
* @throws if any parts of the offer are determined to be invalid before calling Zoe's `offer()`
|
|
35
|
-
*/
|
|
36
|
-
executeOffer(offerSpec: OfferSpec, onSeatCreated: (seatRef: UserSeat) => void): Promise<void>;
|
|
37
|
-
};
|
|
38
14
|
export type OfferId = number | string;
|
|
39
15
|
export type OfferSpec = {
|
|
40
16
|
id: OfferId;
|
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":"AAAA;;GAEG;AAEH;;;;;;;GAOG;AAEH,kEAAkE;AAClE,+CAAgD;sBAbnC,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,7 +1,3 @@
|
|
|
1
|
-
import { E, passStyleOf } from '@endo/far';
|
|
2
|
-
import { deeplyFulfilledObject } from '@agoric/internal';
|
|
3
|
-
import { makePaymentsHelper } from './payments.js';
|
|
4
|
-
|
|
5
1
|
/**
|
|
6
2
|
* @typedef {number | string} OfferId
|
|
7
3
|
*/
|
|
@@ -26,173 +22,3 @@ export const UNPUBLISHED_RESULT = 'UNPUBLISHED';
|
|
|
26
22
|
* payouts?: AmountKeywordRecord,
|
|
27
23
|
* }} OfferStatus
|
|
28
24
|
*/
|
|
29
|
-
|
|
30
|
-
/* eslint-disable jsdoc/check-param-names -- bug(?) with nested objects */
|
|
31
|
-
/**
|
|
32
|
-
* @param {object} opts
|
|
33
|
-
* @param {ERef<ZoeService>} opts.zoe
|
|
34
|
-
* @param {{ receive: (payment: *) => Promise<Amount> }} opts.depositFacet
|
|
35
|
-
* @param {ERef<Issuer<'set'>>} opts.invitationIssuer
|
|
36
|
-
* @param {object} opts.powers
|
|
37
|
-
* @param {Pick<Console, 'info'| 'error'>} opts.powers.logger
|
|
38
|
-
* @param {(spec: import('./invitations').InvitationSpec) => ERef<Invitation>} opts.powers.invitationFromSpec
|
|
39
|
-
* @param {(brand: Brand) => Promise<import('./types').RemotePurse>} opts.powers.purseForBrand
|
|
40
|
-
* @param {(status: OfferStatus) => void} opts.onStatusChange
|
|
41
|
-
* @param {(offerId: string, invitationAmount: Amount<'set'>, invitationMakers: import('./types').RemoteInvitationMakers, publicSubscribers: import('./types').PublicSubscribers | import('@agoric/zoe/src/contractSupport').TopicsRecord ) => Promise<void>} opts.onNewContinuingOffer
|
|
42
|
-
*/
|
|
43
|
-
export const makeOfferExecutor = ({
|
|
44
|
-
zoe,
|
|
45
|
-
depositFacet,
|
|
46
|
-
invitationIssuer,
|
|
47
|
-
powers,
|
|
48
|
-
onStatusChange,
|
|
49
|
-
onNewContinuingOffer,
|
|
50
|
-
}) => {
|
|
51
|
-
const { invitationFromSpec, logger, purseForBrand } = powers;
|
|
52
|
-
|
|
53
|
-
return {
|
|
54
|
-
/**
|
|
55
|
-
* Take an offer description provided in capData, augment it with payments and call zoe.offer()
|
|
56
|
-
*
|
|
57
|
-
* @param {OfferSpec} offerSpec
|
|
58
|
-
* @param {(seatRef: UserSeat) => void} onSeatCreated
|
|
59
|
-
* @returns {Promise<void>} when the offer has been sent to Zoe; payouts go into this wallet's purses
|
|
60
|
-
* @throws if any parts of the offer are determined to be invalid before calling Zoe's `offer()`
|
|
61
|
-
*/
|
|
62
|
-
async executeOffer(offerSpec, onSeatCreated) {
|
|
63
|
-
logger.info('starting executeOffer', offerSpec.id);
|
|
64
|
-
|
|
65
|
-
const paymentsManager = makePaymentsHelper(purseForBrand, depositFacet);
|
|
66
|
-
|
|
67
|
-
/** @type {OfferStatus} */
|
|
68
|
-
let status = {
|
|
69
|
-
...offerSpec,
|
|
70
|
-
};
|
|
71
|
-
/** @param {Partial<OfferStatus>} changes */
|
|
72
|
-
const updateStatus = changes => {
|
|
73
|
-
status = { ...status, ...changes };
|
|
74
|
-
onStatusChange(status);
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
/** @type {UserSeat} */
|
|
78
|
-
let seatRef;
|
|
79
|
-
|
|
80
|
-
const tryBody = async () => {
|
|
81
|
-
// 1. Prepare values and validate synchronously.
|
|
82
|
-
const { id, invitationSpec, proposal, offerArgs } = offerSpec;
|
|
83
|
-
|
|
84
|
-
/** @type {PaymentKeywordRecord | undefined} */
|
|
85
|
-
const paymentKeywordRecord = await (proposal?.give &&
|
|
86
|
-
deeplyFulfilledObject(paymentsManager.withdrawGive(proposal.give)));
|
|
87
|
-
|
|
88
|
-
const invitation = invitationFromSpec(invitationSpec);
|
|
89
|
-
const invitationAmount = await E(invitationIssuer).getAmountOf(
|
|
90
|
-
invitation,
|
|
91
|
-
);
|
|
92
|
-
|
|
93
|
-
// 2. Begin executing offer
|
|
94
|
-
// No explicit signal to user that we reached here but if anything above
|
|
95
|
-
// failed they'd get an 'error' status update.
|
|
96
|
-
|
|
97
|
-
// eslint-disable-next-line @jessie.js/no-nested-await -- unconditional
|
|
98
|
-
seatRef = await E(zoe).offer(
|
|
99
|
-
invitation,
|
|
100
|
-
proposal,
|
|
101
|
-
paymentKeywordRecord,
|
|
102
|
-
offerArgs,
|
|
103
|
-
);
|
|
104
|
-
logger.info(id, 'seated');
|
|
105
|
-
onSeatCreated(seatRef);
|
|
106
|
-
|
|
107
|
-
const publishResult = E.when(E(seatRef).getOfferResult(), result => {
|
|
108
|
-
const passStyle = passStyleOf(result);
|
|
109
|
-
logger.info(id, 'offerResult', passStyle, result);
|
|
110
|
-
// someday can we get TS to type narrow based on the passStyleOf result match?
|
|
111
|
-
switch (passStyle) {
|
|
112
|
-
case 'bigint':
|
|
113
|
-
case 'boolean':
|
|
114
|
-
case 'null':
|
|
115
|
-
case 'number':
|
|
116
|
-
case 'string':
|
|
117
|
-
case 'symbol':
|
|
118
|
-
case 'undefined':
|
|
119
|
-
updateStatus({ result });
|
|
120
|
-
break;
|
|
121
|
-
case 'copyRecord':
|
|
122
|
-
// @ts-expect-error result narrowed by passStyle
|
|
123
|
-
if ('invitationMakers' in result) {
|
|
124
|
-
// save for continuing invitation offer
|
|
125
|
-
void onNewContinuingOffer(
|
|
126
|
-
String(id),
|
|
127
|
-
invitationAmount,
|
|
128
|
-
// @ts-expect-error result narrowed by passStyle
|
|
129
|
-
result.invitationMakers,
|
|
130
|
-
// @ts-expect-error result narrowed by passStyle
|
|
131
|
-
result.publicSubscribers,
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
// copyRecord is valid to publish but not safe as it may have private info
|
|
135
|
-
updateStatus({ result: UNPUBLISHED_RESULT });
|
|
136
|
-
break;
|
|
137
|
-
default:
|
|
138
|
-
// drop the result
|
|
139
|
-
updateStatus({ result: UNPUBLISHED_RESULT });
|
|
140
|
-
}
|
|
141
|
-
});
|
|
142
|
-
|
|
143
|
-
const publishWantsSatisfied = E.when(
|
|
144
|
-
E(seatRef).numWantsSatisfied(),
|
|
145
|
-
numSatisfied => {
|
|
146
|
-
logger.info(id, 'numSatisfied', numSatisfied);
|
|
147
|
-
if (numSatisfied === 0) {
|
|
148
|
-
updateStatus({ numWantsSatisfied: 0 });
|
|
149
|
-
}
|
|
150
|
-
updateStatus({
|
|
151
|
-
numWantsSatisfied: numSatisfied,
|
|
152
|
-
});
|
|
153
|
-
},
|
|
154
|
-
);
|
|
155
|
-
|
|
156
|
-
// This will block until all payouts succeed, but user will be updated
|
|
157
|
-
// as each payout will trigger its corresponding purse notifier.
|
|
158
|
-
const publishPayouts = E.when(E(seatRef).getPayouts(), payouts =>
|
|
159
|
-
paymentsManager.depositPayouts(payouts).then(amountsOrDeferred => {
|
|
160
|
-
updateStatus({ payouts: amountsOrDeferred });
|
|
161
|
-
}),
|
|
162
|
-
);
|
|
163
|
-
|
|
164
|
-
// The offer is complete when these promises are resolved.
|
|
165
|
-
// If any reject then executeOffer rejects and that must be handled.
|
|
166
|
-
return Promise.all([
|
|
167
|
-
publishResult,
|
|
168
|
-
publishWantsSatisfied,
|
|
169
|
-
publishPayouts,
|
|
170
|
-
]);
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
await tryBody().catch(err => {
|
|
174
|
-
logger.error('OFFER ERROR:', err);
|
|
175
|
-
// Notify the user
|
|
176
|
-
updateStatus({ error: err.toString() });
|
|
177
|
-
// Attempt to recover payments
|
|
178
|
-
void paymentsManager.tryReclaimingWithdrawnPayments().then(result => {
|
|
179
|
-
if (result) {
|
|
180
|
-
updateStatus({ result });
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
if (seatRef) {
|
|
184
|
-
void E(seatRef)
|
|
185
|
-
.hasExited()
|
|
186
|
-
.then(hasExited => {
|
|
187
|
-
if (!hasExited) {
|
|
188
|
-
void E(seatRef).tryExit();
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
}
|
|
192
|
-
// propagate to caller
|
|
193
|
-
throw err;
|
|
194
|
-
});
|
|
195
|
-
},
|
|
196
|
-
};
|
|
197
|
-
};
|
|
198
|
-
harden(makeOfferExecutor);
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export function upgradeWalletFactory({ consume: { walletFactoryStartResult, provisionPoolStartResult, chainStorage, walletBridgeManager: walletBridgeManagerP, }, }: BootstrapPowers & ChainBootstrapSpace, options: {
|
|
2
|
+
options: {
|
|
3
|
+
walletRef: VatSourceRef;
|
|
4
|
+
};
|
|
5
|
+
}): Promise<void>;
|
|
6
|
+
export function getManifestForUpgradeWallet(_powers: any, { walletRef }: {
|
|
7
|
+
walletRef: any;
|
|
8
|
+
}): {
|
|
9
|
+
manifest: {
|
|
10
|
+
[x: string]: {
|
|
11
|
+
consume: {
|
|
12
|
+
walletFactoryStartResult: string;
|
|
13
|
+
provisionPoolStartResult: string;
|
|
14
|
+
chainStorage: string;
|
|
15
|
+
walletBridgeManager: string;
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
options: {
|
|
20
|
+
walletRef: any;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=upgrade-wallet-factory2-proposal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upgrade-wallet-factory2-proposal.d.ts","sourceRoot":"","sources":["upgrade-wallet-factory2-proposal.js"],"names":[],"mappings":"AASO,qKAJI,eAAe,GAAG,mBAAmB;;mBAExB,YAAY;;kBAqCnC;AAEM;;;;;;;;;;;;;;;;EAYL"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
import { E } from '@endo/far';
|
|
3
|
+
import { makeStorageNodeChild } from '@agoric/internal/src/lib-chainStorage.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {BootstrapPowers & ChainBootstrapSpace} powers
|
|
7
|
+
* @param {object} options
|
|
8
|
+
* @param {{ walletRef: VatSourceRef }} options.options
|
|
9
|
+
*/
|
|
10
|
+
export const upgradeWalletFactory = async (
|
|
11
|
+
{
|
|
12
|
+
consume: {
|
|
13
|
+
walletFactoryStartResult,
|
|
14
|
+
provisionPoolStartResult,
|
|
15
|
+
chainStorage,
|
|
16
|
+
walletBridgeManager: walletBridgeManagerP,
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
options,
|
|
20
|
+
) => {
|
|
21
|
+
const WALLET_STORAGE_PATH_SEGMENT = 'wallet';
|
|
22
|
+
|
|
23
|
+
const { walletRef } = options.options;
|
|
24
|
+
|
|
25
|
+
const [walletBridgeManager, walletStorageNode, ppFacets] = await Promise.all([
|
|
26
|
+
walletBridgeManagerP,
|
|
27
|
+
makeStorageNodeChild(chainStorage, WALLET_STORAGE_PATH_SEGMENT),
|
|
28
|
+
provisionPoolStartResult,
|
|
29
|
+
]);
|
|
30
|
+
// @ts-expect-error missing type declaration?
|
|
31
|
+
const walletReviver = await E(ppFacets.creatorFacet).getWalletReviver();
|
|
32
|
+
|
|
33
|
+
const privateArgs = {
|
|
34
|
+
storageNode: walletStorageNode,
|
|
35
|
+
walletBridgeManager,
|
|
36
|
+
walletReviver,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const { adminFacet } = await walletFactoryStartResult;
|
|
40
|
+
|
|
41
|
+
assert(walletRef.bundleID);
|
|
42
|
+
await E(adminFacet).upgradeContract(walletRef.bundleID, privateArgs);
|
|
43
|
+
|
|
44
|
+
console.log(`Successfully upgraded WalletFactory`);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export const getManifestForUpgradeWallet = (_powers, { walletRef }) => ({
|
|
48
|
+
manifest: {
|
|
49
|
+
[upgradeWalletFactory.name]: {
|
|
50
|
+
consume: {
|
|
51
|
+
walletFactoryStartResult: 'walletFactoryStartResult',
|
|
52
|
+
provisionPoolStartResult: 'provisionPoolStartResult',
|
|
53
|
+
chainStorage: 'chainStorage',
|
|
54
|
+
walletBridgeManager: 'walletBridgeManager',
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
options: { walletRef },
|
|
59
|
+
});
|