anilhelvaci / agoric-sdk

monorepo for the Agoric Javascript smart contract platform
Apache License 2.0
0 stars 0 forks source link

Analysis Milestone: 2 #20

Open Jorge-Lopes opened 2 months ago

Jorge-Lopes commented 2 months ago

Context

This document contains all the latest decisions about how the Multi Vault Manager Per One Collateral Type work. For history see #4.

According to the questions and their answers here, we will carry out our development.

Product Questions Asked and Answered

Questions

  1. Is it possible to have more than one retail vault manager? In other words, for a given and already accepted collateral type, is it safe to assume that all incoming new vault managers will be of type institutional or can EC choose to create a new retail vault manager?
  2. Can EC add new accounts to the whitelist for a particular vault manager? Adding new accounts to an existing institutional vault manager can be done. However, it will (probably) go through EC so it will result having its own user flow. Do we want this?
  3. Can EC remove accounts from the whitelist for a particular vault manager? I am not sure how this can be done but I think this would make sense when we think about the possibility business relationships coming to an end with certain institutions. Should we work on solving this problem?

Agoric OpCo Answers

@otoole-brendan answered;

  1. Yes
  2. Yes
  3. No

For reference, see https://github.com/anilhelvaci/agoric-sdk/issues/4#issuecomment-2223755482

Case for PostalService

Using a core-eval is the usual way for sending invitations, for example EC member invitations, by requesting either namesByAddresses or namesByAddressesAdmin to get the depositFacet for a certain account then invoking depositFacet.receive(invitation). This process, of course, includes a BLDer DAO voting as to the nature of core-evals.

For our case, we want EC to handle all the action which means no BLDer DAO interaction. So we need a service that can be invoked from vaultFactory. Implementing the logic in the paragraph above just for one governed api in vaultFactory seemed a little bit too ad-hoc given the generic usage such a service might have. As we are aware of @dckc's existing work called postalService, our plan is to refine that contract and deploy it on Agoric Blockchain to use for our case.

Development Questions Answered During Analysis

How is EC going to update parameters for retail and institutional VMs?

The process represented in the diagram below is expected to be the same for both retail and institutional managers as institutional manager will also have their own identifier in vstorage.

sequenceDiagram
    actor mem as Member
    participant ec as EC UI
    participant vs as vStorage
    participant sw as Member SmartWallet
    participant ch as EconCharter
    participant gv as VF Governor
    participant vf as VaultFactory
    mem ->> ec: Raise DebtLimit for ATOM-A
    ec ->> vs: Query vaultManager specifiers
    vs -->> ec: { collateralBrand, managerIdentifier }
    ec ->> ec: Build offerSpec
    ec ->> sw: Initiate election
    Note over ec, sw: offerSpec = {..., offerArgs = {..., path = {paramPath = {key = {collateralBrand, managerIdentifier}}}}}
    sw ->> ch: Forward offer
    ch ->> ch: Lookup relevant governor
    ch ->> gv: voteOnParamChanges(..., {...path})
    gv ->> vf: Lookup path
    vf -->> gv: ATOM-A paramManager
    gv ->> gv: Election result = Positive
    gv ->> gv: Update params
    gv -->> sw: Offer succesful
    sw -->> vs: Offer succesful
    vf ->> vs: Params updated
    ec ->> vs: Lookup params
    ec ->> ec: Display updated params

How is an ordinary user will find the respective VM identifiers?

The new design to identify the correct vaultManager introduces a new child node under manager{manager-index} called metadata.

This metadata child can have a data model similar to below;

Note that data shown below is just a thought and not the final data model

const metadata = {
identifier,
title: "ATOM-A",
whitelist: ["agoric1....4w", "agoric1....2q", ...], // Means this is an institutional VM
}

So vstorage after the upgrade will look like below;

  published
  │__vaultFactory
  │  │__managers
  │     │__manager0
  │        │__governance
  │        │__metrics
  │        │__quotes
  │        │__vaults
  │        │__metadata ***
  │     │__manager1
  │        │   ...

Form of VM Identifiers: String vs Handle? [WIP]

VM identifiers are intended to serve as the key in vmStore. Here are main parameters I use to decide;

