@agoric/inter-protocol 0.13.2-dev-02e99df.0 → 0.13.2-dev-ab7a341.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/bundles/bundle-auctioneer-js-meta.json +115 -115
- package/bundles/bundle-econCommitteeCharter-js-meta.json +76 -76
- package/bundles/bundle-feeDistributor-js-meta.json +59 -59
- package/bundles/bundle-fluxAggregatorKit-js-meta.json +110 -110
- package/bundles/bundle-psm-js-meta.json +108 -108
- package/bundles/bundle-reserve-js-meta.json +268 -264
- package/bundles/bundle-reserve.js +1 -1
- package/bundles/bundle-scaledPriceAuthority-js-meta.json +77 -77
- package/bundles/bundle-stakeFactory-js-meta.json +271 -271
- package/bundles/bundle-vaultFactory-js-meta.json +131 -131
- package/bundles/bundle-vaultFactory.js +1 -1
- package/package.json +17 -17
- package/src/proposals/econ-behaviors.js +1 -2
- package/src/reserve/assetReserve.js +48 -258
- package/src/reserve/assetReserveKit.js +303 -0
- package/src/vaultFactory/vaultManager.js +1 -0
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
import { Fail } from '@agoric/assert';
|
|
2
|
+
import { AmountMath, AmountShape, IssuerShape } from '@agoric/ertp';
|
|
3
|
+
import { makeTracer } from '@agoric/internal';
|
|
4
|
+
import { M, makeScalarBigMapStore, prepareExoClassKit } from '@agoric/vat-data';
|
|
5
|
+
import { atomicTransfer } from '@agoric/zoe/src/contractSupport/atomicTransfer.js';
|
|
6
|
+
import {
|
|
7
|
+
makeRecorderTopic,
|
|
8
|
+
SubscriberShape,
|
|
9
|
+
TopicsRecordShape,
|
|
10
|
+
} from '@agoric/zoe/src/contractSupport/topics.js';
|
|
11
|
+
import { AmountKeywordRecordShape } from '@agoric/zoe/src/typeGuards.js';
|
|
12
|
+
import { E } from '@endo/eventual-send';
|
|
13
|
+
import { UnguardedHelperI } from '../typeGuards.js';
|
|
14
|
+
|
|
15
|
+
const { quote: q } = assert;
|
|
16
|
+
|
|
17
|
+
const trace = makeTracer('ReserveKit', false);
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @typedef {object} MetricsNotification
|
|
21
|
+
*
|
|
22
|
+
* @property {AmountKeywordRecord} allocations
|
|
23
|
+
* @property {Amount<'nat'>} shortfallBalance shortfall from liquidation that
|
|
24
|
+
* has not yet been compensated.
|
|
25
|
+
* @property {Amount<'nat'>} totalFeeMinted total Fee tokens minted to date
|
|
26
|
+
* @property {Amount<'nat'>} totalFeeBurned total Fee tokens burned to date
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {import('@agoric/vat-data').Baggage} baggage
|
|
31
|
+
* @param {{
|
|
32
|
+
* feeMint: ZCFMint<'nat'>,
|
|
33
|
+
* makeRecorderKit: import('@agoric/zoe/src/contractSupport/recorder.js').MakeRecorderKit,
|
|
34
|
+
* storageNode: StorageNode,
|
|
35
|
+
* zcf: ZCF}} powers
|
|
36
|
+
*/
|
|
37
|
+
export const prepareAssetReserveKit = async (
|
|
38
|
+
baggage,
|
|
39
|
+
{ feeMint, makeRecorderKit, storageNode, zcf },
|
|
40
|
+
) => {
|
|
41
|
+
trace('prepareAssetReserveKit', [...baggage.keys()]);
|
|
42
|
+
const feeKit = feeMint.getIssuerRecord();
|
|
43
|
+
const emptyAmount = AmountMath.makeEmpty(feeKit.brand);
|
|
44
|
+
|
|
45
|
+
const makeAssetReserveKitInternal = prepareExoClassKit(
|
|
46
|
+
baggage,
|
|
47
|
+
'AssetReserveKit',
|
|
48
|
+
{
|
|
49
|
+
helper: UnguardedHelperI,
|
|
50
|
+
governedApis: M.interface('AssetReserve governedApis', {
|
|
51
|
+
burnFeesToReduceShortfall: M.call(AmountShape).returns(),
|
|
52
|
+
}),
|
|
53
|
+
machine: M.interface('AssetReserve machine', {
|
|
54
|
+
addIssuer: M.call(IssuerShape, M.string()).returns(M.promise()),
|
|
55
|
+
getAllocations: M.call().returns(AmountKeywordRecordShape),
|
|
56
|
+
makeShortfallReportingInvitation: M.call().returns(M.promise()),
|
|
57
|
+
}),
|
|
58
|
+
public: M.interface('AssetReserve public', {
|
|
59
|
+
makeAddCollateralInvitation: M.call().returns(M.promise()),
|
|
60
|
+
getMetrics: M.call().returns(SubscriberShape),
|
|
61
|
+
getPublicTopics: M.call().returns(TopicsRecordShape),
|
|
62
|
+
}),
|
|
63
|
+
shortfallReportingFacet: M.interface('AssetReserve shortfall reporter', {
|
|
64
|
+
increaseLiquidationShortfall: M.call(AmountShape).returns(),
|
|
65
|
+
reduceLiquidationShortfall: M.call(AmountShape).returns(),
|
|
66
|
+
}),
|
|
67
|
+
},
|
|
68
|
+
/**
|
|
69
|
+
*
|
|
70
|
+
* @param {StorageNode} metricsNode
|
|
71
|
+
*/
|
|
72
|
+
metricsNode => {
|
|
73
|
+
/**
|
|
74
|
+
* Used to look up the unique keyword for each brand, including Fee brand.
|
|
75
|
+
*
|
|
76
|
+
* @type {MapStore<Brand, Keyword>}
|
|
77
|
+
*/
|
|
78
|
+
const keywordForBrand = makeScalarBigMapStore('keywordForBrand', {
|
|
79
|
+
durable: true,
|
|
80
|
+
});
|
|
81
|
+
/**
|
|
82
|
+
* Used to look up the brands for keywords, excluding Fee because it's a special case.
|
|
83
|
+
*
|
|
84
|
+
* @type {MapStore<Keyword, Brand>}
|
|
85
|
+
*/
|
|
86
|
+
const brandForKeyword = makeScalarBigMapStore('brandForKeyword', {
|
|
87
|
+
durable: true,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
brandForKeyword,
|
|
92
|
+
// We keep the associated liquidity tokens in the same seat
|
|
93
|
+
collateralSeat: zcf.makeEmptySeatKit().zcfSeat,
|
|
94
|
+
keywordForBrand,
|
|
95
|
+
metricsKit: makeRecorderKit(
|
|
96
|
+
metricsNode,
|
|
97
|
+
/** @type {import('@agoric/zoe/src/contractSupport/recorder.js').TypedMatcher<MetricsNotification>} */ (
|
|
98
|
+
M.any()
|
|
99
|
+
),
|
|
100
|
+
),
|
|
101
|
+
totalFeeMinted: emptyAmount,
|
|
102
|
+
totalFeeBurned: emptyAmount,
|
|
103
|
+
shortfallBalance: emptyAmount,
|
|
104
|
+
};
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
helper: {
|
|
108
|
+
/** @param {Brand} brand */
|
|
109
|
+
getKeywordForBrand(brand) {
|
|
110
|
+
const { keywordForBrand } = this.state;
|
|
111
|
+
keywordForBrand.has(brand) ||
|
|
112
|
+
Fail`Issuer not defined for brand ${q(
|
|
113
|
+
brand,
|
|
114
|
+
)}; first call addIssuer()`;
|
|
115
|
+
return keywordForBrand.get(brand);
|
|
116
|
+
},
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* @param {Brand} brand
|
|
120
|
+
* @param {Keyword} keyword
|
|
121
|
+
*/
|
|
122
|
+
saveBrandKeyword(brand, keyword) {
|
|
123
|
+
trace('saveBrandKeyword', brand, keyword);
|
|
124
|
+
const { keywordForBrand, brandForKeyword } = this.state;
|
|
125
|
+
keywordForBrand.init(brand, keyword);
|
|
126
|
+
brandForKeyword.init(keyword, brand);
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
writeMetrics() {
|
|
130
|
+
const { state } = this;
|
|
131
|
+
const metrics = harden({
|
|
132
|
+
allocations: state.collateralSeat.getCurrentAllocation(),
|
|
133
|
+
shortfallBalance: state.shortfallBalance,
|
|
134
|
+
totalFeeMinted: state.totalFeeMinted,
|
|
135
|
+
totalFeeBurned: state.totalFeeBurned,
|
|
136
|
+
});
|
|
137
|
+
state.metricsKit.recorder.write(metrics);
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
governedApis: {
|
|
141
|
+
/**
|
|
142
|
+
*
|
|
143
|
+
* @param {Amount<'nat'>} reduction
|
|
144
|
+
* @returns {void}
|
|
145
|
+
*/
|
|
146
|
+
burnFeesToReduceShortfall(reduction) {
|
|
147
|
+
const { facets, state } = this;
|
|
148
|
+
trace('burnFeesToReduceShortfall', reduction);
|
|
149
|
+
reduction = AmountMath.coerce(feeKit.brand, reduction);
|
|
150
|
+
const feeKeyword = state.keywordForBrand.get(feeKit.brand);
|
|
151
|
+
const feeBalance =
|
|
152
|
+
state.collateralSeat.getAmountAllocated(feeKeyword);
|
|
153
|
+
const amountToBurn = AmountMath.min(reduction, feeBalance);
|
|
154
|
+
if (AmountMath.isEmpty(amountToBurn)) {
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
feeMint.burnLosses(
|
|
159
|
+
harden({ [feeKeyword]: amountToBurn }),
|
|
160
|
+
state.collateralSeat,
|
|
161
|
+
);
|
|
162
|
+
state.totalFeeBurned = AmountMath.add(
|
|
163
|
+
state.totalFeeBurned,
|
|
164
|
+
amountToBurn,
|
|
165
|
+
);
|
|
166
|
+
facets.helper.writeMetrics();
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
machine: {
|
|
170
|
+
// add makeRedeemLiquidityTokensInvitation later. For now just store them
|
|
171
|
+
/**
|
|
172
|
+
* @param {Issuer} issuer
|
|
173
|
+
* @param {string} keyword
|
|
174
|
+
*/
|
|
175
|
+
async addIssuer(issuer, keyword) {
|
|
176
|
+
const brand = await E(issuer).getBrand();
|
|
177
|
+
trace('addIssuer', { brand, keyword });
|
|
178
|
+
assert(
|
|
179
|
+
keyword !== 'Fee' && brand !== feeKit.brand,
|
|
180
|
+
`'Fee' brand is a special case handled by the reserve contract`,
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
trace('addIssuer storing', {
|
|
184
|
+
keyword,
|
|
185
|
+
brand,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
this.facets.helper.saveBrandKeyword(brand, keyword);
|
|
189
|
+
await zcf.saveIssuer(issuer, keyword);
|
|
190
|
+
},
|
|
191
|
+
|
|
192
|
+
/** @deprecated use getPublicTopics metrics allocation */
|
|
193
|
+
getAllocations() {
|
|
194
|
+
return this.state.collateralSeat.getCurrentAllocation();
|
|
195
|
+
},
|
|
196
|
+
|
|
197
|
+
makeShortfallReportingInvitation() {
|
|
198
|
+
const { facets } = this;
|
|
199
|
+
const handleShortfallReportingOffer = () => {
|
|
200
|
+
return facets.shortfallReportingFacet;
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
return zcf.makeInvitation(
|
|
204
|
+
handleShortfallReportingOffer,
|
|
205
|
+
'getFacetForReportingShortfalls',
|
|
206
|
+
);
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
/**
|
|
210
|
+
* XXX missing governance public methods https://github.com/Agoric/agoric-sdk/issues/5200
|
|
211
|
+
*/
|
|
212
|
+
public: {
|
|
213
|
+
/**
|
|
214
|
+
* Anyone can deposit any assets to the reserve
|
|
215
|
+
*/
|
|
216
|
+
makeAddCollateralInvitation() {
|
|
217
|
+
/** @type {OfferHandler<Promise<string>>} */
|
|
218
|
+
const handler = async seat => {
|
|
219
|
+
const {
|
|
220
|
+
give: { Collateral: amountIn },
|
|
221
|
+
} = seat.getProposal();
|
|
222
|
+
const { facets, state } = this;
|
|
223
|
+
const { helper } = facets;
|
|
224
|
+
|
|
225
|
+
const collateralKeyword = helper.getKeywordForBrand(amountIn.brand);
|
|
226
|
+
|
|
227
|
+
atomicTransfer(
|
|
228
|
+
zcf,
|
|
229
|
+
seat,
|
|
230
|
+
state.collateralSeat,
|
|
231
|
+
{ Collateral: amountIn },
|
|
232
|
+
{ [collateralKeyword]: amountIn },
|
|
233
|
+
);
|
|
234
|
+
seat.exit();
|
|
235
|
+
helper.writeMetrics();
|
|
236
|
+
|
|
237
|
+
trace('received collateral', amountIn);
|
|
238
|
+
return 'added Collateral to the Reserve';
|
|
239
|
+
};
|
|
240
|
+
return zcf.makeInvitation(handler, 'Add Collateral');
|
|
241
|
+
},
|
|
242
|
+
/** @deprecated */
|
|
243
|
+
getMetrics() {
|
|
244
|
+
return this.state.metricsKit.subscriber;
|
|
245
|
+
},
|
|
246
|
+
getPublicTopics() {
|
|
247
|
+
return {
|
|
248
|
+
metrics: makeRecorderTopic(
|
|
249
|
+
'Asset Reserve metrics',
|
|
250
|
+
this.state.metricsKit,
|
|
251
|
+
),
|
|
252
|
+
};
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
shortfallReportingFacet: {
|
|
256
|
+
/**
|
|
257
|
+
* @param {Amount<"nat">} shortfall
|
|
258
|
+
*/
|
|
259
|
+
increaseLiquidationShortfall(shortfall) {
|
|
260
|
+
const { facets, state } = this;
|
|
261
|
+
state.shortfallBalance = AmountMath.add(
|
|
262
|
+
state.shortfallBalance,
|
|
263
|
+
shortfall,
|
|
264
|
+
);
|
|
265
|
+
facets.helper.writeMetrics();
|
|
266
|
+
},
|
|
267
|
+
|
|
268
|
+
// currently exposed for testing. Maybe it only gets called internally?
|
|
269
|
+
/**
|
|
270
|
+
* @param {Amount<"nat">} reduction
|
|
271
|
+
*/
|
|
272
|
+
reduceLiquidationShortfall(reduction) {
|
|
273
|
+
const { state } = this;
|
|
274
|
+
if (AmountMath.isGTE(reduction, state.shortfallBalance)) {
|
|
275
|
+
state.shortfallBalance = emptyAmount;
|
|
276
|
+
} else {
|
|
277
|
+
state.shortfallBalance = AmountMath.subtract(
|
|
278
|
+
state.shortfallBalance,
|
|
279
|
+
reduction,
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
this.facets.helper.writeMetrics();
|
|
283
|
+
},
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
finish: ({ facets: { helper } }) => {
|
|
288
|
+
// no need to saveIssuer() b/c registerFeeMint did it
|
|
289
|
+
helper.saveBrandKeyword(feeKit.brand, 'Fee');
|
|
290
|
+
|
|
291
|
+
helper.writeMetrics();
|
|
292
|
+
},
|
|
293
|
+
},
|
|
294
|
+
);
|
|
295
|
+
|
|
296
|
+
const makeAssetReserveKit = async () => {
|
|
297
|
+
const metricsNode = await E(storageNode).makeChildNode('metrics');
|
|
298
|
+
return makeAssetReserveKitInternal(metricsNode);
|
|
299
|
+
};
|
|
300
|
+
return makeAssetReserveKit;
|
|
301
|
+
};
|
|
302
|
+
harden(prepareAssetReserveKit);
|
|
303
|
+
/** @typedef {ReturnType<Awaited<ReturnType<typeof prepareAssetReserveKit>>>} AssetReserveKit */
|
|
@@ -489,6 +489,7 @@ export const prepareVaultManagerKit = (
|
|
|
489
489
|
|
|
490
490
|
/** @type {(accounting: { overage: Amount<'nat'>, shortfall: Amount<'nat'> }) => void} */
|
|
491
491
|
recordShortfallAndProceeds(accounting) {
|
|
492
|
+
trace('recordShortfallAndProceeds', accounting);
|
|
492
493
|
const { state } = this;
|
|
493
494
|
|
|
494
495
|
const { overage, shortfall } = accounting;
|