Skip to content

Commit cb1aea9

Browse files
authored
Merge pull request #19 from ssvlabs/strategy-weights
Strategy weights
2 parents 0eadd82 + 8cf4a1d commit cb1aea9

File tree

9 files changed

+596
-230
lines changed

9 files changed

+596
-230
lines changed

docs/based-applications/developers/based-application-depvelopment.md

Lines changed: 0 additions & 130 deletions
This file was deleted.
Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
---
2+
sidebar_label: 'Based App Development'
3+
sidebar_position: 2
4+
---
5+
6+
# Based Application Development
7+
8+
This guide outlines the steps for based applications developers looking to build on the Based Applications platform.
9+
10+
<!-- ## 0. Developing a Based Application Middleware smart contract
11+
12+
The `BAppManager` smart contract developed by SSV Labs accepts registrations of BApps that implement a specific interface. This is outlined [in this dedicated page](./smart-contracts/based-app-middleware-example.md), that also provides a simple example. -->
13+
14+
## 1. Configuring and Registering the bApp
15+
16+
1. **Define core attributes**:
17+
- `bApp`: a unique 20-byte EVM address that uniquely identifies the bApp.
18+
- `tokens`: A list of ERC-20 tokens to be used in the bApp's security mechanism. For the native ETH token, use the special address [`0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE`](https://github.com/ssvlabs/based-applications/blob/main/src/BasedAppManager.sol#L62).
19+
- `sharedRiskLevels`: a list with $\beta$ values, one for each token, representing the bApp's tolerance for risk (token over-usage).
20+
2. **Optional Non-Slashable Validator Balance**: If the bApp uses non-slashable validator balance, it should be configured off-chain, in the bApp's network.
21+
3. **Register the bApp**: Use the [`registerBApp`](./smart-contracts/BasedAppManager#registerbappbapp-tokens-sharedrisklevels-metadatauri) function of the smart contract:
22+
```javascript
23+
function registerBApp(
24+
address bApp,
25+
address[] calldata tokens,
26+
uint32[] calldata sharedRiskLevels,
27+
string calldata metadataURI
28+
)
29+
```
30+
- `metadataURI`: A JSON object containing additional details about your bApp, such as its name, description, logo, and website.
31+
4. **Update Configuration**: After registering, the bApp configuration can be updated only by the `owner` account.
32+
33+
## 2. Securing the bApp
34+
35+
Once the bApp is registered, `Strategies` can join it and allocate capital to secure it.
36+
37+
### 2.1 Opting in
38+
39+
A Strategy opts-in to the bApp by using the [`optInToBApp`](./smart-contracts/BasedAppManager#optintobappstrategyid-bapp-tokens-obligationpercentages-data) function of the smart contract:
40+
```javascript
41+
function optInToBApp(
42+
uint256 strategyId,
43+
address bApp,
44+
address[] calldata tokens,
45+
uint32[] calldata obligationPercentages,
46+
bytes calldata data
47+
)
48+
```
49+
- `tokens`: List of tokens to obligate to the bApp.
50+
- `obligationPercentages`: The proportion of each token's balance to commit to the bApp.
51+
- `data`: An extra optional field for off-chain information required by the bApp for participation.
52+
53+
For example, if `tokens = [SSV]` and `obligationPercentages = [50%]`, then 50% of the strategy's `SSV` balance will be obligated to the bApp.
54+
55+
The strategy’s owner can later update their obligations by modifying existing ones or adding a new token obligation.
56+
57+
### 2.2 Strategy's Funds
58+
59+
To compose their balances, strategies:
60+
1. receive ERC20 (or ETH) via [**deposits**](https://github.com/ssvlabs/based-applications/blob/main/src/BasedAppManager.sol#L376) from accounts.
61+
2. inherit the non-slashable validator balance from the strategy's owner account. Accounts [**delegate**](https://github.com/ssvlabs/based-applications/blob/main/src/BasedAppManager.sol#L201) validator balances between themselves, and the strategy inherits its owner's non-delegated balance plus the received balances from other accounts.
62+
63+
## 3. Participant Weight
64+
65+
Based Application managers need to track the weight of each participant (strategy) in the bApp itself. This process entails two separate steps:
66+
67+
1. Collecting risk-adjusted strategy weights for each token
68+
2. Combining such weights into a strategy weight, for each strategy
69+
70+
### Risk-adjusted strategy-token weights
71+
72+
The first step is made fairly easier thanks to the `based-apps-sdk`, which needs to be installed first:
73+
74+
```sh
75+
npm i @ssv-labs/based-apps-sdk
76+
```
77+
78+
The SDK provides a function that returns all the risk-adjusted weights for each token, for all the strategies that opted in to a given bApp:
79+
80+
```ts
81+
import { BasedAppsSDK, chains } from "@ssv-labs/based-apps-sdk";
82+
83+
const sdk = new BasedAppsSDK({
84+
chain: chains.holesky.id,
85+
});
86+
87+
// calculate strategy-token weights via the SDK
88+
const strategyTokenWeights = await sdk.api.calculateParticipantWeights({
89+
bAppId: "0x64714cf5db177398729e37627be0fc08f43b17a6",
90+
});
91+
92+
console.info(
93+
`Strategy-token weights: ${JSON.stringify(
94+
strategyTokenWeights,
95+
undefined,
96+
2
97+
)}`
98+
);
99+
```
100+
101+
This returns a matrix, mapping the risk-adjusted weight of each token to a given strategy.
102+
103+
```sh
104+
Strategy-token weights: [
105+
{
106+
"id": "10",
107+
"tokenWeights": [
108+
{
109+
"token": "0x68a8ddd7a59a900e0657e9f8bbe02b70c947f25f",
110+
"weight": 0.9267840593141798
111+
}
112+
],
113+
"validatorBalanceWeight": 0.3
114+
},
115+
{
116+
"id": "2",
117+
"tokenWeights": [
118+
{
119+
"token": "0x68a8ddd7a59a900e0657e9f8bbe02b70c947f25f",
120+
"weight": 0.07321594068582021
121+
}
122+
],
123+
"validatorBalanceWeight": 0.7
124+
}
125+
]
126+
```
127+
128+
In this example, strategy number `2` has a risk-adjusted weight of `~0.07` for the specified token, but it has a validator balance weight of `0.7`.
129+
130+
Strategy number `10`, has a much bigger risk-adjusted weight of `~0.93` for specified token, but it has a validator balance weight of `0.3`.
131+
132+
For more information on how these risk-adjusted strategy-token weights are calculated, [please visit this page](../learn/based-applications/strategy-weights.md).
133+
134+
### Final weight
135+
136+
To combine data from the previous step into the final Weight it is necessary to use a **combination function**. Such function has to be defined by the bApp itself and can be tailored to its specific needs. Traditionally, one good combination functions include the arithmetic mean, geometric mean, and harmonic mean.
137+
138+
Let's consider the bApp from step 1, which uses tokens **`0x68a8ddd7a59a900e0657e9f8bbe02b70c947f25f`** and **validator balance**. For the purpose of our example, this bApp considers **`0x68a8ddd7a59a900e0657e9f8bbe02b70c947f25f`** to be twice times as important as **validator balance**.
139+
140+
:::info
141+
Note: this is a purely fictional scenario, to show the strong impact of the coefficients attributed to tokens and validator balance, with respect to the final combined weight of a strategy.
142+
:::
143+
144+
Below it's reported a code snippet, showing how to combine weights from step 1 using a simple arithmetic weighted average in the described scenario:
145+
146+
```ts
147+
const validatorImportance = 1;
148+
const ssvTokenImportance = 2;
149+
150+
console.info(`Using arithmetic weighted average to calculate Strategy weights.
151+
Validator Balance is 2 times more important than 0x68a8ddd7a59a900e0657e9f8bbe02b70c947f25f`);
152+
153+
let simpleAverageStrategyWeights = new Map();
154+
for (const strategy of strategyTokenWeights) {
155+
// calculate the strategy weight, combining token weight and validator balance weight
156+
let strategyWeight =
157+
((strategy.validatorBalanceWeight || 0) * validatorImportance +
158+
strategy.tokenWeights[0].weight * ssvTokenImportance) /
159+
(validatorImportance + ssvTokenImportance);
160+
// set the value in the mapping
161+
simpleAverageStrategyWeights.set(strategy.id, strategyWeight);
162+
}
163+
164+
console.info(
165+
`Final Strategy weights: ${JSON.stringify(
166+
Object.fromEntries(simpleAverageStrategyWeights),
167+
undefined,
168+
2
169+
)}`
170+
);
171+
```
172+
173+
This returns a map with the combined risk-adjusted weight of each strategy.
174+
175+
```json
176+
Using arithmetic weighted average to calculate Strategy weights.
177+
Validator Balance is 2 times more important than 0x68a8ddd7a59a900e0657e9f8bbe02b70c947f25f
178+
Final Strategy weights: {
179+
"2": 0.28214396045721346,
180+
"10": 0.7178560395427865
181+
}
182+
```
183+
184+
### Complete example
185+
186+
[The following page](./participant-weight-example.md), shows the full coded example of how to obtain risk-adjusted strategy-token weights, and how to combine them. The example uses a weighted simple average (as shown here), as well as a slightly more involved **combination functions** like weighted geometric average and weighted harmonic average ([explained here](../learn/based-applications/strategy-weights.md)), and shows the different outcome of the three.

0 commit comments

Comments
 (0)