@agoric/fast-usdc 0.2.0-u18.0 → 0.2.0-u19.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.
@@ -1,7 +1,7 @@
1
1
  import { makeTracer } from '@agoric/internal';
2
2
  import { prepareDurablePublishKit } from '@agoric/notifier';
3
3
  import { keyEQ, M } from '@endo/patterns';
4
- import { Fail } from '@endo/errors';
4
+ import { Fail, quote } from '@endo/errors';
5
5
  import { CctpTxEvidenceShape, RiskAssessmentShape } from '../type-guards.js';
6
6
  import { defineInertInvitation } from '../utils/zoe.js';
7
7
  import { prepareOperatorKit } from './operator-kit.js';
@@ -15,6 +15,10 @@ import { prepareOperatorKit } from './operator-kit.js';
15
15
 
16
16
  const trace = makeTracer('TxFeed', true);
17
17
 
18
+ /**
19
+ * @typedef {Pick<OperatorKit, 'invitationMakers' | 'operator'>} OperatorOfferResult
20
+ */
21
+
18
22
  /** Name in the invitation purse (keyed also by this contract instance) */
19
23
  export const INVITATION_MAKERS_DESC = 'oracle operator invitation';
20
24
 
@@ -27,8 +31,10 @@ const TransactionFeedKitI = harden({
27
31
  ).returns(),
28
32
  }),
29
33
  creator: M.interface('Transaction Feed Creator', {
30
- // TODO narrow the return shape to OperatorKit
31
- initOperator: M.call(M.string()).returns(M.record()),
34
+ initOperator: M.call(M.string()).returns({
35
+ invitationMakers: M.remotable(),
36
+ operator: M.remotable(),
37
+ }),
32
38
  makeOperatorInvitation: M.call(M.string()).returns(M.promise()),
33
39
  removeOperator: M.call(M.string()).returns(),
34
40
  }),
@@ -53,6 +59,12 @@ const allRisksIdentified = (riskStores, txHash) => {
53
59
  return [...setOfRisks.values()].sort();
54
60
  };
55
61
 
62
+ export const stateShape = {
63
+ operators: M.remotable(),
64
+ pending: M.remotable(),
65
+ risks: M.remotable(),
66
+ };
67
+
56
68
  /**
57
69
  * @param {Zone} zone
58
70
  * @param {ZCF} zcf
@@ -92,14 +104,14 @@ export const prepareTransactionFeedKit = (zone, zcf) => {
92
104
  * CCTP transactions.
93
105
  *
94
106
  * @param {string} operatorId unique per contract instance
95
- * @returns {Promise<Invitation<OperatorKit>>}
107
+ * @returns {Promise<Invitation<OperatorOfferResult>>}
96
108
  */
97
109
  makeOperatorInvitation(operatorId) {
98
110
  const { creator } = this.facets;
99
111
  trace('makeOperatorInvitation', operatorId);
100
112
 
101
113
  return zcf.makeInvitation(
102
- /** @type {OfferHandler<OperatorKit>} */
114
+ /** @type {OfferHandler<OperatorOfferResult>} */
103
115
  seat => {
104
116
  seat.exit();
105
117
  return creator.initOperator(operatorId);
@@ -107,7 +119,10 @@ export const prepareTransactionFeedKit = (zone, zcf) => {
107
119
  INVITATION_MAKERS_DESC,
108
120
  );
109
121
  },
110
- /** @param {string} operatorId */
122
+ /**
123
+ * @param {string} operatorId
124
+ * @returns {OperatorOfferResult}
125
+ */
111
126
  initOperator(operatorId) {
112
127
  const { operators, pending, risks } = this.state;
113
128
  trace('initOperator', operatorId);
@@ -123,11 +138,16 @@ export const prepareTransactionFeedKit = (zone, zcf) => {
123
138
  );
124
139
  risks.init(operatorId, zone.detached().mapStore('risk assessments'));
125
140
 
126
- return operatorKit;
141
+ // Subset facets to all the off-chain operator needs
142
+ const { invitationMakers, operator } = operatorKit;
143
+ return {
144
+ invitationMakers,
145
+ operator,
146
+ };
127
147
  },
128
148
 
129
149
  /** @param {string} operatorId */
130
- async removeOperator(operatorId) {
150
+ removeOperator(operatorId) {
131
151
  const { operators } = this.state;
132
152
  trace('removeOperator', operatorId);
133
153
  const operatorKit = operators.get(operatorId);
@@ -201,7 +221,7 @@ export const prepareTransactionFeedKit = (zone, zcf) => {
201
221
  '!=',
202
222
  next,
203
223
  );
204
- Fail`conflicting evidence for ${txHash}`;
224
+ Fail`conflicting evidence for ${quote(txHash)}`;
205
225
  }
206
226
  }
207
227
  lastEvidence = next;
@@ -231,6 +251,7 @@ export const prepareTransactionFeedKit = (zone, zcf) => {
231
251
  getEvidenceSubscriber: () => subscriber,
232
252
  },
233
253
  },
254
+ { stateShape },
234
255
  );
