test-poolFactory.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 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 { makeZoeKit } from '@agoric/zoe'; 12 import { AmountMath, AssetKind, makeIssuerKit } from '@agoric/ertp'; 13 import { makeStore } from '@agoric/store'; 14 import { makeRatio } from '@agoric/zoe/src/contractSupport/ratio.js'; 15 import { makeSubscription, makeSubscriptionKit } from '@agoric/notifier'; 16 import { 17 handleError, 18 handleSetIssuerError 19 } from '../src/shared/utils/offers.js'; 20 21 const filename = new URL(import.meta.url).pathname; 22 const dirname = path.dirname(filename); 23 24 const contractPath = `${dirname}/../src/poolFactory.js`; 25 26 const setupTestMints = () => { 27 const dollarKit = makeIssuerKit('dollar'); 28 const { 29 brand: dollarBrand, 30 issuer: dollarIssuer, 31 mint: dollarMint 32 } = dollarKit; 33 const euroKit = makeIssuerKit('euro'); 34 const { brand: euroBrand, issuer: euroIssuer, mint: euroMint } = euroKit; 35 const dollars = x => AmountMath.make(dollarBrand, x); 36 const euros = x => AmountMath.make(euroBrand, x); 37 const { 38 brand: atomBrand, 39 issuer: atomIssuer, 40 mint: atomMint 41 } = makeIssuerKit('atom'); 42 const atoms = x => AmountMath.make(atomBrand, x); 43 return { 44 atomBrand, 45 atomIssuer, 46 atomMint, 47 atoms, 48 dollarKit, 49 dollarBrand, 50 dollarIssuer, 51 dollarMint, 52 dollars, 53 euroKit, 54 euroBrand, 55 euroIssuer, 56 euroMint, 57 euros 58 }; 59 }; 60 61 const setupContract = async contract => { 62 const { zoeService } = makeZoeKit(makeFakeVatAdmin().admin); 63 const feePurse = E(zoeService).makeFeePurse(); 64 const zoe = E(zoeService).bindDefaultFeePurse(feePurse); 65 const bundle = await bundleSource(contract); 66 67 // install the contract 68 const installation = E(zoe).install(bundle); 69 70 const contractInstance = await E(zoe).startInstance(installation); 71 72 return { 73 installation, 74 zoe, 75 bundle, 76 feePurse, 77 zoeService, 78 contractInstance 79 }; 80 }; 81 82 const { 83 dollarIssuer, 84 dollarBrand, 85 dollars, 86 dollarMint, 87 euroIssuer, 88 euroBrand, 89 euros, 90 euroMint, 91 atomIssuer, 92 atomBrand, 93 atoms, 94 atomMint 95 } = setupTestMints(); 96 97 test('poolFactory - deployInitialCollateral:: given incorrect issuerKeywordRecord', async t => { 98 const { contractInstance } = await setupContract(contractPath); 99 100 const { creatorFacet } = contractInstance; 101 102 const incorrectIssuerKeywordRecord = { 103 Atoms: atomIssuer, 104 Dollars: dollarIssuer, 105 Euros: euroBrand 106 }; 107 const deployInitialCollateralInvitation = await E( 108 creatorFacet 109 ).makeDeployInitialCollateralInvitation(incorrectIssuerKeywordRecord); 110 111 const mockSaveIssuerError = TypeError( 112 'target has no method "getBrand", has []' 113 ); 114 115 t.deepEqual( 116 deployInitialCollateralInvitation, 117 handleSetIssuerError(mockSaveIssuerError), 118 'should gracefully handle the error.' 119 ); 120 }); 121 122 test('poolFactory - deployInitialCollateral:: multiple issuerKeywords', async t => { 123 const { contractInstance, zoe } = await setupContract(contractPath); 124 125 const { creatorFacet, publicFacet } = contractInstance; 126 127 const issuerKeywordRecord = { 128 Atoms: atomIssuer, 129 Dollars: dollarIssuer, 130 Euros: euroIssuer 131 }; 132 133 const initialDollars = 10000n; 134 const initialEuros = 50000n; 135 const initialAtoms = 15000n; 136 const deployInitialCollateralProposal = harden({ 137 give: { 138 Atoms: atoms(initialAtoms), 139 Dollars: dollars(initialDollars), 140 Euros: euros(initialEuros) 141 } 142 }); 143 144 const marketManagerFacet = await E( 145 creatorFacet 146 ).makeDeployInitialCollateralInvitation(issuerKeywordRecord); 147 t.true(!marketManagerFacet === false, 'marketManagerFacet should exit.'); 148 149 const store = marketManagerFacet.getStore(); 150 151 t.deepEqual(store.get('Atoms').issuer, atomIssuer); 152 }); 153 154 test('poolFactory - deployInitialCollateral:: setting up marekts', async t => { 155 const { contractInstance, zoe } = await setupContract(contractPath); 156 157 const { creatorFacet, publicFacet } = contractInstance; 158 159 const issuerKeywordRecord = { 160 Atoms: atomIssuer, 161 Dollars: dollarIssuer 162 }; 163 164 const initialDollars = 10000n; 165 const initialEuros = 50000n; 166 const initialAtoms = 15000n; 167 168 const deployInitialCollateralPayments = { 169 Atoms: atomMint.mintPayment(atoms(initialAtoms)) 170 }; 171 172 const debtIssuers = await E(publicFacet).getIssuers(); 173 174 const getLength = ({ length }) => length; 175 176 t.deepEqual( 177 debtIssuers, 178 2, 179 'debtIssuers array should expose the correct issuers' 180 ); 181 const [LiAtomsIssuer, LiDollarsIssuer] = debtIssuers; 182 183 t.truthy( 184 await LiAtomsIssuer.getBrand(), 185 'should expose a reference to the LiAtoms Issuer' 186 ); 187 t.truthy( 188 LiDollarsIssuer.getBrand(), 189 'should expose a reference to the LiDollars Issuer' 190 ); 191 192 const liAtoms = x => AmountMath.make(LiAtomsIssuer.getBrand(), x); 193 const liDollars = x => AmountMath.make(LiDollarsIssuer.getBrand(), x); 194 const marketManagerFacet = await E( 195 creatorFacet 196 ).makeDeployInitialCollateralInvitation(issuerKeywordRecord); 197 198 const setupMarketFn = await E(marketManagerFacet).setMarketParams(); 199 t.truthy(marketManagerFacet.setMarketParams); 200 const dollarsInterestState = { 201 uOptimal: 80, 202 slope1: 4, 203 slope2: 60 204 }; 205 const deployCollateralInvitation = setupMarketFn( 206 'Dollars', 207 dollarsInterestState, 208 makeSubscriptionKit() 209 ); 210 211 const deployDollarsSeat = await E(zoe).offer( 212 await E(marketManagerFacet).deployInitialCollateral(), 213 deployDollarsProposal, 214 { Dollars: dollarMint.mintPayment(dollars(initialDollars)) } 215 ); 216 217 const deployDollarsProposal = harden({ 218 give: { 219 Dollars: dollars(initialDollars) 220 }, 221 want: { 222 LiDollars: liDollars(initialDollars) 223 } 224 }); 225 t.deepEqual(await setParamsResult, {}); 226 }); 227 228 // test('poolFactory - deployInitialCollateral:: given correct issuerKeywordRecord', async t => { 229 // const { contractInstance, zoe } = await setupContract(contractPath); 230 231 // const { creatorFacet, publicFacet } = contractInstance; 232 233 // const issuerKeywordRecord = { 234 // Atoms: atomIssuer, 235 // Dollars: dollarIssuer 236 // }; 237 238 // const initialDollars = 10000n; 239 // const initialEuros = 50000n; 240 // const initialAtoms = 15000n; 241 242 // const deployInitialCollateralPayments = { 243 // Atoms: atomMint.mintPayment(atoms(initialAtoms)) 244 // }; 245 246 // const marketManagerFacet = await E( 247 // creatorFacet 248 // ).makeDeployInitialCollateralInvitation(issuerKeywordRecord); 249 250 // const debtIssuers = await E(publicFacet).getIssuers(); 251 252 // const getLength = ({ length }) => length; 253 254 // t.deepEqual( 255 // getLength(debtIssuers), 256 // 2, 257 // 'debtIssuers array should expose the correct issuers' 258 // ); 259 // const [LiAtomsIssuer, LiDollarsIssuer] = debtIssuers; 260 261 // t.truthy( 262 // await LiAtomsIssuer.getBrand(), 263 // 'should expose a reference to the LiAtoms Issuer' 264 // ); 265 // t.truthy( 266 // LiDollarsIssuer.getBrand(), 267 // 'should expose a reference to the LiDollars Issuer' 268 // ); 269 270 // const liAtoms = x => AmountMath.make(LiAtomsIssuer.getBrand(), x); 271 // const liDollars = x => AmountMath.make(LiDollarsIssuer.getBrand(), x); 272 273 // const deployInitialCollateralProposal = harden({ 274 // give: { 275 // Atoms: atoms(initialAtoms) 276 // }, 277 // want: { 278 // LiAtoms: liAtoms(initialAtoms) 279 // } 280 // }); 281 // /** 282 // * @type {Invitation} 283 // */ 284 // const deployInitialCollateralInvitation = await E( 285 // marketManagerFacet 286 // ).deployInitialCollateral(); 287 288 // /** 289 // * @type {UserSeat} 290 // */ 291 292 // const deployCollateralSeat = await E(zoe).offer( 293 // deployInitialCollateralInvitation, 294 // deployInitialCollateralProposal, 295 // deployInitialCollateralPayments 296 // ); 297 298 // const deployCollateralOfferResult = 299 // await deployCollateralSeat.getOfferResult(); 300 // const setupTestMarketParams = 301 // await deployCollateralOfferResult.setMarketParams(); 302 // console.log({ deployCollateralOfferResult }); 303 // const dollarsInterestState = { 304 // uOptimal: 80, 305 // slope1: 4, 306 // slope2: 60 307 // }; 308 // const setParamsResult = setupTestMarketParams( 309 // 'Dollars', 310 // dollarsInterestState, 311 // makeSubscriptionKit() 312 // ); 313 314 // t.truthy( 315 // deployCollateralOfferResult.getStore, 316 // 'deployCollateralOfferResult should expose getStore' 317 // ); 318 319 // const poolCollateralTypes = await deployCollateralOfferResult.getStore(); 320 321 // t.deepEqual( 322 // poolCollateralTypes.get('Atoms').totalSupply, 323 // atoms(initialAtoms), 324 // 'should return the correct value' 325 // ); 326 327 // t.deepEqual( 328 // poolCollateralTypes.get('Atoms').issuer, 329 // atomIssuer, 330 // 'should return the atom issuer type' 331 // ); 332 333 // t.deepEqual( 334 // poolCollateralTypes.get('Dollars').totalSupply, 335 // dollars(0n), 336 // 'should return the correct value' 337 // ); 338 339 // t.deepEqual( 340 // poolCollateralTypes.get('Dollars').issuer, 341 // dollarIssuer, 342 // 'should return the Dollar issuer type' 343 // ); 344 345 // const getLiAtomsAmount = payment => LiAtomsIssuer.getAmountOf(payment); 346 // const getLiDollarsAmount = payment => LiDollarsIssuer.getAmountOf(payment); 347 348 // const liAtomsPayment = deployCollateralSeat.getPayout('LiAtoms'); 349 350 // t.deepEqual( 351 // await getLiAtomsAmount(liAtomsPayment), 352 // liAtoms(initialAtoms), 353 // 'should pay out all expected tokens to the depositer' 354 // ); 355 356 // t.deepEqual(await getLiAtomsAmount(liAtomsPayment), liAtoms(initialAtoms)); 357 358 // const deployDollarsProposal = harden({ 359 // give: { 360 // Dollars: dollars(initialDollars) 361 // }, 362 // want: { 363 // LiDollars: liDollars(initialDollars) 364 // } 365 // }); 366 367 // /** 368 // * @type {UserSeat} 369 // */ 370 371 // const deployDollarsSeat = await E(zoe).offer( 372 // await E(marketManagerFacet).deployInitialCollateral(), 373 // deployDollarsProposal, 374 // { Dollars: dollarMint.mintPayment(dollars(initialDollars)) } 375 // ); 376 377 // await deployCollateralSeat.getOfferResult(); 378 // const liDollarsPayment = deployDollarsSeat.getPayout('LiDollars'); 379 380 // t.deepEqual( 381 // await getLiDollarsAmount(liDollarsPayment), 382 // liDollars(initialDollars), 383 // 'should pay out all expected tokens to the depositer' 384 // ); 385 386 // // Investigate: THESE TESTS GET STALE. 387 // // We should be able to use the same .poolCollateralTypes store every time. 388 // // This test is working, but we should be able to use the .getStore() returned in the initial offerResult L#231 389 390 // t.deepEqual( 391 // await poolCollateralTypes.get('Dollars').totalSupply, 392 // dollars(initialDollars) 393 // ); 394 395 // const additionalAtoms = 5000n; 396 397 // const deployMoreAtomsSeat = await E(zoe).offer( 398 // await E(marketManagerFacet).deployInitialCollateral(), 399 // harden({ 400 // give: { 401 // Atoms: atoms(additionalAtoms) 402 // }, 403 // want: { 404 // LiAtoms: liAtoms(additionalAtoms) 405 // } 406 // }), 407 // { Atoms: atomMint.mintPayment(atoms(additionalAtoms)) } 408 // ); 409 410 // await deployMoreAtomsSeat.getOfferResult(); 411 // const liAtomsPaymentTwo = deployMoreAtomsSeat.getPayout('LiAtoms'); 412 413 // t.deepEqual( 414 // await getLiAtomsAmount(liAtomsPaymentTwo), 415 // liAtoms(additionalAtoms), 416 // 'Payment amount should contain the correct amount of LiAtoms' 417 // ); 418 419 // t.deepEqual( 420 // await poolCollateralTypes.get('Atoms').totalSupply, 421 // atoms(initialAtoms + additionalAtoms), 422 // 'poolCollateralTypes store should update the totalSupply of Dollars to equal the updated value.' 423 // ); 424 425 // const additionalDollars = 1250000n; 426 427 // const deployMoreDollarsSeat = await E(zoe).offer( 428 // await E(marketManagerFacet).deployInitialCollateral(), 429 // harden({ 430 // give: { 431 // Dollars: dollars(additionalDollars) 432 // }, 433 // want: { 434 // LiDollars: liDollars(additionalDollars) 435 // } 436 // }), 437 // { Dollars: dollarMint.mintPayment(dollars(additionalDollars)) } 438 // ); 439 440 // const liDollarsPaymentTwo = deployMoreDollarsSeat.getPayout('LiDollars'); 441 442 // t.deepEqual( 443 // await getLiDollarsAmount(liDollarsPaymentTwo), 444 // liDollars(additionalDollars), 445 // 'Payment amount should contain the correct amount of LiDollars' 446 // ); 447 448 // t.deepEqual( 449 // await poolCollateralTypes.get('Dollars').totalSupply, 450 // dollars(initialDollars + additionalDollars), 451 // 'poolCollateralTypes store should update the totalSupply of Dollars to equal the updated value.' 452 // ); 453 // });