@agoric/fast-usdc 0.2.0-u18a.0 → 0.2.0-u19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +26 -25
- package/src/add-operators.core.js +63 -0
- package/src/cli/cli.js +1 -1
- package/src/cli/config-commands.js +1 -1
- package/src/cli/config.js +1 -1
- package/src/cli/lp-commands.js +21 -39
- package/src/cli/operator-commands.js +1 -0
- package/src/cli/transfer.js +5 -5
- package/src/clientSupport.js +98 -0
- package/src/distribute-fees.core.js +93 -0
- package/src/exos/advancer.js +109 -41
- package/src/exos/liquidity-pool.js +81 -34
- package/src/exos/operator-kit.js +0 -2
- package/src/exos/settler.js +154 -95
- package/src/exos/status-manager.js +97 -59
- package/src/exos/transaction-feed.js +30 -9
- package/src/fast-usdc-policy.core.js +2 -12
- package/src/fast-usdc.contract.js +23 -31
- package/src/main.js +1 -0
- package/src/pool-share-math.js +55 -9
- package/src/{fast-usdc.start.js → start-fast-usdc.core.js} +13 -81
- package/src/type-guards.js +37 -8
- package/src/types.ts +34 -5
- package/src/utils/chain-policies.js +140 -0
- package/src/utils/core-eval.js +73 -0
- package/src/utils/deploy-config.js +36 -75
- package/src/utils/fees.js +3 -4
- /package/src/{util → cli/util}/agoric.js +0 -0
- /package/src/{util → cli/util}/bank.js +0 -0
- /package/src/{util → cli/util}/cctp.js +0 -0
- /package/src/{util → cli/util}/file.js +0 -0
- /package/src/{util → cli/util}/noble.js +0 -0
|
@@ -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
|
-
|
|
31
|
-
|
|
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<
|
|
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<
|
|
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
|
-
/**
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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
|
|
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<
|
|
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
|
-
|
|
300
|
-
|
|
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';
|
package/src/pool-share-math.js
CHANGED
|
@@ -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 {
|
|
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(
|
|
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 {
|
|
30
|
+
* @param {Brand<'nat'>} numeratorBrand
|
|
30
31
|
* @param {Brand<'nat'>} denominatorBrand
|
|
31
32
|
*/
|
|
32
|
-
export const makeParity = (
|
|
33
|
-
const
|
|
34
|
-
return makeRatio(
|
|
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
|
|
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 = (
|
|
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
|
|
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 {
|
|
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 {
|
|
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 {
|
|
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
|
|
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 },
|
|
228
|
+
produce: { FastLP: true },
|
|
297
229
|
},
|
|
298
230
|
brand: {
|
|
299
|
-
produce: { FastLP: true },
|
|
231
|
+
produce: { FastLP: true },
|
|
300
232
|
},
|
|
301
233
|
instance: {
|
|
302
234
|
produce: { fastUsdc: true },
|
package/src/type-guards.js
CHANGED
|
@@ -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
|
-
|
|
24
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
});
|