comit-network / ambrosia

UI for trading in the COMIT network
Apache License 2.0
4 stars 3 forks source link

Reusable Features for the SDK #2

Closed yosriady closed 4 years ago

yosriady commented 4 years ago

Introduction

I've worked on building the PoC App with the COMIT SDK for a few sprints. Based on that, I've identified a list of three missing features that an app developer will need to build on COMIT. All three features have already been implemented on the app, since they were required for it to work.

This issue is meant to spark a conversation of whether we want to provide these features to other app developers, by adding it to the COMIT SDK.

1. State Machines

Related SDK issue: https://github.com/comit-network/comit-js-sdk/issues/94

The current SDK provides functions like deploy, fund, and redeem but as an app developer I have no idea when to call each of the functions. Specifically: when is a swap ready for step X? I've had to dig through the internal swap workflow, call swap.fetchDetails() to parse the ledger statuses, and figure out the steps on my own.

I've implemented two state machines (for the Taker app and the Maker service.) The state machine has this interface:

const s = new TakerStateMachine(swap)
await s.next();

Internally, it parses the swap properties to 'understand' what to do next. More details here: https://github.com/comit-network/comit-js-sdk/issues/94#issuecomment-604816783

We can port this to the SDK, so that users can just call next on a Swap:

await swap.next();

How the API will look like is open for discussion.

Note: The current state machine only implements the 'happy path', but to be production ready the state machines will need to handle branches such as the refund and expiry flow.

2. Polling

Both the Taker and Maker needs to execute the next action after the counterparty has executed theirs. The app needs to find this out by repeatedly polling fetchDetails() for the latest swap state.

Since there's no out-of-the-box polling functionality provided by the SDK, I've implemented my own for both the Maker service and the Taker app. It's a simple polling mechanism. Basically:

for (let swap of swaps) {
      await swap.next();
}

Note: There are two polling mechanisms, one for the backend and one for the frontend. The backend uses Node.js async/await, while the frontend approach uses React hooks to be more idiomatic React code.

For the SDK, we could explore a subscription-based API instead, for example:

swap.on('ready', (data) => {
  //  ... do something on the app
  swap.next();
})

I think this API is more flexible and easier to work with.

Feedback most welcome.

3. React Context & Hooks

Based on feedback, the app needed to use swaps as stateful objects and use a singleton global store for this state. This required the app to undergo a rearchitecture. The SDK doesn't provide an out-of-the box way to build a frontend in this style.

React Context and Hooks are key building blocks for modern React apps. Think of it as the idiomatic way to inject and consume dependencies such as modules or services in React.

I've started encapsulating the recommended architecture as reusable React hooks. Behind the scenes, these hooks manage state from a global store, so developers don't have to reinstantiate or rehydrate modules every time. With hooks, your clients and wallets are made available anywhere in the component tree as a singleton:

export default function HomePage(props: Props) {
  const {
    wallet: bitcoinWallet
  } = useBitcoinWallet();
  const {
    wallet: ethereumWallet
  } = useEthereumWallet();
  const { cnd } = useCnd();

  // you can call `cnd.getSwaps()` here
 // ... other code
}

We can package these React-specific helper code to a @comit/comit-react package to further accelerate COMIT App development. These hooks allow React developers to build COMIT apps at a higher level of abstraction with prebuilt components that follow our recommended practices.

yosriady commented 4 years ago

@D4nte @bonomat

yosriady commented 4 years ago

As discussed, this is not a high priority. We want to focus our efforts on user-facing app progress first, and only port features to the SDK once we are certain the app is more finalized.