Technical Architecture Overview
The DeStreet tech stack is split into 3 components:
DeStreet Saga dApp (not covered)
DeStreet on-chain smart contract (covered here)
DeStreet off-chain backend (covered here)
The on-chain smart contract models different entities in the DeStreet application as accounts:
Trade (represents a directional trade between 2 assets: base and target)
Deposit (represents a deposit into a Trade)
Trade Global Config (a singleton global configuration account with fees and other misc. config items)
DeStreet Program
DeStreet Keeper
The on-chain lifecycle of a Trade
Every time a "trader" creates a new trade on DeStreet, a Trade account is initialized onchain which captures the trader's intent (base asset, target asset, long/short, expiry). This creation logic also creates escrow token accounts for either side of the trade. The "Trade" account is now in the "open" phase.
Depositors can now add funds to a trade while it's in the "open" phase by creating "Deposit" accounts - these accounts simply store the accounting state for deposits and not the funds itself. The funds are all pooled into the "Trade" account's associated token account (check special notes below) for the base asset (i.e. deposit asset).
DeStreet supports an arbitrary number of deposits for a specific trade. The trader is free to "start" the trade as they please and once the trade moves from the "open" phase to the "live" phase, no further deposits are allowed. The transition from "open" to "live" occurs when the trader makes their first swap from base asset to target asset. In the "live" phase, the trader is free to partially or fully swap back and forth between base and target assets with the goal to maximize the base asset (this is not currently restricted on chain and hence lossy trades are possible).
During trade creation, an "expiry" is set on the trade which also lives onchain. While the trader is free to "close" a trade before expiry, our off-chain backend systems (keeper) will automatically swap all remaining target assets back to base and close the trade should the trader abandon it/forget to close it. The trade is now in the "closed" phase.
During the "closed" phase, while the program exposes instructions that allow the trader and depositors to withdraw their fees and funds respectively, we automate it using our keeper. Hence, the keeper is a privileged account that is specified in the global config and is able to swap target assets to base as well as withdraw funds and fees to the depositors and traders respectively (note that the keeper cannot withdraw to any other token account).
Special notes
While the funds in a Trade need to live in token accounts owned by a PDA, we decided to make the Trade account a keypair account and have an associated TradeSigner PDA account that actually owns the funds. This decouples the program self-signing feature of the PDA from the Trader -> Trade mapping allowing a Trader to freely create an arbitrary number of trades.
The Deposit account is a PDA since we want to restrict the account space to 1 Deposit account per Trade per depositor. But, in this case we don't need the self-signing feature of PDAs.
Last updated