@agoric/inter-protocol 0.13.3 → 0.13.4-dev-d32a66a.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 (140) hide show
  1. package/README.md +26 -20
  2. package/bundles/bundle-auctioneer-js-meta.json +722 -0
  3. package/bundles/bundle-auctioneer.js +1 -0
  4. package/bundles/bundle-econCommitteeCharter-js-meta.json +514 -0
  5. package/bundles/bundle-econCommitteeCharter.js +1 -0
  6. package/bundles/bundle-feeDistributor-js-meta.json +458 -0
  7. package/bundles/bundle-feeDistributor.js +1 -1
  8. package/bundles/bundle-fluxAggregatorKit-js-meta.json +674 -0
  9. package/bundles/bundle-fluxAggregatorKit.js +1 -0
  10. package/bundles/bundle-psm-js-meta.json +666 -0
  11. package/bundles/bundle-psm.js +1 -1
  12. package/bundles/bundle-reserve-js-meta.json +662 -0
  13. package/bundles/bundle-reserve.js +1 -1
  14. package/bundles/bundle-scaledPriceAuthority-js-meta.json +542 -0
  15. package/bundles/bundle-scaledPriceAuthority.js +1 -1
  16. package/bundles/bundle-vaultFactory-js-meta.json +786 -0
  17. package/bundles/bundle-vaultFactory.js +1 -1
  18. package/exported.js +0 -2
  19. package/package.json +34 -31
  20. package/scripts/add-collateral-core.js +14 -4
  21. package/scripts/build-bundles.js +9 -2
  22. package/scripts/deploy-contracts.js +1 -4
  23. package/scripts/init-core.js +20 -38
  24. package/scripts/invite-committee-core.js +1 -1
  25. package/scripts/manual-price-feed.js +2 -2
  26. package/scripts/price-feed-core.js +7 -6
  27. package/scripts/start-local-chain.sh +84 -0
  28. package/src/auction/auctionBook.js +755 -0
  29. package/src/auction/auctioneer.js +720 -0
  30. package/src/auction/offerBook.js +221 -0
  31. package/src/auction/params.js +174 -0
  32. package/src/auction/scheduleMath.js +167 -0
  33. package/src/auction/scheduler.js +370 -0
  34. package/src/auction/sortedOffers.js +136 -0
  35. package/src/auction/util.js +55 -0
  36. package/src/clientSupport.js +324 -0
  37. package/src/collectFees.js +8 -14
  38. package/src/contractSupport.js +24 -68
  39. package/src/econCommitteeCharter.js +161 -77
  40. package/src/feeDistributor.js +60 -20
  41. package/src/index.js +2 -0
  42. package/src/interest-math.js +1 -4
  43. package/src/interest.js +20 -13
  44. package/src/price/README.md +57 -0
  45. package/src/price/fluxAggregatorContract.js +190 -0
  46. package/src/price/fluxAggregatorKit.js +375 -0
  47. package/src/price/priceOracleKit.js +127 -0
  48. package/src/price/roundsManager.js +726 -0
  49. package/src/proposals/addAssetToVault.js +89 -94
  50. package/src/proposals/committee-proposal.js +141 -40
  51. package/src/proposals/core-proposal.js +100 -167
  52. package/src/proposals/econ-behaviors.js +320 -564
  53. package/src/proposals/price-feed-proposal.js +175 -78
  54. package/src/proposals/startEconCommittee.js +25 -12
  55. package/src/proposals/startPSM.js +231 -211
  56. package/src/proposals/utils.js +31 -17
  57. package/src/psm/README.md +71 -0
  58. package/src/psm/psm.js +272 -160
  59. package/src/psm/types.js +2 -0
  60. package/src/reserve/assetReserve.js +56 -413
  61. package/src/reserve/assetReserveKit.js +303 -0
  62. package/src/reserve/doc.md +1 -3
  63. package/src/reserve/params.js +2 -5
  64. package/src/typeGuards.js +13 -0
  65. package/src/vaultFactory/Liquidation.md +100 -0
  66. package/src/vaultFactory/burn.js +2 -1
  67. package/src/vaultFactory/liquidation.js +270 -108
  68. package/src/vaultFactory/math.js +95 -0
  69. package/src/vaultFactory/orderedVaultStore.js +0 -1
  70. package/src/vaultFactory/params.js +133 -112
  71. package/src/vaultFactory/prioritizedVaults.js +36 -79
  72. package/src/vaultFactory/storeUtils.js +67 -9
  73. package/src/vaultFactory/type-imports.js +2 -0
  74. package/src/vaultFactory/types.js +22 -26
  75. package/src/vaultFactory/vault.js +772 -709
  76. package/src/vaultFactory/vaultDirector.js +480 -483
  77. package/src/vaultFactory/vaultFactory.js +99 -60
  78. package/src/vaultFactory/vaultHolder.js +121 -95
  79. package/src/vaultFactory/vaultKit.js +39 -31
  80. package/src/vaultFactory/vaultManager.js +1249 -868
  81. package/bundles/bundle-amm-meta.js +0 -618
  82. package/bundles/bundle-amm.js +0 -1
  83. package/bundles/bundle-feeDistributor-meta.js +0 -346
  84. package/bundles/bundle-interchainPool-meta.js +0 -534
  85. package/bundles/bundle-interchainPool.js +0 -1
  86. package/bundles/bundle-liquidateIncrementally-meta.js +0 -442
  87. package/bundles/bundle-liquidateIncrementally.js +0 -1
  88. package/bundles/bundle-liquidateMinimum-meta.js +0 -442
  89. package/bundles/bundle-liquidateMinimum.js +0 -1
  90. package/bundles/bundle-psm-meta.js +0 -538
  91. package/bundles/bundle-psmCharter-meta.js +0 -418
  92. package/bundles/bundle-psmCharter.js +0 -1
  93. package/bundles/bundle-reserve-meta.js +0 -542
  94. package/bundles/bundle-scaledPriceAuthority-meta.js +0 -442
  95. package/bundles/bundle-stakeFactory-meta.js +0 -574
  96. package/bundles/bundle-stakeFactory.js +0 -1
  97. package/bundles/bundle-vaultFactory-meta.js +0 -598
  98. package/scripts/add-initial-liquidity.js +0 -180
  99. package/src/collect.js +0 -13
  100. package/src/interchainPool.js +0 -135
  101. package/src/makeTracer.js +0 -36
  102. package/src/my-lien.js +0 -85
  103. package/src/proposals/demoIssuers.js +0 -685
  104. package/src/proposals/sim-behaviors.js +0 -40
  105. package/src/psm/psmCharter.js +0 -139
  106. package/src/stakeFactory/README.md +0 -62
  107. package/src/stakeFactory/attestation.js +0 -267
  108. package/src/stakeFactory/attestationTool.js +0 -66
  109. package/src/stakeFactory/constants.js +0 -16
  110. package/src/stakeFactory/params.js +0 -31
  111. package/src/stakeFactory/stakeFactory.js +0 -236
  112. package/src/stakeFactory/stakeFactoryKit.js +0 -455
  113. package/src/stakeFactory/stakeFactoryManager.js +0 -296
  114. package/src/stakeFactory/types.js +0 -42
  115. package/src/vaultFactory/liquidateIncrementally.js +0 -350
  116. package/src/vaultFactory/liquidateMinimum.js +0 -100
  117. package/src/vpool-xyk-amm/AttackersGuide.md +0 -89
  118. package/src/vpool-xyk-amm/addLiquidity.js +0 -222
  119. package/src/vpool-xyk-amm/addPool.js +0 -197
  120. package/src/vpool-xyk-amm/constantProduct/AMM-Trade.jpeg +0 -0
  121. package/src/vpool-xyk-amm/constantProduct/README.md +0 -204
  122. package/src/vpool-xyk-amm/constantProduct/calcFees.js +0 -99
  123. package/src/vpool-xyk-amm/constantProduct/calcSwapPrices.js +0 -85
  124. package/src/vpool-xyk-amm/constantProduct/core.js +0 -153
  125. package/src/vpool-xyk-amm/constantProduct/defaults.js +0 -5
  126. package/src/vpool-xyk-amm/constantProduct/getXY.js +0 -52
  127. package/src/vpool-xyk-amm/constantProduct/internal-types.js +0 -116
  128. package/src/vpool-xyk-amm/constantProduct/invariants.js +0 -43
  129. package/src/vpool-xyk-amm/constantProduct/swap.js +0 -272
  130. package/src/vpool-xyk-amm/constantProduct/types.js +0 -32
  131. package/src/vpool-xyk-amm/doublePool.js +0 -194
  132. package/src/vpool-xyk-amm/estimate.js +0 -155
  133. package/src/vpool-xyk-amm/multipoolMarketMaker.js +0 -520
  134. package/src/vpool-xyk-amm/params.js +0 -61
  135. package/src/vpool-xyk-amm/pool.js +0 -396
  136. package/src/vpool-xyk-amm/priceAuthority.js +0 -94
  137. package/src/vpool-xyk-amm/removeLiquidity.js +0 -31
  138. package/src/vpool-xyk-amm/singlePool.js +0 -73
  139. package/src/vpool-xyk-amm/swap.js +0 -69
  140. 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 */