@agoric/inter-protocol 0.13.4-pismo-dev-0d5327f.0 → 0.14.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.
Files changed (141) hide show
  1. package/CHANGELOG.md +287 -0
  2. package/README.md +26 -20
  3. package/bundles/bundle-auctioneer-js-meta.json +722 -0
  4. package/bundles/bundle-auctioneer.js +1 -0
  5. package/bundles/bundle-econCommitteeCharter-js-meta.json +514 -0
  6. package/bundles/bundle-econCommitteeCharter.js +1 -0
  7. package/bundles/bundle-feeDistributor-js-meta.json +458 -0
  8. package/bundles/bundle-feeDistributor.js +1 -1
  9. package/bundles/bundle-fluxAggregatorKit-js-meta.json +674 -0
  10. package/bundles/bundle-fluxAggregatorKit.js +1 -0
  11. package/bundles/bundle-psm-js-meta.json +666 -0
  12. package/bundles/bundle-psm.js +1 -1
  13. package/bundles/bundle-reserve-js-meta.json +662 -0
  14. package/bundles/bundle-reserve.js +1 -1
  15. package/bundles/bundle-scaledPriceAuthority-js-meta.json +542 -0
  16. package/bundles/bundle-scaledPriceAuthority.js +1 -1
  17. package/bundles/bundle-vaultFactory-js-meta.json +786 -0
  18. package/bundles/bundle-vaultFactory.js +1 -1
  19. package/exported.js +0 -2
  20. package/package.json +34 -31
  21. package/scripts/add-collateral-core.js +14 -4
  22. package/scripts/build-bundles.js +9 -2
  23. package/scripts/deploy-contracts.js +1 -4
  24. package/scripts/init-core.js +20 -38
  25. package/scripts/invite-committee-core.js +1 -1
  26. package/scripts/manual-price-feed.js +2 -2
  27. package/scripts/price-feed-core.js +7 -6
  28. package/scripts/start-local-chain.sh +84 -0
  29. package/src/auction/auctionBook.js +755 -0
  30. package/src/auction/auctioneer.js +720 -0
  31. package/src/auction/offerBook.js +221 -0
  32. package/src/auction/params.js +174 -0
  33. package/src/auction/scheduleMath.js +167 -0
  34. package/src/auction/scheduler.js +370 -0
  35. package/src/auction/sortedOffers.js +136 -0
  36. package/src/auction/util.js +55 -0
  37. package/src/clientSupport.js +324 -0
  38. package/src/collectFees.js +8 -14
  39. package/src/contractSupport.js +24 -68
  40. package/src/econCommitteeCharter.js +161 -77
  41. package/src/feeDistributor.js +60 -20
  42. package/src/index.js +2 -0
  43. package/src/interest-math.js +1 -4
  44. package/src/interest.js +20 -13
  45. package/src/price/README.md +57 -0
  46. package/src/price/fluxAggregatorContract.js +190 -0
  47. package/src/price/fluxAggregatorKit.js +375 -0
  48. package/src/price/priceOracleKit.js +127 -0
  49. package/src/price/roundsManager.js +726 -0
  50. package/src/proposals/addAssetToVault.js +89 -94
  51. package/src/proposals/committee-proposal.js +141 -40
  52. package/src/proposals/core-proposal.js +100 -167
  53. package/src/proposals/econ-behaviors.js +320 -564
  54. package/src/proposals/price-feed-proposal.js +175 -78
  55. package/src/proposals/startEconCommittee.js +25 -12
  56. package/src/proposals/startPSM.js +231 -211
  57. package/src/proposals/utils.js +31 -17
  58. package/src/psm/README.md +71 -0
  59. package/src/psm/psm.js +272 -160
  60. package/src/psm/types.js +2 -0
  61. package/src/reserve/assetReserve.js +56 -413
  62. package/src/reserve/assetReserveKit.js +303 -0
  63. package/src/reserve/doc.md +1 -3
  64. package/src/reserve/params.js +2 -5
  65. package/src/typeGuards.js +13 -0
  66. package/src/vaultFactory/Liquidation.md +100 -0
  67. package/src/vaultFactory/burn.js +2 -1
  68. package/src/vaultFactory/liquidation.js +270 -108
  69. package/src/vaultFactory/math.js +95 -0
  70. package/src/vaultFactory/orderedVaultStore.js +0 -1
  71. package/src/vaultFactory/params.js +133 -112
  72. package/src/vaultFactory/prioritizedVaults.js +36 -79
  73. package/src/vaultFactory/storeUtils.js +67 -9
  74. package/src/vaultFactory/type-imports.js +2 -0
  75. package/src/vaultFactory/types.js +22 -26
  76. package/src/vaultFactory/vault.js +772 -709
  77. package/src/vaultFactory/vaultDirector.js +480 -483
  78. package/src/vaultFactory/vaultFactory.js +99 -60
  79. package/src/vaultFactory/vaultHolder.js +121 -95
  80. package/src/vaultFactory/vaultKit.js +39 -31
  81. package/src/vaultFactory/vaultManager.js +1249 -868
  82. package/bundles/bundle-amm-meta.js +0 -618
  83. package/bundles/bundle-amm.js +0 -1
  84. package/bundles/bundle-feeDistributor-meta.js +0 -346
  85. package/bundles/bundle-interchainPool-meta.js +0 -534
  86. package/bundles/bundle-interchainPool.js +0 -1
  87. package/bundles/bundle-liquidateIncrementally-meta.js +0 -442
  88. package/bundles/bundle-liquidateIncrementally.js +0 -1
  89. package/bundles/bundle-liquidateMinimum-meta.js +0 -442
  90. package/bundles/bundle-liquidateMinimum.js +0 -1
  91. package/bundles/bundle-psm-meta.js +0 -538
  92. package/bundles/bundle-psmCharter-meta.js +0 -418
  93. package/bundles/bundle-psmCharter.js +0 -1
  94. package/bundles/bundle-reserve-meta.js +0 -542
  95. package/bundles/bundle-scaledPriceAuthority-meta.js +0 -442
  96. package/bundles/bundle-stakeFactory-meta.js +0 -574
  97. package/bundles/bundle-stakeFactory.js +0 -1
  98. package/bundles/bundle-vaultFactory-meta.js +0 -598
  99. package/scripts/add-initial-liquidity.js +0 -180
  100. package/src/collect.js +0 -13
  101. package/src/interchainPool.js +0 -135
  102. package/src/makeTracer.js +0 -36
  103. package/src/my-lien.js +0 -85
  104. package/src/proposals/demoIssuers.js +0 -685
  105. package/src/proposals/sim-behaviors.js +0 -40
  106. package/src/psm/psmCharter.js +0 -139
  107. package/src/stakeFactory/README.md +0 -62
  108. package/src/stakeFactory/attestation.js +0 -267
  109. package/src/stakeFactory/attestationTool.js +0 -66
  110. package/src/stakeFactory/constants.js +0 -16
  111. package/src/stakeFactory/params.js +0 -31
  112. package/src/stakeFactory/stakeFactory.js +0 -236
  113. package/src/stakeFactory/stakeFactoryKit.js +0 -455
  114. package/src/stakeFactory/stakeFactoryManager.js +0 -296
  115. package/src/stakeFactory/types.js +0 -42
  116. package/src/vaultFactory/liquidateIncrementally.js +0 -350
  117. package/src/vaultFactory/liquidateMinimum.js +0 -100
  118. package/src/vpool-xyk-amm/AttackersGuide.md +0 -89
  119. package/src/vpool-xyk-amm/addLiquidity.js +0 -222
  120. package/src/vpool-xyk-amm/addPool.js +0 -197
  121. package/src/vpool-xyk-amm/constantProduct/AMM-Trade.jpeg +0 -0
  122. package/src/vpool-xyk-amm/constantProduct/README.md +0 -204
  123. package/src/vpool-xyk-amm/constantProduct/calcFees.js +0 -99
  124. package/src/vpool-xyk-amm/constantProduct/calcSwapPrices.js +0 -85
  125. package/src/vpool-xyk-amm/constantProduct/core.js +0 -153
  126. package/src/vpool-xyk-amm/constantProduct/defaults.js +0 -5
  127. package/src/vpool-xyk-amm/constantProduct/getXY.js +0 -52
  128. package/src/vpool-xyk-amm/constantProduct/internal-types.js +0 -116
  129. package/src/vpool-xyk-amm/constantProduct/invariants.js +0 -43
  130. package/src/vpool-xyk-amm/constantProduct/swap.js +0 -272
  131. package/src/vpool-xyk-amm/constantProduct/types.js +0 -32
  132. package/src/vpool-xyk-amm/doublePool.js +0 -194
  133. package/src/vpool-xyk-amm/estimate.js +0 -155
  134. package/src/vpool-xyk-amm/multipoolMarketMaker.js +0 -520
  135. package/src/vpool-xyk-amm/params.js +0 -61
  136. package/src/vpool-xyk-amm/pool.js +0 -396
  137. package/src/vpool-xyk-amm/priceAuthority.js +0 -94
  138. package/src/vpool-xyk-amm/removeLiquidity.js +0 -31
  139. package/src/vpool-xyk-amm/singlePool.js +0 -73
  140. package/src/vpool-xyk-amm/swap.js +0 -69
  141. package/src/vpool-xyk-amm/types.js +0 -154
