/ contract / src / shared / reader.js
reader.js
  1  /**
  2   * @file shared functions used when operating with the reader monad.
  3   */
  4  import { AmountMath } from '@agoric/ertp';
  5  import { Fn } from '../../data.types.js';
  6  import {
  7    formatHeadOffer,
  8    formatOfferSide,
  9    handleBasicExchange
 10  } from './utils/offers.js';
 11  import { actionTypes } from './state/index.js';
 12  
 13  const { ask } = Fn;
 14  
 15  const initOrSet =
 16    store =>
 17    ({ keyword, brand, value, ...rest }) =>
 18      !store.has(keyword)
 19        ? store.init(keyword, {
 20            value,
 21            brand,
 22            ...rest
 23          })
 24        : store.set(keyword, {
 25            totalSupply: store.get(keyword).totalSupply + value,
 26            ...rest
 27          });
 28  
 29  const runGetWantAmount = () =>
 30    ask.map(({ userSeat }) => formatHeadOffer(userSeat.getProposal().want));
 31  
 32  const runGetGiveAmounts = () =>
 33    ask.map(env => formatOfferSide(env.userSeat.getProposal().give));
 34  const runGetWantAmounts = () =>
 35    ask.map(env => formatOfferSide(env.userSeat.getProposal().want));
 36  
 37  const runGetGiveAmount = () =>
 38    ask.map(({ userSeat }) => formatHeadOffer(userSeat.getProposal().give));
 39  /**
 40   * @description the resulting allocations held by an adminSeat following an exchange.
 41   * @typedef {Object <Allocation, Allocation>} ResultAdminAllocations
 42   */
 43  /**
 44   *
 45   * @function runIncrementAdmin
 46   * @returns {ReturnType <ResultAdminAllocations>} the resulting allocations held by an adminSeat following an exchange.
 47   */
 48  const runIncrementAdmin = () =>
 49    ask.map(({ userSeat, poolSeat }) => handleBasicExchange(poolSeat, userSeat));
 50  
 51  /**
 52   * @function runReallocate
 53   * @returns {ReturnType <Reallocate<UserSeat, ZCFSeat>>}
 54   */
 55  const runReallocate = () =>
 56    ask.map(({ zcf, userSeat, poolSeat }) => zcf.reallocate(userSeat, poolSeat));
 57  
 58  /**
 59   * @function runExitUserSeat
 60   * @returns {void} succesfully exit will return void.
 61   * @description exits the userSeat from an offer handler.
 62   */
 63  const runExitUserSeat = () => ask.map(({ userSeat }) => userSeat.exit());
 64  
 65  const runGetIssuerRecord = () =>
 66    ask.map(state => ({ ...state, ...state.zcfMint.getIssuerRecord() }));
 67  
 68  const runPublishMarketEvent = giveObject =>
 69    ask.map(env =>
 70      env[giveObject.keyword].marketPubisher.updateState({
 71        type: actionTypes.private.poolManager.SUPPLY,
 72        payload: { ...giveObject, accountId: env.userStore.get('id').accountId }
 73      })
 74    );
 75  
 76  const handleUpdateUserStore =
 77    (userStore, accountId) =>
 78    ({ keyword, brand, value }) =>
 79      userStore.has(keyword)
 80        ? userStore.set(
 81            keyword,
 82            harden({
 83              accountId,
 84              supplied: AmountMath.add(
 85                userStore.get(keyword).supplied,
 86                AmountMath.make(brand, value)
 87              )
 88            })
 89          )
 90        : userStore.init(
 91            keyword,
 92            harden({
 93              accountId,
 94              supplied: AmountMath.make(brand, value)
 95            })
 96          );
 97  
 98  const runUpdateUserStore = giveObject =>
 99    ask.map(({ userStore }) =>
100      handleUpdateUserStore(userStore, userStore.get('id').accountId)(giveObject)
101    );
102  
103  const runRecordUserDeposit = () => runGetGiveAmount().chain(runUpdateUserStore);
104  
105  const runRecordAdminDeposit = () =>
106    runGetGiveAmount().chain(runPublishMarketEvent);
107  
108  const mergeReader = inner => Fn(x => ({ ...x, ...inner }));
109  
110  const runMintTokens = ({ currentMint, value, keyword }) =>
111    Fn.ask.map(env =>
112      currentMint.mint.mintGains(
113        {
114          [keyword]: currentMint.makeAmount(value)
115        },
116        env.userSeat
117      )
118    );
119  
120  /**
121   * Flow
122   * 1. exchange user allocation into poolSeat.
123   * 2. grab the userSeat "want" property from offer.
124   * 3. find debt token mint requested.
125   * 4. mint debt tokens directly to the userSeat (at this point, the poolSeat and userSeat both have their staged allocations)
126   */
127  
128  const runPrepareMint = ({ keyword, value }) =>
129    Fn.ask.map(env => ({
130      currentMint: env[keyword.slice(2)].mint.mintDetails,
131      value,
132      keyword
133    }));
134  
135  const runHandleDebtTokenMint = () =>
136    runIncrementAdmin()
137      .chain(runGetWantAmount)
138      .chain(runPrepareMint)
139      .chain(runMintTokens);
140  
141  // userStore creation or find process - START
142  // ######################################
143  const handleFindOrCreateUserId = (userStore, activeAccountsStore) =>
144    !userStore.has('id')
145      ? userStore.init(
146          'id',
147          harden({
148            accountId: activeAccountsStore
149          })
150        )
151      : userStore;
152  
153  const runFindUserAccount = activeAccountsLength =>
154    Fn.ask.map(env =>
155      handleFindOrCreateUserId(env.userStore, activeAccountsLength)
156    );
157  const runGetActiveAccountLength = Fn(env => env.activeAccountsStore.getSize());
158  
159  const runAccountStoreFns = runGetActiveAccountLength.chain(runFindUserAccount);
160  // ######################################
161  // userStore creation or find process - END
162  
163  export {
164    mergeReader,
165    initOrSet,
166    runAccountStoreFns,
167    runGetIssuerRecord,
168    runHandleDebtTokenMint,
169    runGetWantAmount,
170    runIncrementAdmin,
171    runReallocate,
172    runExitUserSeat,
173    runGetGiveAmount,
174    runGetGiveAmounts,
175    runGetWantAmounts,
176    runRecordAdminDeposit,
177    runRecordUserDeposit
178  };