235
256
  };
236
257
  harden(prepareTransactionFeedKit);
@@ -3,8 +3,10 @@
3
3
  import { E } from '@endo/far';
4
4
  import { fromExternalConfig } from './utils/config-marshal.js';
5
5
  import { FeedPolicyShape } from './type-guards.js';
6
+ import { publishFeedPolicy } from './utils/core-eval.js';
6
7
 
7
8
  /**
9
+ * @import {Issuer} from '@agoric/ertp';
8
10
  * @import {Passable} from '@endo/pass-style'
9
11
  * @import {BootstrapManifest} from '@agoric/vats/src/core/lib-boot.js'
10
12
  * @import {LegibleCapData} from './utils/config-marshal.js'
@@ -12,18 +14,6 @@ import { FeedPolicyShape } from './type-guards.js';
12
14
  */
13
15
 
14
16
  const contractName = 'fastUsdc';
15
- const FEED_POLICY = 'feedPolicy';
16
-
17
- /**
18
- * XXX copied from fast-usdc.start.js
19
- *
20
- * @param {ERef<StorageNode>} node
21
- * @param {FeedPolicy} policy
22
- */
23
- const publishFeedPolicy = async (node, policy) => {
24
- const feedPolicy = E(node).makeChildNode(FEED_POLICY);
25
- await E(feedPolicy).setValue(JSON.stringify(policy));
26
- };
27
17
 
28
18
  /**
29
19
  * @param {BootstrapPowers &
@@ -22,7 +22,6 @@ import { prepareStatusManager } from './exos/status-manager.js';
22
22
  import { prepareTransactionFeedKit } from './exos/transaction-feed.js';
23
23
  import * as flows from './fast-usdc.flows.js';
24
24
  import { FastUSDCTermsShape, FeeConfigShape } from './type-guards.js';
25
- import { defineInertInvitation } from './utils/zoe.js';
26
25
 
27
26
  const trace = makeTracer('FastUsdc');
28
27
 
@@ -37,8 +36,9 @@ const ADDRESSES_BAGGAGE_KEY = 'addresses';
37
36
  * @import {Remote} from '@agoric/internal';
38
37
  * @import {Marshaller, StorageNode} from '@agoric/internal/src/lib-chainStorage.js'
39
38
  * @import {Zone} from '@agoric/zone';
39
+ * @import {OperatorOfferResult} from './exos/transaction-feed.js';
40
40
  * @import {OperatorKit} from './exos/operator-kit.js';
41
- * @import {CctpTxEvidence, FeeConfig, RiskAssessment} from './types.js';
41
+ * @import {CctpTxEvidence, ContractRecord, FeeConfig} from './types.js';
42
42
  */
43
43
 
44
44
  /**
@@ -76,10 +76,7 @@ const publishFeeConfig = async (node, marshaller, feeConfig) => {
76
76
 
77
77
  /**
78
78
  * @param {Remote<StorageNode>} contractNode
79
- * @param {{
80
- * poolAccount: ChainAddress['value'];
81
- * settlementAccount: ChainAddress['value'];
82
- * }} addresses
79
+ * @param {ContractRecord} addresses
83
80
  */
