Architecture Description¶
The goal of this document is to outline the interactions of all the pieces involved in the current iteration of the protocol. It aims to fix interaction patterns of certain subsystems without finalising decisions on implementation choices. This should also make Phase 0.5 more understandable for everybody.
Prerequisites¶
We expect a certain baseline understanding of what we are doing in general (Building software systems for Stores which sell physical Goods. Currently in a physical location, meaning not e-commerce. If you are new to this, you might want to read our introduction blog post).
Conceptual familiarity with Public-Key signature schemes.
Smart Contracts: The Registries managing configuration and discovery of Stores and Relays. For now we assume that the mapping between a Store and its Relays is known.
Creating a Store¶
The first thing a merchant needs to do is the creation of their store itself.
This is done by minting NFT since the Store Registry is an extension of EIP721.
It therefore supplies the standard conformant mint
function.
The storeId
can be chosen by the caller but already taken IDs will lead to a revert.
Adding Users and Logging in¶
Next, we introduce the concept of Users, how they are registered with a Store and how they get access to the Listing and Inventory. For this interaction flow, we differentiate Users into Clerks and Admins.
Registered are all Users which have a Wallet Address (WA) assigned to the Store Registry.
Admins can add or remove Clerks
registered Users can authorise KeyCards (KC) which give them access to the Store
Note
There is only one Owner, which also counts as an Admin. Only the Owner can turn Clerks into Admins and vice versa.
Onboarding a Clerk¶
To add a new Clerk, an Admin creates a Invite Secret IS
and a corresponding Invite Verifier IV
via their Client software and sends the Link containing the IS
to the Clerk via some side-channel (for example E-Mail or Signal). Its public part, the IV
, is submitted to the Store Registry.
IS
andIV
are the secret and public part of an ECDSA key-pair.(While this processes could be modelled with a hash-function, we need to account for what is known as front running in Ethereum and similar systems, where the inputs to a contract are revealed to the public. Using signatures instead ensures only the Clerk had possession of the
IS
)
The
IS
is single use.All Admins can see all
IV
s for their Store.
When the Clerk opens the Link, they are presented with a registration page. The main goal here is to connect with MetaMask to get the WA of the new Clerk. We could also collect other metadata about the Clerk at this point, like their name, an avatar or their e-mail. We could also do a reverse-lookup of an associated ENS address (e.g. my WA maps to cptx.eth
) but this might have to wait until a later stage.
The IS
is redeemed by calling the contract function redeemInvite
, which changes the invites status for the Admins. It checks the signature by using ecrecover and checks if that returns a valid IP. Afterwards this process finally adds the new WA to the Relay configuration, which completes the registration of the Clerk.
The “Adding a Clerk” flowchart shows the interaction between the different actors.
Logging in¶
The Login mechanism is necessary for elevated RPC commands that are not public, like changing the Inventory of the Store.
It follows a simple challenge/response scheme to protect against replaying.
It is started by sending AuthenticateRequest to the Relay.
The Clerk proves control over their KC by signing a
challenge
the Relay responds with.The Relay checks the
signature
in ChallengeSolvedRequest.Afterwards the Clerk can use the KC to sign Events and perform actions on the Store.
The “Logging in” flowchart shows the interaction between the different systems.
Store and Relay synchronization¶
Note
Our working assumption is that Relays and their Clients will build the Listing and Inventory with Eventual Consistency. Meaning, all changes to a Listing will be individual Events. To gain the current state of a Listing, all Events are replayed and applied locally.
Items in the Store: Retrieving the Listing¶
Now that the Clerk can do things in the Store, let’s discuss the first common action: display items in the Store, also known as: the Listing.
The Relay keeps track of which Events have been acknowledged by a KeyCard and which have not.
Once the Store connects to the Relay, the Relay will send all Events that have not been acknowledged yet.
Store should verify listing state against on-chain data
The “Retrieving the Listing” flowchart shows the interaction between the different systems.
Updating the Listing¶
To change the Listing we need to create Events. The Event will result in a new reduced state of the Listing, also known as the root hash. To keep Relays honest, this root hash is also saved on the block chain, to protect against omissions or other corruptions. See Store Configuration for more details.
Events have to have a known type. Currently we foresee:
Add new Item (which creates a new identity)
De-list an Item (marks the Identity invalid for future use but not non-existent)
Update metadata associated with an Item
Change stock count of an Item
Creating Carts and assigning Items to them
See schema.proto for a full list.
See Events mutate the listing for simplified visual illustration of the concept.
Note
We might have a 2nd class of Events, that are non-durable. Specifically, these might be cart-related events or other session data that will have to be kept in sync between relays but not mutate the listing, and thus on-chain data, immediately.
Selling Items¶
Now that we can add and remove Items from the Store, let’s discuss how they are actually sold with our system.
Warning
To protect from selling items twice, the Relays will help with book-keeping. To use an analogy from the physical world: the Relays will keep a virtual copy of the shopping cart, marking items as used once a cart is finalized or the process expires.
Building a Cart for a Customer¶
Note
This flow follows the assumption that we are in pop-up mode. Meaning, the Clerk will build the cart for the Customer. Changing this mode of operation to an e-commerce/self-checkout setting would not be that much different, though.
When a Clerk adds an Item to the Cart the Client creates an ChangeCart Event, which is sent to the Relay. The Relay checks the event and signals availability of Inventory back to the Store page. (As well as other Relays, in Phase 0.75 and onward.)
The “Building a Cart for a Customer” flowchart shows the interaction between the different systems.
Warning
Item counts are checked against the total stock. Carts don’t lock up stuck until check-out has begun. This means that the stock count can change between adding an item to the cart and checking out. However, Clients can see when other carts use up stock (via ChangeCart) and will also receive ChangeStock Events when other carts completed checkout.
Completing the Purchase¶
Once the Cart is filled with the desired Items, the Clerk initiates the check-out via CommitCartRequest. This will collapse the Cart into a single update of the inventory and the Relay will yield a CartFinalized with the needed infromation, like the purchase address and the amount to pay. Once the Customer has paid their purchase, the ChangeStock Event is applied to the inventory by the Relay and on-chain data is updated.
The “Completing the Purchase” flowchart shows the interaction between the different systems.
Privacy Considerations¶
Warning
Now and next: There is a bunch of things in this current iteration we want to test, knowing that they won’t remain that way. There might be breaking changes in future versions of the protocol.
- Listing data will be public - we want to make it possible to be indexed and aggregated in the future.
Inventory counts, too? This will give a clear transparent picture of how good or bad a store is doing.
- Users that are running the store. This should be private/internal company data.
We need to think about how to protect this data from being leaked. Probably using seperate logs with stricter access control.
- The merchantAddr will be where all purchases is are collected.
can someone backtrace all sales from that account address?
assuming yes, we will see the paymentAddr of individual sales and thus their account address, too?
- What exactly hashes into the receiptHash?
Can listing changes be correlated to purchases?