@@ -0,0 +1,190 @@
1
+ // @jessie-check
2
+
3
+ import {
4
+ hasIssuer,
5
+ makeDurableIssuerKit,
6
+ prepareIssuerKit,
7
+ } from '@agoric/ertp';
8
+ import { handleParamGovernance } from '@agoric/governance';
9
+ import { makeTracer, StorageNodeShape } from '@agoric/internal';
10
+ import { prepareDurablePublishKit } from '@agoric/notifier';
11
+ import { M } from '@agoric/store';
12
+ import { provideAll } from '@agoric/zoe/src/contractSupport/durability.js';
13
+ import { prepareRecorder } from '@agoric/zoe/src/contractSupport/recorder.js';
14
+ import { E } from '@endo/eventual-send';
15
+ import { reserveThenDeposit } from '../proposals/utils.js';
16
+ import { prepareFluxAggregatorKit } from './fluxAggregatorKit.js';
17
+
18
+ const trace = makeTracer('FluxAgg');
19
+ /**
20
+ * @typedef {import('@agoric/vat-data').Baggage} Baggage
21
+ * @typedef {import('@agoric/time/src/types').TimerService} TimerService
22
+ */
23
+
24
+ export const privateArgsShape = M.splitRecord(
25
+ harden({
26
+ storageNode: StorageNodeShape,
27
+ marshaller: M.eref(M.remotable('marshaller')),
28
+ namesByAddressAdmin: M.any(),
29
+ }),
30
+ harden({
31
+ // always optional. XXX some code is including the key, set to null
32
+ highPrioritySendersManager: M.or(
33
+ M.remotable('prioritySenders manager'),
34
+ M.null(),
35
+ ),
36
+ // only necessary on first invocation, not subsequent
37
+ initialPoserInvitation: M.remotable('Invitation'),
38
+ }),
39
+ );
40
+
41
+ /**
42
+ * PriceAuthority for their median. Unlike the simpler `priceAggregator.js`, this approximates
43
+ * the *Node Operator Aggregation* logic of [Chainlink price
44
+ * feeds](https://blog.chain.link/levels-of-data-aggregation-in-chainlink-price-feeds/).
45
+ *
46
+ * @param {ZCF<import('./fluxAggregatorKit.js').ChainlinkConfig & {
47
+ * timer: TimerService,
48
+ * brandIn: Brand<'nat'>,
49
+ * brandOut: Brand<'nat'>,
50
+ * description: string,
51
+ * unitAmountIn?: Amount<'nat'>,
52
+ * }>} zcf
53
+ * @param {{
54
+ * highPrioritySendersManager?: import('@agoric/internal/src/priority-senders.js').PrioritySendersManager,
55
+ * initialPoserInvitation: Invitation,
56
+ * marshaller: ERef<Marshaller>,
57
+ * namesByAddressAdmin: ERef<import('@agoric/vats').NameAdmin>,
58
+ * storageNode: StorageNode,
59
+ * }} privateArgs
60
+ * @param {Baggage} baggage
61
+ */
62
+ export const prepare = async (zcf, privateArgs, baggage) => {
63
+ trace('prepare with baggage keys', [...baggage.keys()]);
64
+
65
+ // xxx uses contract baggage as issuerBagage, assumes one issuer in this contract
66
+ /** @type {import('./roundsManager.js').QuoteKit} */
67
+ const quoteIssuerKit = hasIssuer(baggage)
68
+ ? prepareIssuerKit(baggage)
69
+ : makeDurableIssuerKit(baggage, 'quote', 'set');
70
+
71
+ const {
72
+ highPrioritySendersManager,
73
+ initialPoserInvitation,
74
+ marshaller,
75
+ namesByAddressAdmin,
76
+ storageNode,
77
+ } = privateArgs;
78
+
79
+ const { description, timer } = zcf.getTerms();
80
+
81
+ trace('awaited args');
82
+
83
+ const makeDurablePublishKit = prepareDurablePublishKit(
84
+ baggage,
85
+ 'Price Aggregator publish kit',
86
+ );
87
+ const makeRecorder = prepareRecorder(baggage, marshaller);
88
+
89
+ const makeFluxAggregatorKit = await prepareFluxAggregatorKit(
90
+ baggage,
91
+ zcf,
92
+ timer,
93
+ quoteIssuerKit,
94
+ storageNode,
95
+ makeDurablePublishKit,
96
+ makeRecorder,
97
+ );
98
+
99
+ const { faKit } = await provideAll(baggage, {
100
+ faKit: () => makeFluxAggregatorKit(),
101
+ });
102
+ trace('got faKit', faKit);
103
+
104
+ // cannot be stored in baggage because not durable
105
+ // UNTIL https://github.com/Agoric/agoric-sdk/issues/4343
106
+ const { makeDurableGovernorFacet } = handleParamGovernance(
107
+ // @ts-expect-error FIXME include Governance params
108
+ zcf,
109
+ initialPoserInvitation,
110
+ {
111
+ // No governed parameters. Governance just for API methods.
112
+ },
113
+ storageNode,
114
+ marshaller,
115
+ );
116
+
117
+ trace('got makeDurableGovernorFacet', makeDurableGovernorFacet);
118
+
119
+ /**
120
+ * Initialize a new oracle and send an invitation to control it.
121
+ *
122
+ * @param {string} addr
123
+ */
124
+ const addOracle = async addr => {
125
+ trace('addOracle', addr);
126
+ const invitation = await E(faKit.creator).makeOracleInvitation(addr);
127
+ // XXX imported from 'proposals' path
128
+ await reserveThenDeposit(
129
+ `fluxAggregator oracle ${addr}`,
130
+ namesByAddressAdmin,
131
+ addr,
132
+ [invitation],
133
+ );
134
+ if (highPrioritySendersManager) {
135
+ // eslint-disable-next-line @jessie.js/no-nested-await -- after another await
136
+ await E(highPrioritySendersManager).add(description, addr);
137
+ }
138
+ return `added ${addr}`;
139
+ };
140
+
141
+ /**
142
+ * Remove an oracle from aggregation and disable its facet.
143
+ *
144
+ * @param {string} addr
145
+ */
146
+ const removeOracle = async addr => {
147
+ trace('removeOracle', addr);
148
+ await E(faKit.creator).removeOracle(addr);
149
+ if (highPrioritySendersManager) {
150
+ // eslint-disable-next-line @jessie.js/no-nested-await -- after another await
151
+ await E(highPrioritySendersManager).remove(description, addr);
152
+ }
153
+ return `removed ${addr}`;
154
+ };
155
+
156
+ const governedApis = {
157
+ /**
158
+ * Add the specified oracles. May partially fail, such that some oracles are added and others aren't.
159
+ *
160
+ * @param {string[]} addrs
161
+ * @returns {Promise<Array<PromiseSettledResult<string>>>}
162
+ */
163
+ addOracles: addrs => {
164
+ return Promise.allSettled(addrs.map(addOracle));
165
+ },
166
+ /**
167
+ * Remove the specified oracles. May partially fail, such that some oracles are removed and others aren't.
168
+ * If the oracle was never part of the set that's a PromiseRejectedResult
169
+ *
170
+ * @param {string[]} addrs
171
+ * @returns {Promise<Array<PromiseSettledResult<string>>>}
172
+ */
173
+ removeOracles: addrs => {
174
+ return Promise.allSettled(addrs.map(removeOracle));
175
+ },
176
+ };
177
+
178
+ const { governorFacet } = makeDurableGovernorFacet(
179
+ baggage,
180
+ faKit.creator,
181
+ governedApis,
182
+ );
183
+ trace('made governorFacet', governorFacet);
184
+
185
+ return harden({
186
+ creatorFacet: governorFacet,
187
+ publicFacet: faKit.public,
188
+ });
189
+ };
190
+ harden(prepare);
@@ -0,0 +1,375 @@
1
+ /**
2
+ * @file
3
+ * Adaptation of Chainlink algorithm to the Agoric platform.
4
+ * Modeled on https://github.com/smartcontractkit/chainlink/blob/master/contracts/src/v0.6/FluxAggregator.sol (version?)
5
+ */
6
+ import { AmountMath } from '@agoric/ertp';
7
+ import { assertAllDefined, makeTracer } from '@agoric/internal';
8
+ import {
9
+ makeNotifierFromSubscriber,
10
+ observeNotifier,
11
+ SubscriberShape,
12
+ } from '@agoric/notifier';
13
+ import { M, makeScalarBigMapStore, prepareExoClassKit } from '@agoric/vat-data';
14
+ import {
15
+ defineRecorderKit,
16
+ makeOnewayPriceAuthorityKit,
17
+ makeRecorderTopic,
18
+ provideAll,
19
+ } from '@agoric/zoe/src/contractSupport/index.js';
20
+ import { E } from '@endo/eventual-send';
21
+ import { Far } from '@endo/marshal';
22
+ import { prepareOracleAdminKit } from './priceOracleKit.js';
23
+ import { prepareRoundsManagerKit } from './roundsManager.js';
24
+
25
+ const trace = makeTracer('FlxAgg', true);
26
+
27
+ export const INVITATION_MAKERS_DESC = 'oracle invitation';
28
+
29
+ /**
30
+ * @typedef {import('@agoric/vat-data').Baggage} Baggage
31
+ * @typedef {import('@agoric/time/src/types').Timestamp} Timestamp
32
+ * @typedef {import('@agoric/time/src/types').RelativeTime} RelativeTime
33
+ * // TODO: use RelativeTime, not RelativeTimeValue
34
+ * @typedef {import('@agoric/time/src/types').RelativeTimeValue} RelativeTimeValue
35
+ * @typedef {import('@agoric/time/src/types').TimerService} TimerService
36
+ */
37
+
38
+ /** @type {(quote: PriceQuote) => PriceDescription} */
39
+ const priceDescriptionFromQuote = quote => quote.quoteAmount.value[0];
40
+
41
+ /**
42
+ * @typedef {object} RoundState
43
+ * @property {boolean} eligibleForSpecificRound
44
+ * @property {bigint} queriedRoundId
45
+ * @property {bigint} latestSubmission
46
+ * @property {Timestamp} startedAt
47
+ * @property {number} roundTimeout
48
+ * @property {number} oracleCount
49
+ */
50
+
51
+ // Partly documented at https://github.com/smartcontractkit/chainlink/blob/b045416ebca769aa69bde2da23b5109abe07a8b5/contracts/src/v0.6/FluxAggregator.sol#L153
52
+ /**
53
+ * @typedef {object} ChainlinkConfig
54
+ * @property {number} maxSubmissionCount
55
+ * @property {number} minSubmissionCount
56
+ * @property {bigint} restartDelay the number of rounds an Oracle has to wait before they can initiate a round
57
+ * @property {number} minSubmissionValue an immutable check for a lower bound of what
58
+ * submission values are accepted from an oracle
59
+ * @property {number} maxSubmissionValue an immutable check for an upper bound of what
60
+ * submission values are accepted from an oracle
61
+ * @property {number} timeout the number of seconds after the previous round that
62
+ * allowed to lapse before allowing an oracle to skip an unfinished round
63
+ */
64
+
65
+ /**
66
+ * Returns a maker for a single durable FluxAggregatorKit, closed over the prepare() arguments.
67
+ *
68
+ * The kit aggregates price inputs to produce a PriceAuthority. Unlike the
69
+ * simpler `priceAggregator.js`, this approximates the *Node Operator
70
+ * Aggregation* logic of [Chainlink price
71
+ * feeds](https://blog.chain.link/levels-of-data-aggregation-in-chainlink-price-feeds/).
72
+ *
73
+ * @param {Baggage} baggage
74
+ * @param {ZCF<ChainlinkConfig & {
75
+ * timer: TimerService,
76
+ * brandIn: Brand<'nat'>,
77
+ * brandOut: Brand<'nat'>,
78
+ * unitAmountIn?: Amount<'nat'>,
79
+ * }>} zcf
80
+ * @param {TimerService} timerPresence
81
+ * @param {import('./roundsManager.js').QuoteKit} quoteKit
82
+ * @param {StorageNode} storageNode
83
+ * @param {() => PublishKit<any>} makeDurablePublishKit
84
+ * @param {import('@agoric/zoe/src/contractSupport/recorder.js').MakeRecorder} makeRecorder
85
+ */
86
+ export const prepareFluxAggregatorKit = async (
87
+ baggage,
88
+ zcf,
89
+ timerPresence,
90
+ quoteKit,
91
+ storageNode,
92
+ makeDurablePublishKit,
93
+ makeRecorder,
94
+ ) => {
95
+ // brands come from named terms instead of `brands` key because the latter is
96
+ // a StandardTerm that Zoe creates from the `issuerKeywordRecord` argument and
97
+ // Oracle brands are inert (without issuers or mints).
98
+ const {
99
+ brandIn,
100
+ brandOut,
101
+ maxSubmissionCount,
102
+ maxSubmissionValue,
103
+ minSubmissionCount,
104
+ minSubmissionValue,
105
+ restartDelay,
106
+ timeout,
107
+
108
+ unitAmountIn = AmountMath.make(brandIn, 1n),
109
+ } = zcf.getTerms();
110
+
111
+ assertAllDefined({
112
+ brandIn,
113
+ brandOut,
114
+ maxSubmissionCount,
115
+ maxSubmissionValue,
116
+ minSubmissionCount,
117
+ minSubmissionValue,
118
+ restartDelay,
119
+ timeout,
120
+ unitAmountIn,
121
+ });
122
+
123
+ const makeRoundsManagerKit = prepareRoundsManagerKit(baggage);
124
+ const makeOracleAdminKit = prepareOracleAdminKit(baggage);
125
+
126
+ const makeRecorderKit = defineRecorderKit({
127
+ // @ts-expect-error XXX
128
+ makeDurablePublishKit,
129
+ makeRecorder,
130
+ });
131
+
132
+ // end of maker definitions /////////////////////////////////
133
+
134
+ const { answerKit, latestRoundKit, priceKit } = await provideAll(baggage, {
135
+ /** This is just a signal that there's a new answer, which is read from `lastValueOutForUnitIn` */
136
+ answerKit: () => makeDurablePublishKit(),
137
+ /** For publishing priceAuthority values to off-chain storage */
138
+ priceKit: () =>
139
+ makeRecorderKit(
140
+ storageNode,
141
+ /** @type {import('@agoric/zoe/src/contractSupport/recorder.js').TypedMatcher<PriceDescription>} */ (
142
+ M.any()
143
+ ),
144
+ ),
145
+ latestRoundKit: () =>
146
+ E.when(E(storageNode).makeChildNode('latestRound'), node =>
147
+ makeRecorderKit(
148
+ node,
149
+ /** @type {import('@agoric/zoe/src/contractSupport/recorder.js').TypedMatcher<import('./roundsManager.js').LatestRound>} */ (
150
+ M.any()
151
+ ),
152
+ ),
153
+ ),
154
+ });
155
+
156
+ const { roundsManagerKit } = await provideAll(baggage, {
157
+ roundsManagerKit: () =>
158
+ makeRoundsManagerKit(
159
+ harden({
160
+ answerPublisher: answerKit.publisher,
161
+ brandIn,
162
+ brandOut,
163
+ latestRoundPublisher: latestRoundKit.recorder,
164
+ minSubmissionCount,
165
+ maxSubmissionCount,
166
+ minSubmissionValue,
167
+ maxSubmissionValue,
168
+ quoteKit,
169
+ restartDelay,
170
+ timerPresence,
171
+ timeout,
172
+ unitAmountIn,
173
+ }),
174
+ ),
175
+ });
176
+
177
+ // not durable, held in closure and remade in every call of enclosing
178
+ const { priceAuthority } = makeOnewayPriceAuthorityKit({
179
+ createQuote: roundsManagerKit.contract.makeCreateQuote(),
180
+ notifier: makeNotifierFromSubscriber(answerKit.subscriber),
181
+ quoteIssuer: quoteKit.issuer,
182
+ timer: timerPresence,
183
+ actualBrandIn: brandIn,
184
+ actualBrandOut: brandOut,
185
+ });
186
+
187
+ // for each new quote from the priceAuthority, publish it to off-chain storage
188
+ void observeNotifier(
189
+ priceAuthority.makeQuoteNotifier(unitAmountIn, brandOut),
190
+ {
191
+ updateState: quote => {
192
+ void priceKit.recorder.write(priceDescriptionFromQuote(quote));
193
+ },
194
+ fail: reason => {
195
+ throw Error(`priceAuthority observer failed: ${reason}`);
196
+ },
197
+ finish: done => {
198
+ throw Error(`priceAuthority observer died: ${done}`);
199
+ },
200
+ },
201
+ );
202
+
203
+ const makeFluxAggregatorKit = prepareExoClassKit(
204
+ baggage,
205
+ 'fluxAggregator',
206
+ {
207
+ creator: M.interface('fluxAggregator creatorFacet', {}, { sloppy: true }),
208
+ public: M.interface('fluxAggregator publicFacet', {
209
+ getPriceAuthority: M.call().returns(M.any()),
210
+ getSubscriber: M.call().returns(SubscriberShape),
211
+ getRoundStartNotifier: M.call().returns(SubscriberShape),
212
+ getPublicTopics: M.call().returns({
213
+ quotes: M.any(),
214
+ latestRound: M.any(),
215
+ }),
216
+ }),
217
+ },
218
+ () => {
219
+ /** @type {MapStore<string, import('./priceOracleKit.js').OracleKit>} */
220
+ const oracles = makeScalarBigMapStore('oracles', {
221
+ durable: true,
222
+ });
223
+ return { oracles };
224
+ },
225
+ {
226
+ creator: {
227
+ /**
228
+ * An "oracle invitation" is an invitation to be able to submit data to
229
+ * include in the priceAggregator's results.
230
+ *
231
+ * The offer result from this invitation is a OracleAdmin, which can be used
232
+ * directly to manage the price submissions as well as to terminate the
233
+ * relationship.
234
+ *
235
+ * @param {string} oracleId unique per contract instance
236
+ */
237
+ async makeOracleInvitation(oracleId) {
238
+ const { facets } = this;
239
+ trace('makeOracleInvitation', oracleId);
240
+ /**
241
+ * If custom arguments are supplied to the `zoe.offer` call, they can
242
+ * indicate an OraclePriceSubmission notifier and a corresponding
243
+ * `shiftValueOut` that should be adapted as part of the priceAuthority's
244
+ * reported data.
245
+ *
246
+ * @param {ZCFSeat} seat
247
+ */
248
+ const offerHandler = async seat => {
249
+ const { oracle } = await facets.creator.initOracle(oracleId);
250
+ const invitationMakers = Far('invitation makers', {
251
+ /** @param {import('./roundsManager.js').PriceRound} result */
252
+ PushPrice(result) {
253
+ return zcf.makeInvitation(
254
+ /** @param {ZCFSeat} cSeat */
255
+ async cSeat => {
256
+ cSeat.exit();
257
+ await oracle.pushPrice(result);
258
+ },
259
+ 'PushPrice',
260
+ );
261
+ },
262
+ });
263
+ seat.exit();
264
+
265
+ return harden({
266
+ invitationMakers,
267
+ oracle,
268
+ });
269
+ };
270
+
271
+ return zcf.makeInvitation(offerHandler, INVITATION_MAKERS_DESC);
272
+ },
273
+ /** @param {string} oracleId */
274
+ async removeOracle(oracleId) {
275
+ const { oracles } = this.state;
276
+ trace('deleteOracle', oracleId);
277
+ const kit = oracles.get(oracleId);
278
+ kit.admin.disable();
279
+ oracles.delete(oracleId);
280
+ },
281
+
282
+ getRoundData: roundIdRaw => {
283
+ return roundsManagerKit.contract.getRoundData(roundIdRaw);
284
+ },
285
+
286
+ /** @param {string} oracleId */
287
+ async initOracle(oracleId) {
288
+ const { oracles } = this.state;
289
+ trace('initOracle', oracleId);
290
+ assert.typeof(oracleId, 'string');
291
+
292
+ const oracleKit = makeOracleAdminKit(
293
+ harden({
294
+ minSubmissionValue,
295
+ maxSubmissionValue,
296
+ oracleId, // must be unique per vat
297
+ roundPowers: roundsManagerKit.oracle,
298
+ timer: timerPresence,
299
+ }),
300
+ );
301
+ oracles.init(oracleId, oracleKit);
302
+
303
+ return oracleKit;
304
+ },
305
+
306
+ /**
307
+ * a method to provide all current info oracleStatuses need. Intended only
308
+ * only to be callable by oracleStatuses. Not for use by contracts to read state.
309
+ *
310
+ * @param {string} oracleId
311
+ * @param {bigint} queriedRoundId
312
+ * @returns {Promise<RoundState>}
313
+ */
314
+ async oracleRoundState(oracleId, queriedRoundId) {
315
+ const { oracles } = this.state;
316
+ const blockTimestamp = await E(timerPresence).getCurrentTimestamp();
317
+ const status = await E(oracles.get(oracleId).oracle).getStatus();
318
+
319
+ const oracleCount = oracles.getSize();
320
+
321
+ const { contract } = roundsManagerKit;
322
+ if (queriedRoundId > 0) {
323
+ const roundStatus = contract.getRoundStatus(queriedRoundId);
324
+ return {
325
+ eligibleForSpecificRound: contract.eligibleForSpecificRound(
326
+ status,
327
+ queriedRoundId,
328
+ blockTimestamp,
329
+ ),
330
+ queriedRoundId,
331
+ latestSubmission: status.latestSubmission,
332
+ startedAt: roundStatus.startedAt,
333
+ roundTimeout: roundStatus.roundTimeout,
334
+ oracleCount,
335
+ };
336
+ } else {
337
+ return {
338
+ ...contract.oracleRoundStateSuggestRound(status, blockTimestamp),
339
+ oracleCount,
340
+ };
341
+ }
342
+ },
343
+ },
344
+ public: {
345
+ getPriceAuthority() {
346
+ return priceAuthority;
347
+ },
348
+ /** @deprecated use getPublicTopics */
349
+ getSubscriber: () => {
350
+ return priceKit.subscriber;
351
+ },
352
+ /** @deprecated use getPublicTopics */
353
+ getRoundStartNotifier() {
354
+ return latestRoundKit.subscriber;
355
+ },
356
+ getPublicTopics() {
357
+ return {
358
+ quotes: makeRecorderTopic(
359
+ 'Quotes from this price aggregator',
360
+ priceKit,
361
+ ),
362
+ latestRound: makeRecorderTopic(
363
+ 'Notification of each round',
364
+ latestRoundKit,
365
+ ),
366
+ };
367
+ },
368
+ },
369
+ },
370
+ );
371
+
372
+ return makeFluxAggregatorKit;
373
+ };
374
+ harden(prepareFluxAggregatorKit);
375
+ /** @typedef {ReturnType<Awaited<ReturnType<typeof prepareFluxAggregatorKit>>>} FluxAggregatorKit */
@@ -0,0 +1,127 @@
1
+ import { Fail } from '@agoric/assert';
2
+ import { makeTracer } from '@agoric/internal';
3
+ import { M, prepareExoClassKit } from '@agoric/vat-data';
4
+
5
+ const trace = makeTracer('OrKit', true);
6
+
7
+ export const INVITATION_MAKERS_DESC = 'oracle invitation';
8
+
9
+ /**
10
+ * @typedef {{
11
+ * oracleId: string,
12
+ * roundPowers: { handlePush: (status: OracleStatus, result: import('./roundsManager.js').PriceRound) => Promise<OracleStatus> }
13
+ * }} HeldParams
14
+ */
15
+
16
+ /**
17
+ * @typedef {{ roundId: number | undefined, unitPrice: NatValue }} PriceDatum
18
+ */
19
+
20
+ /**
21
+ * @typedef {object} OracleStatus
22
+ * @property {boolean} [disabled]
23
+ * @property {bigint} lastReportedRound
24
+ * @property {bigint} lastStartedRound
25
+ * @property {bigint} latestSubmission
26
+ * @property {string} oracleId
27
+ */
28
+ /**
29
+ * @typedef {Readonly<HeldParams & {
30
+ * }>} ImmutableState
31
+ *
32
+ * @typedef {OracleStatus & {
33
+ * }} MutableState
34
+ */
35
+ /** @typedef {ImmutableState & MutableState} State */
36
+
37
+ /**
38
+ * @param {HeldParams} heldParams
39
+ * @returns {State}
40
+ */
41
+ const initState = ({ oracleId, roundPowers }) => {
42
+ return {
43
+ oracleId,
44
+ roundPowers,
45
+ disabled: false,
46
+ lastReportedRound: 0n,
47
+ lastStartedRound: 0n,
48
+ latestSubmission: 0n,
49
+ };
50
+ };
51
+
52
+ const AdminI = M.interface('OracleKitAdmin', {
53
+ disable: M.call().returns(),
54
+ });
55
+
56
+ const OracleI = M.interface('Oracle', {
57
+ pushPrice: M.call(
58
+ M.splitRecord(
59
+ { unitPrice: M.bigint() },
60
+ { roundId: M.or(M.bigint(), M.number()) },
61
+ ),
62
+ ).returns(M.promise()),
63
+ getStatus: M.call().returns(M.record()),
64
+ });
65
+
66
+ export const prepareOracleAdminKit = baggage =>
67
+ prepareExoClassKit(
68
+ baggage,
69
+ 'OracleKit',
70
+ { admin: AdminI, oracle: OracleI },
71
+ initState,
72
+ {
73
+ admin: {
74
+ disable() {
75
+ trace(`oracle ${this.state.oracleId} disabled`);
76
+ this.state.disabled = true;
77
+ },
78
+ },
79
+ oracle: {
80
+ /**
81
+ * push a unitPrice result from this oracle
82
+ *
83
+ * @param {PriceDatum} datum
84
+ */
85
+ async pushPrice({
86
+ roundId: roundIdRaw = undefined,
87
+ unitPrice: valueRaw,
88
+ }) {
89
+ const { state } = this;
90
+ !state.disabled || Fail`pushPrice for disabled oracle`;
91
+ const { roundPowers } = state;
92
+ const result = await roundPowers.handlePush(
93
+ {
94
+ oracleId: state.oracleId,
95
+ lastReportedRound: state.lastReportedRound,
96
+ lastStartedRound: state.lastStartedRound,
97
+ latestSubmission: state.latestSubmission,
98
+ },
99
+ {
100
+ roundId: roundIdRaw,
101
+ unitPrice: valueRaw,
102
+ },
103
+ );
104
+
105
+ state.lastReportedRound = result.lastReportedRound;
106
+ state.lastStartedRound = result.lastStartedRound;
107
+ state.latestSubmission = result.latestSubmission;
108
+ },
109
+ /**
110
+ *
111
+ * @returns {OracleStatus}
112
+ */
113
+ getStatus() {
114
+ const { state } = this;
115
+ return {
116
+ oracleId: state.oracleId,
117
+ disabled: state.disabled,
118
+ lastReportedRound: state.lastReportedRound,
119
+ lastStartedRound: state.lastStartedRound,
120
+ latestSubmission: state.latestSubmission,
121
+ };
122
+ },
123
+ },
124
+ },
125
+ );
126
+
127
+ /** @typedef {ReturnType<ReturnType<typeof prepareOracleAdminKit>>} OracleKit */