84
81
  const publishAddresses = (contractNode, addresses) => {
85
82
  return E(contractNode).setValue(JSON.stringify(addresses));
@@ -93,6 +90,7 @@ const publishAddresses = (contractNode, addresses) => {
93
90
  * feeConfig: FeeConfig;
94
91
  * marshaller: Marshaller;
95
92
  * poolMetricsNode: Remote<StorageNode>;
93
+ * storageNode: Remote<StorageNode>;
96
94
  * }} privateArgs
97
95
  * @param {Zone} zone
98
96
  * @param {OrchestrationTools} tools
@@ -128,11 +126,10 @@ export const contract = async (zcf, privateArgs, zone, tools) => {
128
126
  chainHub,
129
127
  });
130
128
 
131
- const { localTransfer } = makeZoeTools(zcf, vowTools);
129
+ const zoeTools = makeZoeTools(zcf, vowTools);
132
130
  const makeAdvancer = prepareAdvancer(zone, {
133
131
  chainHub,
134
132
  feeConfig,
135
- localTransfer,
136
133
  usdc: harden({
137
134
  brand: terms.brands.USDC,
138
135
  denom: terms.usdcDenom,
@@ -140,6 +137,7 @@ export const contract = async (zcf, privateArgs, zone, tools) => {
140
137
  statusManager,
141
138
  vowTools,
142
139
  zcf,
140
+ zoeTools,
143
141
  });
144
142
 
145
143
  const makeFeedKit = prepareTransactionFeedKit(zone, zcf);
@@ -151,18 +149,24 @@ export const contract = async (zcf, privateArgs, zone, tools) => {
151
149
  { makeRecorderKit },
152
150
  );
153
151
 
154
- const makeTestInvitation = defineInertInvitation(
155
- zcf,
156
- 'test of forcing evidence',
157
- );
158
-
159
152
  const { makeLocalAccount, makeNobleAccount } = orchestrateAll(flows, {});
160
153
 
161
154
  const creatorFacet = zone.exo('Fast USDC Creator', undefined, {
162
- /** @type {(operatorId: string) => Promise<Invitation<OperatorKit>>} */
155
+ /** @type {(operatorId: string) => Promise<Invitation<OperatorOfferResult>>} */
163
156
  async makeOperatorInvitation(operatorId) {
164
157
  return feedKit.creator.makeOperatorInvitation(operatorId);
165
158
  },
159
+ /** @type {(operatorId: string) => void} */
160
+ removeOperator(operatorId) {
161
+ return feedKit.creator.removeOperator(operatorId);
162
+ },
163
+ async getContractFeeBalance() {
164
+ return poolKit.feeRecipient.getContractFeeBalance();
165
+ },
166
+ /** @type {() => Promise<Invitation<unknown>>} */
167
+ async makeWithdrawFeesInvitation() {
168
+ return poolKit.feeRecipient.makeWithdrawFeesInvitation();
169
+ },
166
170
  async connectToNoble() {
167
171
  return vowTools.when(nobleAccountV, nobleAccount => {
168
172
  trace('nobleAccount', nobleAccount);
@@ -190,24 +194,12 @@ export const contract = async (zcf, privateArgs, zone, tools) => {
190
194
  await publishAddresses(storageNode, addresses);
191
195
  return addresses;
192
196
  },
197
+ deleteCompletedTxs() {
198
+ return statusManager.deleteCompletedTxs();
199
+ },
193
200
  });
194
201
 
195
202
  const publicFacet = zone.exo('Fast USDC Public', undefined, {
196
- // XXX to be removed before production
197
- /**
198
- * NB: Any caller with access to this invitation maker has the ability to
199
- * force handling of evidence.
200
- *
201
- * Provide an API call in the form of an invitation maker, so that the
202
- * capability is available in the smart-wallet bridge during UI testing.
203
- *
204
- * @param {CctpTxEvidence} evidence
205
- * @param {RiskAssessment} [risk]
206
- */
207
- makeTestPushInvitation(evidence, risk = {}) {
208
- void advancer.handleTransactionEvent({ evidence, risk });
209
- return makeTestInvitation();
210
- },
211
203
  makeDepositInvitation() {
212
204
  return poolKit.public.makeDepositInvitation();
213
205
  },
@@ -296,8 +288,8 @@ export const contract = async (zcf, privateArgs, zone, tools) => {
296
288
 
297
289
  const advancer = zone.makeOnce('Advancer', () =>
298
290
  makeAdvancer({
299
- borrowerFacet: poolKit.borrower,
300
- notifyFacet: settlerKit.notify,
291
+ borrower: poolKit.borrower,
292
+ notifier: settlerKit.notifier,
301
293
  poolAccount,
302
294
  settlementAddress,
303
295
  }),
package/src/main.js ADDED
@@ -0,0 +1 @@
1
+ export * from './types.js';
@@ -7,9 +7,11 @@ import {
7
7
  } from '@agoric/zoe/src/contractSupport/ratio.js';
8
8
  import { Fail, q } from '@endo/errors';
9
9
 
10
- const { getValue, add, isEmpty, isEqual, isGTE, subtract } = AmountMath;
10
+ const { keys } = Object;
11
+ const { add, isEmpty, isEqual, isGTE, make, makeEmpty, subtract } = AmountMath;
11
12
 
12
13
  /**
14
+ * @import {Amount, Brand, DepositFacet, NatValue, Payment} from '@agoric/ertp';
13
15
  * @import {PoolStats} from './types';
14
16
  * @import {RepayAmountKWR} from './exos/liquidity-pool';
15
17
  */
@@ -17,8 +19,7 @@ const { getValue, add, isEmpty, isEqual, isGTE, subtract } = AmountMath;
17
19
  /**
18
20
  * Invariant: shareWorth is the pool balance divided by shares outstanding.
19
21
  *
20
- * Use `makeParity(make(USDC, epsilon), PoolShares)` for an initial
21
- * value, for some negligible `epsilon` such as 1n.
22
+ * Use `makeParity(USDC, PoolShares)` for an initial value.
22
23
  *
23
24
  * @typedef {Ratio} ShareWorth
24
25
  */
@@ -26,23 +27,26 @@ const { getValue, add, isEmpty, isEqual, isGTE, subtract } = AmountMath;
26
27
  /**
27
28
  * Make a 1-to-1 ratio between amounts of 2 brands.
28
29
  *
29
- * @param {Amount<'nat'>} numerator
30
+ * @param {Brand<'nat'>} numeratorBrand
30
31
  * @param {Brand<'nat'>} denominatorBrand
31
32
  */
32
- export const makeParity = (numerator, denominatorBrand) => {
33
- const value = getValue(numerator.brand, numerator);
34
- return makeRatio(value, numerator.brand, value, denominatorBrand);
33
+ export const makeParity = (numeratorBrand, denominatorBrand) => {
34
+ const dust = 1n;
35
+ return makeRatio(dust, numeratorBrand, dust, denominatorBrand);
35
36
  };
36
37
 
37
38
  /**
38
39
  * @typedef {{
39
40
  * deposit: {
40
41
  * give: { USDC: Amount<'nat'> },
41
- * want?: { PoolShare: Amount<'nat'> }
42
+ * want: { PoolShare: Amount<'nat'> }
42
43
  * },
43
44
  * withdraw: {
44
45
  * give: { PoolShare: Amount<'nat'> }
45
46
  * want: { USDC: Amount<'nat'> },
47
+ * },
48
+ * withdrawFees: {
49
+ * want: { USDC: Amount<'nat'> }
46
50
  * }
47
51
  * }} USDCProposalShapes
48
52
  */
@@ -91,14 +95,54 @@ export const depositCalc = (shareWorth, { give, want }) => {
91
95
  });
92
96
  };
93
97
 
98
+ /**
99
+ * Verifies that the total pool balance (unencumbered + encumbered) matches the
100
+ * shareWorth numerator. The total pool balance consists of:
101
+ * 1. unencumbered balance - USDC available in the pool for borrowing
102
+ * 2. encumbered balance - USDC currently lent out
103
+ *
104
+ * A negligible `dust` amount is used to initialize shareWorth with a non-zero
105
+ * denominator. It must remain in the pool at all times.
106
+ *
107
+ * @param {Allocation} poolAlloc
108
+ * @param {ShareWorth} shareWorth
109
+ * @param {Amount<'nat'>} encumberedBalance
110
+ */
111
+ export const checkPoolBalance = (poolAlloc, shareWorth, encumberedBalance) => {
112
+ const { brand: usdcBrand } = encumberedBalance;
113
+ const unencumberedBalance = poolAlloc.USDC || makeEmpty(usdcBrand);
114
+ const kwds = keys(poolAlloc);
115
+ kwds.length === 0 ||
116
+ (kwds.length === 1 && kwds[0] === 'USDC') ||
117
+ Fail`unexpected pool allocations: ${poolAlloc}`;
118
+ const dust = make(usdcBrand, 1n);
119
+ const grossBalance = add(add(unencumberedBalance, dust), encumberedBalance);
120
+ isEqual(grossBalance, shareWorth.numerator) ||
121
+ Fail`🚨 pool balance ${q(unencumberedBalance)} and encumbered balance ${q(encumberedBalance)} inconsistent with shareWorth ${q(shareWorth)}`;
122
+ return harden({ unencumberedBalance, grossBalance });
123
+ };
124
+
94
125
  /**
95
126
  * Compute payout from a withdraw proposal, along with updated shareWorth
96
127
  *
97
128
  * @param {ShareWorth} shareWorth
98
129
  * @param {USDCProposalShapes['withdraw']} proposal
130
+ * @param {Allocation} poolAlloc
131
+ * @param {Amount<'nat'>} [encumberedBalance]
99
132
  * @returns {{ shareWorth: ShareWorth, payouts: { USDC: Amount<'nat'> }}}
100
133
  */
101
- export const withdrawCalc = (shareWorth, { give, want }) => {
134
+ export const withdrawCalc = (
135
+ shareWorth,
136
+ { give, want },
137
+ poolAlloc,
138
+ encumberedBalance = makeEmpty(shareWorth.numerator.brand),
139
+ ) => {
140
+ const { unencumberedBalance } = checkPoolBalance(
141
+ poolAlloc,
142
+ shareWorth,
143
+ encumberedBalance,
144
+ );
145
+
102
146
  assert(!isEmpty(give.PoolShare));
103
147
  assert(!isEmpty(want.USDC));
104
148
 
@@ -108,6 +152,8 @@ export const withdrawCalc = (shareWorth, { give, want }) => {
108
152
  const { denominator: sharesOutstanding, numerator: poolBalance } = shareWorth;
109
153
  !isGTE(want.USDC, poolBalance) ||
110
154
  Fail`cannot withdraw ${q(want.USDC)}; only ${q(poolBalance)} in pool`;
155
+ isGTE(unencumberedBalance, want.USDC) ||
156
+ Fail`cannot withdraw ${q(want.USDC)}; ${q(encumberedBalance)} is in use; stand by for pool to return to ${q(poolBalance)}`;
111
157
  const balancePost = subtract(poolBalance, payout);
112
158
  // giving more shares than are outstanding is impossible,
113
159
  // so it's not worth a custom diagnostic. subtract will fail
@@ -1,30 +1,22 @@
1
- import { deeplyFulfilledObject, makeTracer, objectMap } from '@agoric/internal';
2
- import {
3
- CosmosChainInfoShape,
4
- DenomDetailShape,
5
- DenomShape,
6
- } from '@agoric/orchestration';
7
- import { Fail } from '@endo/errors';
1
+ import { deeplyFulfilledObject, makeTracer } from '@agoric/internal';
8
2
  import { E } from '@endo/far';
9
- import { makeMarshal } from '@endo/marshal';
10
- import { M } from '@endo/patterns';
11
- import {
12
- FastUSDCTermsShape,
13
- FeeConfigShape,
14
- FeedPolicyShape,
15
- } from './type-guards.js';
3
+ import { FastUSDCConfigShape } from './type-guards.js';
16
4
  import { fromExternalConfig } from './utils/config-marshal.js';
5
+ import {
6
+ inviteOracles,
7
+ publishDisplayInfo,
8
+ publishFeedPolicy,
9
+ } from './utils/core-eval.js';
17
10
 
18
11
  /**
19
- * @import {DepositFacet} from '@agoric/ertp/src/types.js'
20
- * @import {TypedPattern} from '@agoric/internal'
12
+ * @import {Brand, Issuer} from '@agoric/ertp';
21
13
  * @import {Instance, StartParams} from '@agoric/zoe/src/zoeService/utils'
22
14
  * @import {Board} from '@agoric/vats'
23
15
  * @import {ManifestBundleRef} from '@agoric/deploy-script-support/src/externalTypes.js'
24
16
  * @import {BootstrapManifest} from '@agoric/vats/src/core/lib-boot.js'
25
17
  * @import {LegibleCapData} from './utils/config-marshal.js'
26
18
  * @import {FastUsdcSF} from './fast-usdc.contract.js'
27
- * @import {FeedPolicy, FastUSDCConfig} from './types.js'
19
+ * @import {FastUSDCConfig} from './types.js'
28
20
  */
29
21
 
30
22
  const ShareAssetInfo = /** @type {const} */ harden({
@@ -38,16 +30,6 @@ const trace = makeTracer('FUSD-Start', true);
38
30
 
39
31
  const contractName = 'fastUsdc';
40
32
 
41
- /** @type {TypedPattern<FastUSDCConfig>} */
42
- export const FastUSDCConfigShape = M.splitRecord({
43
- terms: FastUSDCTermsShape,
44
- oracles: M.recordOf(M.string(), M.string()),
45
- feeConfig: FeeConfigShape,
46
- feedPolicy: FeedPolicyShape,
47
- chainInfo: M.recordOf(M.string(), CosmosChainInfoShape),
48
- assetInfo: M.arrayOf([DenomShape, DenomDetailShape]),
49
- });
50
-
51
33
  /**
52
34
  * XXX Shouldn't the bridge or board vat handle this?
53
35
  *
@@ -64,38 +46,8 @@ const makePublishingStorageKit = async (path, { chainStorage, board }) => {
64
46
  return { storageNode, marshaller };
65
47
  };
66
48
 
67
- const BOARD_AUX = 'boardAux';
68
- const marshalData = makeMarshal(_val => Fail`data only`);
69
- /**
70
- * @param {Brand} brand
71
- * @param {Pick<BootstrapPowers['consume'], 'board' | 'chainStorage'>} powers
72
- */
73
- const publishDisplayInfo = async (brand, { board, chainStorage }) => {
74
- // chainStorage type includes undefined, which doesn't apply here.
75
- // @ts-expect-error UNTIL https://github.com/Agoric/agoric-sdk/issues/8247
76
- const boardAux = E(chainStorage).makeChildNode(BOARD_AUX);
77
- const [id, displayInfo, allegedName] = await Promise.all([
78
- E(board).getId(brand),
79
- E(brand).getDisplayInfo(),
80
- E(brand).getAllegedName(),
81
- ]);
82
- const node = E(boardAux).makeChildNode(id);
83
- const aux = marshalData.toCapData(harden({ allegedName, displayInfo }));
84
- await E(node).setValue(JSON.stringify(aux));
85
- };
86
-
87
- const FEED_POLICY = 'feedPolicy';
88
49
  const POOL_METRICS = 'poolMetrics';
89
50
 
90
- /**
91
- * @param {ERef<StorageNode>} node
92
- * @param {FeedPolicy} policy
93
- */
94
- const publishFeedPolicy = async (node, policy) => {
95
- const feedPolicy = E(node).makeChildNode(FEED_POLICY);
96
- await E(feedPolicy).setValue(JSON.stringify(policy));
97
- };
98
-
99
51
  /**
100
52
  * @typedef { PromiseSpaceOf<{
101
53
  * fastUsdcKit: FastUSDCKit
@@ -107,6 +59,7 @@ const publishFeedPolicy = async (node, policy) => {
107
59
  * }} FastUSDCCorePowers
108
60
  *
109
61
  * @typedef {StartedInstanceKitWithLabel & {
62
+ * creatorFacet: StartedInstanceKit<FastUsdcSF>['creatorFacet'];
110
63
  * privateArgs: StartParams<FastUsdcSF>['privateArgs'];
111
64
  * }} FastUSDCKit
112
65
  */
@@ -164,18 +117,6 @@ export const startFastUSDC = async (
164
117
  trace('using terms', terms);
165
118
  trace('using fee config', feeConfig);
166
119
 
167
- trace('look up oracle deposit facets');
168
- const oracleDepositFacets = await deeplyFulfilledObject(
169
- objectMap(oracles, async address => {
170
- /** @type {DepositFacet} */
171
- const depositFacet = await E(namesByAddress).lookup(
172
- address,
173
- 'depositFacet',
174
- );
175
- return depositFacet;
176
- }),
177
- );
178
-
179
120
  const { storageNode, marshaller } = await makePublishingStorageKit(
180
121
  contractName,
181
122
  {
@@ -231,16 +172,7 @@ export const startFastUSDC = async (
231
172
  brand: shareBrand,
232
173
  });
233
174
 
234
- await Promise.all(
235
- Object.entries(oracleDepositFacets).map(async ([name, depositFacet]) => {
236
- const address = oracles[name];
237
- trace('making invitation for', name, address);
238
- const toWatch = await E(creatorFacet).makeOperatorInvitation(address);
239
-
240
- const amt = await E(depositFacet).receive(toWatch);
241
- trace('sent', amt, 'to', name);
242
- }),
243
- );
175
+ await inviteOracles({ creatorFacet, namesByAddress }, oracles);
244
176
 
245
177
  produceInstance.reset();
246
178
  produceInstance.resolve(instance);
@@ -293,10 +225,10 @@ export const getManifestForFastUSDC = (
293
225
  board: true,
294
226
  },
295
227
  issuer: {
296
- produce: { FastLP: true }, // UNTIL #10432
228
+ produce: { FastLP: true },
297
229
  },
298
230
  brand: {
299
- produce: { FastLP: true }, // UNTIL #10432
231
+ produce: { FastLP: true },
300
232
  },
301
233
  instance: {
302
234
  produce: { fastUsdc: true },
@@ -1,12 +1,18 @@
1
1
  import { AmountShape, BrandShape, RatioShape } from '@agoric/ertp';
2
2
  import { M } from '@endo/patterns';
3
+ import {
4
+ CosmosChainInfoShape,
5
+ DenomDetailShape,
6
+ DenomShape,
7
+ } from '@agoric/orchestration/src/typeGuards.js';
3
8
  import { PendingTxStatus } from './constants.js';
4
9
 
5
10
  /**
11
+ * @import {Amount, Brand, NatValue, Payment} from '@agoric/ertp';
6
12
  * @import {TypedPattern} from '@agoric/internal';
7
13
  * @import {FastUsdcTerms} from './fast-usdc.contract.js';
8
14
  * @import {USDCProposalShapes} from './pool-share-math.js';
9
- * @import {CctpTxEvidence, FeeConfig, PendingTx, PoolMetrics, ChainPolicy, FeedPolicy, AddressHook, EvmAddress, EvmHash, RiskAssessment, EvidenceWithRisk} from './types.js';
15
+ * @import {CctpTxEvidence, FastUSDCConfig, FeeConfig, PendingTx, PoolMetrics, ChainPolicy, FeedPolicy, AddressHook, EvmAddress, EvmHash, RiskAssessment, EvidenceWithRisk} from './types.js';
10
16
  */
11
17
 
12
18
  /**
@@ -19,16 +25,20 @@ export const makeNatAmountShape = (brand, min) =>
19
25
  /** @param {Record<'PoolShares' | 'USDC', Brand<'nat'>>} brands */
20
26
  export const makeProposalShapes = ({ PoolShares, USDC }) => {
21
27
  /** @type {TypedPattern<USDCProposalShapes['deposit']>} */
22
- const deposit = M.splitRecord(
23
- { give: { USDC: makeNatAmountShape(USDC, 1n) } },
24
- { want: M.splitRecord({}, { PoolShare: makeNatAmountShape(PoolShares) }) },
25
- );
28
+ const deposit = M.splitRecord({
29
+ give: { USDC: makeNatAmountShape(USDC, 1n) },
30
+ want: { PoolShare: makeNatAmountShape(PoolShares) },
31
+ });
26
32
  /** @type {TypedPattern<USDCProposalShapes['withdraw']>} */
27
33
  const withdraw = M.splitRecord({
28
34
  give: { PoolShare: makeNatAmountShape(PoolShares, 1n) },
29
35
  want: { USDC: makeNatAmountShape(USDC, 1n) },
30
36
  });
31
- return harden({ deposit, withdraw });
37
+ /** @type {TypedPattern<USDCProposalShapes['withdrawFees']>} */
38
+ const withdrawFees = M.splitRecord({
39
+ want: { USDC: makeNatAmountShape(USDC, 1n) },
40
+ });
41
+ return harden({ deposit, withdraw, withdrawFees });
32
42
  };
33
43
 
34
44
  /** @type {TypedPattern<FastUsdcTerms>} */
@@ -66,6 +76,7 @@ export const CctpTxEvidenceShape = {
66
76
  },
67
77
  blockHash: EvmHashShape,
68
78
  blockNumber: M.nat(),
79
+ blockTimestamp: M.nat(),
69
80
  chainId: M.number(),
70
81
  tx: {
71
82
  amount: M.nat(),
@@ -103,7 +114,6 @@ const NatAmountShape = { brand: BrandShape, value: M.nat() };
103
114
  export const FeeConfigShape = {
104
115
  flat: NatAmountShape,
105
116
  variableRate: RatioShape,
106
- maxVariable: NatAmountShape,
107
117
  contractRate: RatioShape,
108
118
  };
109
119
  harden(FeeConfigShape);
@@ -121,10 +131,19 @@ harden(PoolMetricsShape);
121
131
 
122
132
  /** @type {TypedPattern<ChainPolicy>} */
123
133
  export const ChainPolicyShape = {
124
- attenuatedCttpBridgeAddress: EvmHashShape,
134
+ attenuatedCttpBridgeAddresses: M.splitArray(
135
+ [EvmHashShape],
136
+ undefined,
137
+ M.arrayOf(EvmHashShape),
138
+ ),
125
139
  cctpTokenMessengerAddress: EvmHashShape,
126
140
  confirmations: M.number(),
127
141
  chainId: M.number(),
142
+ rateLimits: {
143
+ tx: M.bigint(),
144
+ blockWindow: M.bigint(),
145
+ blockWindowSize: M.number(),
146
+ },
128
147
  };
129
148
  harden(ChainPolicyShape);
130
149
 
@@ -143,3 +162,13 @@ export const FeedPolicyShape = M.splitRecord(
143
162
  { eventFilter: M.string() },
144
163
  );
145
164
  harden(FeedPolicyShape);
165
+
166
+ /** @type {TypedPattern<FastUSDCConfig>} */
167
+ export const FastUSDCConfigShape = M.splitRecord({
168
+ terms: FastUSDCTermsShape,
169
+ oracles: M.recordOf(M.string(), M.string()),
170
+ feeConfig: FeeConfigShape,
171
+ feedPolicy: FeedPolicyShape,
172
+ chainInfo: M.recordOf(M.string(), CosmosChainInfoShape),
173
+ assetInfo: M.arrayOf([DenomShape, DenomDetailShape]),
174
+ });