@agoric/inter-protocol 0.13.2-dev-73ca139.0 → 0.13.2-dev-a9d6a3b.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/my-lien.js DELETED
@@ -1,84 +0,0 @@
1
- // @jessie-check
2
-
3
- import { AmountMath } from '@agoric/ertp';
4
- import { E, Far } from '@endo/far';
5
-
6
- const { Fail } = assert;
7
-
8
- /**
9
- * per golang/cosmos/x/lien/lien.go
10
- *
11
- * @typedef { 'bonded' | 'liened' | 'locked' | 'total' | 'unbonding' } AccountProperty
12
- */
13
- const XLien = /** @type { const } */ ({
14
- LIEN_CHANGE_LIENED: 'LIEN_CHANGE_LIENED',
15
- LIEN_GET_ACCOUNT_STATE: 'LIEN_GET_ACCOUNT_STATE',
16
- });
17
-
18
- /**
19
- * @typedef { Record<AccountProperty, T> & { currentTime: bigint } } AccountState<T>
20
- * @template T
21
- */
22
-
23
- export const LienBridgeId = /** @type {const} */ ('lien');
24
-
25
- /**
26
- * @param {ERef<import('@agoric/vats').ScopedBridgeManager>} lienBridgeManager
27
- * @param {Brand<'nat'>} brand
28
- * @param {string} [denom]
29
- * @returns {StakingAuthority}
30
- */
31
- export const makeStakeReporter = (lienBridgeManager, brand, denom = 'ubld') => {
32
- const { make: makeAmt } = AmountMath;
33
- const toStake = numeral => makeAmt(brand, BigInt(numeral));
34
- /**
35
- * @param {string} address
36
- * @param {bigint} delta
37
- * @returns {Promise<Amount<`nat`>>}
38
- */
39
- const changeLiened = async (address, delta) => {
40
- assert.typeof(address, 'string');
41
- const newAmount = await E(lienBridgeManager).toBridge({
42
- type: XLien.LIEN_CHANGE_LIENED,
43
- address,
44
- denom,
45
- delta: `${delta}`,
46
- });
47
- return harden(toStake(newAmount));
48
- };
49
-
50
- /** @type {StakingAuthority} */
51
- const stakeReporter = Far('stakeReporter', {
52
- increaseLiened: async (address, increase) => {
53
- const delta = AmountMath.getValue(brand, increase);
54
- return changeLiened(address, delta);
55
- },
56
- decreaseLiened: async (address, decrease) => {
57
- const delta = -1n * AmountMath.getValue(brand, decrease);
58
- return changeLiened(address, delta);
59
- },
60
- getAccountState: async (address, wantedBrand) => {
61
- wantedBrand === brand ||
62
- Fail`Cannot getAccountState for ${wantedBrand}. Expected ${brand}.`;
63
- /** @type { AccountState<string> } */
64
- const { currentTime, bonded, liened, locked, total, unbonding } = await E(
65
- lienBridgeManager,
66
- ).toBridge({
67
- type: XLien.LIEN_GET_ACCOUNT_STATE,
68
- address,
69
- denom,
70
- amount: '0',
71
- });
72
- return harden({
73
- bonded: toStake(bonded),
74
- liened: toStake(liened),
75
- locked: toStake(locked),
76
- total: toStake(total),
77
- unbonding: toStake(unbonding),
78
- currentTime: BigInt(currentTime),
79
- });
80
- },
81
- });
82
-
83
- return stakeReporter;
84
- };
@@ -1,62 +0,0 @@
1
- # stakeFactory design notes
2
-
3
- The stakeFactory contract provides loans on the basis of
4
- staked assets that earn rewards.
5
-
6
- The following sequence diagram shows an interaction between stakeFactory and:
7
- - dapp: with rich interaction but low privilege
8
- - walletBridge: with high privilege and constrained interaction
9
- - attestation: a service within the stakeFactory contract
10
- - Cosmos_SDK: the Cosmos SDK layer, including the `x/lien` module
11
-
12
- Before this interaction, an `ag123` account has been provisioned,
13
- which provides an `AttestationMaker` for that account to the wallet.
14
-
15
- Note that the account already has 4000 BLD liened before this interaction.
16
-
17
- ```mermaid
18
- sequenceDiagram
19
- actor dapp
20
- participant walletBridge
21
- participant attestation
22
- participant stakeFactory
23
- participant Cosmos_SDK
24
-
25
- note right of dapp: How dapp finds the current state
26
-
27
- note right of walletBridge: walletBridge is provided to dapps and controlled by Wallet UI
28
- dapp ->>+ walletBridge: getPurseBalance("BLD")
29
- dapp -->> walletBridge: 5000
30
-
31
- note right of attestation: ag123 is a cosmos address
32
- dapp ->> attestation: getMax(ag123)
33
- attestation ->> Cosmos_SDK: getAccountState(ag123)
34
- note right of Cosmos_SDK: Cosmos supports lien
35
- Cosmos_SDK -->> attestation: account status in which 4000 BLD liened
36
- attestation -->> dapp: account status in which 4000 BLD liened
37
- note right of dapp: Treasury now knows
38
-
39
- note right of dapp: Want to get 450 IST by liening 500 BLD
40
- dapp ->> walletBridge: getReturnableAttestation(want: 450 IST, give: 500 BLD-Att)
41
- note right of walletBridge: Blocks on user approval in wallet
42
- walletBridge ->> attestation: makeAttestation(500 BLD)
43
- attestation ->> Cosmos_SDK: increaseLiened(+500 BLD)
44
- Cosmos_SDK -->> attestation: new lien balance or throws
45
-
46
- attestation -->> walletBridge: Payment of 500 BLD-Att liened on ag123
47
-
48
- walletBridge ->> stakeFactory: offer w/payment for {give: 500 BLD-Att, want: 450 IST}
49
-
50
- stakeFactory --> walletBridge: Payment for 450 IST and offerResult
51
- walletBridge --> dapp: notifiers from offerResult
52
- ```
53
-
54
- ## Components
55
-
56
- In addition to the `stakeFactory.js` module with the contract `start` function:
57
-
58
- - `params.js`: utilities for governance parameters
59
- - `stakeFactoryKit.js`: `makeStakeFactoryKit` is called once per loan
60
- - `stakeFactoryManager.js`: handles interest etc. for all loans
61
- - `attestation.js`: minting tokens that attest to liens,
62
- and wrapping them in per-user attestation maker authorities.
@@ -1,271 +0,0 @@
1
- // @jessie-check
2
-
3
- // Ambient types. https://github.com/Agoric/agoric-sdk/issues/6512
4
- import './types.js';
5
-
6
- import { AmountMath, AssetKind } from '@agoric/ertp';
7
- import { E, Far } from '@endo/far';
8
- import {
9
- mustMatch,
10
- M,
11
- makeCopyBag,
12
- makeScalarMapStore,
13
- provideLazy,
14
- } from '@agoric/store';
15
- import { assertProposalShape } from '@agoric/zoe/src/contractSupport/index.js';
16
- import { AttKW as KW } from './constants.js';
17
- import { makeAttestationTool } from './attestationTool.js';
18
-
19
- const { Fail } = assert;
20
-
21
- /**
22
- * @typedef {{
23
- * mintAttestation: unknown,
24
- * returnAttestation: OfferHandler,
25
- * getLiened: (address: Address, brand: Brand<'nat'>) => Amount<'nat'>,
26
- * getAccountState: unknown,
27
- * wrapLienedAmount: unknown,
28
- * unwrapLienedAmount: unknown,
29
- * }} LienMint
30
- */
31
-
32
- /**
33
- * To support `makeAttestation`, we directly mint attestation payments.
34
- * We still use a ZCFMint because returning attestations is done
35
- * through Zoe offers.
36
- *
37
- * @param {ZCF} zcf
38
- * @template {AssetKind} K
39
- * @param {ZCFMint<K>} zcfMint
40
- * @param {Amount<K>} amountToMint
41
- * @returns {Promise<Payment<K>>}
42
- */
43
- const mintZCFMintPayment = (zcf, zcfMint, amountToMint) => {
44
- const { userSeat, zcfSeat } = zcf.makeEmptySeatKit();
45
- zcfMint.mintGains(harden({ [KW.Attestation]: amountToMint }), zcfSeat);
46
- zcfSeat.exit();
47
- return E(userSeat).getPayout(KW.Attestation);
48
- };
49
-
50
- /**
51
- * Make a ZCFMint attentuated so that minting represents
52
- * putting a lien on staked assets. Payments can be returned,
53
- * releasing (part of) the lien.
54
- *
55
- * NOTE: Using Issuer.combine or AmountMath.add could result in
56
- * Payments / Amounts with multiple addresses.
57
- * Callers are responsible to split any such payment before returning.
58
- *
59
- * @param {ZCF} zcf
60
- * @param {Brand<'nat'>} stakeBrand brand of the staked assets
61
- * @param {ERef<StakingAuthority>} lienBridge bridge to account state
62
- */
63
- const makeAttestationIssuerKit = async (zcf, stakeBrand, lienBridge) => {
64
- const { subtract, makeEmpty, isGTE, coerce } = AmountMath;
65
- const empty = makeEmpty(stakeBrand);
66
- /** @type { ZCFMint<'copyBag'> } */
67
- const attMint = await zcf.makeZCFMint(KW.Attestation, AssetKind.COPY_BAG);
68
- /** @type {{ issuer: Issuer<'copyBag'>, brand: Brand<'copyBag'>}} */
69
- const { issuer, brand: attBrand } = attMint.getIssuerRecord();
70
-
71
- /**
72
- * @param {Address} address
73
- * @param {Amount<'nat'>} lienedAmount
74
- * @returns {Amount<'copyBag'>}
75
- */
76
- const wrapLienedAmount = (address, lienedAmount) =>
77
- AmountMath.make(attBrand, makeCopyBag([[address, lienedAmount.value]]));
78
-
79
- /** @param {Amount<'copyBag'>} attestationAmount */
80
- const unwrapLienedAmount = attestationAmount => {
81
- attestationAmount.brand === attBrand ||
82
- Fail`The escrowed attestation ${attestationAmount} was not of the attestation brand ${attBrand}`;
83
- mustMatch(
84
- attestationAmount.value.payload,
85
- harden([[M.string(), M.bigint()]]),
86
- 'attestationAmount',
87
- );
88
- /** @type {[Address, bigint][]} */
89
- const [[address, valueReturned]] = attestationAmount.value.payload;
90
- const lienedAmount = AmountMath.make(stakeBrand, valueReturned);
91
- return { address, lienedAmount };
92
- };
93
-
94
- /**
95
- * Non-authoritative store of nonzero lien amounts.
96
- *
97
- * @type {MapStore<Address, Amount<'nat'>>}
98
- */
99
- const amountByAddress = makeScalarMapStore('amount');
100
-
101
- /**
102
- * Get non-authoritative liened amount from the JS store, without using the lienBridge.
103
- *
104
- * @param {Address} address
105
- * @param {Brand<'nat'>} brand
106
- */
107
- const getLiened = (address, brand) => {
108
- assert.typeof(address, 'string');
109
- assert.equal(brand, stakeBrand);
110
- if (amountByAddress.has(address)) {
111
- return amountByAddress.get(address);
112
- }
113
- // Don't bother storing empty amounts.
114
- return empty;
115
- };
116
-
117
- const getAccountState = async (address, brand) => {
118
- const liened = getLiened(address, brand);
119
- const s = await E(lienBridge).getAccountState(address, brand);
120
- assert(AmountMath.isEqual(liened, s.liened));
121
- return s;
122
- };
123
-
124
- /** @type {(m: Amount, s: Amount) => Amount} */
125
- const subtractOrZero = (m, s) => (isGTE(m, s) ? subtract(m, s) : empty);
126
- // check that x <= hi - lo
127
- const checkDelta = (x, label, hi, lo) => {
128
- const bound = subtractOrZero(hi, lo);
129
- isGTE(bound, coerce(stakeBrand, x)) ||
130
- // TODO: X`...${raw(label)}...`
131
- Fail`Only ${bound} was ${label}, but an attestation was attempted for ${x}`;
132
- };
133
- const assertAccountStateOK = async (address, toLien) => {
134
- const s = await getAccountState(address, stakeBrand);
135
- const unlocked = subtractOrZero(s.total, s.locked);
136
- checkDelta(toLien, 'unliened', s.total, s.liened);
137
- checkDelta(toLien, 'bonded and unliened', s.bonded, s.liened);
138
- checkDelta(toLien, 'unlocked and unliened', unlocked, s.liened);
139
- };
140
-
141
- /**
142
- * @param {Address} address
143
- * @param {Amount<'nat'>} lienDelta
144
- */
145
- const mintAttestation = async (address, lienDelta) => {
146
- // This account state check is primarily to provide useful diagnostics.
147
- // Since things like the bonded amount can change out from under us,
148
- // we shouldn't rely on it completely.
149
- // PERFORMANCE NOTE: this check shouldn't be necessary and skipping it
150
- // may speed things up.
151
- await assertAccountStateOK(address, lienDelta);
152
-
153
- // Since our mint is not subject to normal supply/demand,
154
- // minting here and failing in changeLiened below does no harm.
155
- const attestationPayment = await mintZCFMintPayment(
156
- zcf,
157
- attMint,
158
- wrapLienedAmount(address, lienDelta),
159
- );
160
-
161
- const newLiened = await E(lienBridge).increaseLiened(address, lienDelta);
162
- // COMMIT: update the stored liened amount and issue the attestation.
163
- if (amountByAddress.has(address)) {
164
- amountByAddress.set(address, newLiened);
165
- } else {
166
- amountByAddress.init(address, newLiened);
167
- }
168
- return attestationPayment;
169
- };
170
-
171
- /** @param {ZCFSeat} seat */
172
- const returnAttestation = async seat => {
173
- assertProposalShape(seat, {
174
- give: { [KW.Attestation]: null },
175
- want: {},
176
- });
177
-
178
- const {
179
- give: { [KW.Attestation]: attestationAmount },
180
- } = seat.getProposal();
181
- if (AmountMath.isEmpty(attestationAmount)) {
182
- seat.exit();
183
- return;
184
- }
185
- const { address, lienedAmount: amountReturned } =
186
- unwrapLienedAmount(attestationAmount);
187
- const newLiened = await E(lienBridge).decreaseLiened(
188
- address,
189
- amountReturned,
190
- );
191
- // COMMIT. Burn the escrowed attestation payment and exit the seat.
192
- if (newLiened === empty) {
193
- amountByAddress.delete(address);
194
- } else {
195
- amountByAddress.set(address, newLiened);
196
- }
197
- attMint.burnLosses(harden({ Attestation: attestationAmount }), seat);
198
- seat.exit();
199
- };
200
-
201
- /** @type {ERef<LienMint>} */
202
- const lienMint = Far('LienMint', {
203
- mintAttestation,
204
- returnAttestation,
205
- getLiened,
206
- getAccountState,
207
- wrapLienedAmount,
208
- /**
209
- * @param {Amount<'copyBag'>} attAmt
210
- * @throws if `attAmt` payload length is not 1
211
- */
212
- unwrapLienedAmount: attAmt => unwrapLienedAmount(attAmt).lienedAmount,
213
- });
214
- return harden({ issuer, brand: attBrand, lienMint });
215
- };
216
-
217
- /**
218
- * Authorize each account holder to lien some of their staked assets
219
- * and get an attestation that the lien is in place.
220
- *
221
- * @param {ZCF} zcf
222
- * @param {Brand<'nat'>} stakeBrand
223
- * @param {ERef<StakingAuthority>} lienBridge
224
- *
225
- * NOTE: the liened amount is kept both here in JS and on the
226
- * other side of the lienBridge. The mint created here
227
- * is the authority on the liened amount. The liened amount
228
- * on the other side of the bridge may lag. Do not create two
229
- * mints that share a bridge.
230
- *
231
- * The provideAttestationMaker method on the returned creatorFacet
232
- * provides the authorization for an address. The account holder
233
- * can then use attMaker.makeAttestation(lienDelta).
234
- *
235
- * The keyword for use in returnAttestation offers is `Attestation`.
236
- */
237
- export const makeAttestationFacets = async (zcf, stakeBrand, lienBridge) => {
238
- /** @type {MapStore<Address, AttestationTool>} */
239
- const attMakerByAddress = makeScalarMapStore('address');
240
-
241
- const { issuer, brand, lienMint } = await makeAttestationIssuerKit(
242
- zcf,
243
- stakeBrand,
244
- lienBridge,
245
- );
246
-
247
- return harden({
248
- publicFacet: Far('attestation publicFacet', {
249
- getIssuer: () => issuer,
250
- getBrand: () => brand,
251
- makeReturnAttInvitation: () =>
252
- zcf.makeInvitation(lienMint.returnAttestation, 'returnAttestation'),
253
- }),
254
- creatorFacet: Far('creator', {
255
- /**
256
- * IMPORTANT: The attestation maker should only be given to the owner of the
257
- * address. Only the owner can authorize creation of attestations and
258
- * the resulting liens on their underlying tokens.
259
- *
260
- * @param {Address} address
261
- */
262
- provideAttestationTool: address => {
263
- assert.typeof(address, 'string');
264
- return provideLazy(attMakerByAddress, address, () =>
265
- makeAttestationTool(address, lienMint, stakeBrand, zcf),
266
- );
267
- },
268
- getLiened: lienMint.getLiened,
269
- }),
270
- });
271
- };
@@ -1,67 +0,0 @@
1
- // @jessie-check
2
-
3
- /**
4
- * @typedef {Readonly<{
5
- * address: Address,
6
- * lienMint: *,
7
- * stakeBrand: Brand<'nat'>,
8
- * zcf: ZCF,
9
- * }>} State
10
- * @typedef {{
11
- * state: State,
12
- * }} MethodContext
13
- */
14
-
15
- import { defineKind } from '@agoric/vat-data';
16
- /**
17
- * @param {Address} address
18
- * @param {import('./attestation').LienMint} lienMint
19
- * @param {Brand<'nat'>} stakeBrand
20
- * @param {ZCF} zcf
21
- */
22
- const initState = (address, lienMint, stakeBrand, zcf) => {
23
- return { address, lienMint, stakeBrand, zcf };
24
- };
25
-
26
- const behavior = {
27
- /**
28
- * @param {MethodContext} context
29
- * @param {Amount<'nat'>} lienedDelta
30
- */
31
- makeAttestation: ({ state }, lienedDelta) =>
32
- state.lienMint.mintAttestation(state.address, lienedDelta),
33
-
34
- /** @param {MethodContext} context */
35
- getAccountState: ({ state }) =>
36
- state.lienMint.getAccountState(state.address, state.stakeBrand),
37
-
38
- /** @param {MethodContext} context */
39
- makeReturnAttInvitation: ({ state }) =>
40
- state.zcf.makeInvitation(
41
- state.lienMint.returnAttestation,
42
- 'returnAttestation',
43
- ),
44
-
45
- /**
46
- * @param {MethodContext} context
47
- * @param {Amount<'nat'>} lienedAmount
48
- */
49
- wrapLienedAmount: ({ state }, lienedAmount) =>
50
- state.lienMint.wrapLienedAmount(state.address, lienedAmount),
51
-
52
- /**
53
- * @param {MethodContext} context
54
- * @param {Amount<'copyBag'>} attAmount
55
- */
56
- unwrapLienedAmount: ({ state }, attAmount) =>
57
- state.lienMint.unwrapLienedAmount(attAmount),
58
- };
59
-
60
- /**
61
- * @returns {AttestationTool}
62
- */
63
- export const makeAttestationTool = defineKind(
64
- 'AttestationTool',
65
- initState,
66
- behavior,
67
- );
@@ -1,18 +0,0 @@
1
- // @jessie-check
2
-
3
- export const AttKW = /** @type { const } */ ({
4
- /** seat keyword for use in offers to return an attestation. */
5
- Attestation: 'Attestation',
6
- });
7
-
8
- export const ManagerKW = /** @type { const } */ ({
9
- [AttKW.Attestation]: AttKW.Attestation,
10
- Debt: 'Debt',
11
- });
12
-
13
- export const ParamKW = /** @type { const } */ ({
14
- DebtLimit: 'DebtLimit',
15
- MintingRatio: 'MintingRatio',
16
- InterestRate: 'InterestRate',
17
- MintFee: 'MintFee',
18
- });
@@ -1,30 +0,0 @@
1
- // @jessie-check
2
-
3
- import { CONTRACT_ELECTORATE, ParamTypes } from '@agoric/governance';
4
- import { ParamKW as PKey } from './constants.js';
5
-
6
- export const makeStakeFactoryTerms = (
7
- { timerService, chargingPeriod, recordingPeriod },
8
- {
9
- electorateInvitationAmount,
10
- debtLimit,
11
- mintingRatio,
12
- interestRate,
13
- mintFee,
14
- },
15
- ) => ({
16
- timerService,
17
- chargingPeriod,
18
- recordingPeriod,
19
- governedParams: harden({
20
- [PKey.DebtLimit]: { type: ParamTypes.AMOUNT, value: debtLimit },
21
- [PKey.MintingRatio]: { type: ParamTypes.RATIO, value: mintingRatio },
22
- [PKey.InterestRate]: { type: ParamTypes.RATIO, value: interestRate },
23
- [PKey.MintFee]: { type: ParamTypes.RATIO, value: mintFee },
24
- [CONTRACT_ELECTORATE]: {
25
- type: ParamTypes.INVITATION,
26
- value: electorateInvitationAmount,
27
- },
28
- }),
29
- });
30
- harden(makeStakeFactoryTerms);