/ contract / test / test-contract.js
test-contract.js
  1  // @ts-check
  2  
  3  /* eslint-disable import/order -- https://github.com/endojs/endo/issues/1235 */
  4  import { test } from './prepare-test-env-ava.js';
  5  import path from 'path';
  6  import '@agoric/zoe/exported.js';
  7  import bundleSource from '@endo/bundle-source';
  8  
  9  import { E } from '@endo/eventual-send';
 10  import { makeFakeVatAdmin } from '@agoric/zoe/tools/fakeVatAdmin.js';
 11  import { makeZoeKitForTest } from '@agoric/zoe/tools/setup-zoe.js';
 12  import { AmountMath, makeIssuerKit } from '@agoric/ertp';
 13  import {
 14    invertRatio,
 15    makeRatio,
 16    multiplyBy
 17  } from '@agoric/zoe/src/contractSupport/ratio.js';
 18  
 19  // @ts-ignore
 20  const filename = new URL(import.meta.url).pathname;
 21  const dirname = path.dirname(filename);
 22  
 23  const contractPath = `${dirname}/../src/accounts.js`;
 24  const setupMints = () => {
 25    const {
 26      brand: osmoBrand,
 27      issuer: osmoIssuer,
 28      mint: osmoMint
 29    } = makeIssuerKit('Osmos');
 30    const osmos = x => AmountMath.make(osmoBrand, x);
 31    const {
 32      brand: atomBrand,
 33      issuer: atomIssuer,
 34      mint: atomMint
 35    } = makeIssuerKit('atom');
 36    const {
 37      brand: usdBrand,
 38      issuer: usdIssuer,
 39      mint: usdMint
 40    } = makeIssuerKit('usd');
 41    const atoms = x => AmountMath.make(atomBrand, x);
 42    const usd = x => AmountMath.make(usdBrand, x);
 43    return {
 44      atomBrand,
 45      atomIssuer,
 46      atomMint,
 47      atoms,
 48      osmoBrand,
 49      osmoIssuer,
 50      osmoMint,
 51      osmos,
 52      usdBrand,
 53      usdIssuer,
 54      usdMint,
 55      usd
 56    };
 57  };
 58  
 59  const {
 60    atomBrand,
 61    atomIssuer,
 62    atomMint,
 63    atoms,
 64    osmoBrand,
 65    osmoIssuer,
 66    osmoMint,
 67    osmos,
 68    usdBrand,
 69    usdIssuer,
 70    usdMint,
 71    usd
 72  } = setupMints();
 73  const maxAtomRatio = makeRatio(1n, atomBrand, 7n, usdBrand);
 74  
 75  const maxOsmoRation = makeRatio(10n, osmoBrand, 4n, usdBrand);
 76  const osmoInUSD = invertRatio(maxOsmoRation);
 77  const atomInUSD = invertRatio(maxAtomRatio);
 78  const setupContract = async (contract, issuerRecord, startProps) => {
 79    const { zoeService: zoe } = makeZoeKitForTest(makeFakeVatAdmin().admin);
 80  
 81    // pack the contract
 82    const bundle = await bundleSource(contract);
 83  
 84    // install the contract
 85    const installation = E(zoe).install(bundle);
 86  
 87    const { creatorFacet, publicFacet, instance } = await E(zoe).startInstance(
 88      installation,
 89      issuerRecord,
 90      startProps
 91    );
 92  
 93    const LiOsmoIssuer = E(publicFacet).getLiOsmosIssuer();
 94    const LiOsmoBrand = await E(LiOsmoIssuer).getBrand();
 95    const LiAtomsIssuer = E(publicFacet).getLiAtomsIssuer();
 96    const LiAtomsBrand = await E(LiAtomsIssuer).getBrand();
 97    const LiUSDIssuer = await E(publicFacet).getLiUSDIssuer();
 98    const LiUSDBrand = await E(LiUSDIssuer).getBrand();
 99  
100    return {
101      zoe,
102      creatorFacet,
103      publicFacet,
104      instance,
105      defaultIssuers: {
106        LiOsmoIssuer,
107        LiAtomsIssuer,
108        LiUSDIssuer
109      },
110      defaultDebtAmounts: {
111        liAtoms: x => AmountMath.make(LiAtomsBrand, x),
112        liOsmos: x => AmountMath.make(LiOsmoBrand, x),
113        liUSD: x => AmountMath.make(LiUSDBrand, x)
114      }
115    };
116  };
117  
118  test('zoe - mint payments', async t => {
119    // Let's get the liUSDIssuer from the contract so we can evaluate
120    // what we get as our payout
121    const issuerRecord = {
122      Osmos: osmoIssuer,
123      Atoms: atomIssuer,
124      USD: usdIssuer
125    };
126    const config = {
127      Ratios: {
128        Atoms: atomInUSD,
129        Osmos: osmoInUSD,
130        USD: makeRatio(1n, usdBrand)
131      }
132    };
133  
134    const {
135      zoe,
136      creatorFacet,
137      defaultIssuers: { LiOsmoIssuer, LiAtomsIssuer },
138      defaultDebtAmounts
139    } = await setupContract(contractPath, issuerRecord, config);
140    const { liAtoms, liOsmos, liUSD } = defaultDebtAmounts;
141    const calculateMaxBorrow = amount => multiplyBy(amount, atomInUSD);
142    const calculateMaxBorrowOsmo = amount => multiplyBy(amount, osmoInUSD);
143  
144    t.deepEqual(calculateMaxBorrow(atoms(10n)), usd(70n));
145    t.deepEqual(calculateMaxBorrowOsmo(osmos(100n)), usd(40n));
146  
147    // Alice makes an invitation for Bob that will give him 1000 tokens
148    const invitation = E(creatorFacet).makeInvitation();
149  
150    // Bob makes an offer using the invitation
151    const seat = await E(zoe).offer(
152      invitation,
153      {
154        give: { Osmos: osmos(100n) },
155        want: { LiOsmos: liOsmos(100n) }
156      },
157      { Osmos: osmoMint.mintPayment(osmos(100n)) }
158    );
159  
160    t.deepEqual(await seat.hasExited(), true);
161  
162    const paymentP = await seat.getPayout('LiOsmos');
163    const tokenPayoutAmount = await E(LiOsmoIssuer).getAmountOf(paymentP);
164    t.deepEqual(tokenPayoutAmount, liOsmos(100n));
165  
166    /**
167     * @type {ERef<AccountOfferResult>}
168     */
169    const seatOneResult = await E(seat).getOfferResult();
170  
171    t.truthy(
172      seatOneResult.getStore,
173      'openAccount should return a reference to getStore'
174    );
175    t.truthy(
176      seatOneResult.makeAddCollateralInvitation,
177      'openAccount should return a reference to addCollateral'
178    );
179  
180    t.deepEqual(seatOneResult.getStore().get('Osmos').value, 100n);
181    // Let's get the LiOsmoIssuer from the contract so we can evaluate
182    // what we get as our payout
183  
184    const store = await E(creatorFacet).getStore();
185    // t.deepEqual(store.get('Osmos'), { brand, value: 100n });
186  
187    // Bob makes an offer using the invitation
188    const seatTwo = await E(zoe).offer(
189      E(creatorFacet).makeInvitation(),
190      {
191        give: { Atoms: atoms(200n) },
192        want: { LiAtoms: liAtoms(200n) }
193      },
194      { Atoms: atomMint.mintPayment(atoms(200n)) }
195    );
196    const seatTwoPayment = await seatTwo.getPayout('LiAtoms');
197    const seatTwoPaymentAmt = await E(LiAtomsIssuer).getAmountOf(seatTwoPayment);
198  
199    /**
200     * @type {ERef<AccountOfferResult>}
201     */
202    const seatTwoResult = await seatTwo.getOfferResult();
203  
204    t.deepEqual(seatTwoPaymentAmt, liAtoms(200n));
205    t.deepEqual(store.get('Atoms').value, 200n);
206    t.deepEqual(store.get('Atoms').brand, atomBrand);
207  
208    t.deepEqual(await seatTwo.hasExited(), true);
209  
210    const addCollateralSeat = await E(zoe).offer(
211      E(seatOneResult).makeAddCollateralInvitation(),
212      {
213        give: { Osmos: osmos(900n) },
214        want: { LiOsmos: liOsmos(900n) }
215      },
216      { Osmos: osmoMint.mintPayment(osmos(900n)) }
217    );
218    await addCollateralSeat.getOfferResult();
219    await E(zoe).offer(
220      E(seatOneResult).makeAddCollateralInvitation(),
221      {
222        give: { USD: usd(1200n) },
223        want: { LiUSD: liUSD(1200n) }
224      },
225      { USD: usdMint.mintPayment(usd(1200n)) }
226    );
227    await addCollateralSeat.getOfferResult();
228  
229    t.deepEqual(seatOneResult.getStore().get('USD').value, 1200n);
230    t.deepEqual(store.get('USD'), AmountMath.make(usdBrand, 1200n));
231  
232    t.deepEqual(seatOneResult.getStore().get('Osmos').value, 1000n);
233    t.deepEqual(store.get('Osmos').value, 1000n);
234  
235    const addCollateralToSeatTwo = await E(zoe).offer(
236      E(seatTwoResult).makeAddCollateralInvitation(),
237      {
238        give: { Osmos: osmos(1200n) },
239        want: { LiOsmos: liOsmos(1200n) }
240      },
241      { Osmos: osmoMint.mintPayment(osmos(1200n)) }
242    );
243    const addCollateralToSeatTwoPayment = await addCollateralToSeatTwo.getPayout(
244      'LiOsmos'
245    );
246    const addCollateralToSeatTwoPaymentValue = await E(LiOsmoIssuer).getAmountOf(
247      addCollateralToSeatTwoPayment
248    );
249    // seatTwo :: adding ATOM
250    await E(zoe).offer(
251      E(seatOneResult).makeAddCollateralInvitation(),
252      {
253        give: { Atoms: atoms(1000n) },
254        want: { LiAtoms: liAtoms(1000n) }
255      },
256      { Atoms: atomMint.mintPayment(atoms(1000n)) }
257    );
258    t.deepEqual(addCollateralToSeatTwoPaymentValue, liOsmos(1200n));
259  
260    // borrow
261    const borrowFromSeatOne = await E(zoe).offer(
262      await E(seatOneResult).makeBorrowInvitation(),
263      {
264        want: { USD: AmountMath.make(usdBrand, 200n) }
265      }
266    );
267  
268    /**
269     * @type {ERef<AccountOfferResult>}
270     */
271    const borrowResult = await E(borrowFromSeatOne).getOfferResult();
272  
273    t.deepEqual(!borrowResult.error === true, true);
274  
275    // borrow
276    const borrowFromSeatTwo = await E(zoe).offer(
277      E(seatTwoResult).makeBorrowInvitation(),
278      {
279        want: { USD: AmountMath.make(usdBrand, 22200n) }
280      }
281    );
282  
283    /**
284     * @type {ERef<AccountOfferResult>}
285     */
286    const borrowResultTwo = await E(borrowFromSeatTwo).getOfferResult();
287    t.deepEqual(!borrowResultTwo.error === false, true);
288  });