See discussion in agoric-sdk => [Agoric#9663](https://github.com/Agoric/agoric-sdk/discussions/9663)

How will vaultManagers be stored and organised?

The process represented in the diagram below represents the logic that should be enforced when a new VaultManager is created and how it should handle both Retail and Institutional VMs

flowchart LR
    A(EC) --> |Add new VM| D(VaultDirector)
    D(VaultDirector) --> C{Retail or Institutional}
    C -->|Retail| F(Retail VMs Store)
    --> |collateralBrand| E(Get VM store for a Col Type)
    --> |VM identifier| K(Init new retail VM)
    C -->|Institutional| G(Institutional VM store)
    --> |collateralBrand| N(Get VM store for a Col Type)
    --> |VM identifier| L(Init new retail VM)

Bellow, is a representation of the key-value pairs that will be held in the Retail and Institutional VMs Store:

Retail or Institutional VMs Store Key (collateralBrand) Value (VM store)
stAtom stAtomStore
stOsmo stOsmoStore
stAtomStore Key (VM identifier) Value (VM)
manager101 vaultManager
manager102 vaultManager

How is an ordinary user going to open a vault on a retail VM?

sequenceDiagram
   participant sw as User SmartWallet
   participant vd as VaultDirector
   participant vm as VaultManager

   Note over sw: user selects one of the vaultManagers displayed on dapp-inter
   sw ->> vd: getCollateralManager(brandIn, managerIdentifier)

   vd ->> vd: retailVMsStore.get(brandIn)
   vd ->> vd: ${brandIn}Store.get(managerIndex)

   vd -->> sw : vaultManagerPublicFacet
   sw ->> vm : makeVaultInvitation()
   vm -->> sw : invitation
   sw ->> vm : makeVaultKit()
   vm -->> sw : vaultKit

How is an institutional user going to be granted access to an institutional VM?

sequenceDiagram
    participant vd as VaultDirector
    participant vf as VaultFactory
    participant hl as VM Holder
    participant sw as User SmartWallet

    vd ->> vd: addNewManager(collateralBrand, initialParamValues)
    vd ->> vf: makeVaultManagerKit()
    vf -->> vd: kit
    vd ->> hl: makeVmHolder(kit.self.getPublicFacet(), getIterationCount)
    hl ->> hl: currentIteration = getIterationCount()
    Note over hl: currentIteration enables revoking access
    hl -->> vd: holder
    Note over vd, hl: holder = {invitationMakers = {MakeVault = pf.makeVaultInvitation}, holder = { getQuotes, getCompoundedInterest, getPublicTopics }}
    vd ->> sw: holder

How is an institutional user going to receive the InvitationMakers required to to open a vault?

It is important to highlight that the sendBatchTo method is NOT currently implemented in the postal-service.contract, but we are considering to include it to make the API more friendly for our use case.

sequenceDiagram
    actor I as Institution
    participant VD as VaultDirector
    participant Zoe
    participant PS as PostalService

    Note over VD: VaultDirector is provisioned with PostalService Instance
    VD ->> Zoe: getPublicFacet(PostalServiceInstance)
    Zoe -->> VD: PostalServicePF
    VD ->> PS: sendBatchTo(address, invitationMakers = { makeVaultInvitation })
    loop VaultManager whitelisted addresses
         PS ->> I: invitationMakers
    end

How is an institutional user going to open a vault on an institutional VM?

sequenceDiagram
    actor us as Institutional User
    participant ui as dapp-inter
    participant sw as User SmartWallet
    participant ivm as Institutional VM

    us ->> ui: select institutional VM
    us ->> ui: enter vault parameters
    us ->> ui: click open vault
    ui ->> ui: build offer spec
    note over ui: {invitationSpec= {previousOffer= "{$address-manager-$managerIndex}"}, proposal, offerArgs}
    ui ->> sw: offer sent
    sw ->> sw: find continuing invitation for {$address-manager-$managerIndex}
    sw ->> sw: invitationMakers.makeVaultInvitation()
    sw ->> ivm: forward offer
    ivm ->> ivm: makeVatultKit()
    ivm -->> sw: vaultHolder
    sw -->> ui: success

How is the UX like for an institutional user accept their invitation?

sequenceDiagram
   actor ins as Institutional User
   participant ec as EC UI
   participant sw as User SmartWallet
   participant ecc as EC Charter

   Note over ins, sw: New vm added and invitations already sent
   ec -->> ins: [Off Chain] check your invitation purse and accept it
   ins ->> ec: Click "Accept Institutional Invite"
   ec ->> ec: build offer spec
   note over ec: offerSpec = {invitationSpec= {type = "purse", ...}, ...}
   ec ->> sw: send offer
   sw ->> ecc: accept institutional invite
   ecc -->> sw: invitationMakers = { makeVaultInvitation }
   sw -->> sw: publish offer successful
   note over ins: now ready to open vaults

For ref => https://github.com/anilhelvaci/agoric-sdk/issues/3#issuecomment-2226855685

dapp-inter flow for opening an institutional vault

sequenceDiagram
    participant user as institutionalUser
    participant int as dapp-inter
    participant vs as vStorage
    participant vf as vaultFactory

    user ->> int: connect keplr
    int ->> vs: query = list of institutional managers and the white-list
    vs -->> int: [manager0, manager1]
    Note over int, int: find which managers the user is whitelisted 
    int ->> int: display retail AND institutional managers
    int ->> int: display all vaults belonging to the user
    int -->> user: page loaded
    user ->> int: Click "open vault" for institutional manager
    int ->> int: calculate prevOfferId 
    Note over int,int: Inst users can send offers using continuing invitations
    Note over int,int: e.g {address}-manager-{managerIndex}-{?iteration}
    int ->> vf: Send vault offer
    Note over int, vf: offer = {invitationSpec = {source = continuing, prevOfferId, makeVaultInvitation}}
    vf -->> int: success

What are the structural differences between retail and institutional VMs?

A Retail Vault Manager is a vm that its public facing methods (collateral facet) are accessible to anybody. Anyone wishing to open a vault in these VMs can do so.

An Institutional Vault Manager is a vm that only a set whitelisted account can access its public facing methods (collateral facet). EC is in charge of determining the whitelisted accounts. If manager{managerIndex} storage node's child node metadata has a non-empty whitelist array, this means that vault manager is for institutional purposes and only those accounts listed under metadata.whitelist can send transactions to interact with that VM.

Is this new way of storing VMs going to cause any changes how vault lifecycles are carried out?

As far as I can see, vault lifecycle is handled separately via methods of vaultHolder. As a result for an institutional user having vaults from both institutional and retails VMs, all those vaults show up under wallet.{address}.current.offerToPublicSubscriberPaths with their own offerId as the key value. As a result an institutional user's smart wallet will have lifecycle methods for both institutional and retail vaults. Therefor, I don't expect any changes to the process as well.

Test Plan

The functionality we want to make sure works properly here is;