Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add StarkEx tutorials/guides #497

Merged
merged 17 commits into from
Nov 7, 2023
Merged
21 changes: 21 additions & 0 deletions packages/backend/src/content/tutorials/escapehatch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Escape Hatch Explained

For an introduction to StarkEx Explorer, see this guide:

- [Introduction to StarkEx Explorer](/tutorials/introduction)

Escape Hatch is a functionality available as the last resort for users to withdraw their funds from the StarkEx system to Ethereum.

When the StarkEx system is operating normally but a user is unable to use the regular interface (e.g., an exchange's web page), they should initiate a Forced Action request, as described in a separate guide ([All about Forced Actions](/tutorials/forcedactions)), to attempt the withdrawal of their funds. If Forced Action is not honored within a predefined amount of time (configured by StarkEx, usually 7 or 14 days), either due to inaction or because the operator is not functioning, the StarkEx Explorer will detect this state and display an option in the website header to "Request Freeze" of the StarkEx system.

## Exchange Freeze

Freezing the StarkEx system can be initiated by any user if at least one Forced Action has not been honored by the StarkEx Operator within the predefined time. By clicking on the "Request Freeze" button and confirming the Metamask transaction, the entire StarkEx system will enter a frozen state, in which no off-chain (L2) operations can be performed (e.g., no trades), and users will only be able to request the withdrawal of their full balances.

The StarkEx Explorer's interface will change accordingly, with the webpage header displaying an appropriate message on each page, and operations available to users will be altered as well.

## Performing an Escape

After visiting their User Page, users will find an "Escape" button next to their non-perpetual tokens in the Assets panel (the values of perpetual positions are automatically included in the collateral escape). Upon clicking this button, if a user's Ethereum address has not been registered on Ethereum (which implies that Ethereum contracts do not recognize which StarkKey belongs to that Ethereum address), they will need to register it via an Ethereum transaction. Next, the user will be presented with a description of the escape process and prompted to click on the "Initiate Escape" button. This action will prompt a Metamask transaction, which may incur significant cost due to the amount of data, specifically a Merkle Proof, which proves to the Ethereum smart contract that the user indeed owns the claimed assets as of the last state update.

Once the transaction has been confirmed on Ethereum, the User Page will display a "Pending Escapes" section. By clicking on the "Finalize Escape" button next to an asset, the user will be prompted to send a transaction via Metamask, which will complete the transfer of funds to the user's Ethereum wallet.
54 changes: 54 additions & 0 deletions packages/backend/src/content/tutorials/forcedactions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# All about Forced Actions

For an introduction to the StarkEx Explorer, see this guide:

- [Introduction to StarkEx Explorer](/tutorials/introduction)

Forced Actions are special operations initiated via the Ethereum blockchain. They are emergency measures that **should not be used under normal conditions** due to their high cost and slow execution time. They are useful when:

- the StarkEx system (e.g., an exchange) is operating normally,
- but the user cannot access the system's native interface (e.g., the exchange's website), for example, due to censorship.

In such scenarios, forced actions provide an emergency exit route for users to withdraw their assets to Ethereum.

If the StarkEx system is not operating normally (e.g., the operator's servers have been shut down completely), users will need to use the Escape Hatch, which is an expensive last-resort solution.

### Forced Withdrawal

Forced Withdrawals are used to withdraw user assets, except for "perpetual assets". If any perpetual positions are open, they must be closed via a "Forced Trade" before attempting a Forced Withdrawal.

To initiate a Forced Withdrawal, users should:

1. Open their User Page.
2. Click on the "Withdraw" button next to their token (collateral) entry in the "Assets" table.
3. Optional: If the user's Ethereum address has not been registered on Ethereum (meaning that Ethereum contracts do not recognize which StarkKey belongs to that Ethereum address), they will be prompted to do so via an Ethereum transaction.
4. Enter the requested amount to withdraw. StarkEx in Spot trading mode will only allow the withdrawal of the full balance.
5. Click on the "Prepare for withdrawal" button and send the requested transaction to Ethereum.

The created Forced Withdrawal request will be visible on the User Page in the "Forced transactions" panel.

After initiating a Forced Withdrawal, StarkEx operators have a predefined amount of time (usually 7 or 14 days) to process the requested withdrawal. When they do, the User Page will display a "Withdrawable assets" section with a "Withdraw now" button to trigger the final transfer of funds to the user's Ethereum account.

If the StarkEx Operator does not honor the user's Forced Withdrawal request within the given time, the user will be able to trigger an Exchange Freeze and engage the Escape Hatch functionality, described in a separate guide ([Escape Hatch explained](/tutorials/escapehatch)).

It is important to note that users can manually initiate Forced Withdrawals with incorrect amounts. Such requests will be processed by the StarkEx system, but due to their invalid data, they will not trigger the final withdrawal.

### Forced Trades

Forced Trades are required to close open perpetual positions.

To initiate a Forced Trade, users should:

1. Open their User Page.
2. Click on the "Close" button next to their perpetual asset entry in the "Assets" table. If the user's position is "long", this would trigger a "Sell" trade, or a "Buy" if the position is "short".
3. Optional: If the user's Ethereum address has not been registered on Ethereum (meaning that Ethereum contracts do not recognize which StarkKey belongs to that Ethereum address), they will be prompted to do so via an Ethereum transaction.
4. Enter the desired trade data (perpetual amount and price).
5. Click on the "Create buy/sell offer" button, which will require the user to sign with their MetaMask wallet.

Such a trade will be visible on the StarkEx Explorer Home Page and on the user's User Page in the "Offers" panel.

Offers are internal to the StarkEx Explorer and are not visible on Ethereum or within the StarkEx system.

An offer needs to be accepted by a counterpart via interaction with the offer on the Explorer. When a user "Accepts" the offer, the original creator can either cancel or approve it by sending a Forced Withdrawal transaction to Ethereum.

Just like with the Forced Withdrawal process, the StarkEx Operator has limited time to honor this trade. If they do, the position will disappear from the user's User Page, and the collateral asset balance will be updated accordingly. Otherwise, the user will be able to use the Escape Hatch functionality.
40 changes: 40 additions & 0 deletions packages/backend/src/content/tutorials/introduction.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Introduction to StarkEx Explorer

StarkEx Explorer is an open-source tool with a Web interface that allows users to independently download, verify, and browse data published to Ethereum by StarkEx systems. Additionally, it provides an interface to perform so-called "Forced Actions" and trigger "Escape Hatch" functionalities, which are the main guarantees of self-custody of funds.

## What is StarkEx

StarkEx is an Ethereum Layer 2 (L2) system targeting DeFi and trading applications. While most operations (like trading and creating orders) are created and executed off-chain for speed and low cost, users' balances are periodically hashed (in the form of a "Merkle Root") and published to Ethereum. If StarkEx operates in a "rollup mode," changes to users' balances are also published to Ethereum. In "validium" mode, that data is published to a set of trusted operators, known as the Data Availability Committee (DAC). Although L2 transactions are not published to Ethereum, their validity is ensured via validity proofs (specifically STARK Zero-Knowledge proofs) which are published to Ethereum. This architecture allows users, in case of emergency (such as censorship or exchange shutdown), to independently and trustlessly withdraw their assets to Ethereum using one of two mechanisms:

- Forced Actions - operations that must be included by StarkEx operators within a limited amount of time
- Escape Hatch - direct interaction with Ethereum contracts if Forced Actions are not honored by StarkEx operators

This guide will explore how the StarkEx Explorer can be used to browse data published by StarkEx systems.

To learn how it helps users ensure that their funds are safe and trades are valid, see:

- [Accessing User Page](/tutorials/userpage)

To learn how to perform Forced Actions and trigger Escape Hatch operations, see the following guides:

- [All about Forced Actions](/tutorials/forcedactions)
- [Escape Hatch Explained](/tutorials/escapehatch)

## Understanding Data Available on StarkEx Explorer

A notable feature of the StarkEx system is that users are identified by their StarkKey, not their Ethereum address, although they are related. Specifically, forced actions and the escape hatch require a user's StarkKey to be explicitly mapped to their Ethereum address. This can happen automatically or via user action at any time, depending on the decision made by the StarkEx operator.

### State Updates

Off-chain (L2) operations performed on the StarkEx system update the system state (which includes users' balances). For instance, when a user trades with another user, their balances change accordingly. After some time (typically a few hours, but this depends on the StarkEx Operator), a "State Update" is published to Ethereum (and to the DAC in validium mode). It includes the _changes_ that were made to users' balances since the last published state update.

Users can browse all published state updates in the "State Updates" table. Clicking on any given state update displays its details, which includes the Balance Changes for each StarkKey. It's important to remember that these are not actual transactions but the total change that occurred since the previous state update. Specifically, a user could have performed multiple operations in the time between two state updates, but only the final difference between the two will be presented in the Balance Changes table.

### User Page

Clicking on a specific Balance Change entry or searching for an existing StarkKey or previously mapped Ethereum address presents the "User Page," which displays:

- Assets - the balances of the user's assets **during the last state update**. This means that the most recent balance changes that occurred after the last state update will not be reflected on the Explorer. This is intentional, because only balances published to Ethereum will be considered if an emergency Escape Hatch functionality needs to be triggered.
- Balance Changes - updates to users' balances in past state updates. It's important to remember that these are not single operations performed by the user, but their cumulative effect between subsequent state updates.

Forced Transactions and Offers are described in a separate guide ([All about Forced Actions](/tutorials/forcedactions)). The Transactions (L2) panel is an optional feature available via custom integration with the StarkEx operator, but the validity of that data cannot be verified.
15 changes: 15 additions & 0 deletions packages/backend/src/content/tutorials/userpage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Accessing User Page

For an introduction to StarkEx Explorer, see this guide:

- [Introduction to StarkEx Explorer](/tutorials/introduction)

Accessing the user page is possible in multiple ways:

- If the user knows their StarkKey, they can simply search for it using the search box.
- If the user knows their Ethereum address, they can also search for it, but only if that address was previously **registered as an owner of a StarkKey**. On some exchanges, this process happens automatically, but due to its high cost, it is currently discouraged.
- Connecting via MetaMask to calculate their StarkKey using their Ethereum account.

## Connecting via MetaMask

When a user clicks on the "Connect wallet" button and approves the connection in their MetaMask wallet, the Explorer checks if the user's Ethereum address is already "registered," i.e., mapped to a StarkKey. If it's not, the user will be presented with an option to "Recover StarkKey." This operation is free of cost. By clicking on the "Recover" button, the user will be presented with a "Signature request" by the MetaMask interface. It is important to read the message that is supposed to be signed—it should be a sign-on request to an exchange. By "clicking" on the "Sign" button, the user's StarkKey will be calculated based on their Ethereum account (using the private key signature), and the user will be redirected to their User Page.
35 changes: 19 additions & 16 deletions packages/backend/src/core/TutorialService.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
import { HomeTutorialEntry } from '@explorer/frontend'
import fs from 'fs'

export class TutorialService {
getTutorials(): HomeTutorialEntry[] {
try {
const files = fs.readdirSync('src/content/tutorials')
return files.map((filename) => this.toTutorialEntry(filename))
} catch {
return []
}
}

private toTutorialEntry(filename: string): HomeTutorialEntry {
const filenameWithoutExt = filename.replace('.md', '')
return {
title: filenameWithoutExt.replaceAll('-', ' '),
imageUrl: `/images/${filenameWithoutExt}.jpg`,
slug: filenameWithoutExt.toLowerCase(),
}
const tutorials: HomeTutorialEntry[] = [
{
title: 'Introduction to StarkEx Explorer',
slug: 'introduction',
},
{
title: 'Accessing User Page',
slug: 'userpage',
},
{
title: 'All about Forced Actions',
slug: 'forcedactions',
},
{
title: 'Escape Hatch explained',
slug: 'escapehatch',
},
]
return tutorials
}
}
1 change: 0 additions & 1 deletion packages/backend/src/utils/markdown/getHtmlFromMarkdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ export function getHtmlFromMarkdown(filePath: string) {
$('a').each(function () {
const $el = $(this)
$el.attr('rel', 'noopener noreferrer')
$el.attr('target', '_blank')
})
$('h1, h2, h3, h4, h5, h6').each(function () {
const $el = $(this)
Expand Down
20 changes: 8 additions & 12 deletions packages/frontend/src/preview/data/tutorial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,23 +137,19 @@ line 3 of code

export const tutorials: HomeTutorialEntry[] = [
{
title: 'Learn how to use StarkEx Explorer efficiently',
imageUrl: '/images/tutorial.jpg',
slug: 'learn-how-to-use-starkex-explorer-efficiently',
title: 'Introduction to StarkEx Explorer',
slug: 'introduction',
},
{
title: 'All about forced transactions',
imageUrl: '/images/tutorial.jpg',
slug: 'all-about-forced-transactions',
title: 'Accessing User Page',
slug: 'userpage',
},
{
title: 'Stark key registration',
imageUrl: '/images/tutorial.jpg',
slug: 'stark-key-registration',
title: 'All about Forced Actions',
slug: 'forcedactions',
},
{
title: 'Escape hatches explained',
imageUrl: '/images/tutorial.jpg',
slug: 'escape-hatch-explained',
title: 'Escape Hatch explained',
slug: 'escapehatch',
},
]
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,7 @@ export function HomeSpotlightArticle(props: HomeSpotlightArticleProps) {
Read now
</Button>
</div>
<img
src={props.spotlightArticle.imageUrl}
data-fallback="/images/tutorial.jpg"
/>
<img src="/images/starkex-logo.png" />
</Card>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { SectionHeading } from '../../../components/SectionHeading'

export interface HomeTutorialEntry {
title: string
imageUrl: string
slug: string
}
interface HomeTutorialsProps {
Expand Down Expand Up @@ -37,11 +36,7 @@ export function HomeTutorials(props: HomeTutorialsProps) {
href={`/tutorials/${tutorial.slug}`}
className="group flex w-full items-center gap-4"
>
<img
className="aspect-video h-[63px] rounded"
src={tutorial.imageUrl}
data-fallback="/images/tutorial.jpg"
/>
<img className="h-[63px] rounded" src="/images/starkex-logo.png" />
<div className="flex-1">
<p className="text-base font-semibold leading-tight">
{tutorial.title}
Expand Down
5 changes: 2 additions & 3 deletions packages/frontend/src/view/pages/tutorial/TutorialsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,8 @@ export function TutorialsPage(props: TutorialsPageProps) {
{props.tutorials.map((tutorial, i) => (
<div key={i} className="group flex w-full gap-11">
<img
className="aspect-video w-[195px] rounded-lg"
src={tutorial.imageUrl}
data-fallback="/images/tutorial.jpg"
className="w-[100px] rounded-lg"
src="/images/starkex-logo.png"
/>
<div className="flex flex-col justify-between">
<p className="text-xl font-semibold leading-tight">
Expand Down