Skip to content

Commit 1f4182b

Browse files
committed
Unlisted Middleware example page
Generated new unlisted participants weight example page Added Google Tag plugin and related config Removed mainnet mentions from smart contracts page Fixed address in Troubleshooting page
1 parent ba3fa22 commit 1f4182b

File tree

6 files changed

+154
-56
lines changed

6 files changed

+154
-56
lines changed

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

Lines changed: 33 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
---
22
sidebar_label: 'Based App Development'
3-
sidebar_position: 1
3+
sidebar_position: 2
44
---
55

66
# Based Application Development
77

88
This guide outlines the steps for based applications developers looking to build on the Based Applications platform.
99

10-
## 0. Developing a Based Application Middleware smart contract
10+
<!-- ## 0. Developing a Based Application Middleware smart contract
1111
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.
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. -->
1313

1414
## 1. Configuring and Registering the bApp
1515

@@ -67,9 +67,8 @@ bApp clients need to track the weight of each participant in the bApp.
6767
A simple way to do so would be to use the Subgraph and perform a request with this query:
6868

6969
```graphql
70-
7170
query MyQuery {
72-
bapp(id: "1") {
71+
bapp(id: "0xaA184b86B4cdb747F4A3BF6e6FCd5e27c1d92c5a") {
7372
# this is a mapping table, representing the many-to-many relationship between bapps and strategies
7473
strategies {
7574
obligations {
@@ -100,48 +99,30 @@ query MyQuery {
10099
```
101100

102101
This will return:
103-
* **all balances** per token for a given strategy
104-
* **all obligations** per token for a given strategy
105-
* TODO add remaining data
102+
* **all `Strategies`** that opted in to the `bApp`
103+
* for each `Strategy`, it will also provide
104+
* **all `Obligation`s** per token
105+
* **all `balance`s** per token
106+
* **all `Account`s** that delegated validator balance to the strategy owner
107+
* the **shared risk level** for each token added to the bApp
106108

107-
For all the strategies that opted-in to a given bApp
109+
For all the strategies that opted-in to a given bApp, clients will have to:
108110

109-
1. Clients will have to use this data to obtain a global mapping of `Token -> Strategy -> Amount`
110-
111+
1. **Gather Obligated Balances**: Get the obligated balance from each strategy, for each token used by the bApp.
112+
```go
113+
ObligatedBalance mapping(Token -> Strategy -> Amount)
114+
```
111115
This is done by multiplying the `percentage` of obligated tokens by the `balance` of such tokens deposited to the strategy
112116

113-
```typescript
114-
// build a map that links each token with the mapping of a strategy and their related obligated balance
115-
let strategiesObligatedBalancesPerToken: Map<string, Map<number, number>> = new Map();
116-
117-
// build the two separate mappings of obligations per token, balances per token
118-
// calculate the actual balance obligated for each token
119-
// and add the entry to the global mapping
120-
for (let strategy of response.data.data.bapp.strategies) {
121-
let obligationsPerToken: Map<string, number> = new Map(strategy.obligations.map(
122-
(obligation) => return [token, percentage]
123-
))
124-
let balancesPerToken: Map<string, number> = new Map(strategy.strategy.balances.map(
125-
(obligation) => return [token, balance]
126-
))
127-
128-
obligationsPerToken.keys().map(
129-
(token) => {
130-
strategiesObligatedBalancesPerToken.set(token) = new Map([strategy.id, obligationsPerToken.get(token) * balancesPerToken.get(token)])
131-
}
132-
)
133-
}
134-
```
135-
2. TODO Add Validator balance calculation
136-
3. **Sum Obligations**: From `ObligatedBalance`, it can sum all obligations and compute the total amount obligated to the bApp by all strategies.
117+
2. **Sum Obligations**: From `ObligatedBalance`, bApps should sum all obligations and compute the total amount obligated to the bApp by all strategies.
137118
```go
138119
TotalBAppBalance mapping(Token -> Amount)
139120
```
140-
4. **Calculate Risk**: For each token, it should get the risk (token-over usage) of each strategy.
121+
3. **Calculate Risk**: For each token, it should get the risk (token-over usage) of each strategy. This is obtained by summing all the `percentages` in all `Obligations` for a given token, and dividing it by `100`.
141122
```go
142123
Risk mapping(Token -> Strategy -> Float)
143124
```
144-
5. **Compute Risk-Aware Weights**: With this information, it can compute the weight of a participant for a certain token by
125+
4. **Compute Risk-Aware Weights**: With this information, bApps can compute the weight of a participant for a certain token by
145126

146127
$$
147128
W_{\text{strategy, token}} = c_{\text{token}} \times \dfrac{ObligatedBalance[\text{token}][\text{strategy}]}{TotalBAppBalance[\text{token}]} e^{-\beta_{\text{token}} \times max(1, Risk[\text{token}][\text{strategy}])}
@@ -153,25 +134,29 @@ For all the strategies that opted-in to a given bApp
153134
c_{\text{token}} = \left( \sum_{\text{strategy}} \dfrac{ObligatedBalance[\text{token}][\text{strategy}]}{TotalBAppBalance[\text{token}]} e^{-\beta_{\text{token}} \times max(1, Risk[\text{token}][\text{strategy}])} \right)^{-1}
154135
$$
155136

156-
:::info
157-
If the bApp uses validator balance, the client should also read a `map[Strategy]ValidatorBalance` with the amount from each strategy. As this capital doesn't involve any type of risk, all risk values can be set to 0. Thus, for this capital, this is equivalent to
137+
5. **If the bApp uses validator balance**, the client should also generate a mapping of `Strategy -> Validator Balance` with the amount from each strategy.
138+
139+
This is obtained as *the sum of all the validator balances delegated to the owner of the strategy*. Bear in mind, these are stored as percentages, so the actual *effective validator balance* for a given `delegator` has to be looked up the beacon chain (the [`based-apps-sdk`](https://github.com/ssvlabs/based-apps-sdk) provides a function to do this: `getValidatorsBalance(account)`), and then multiplied by the percentage that is delegated.
140+
141+
As this capital doesn't involve any type of risk, all risk values can be set to 0. Thus, for this capital, this is equivalent to:
142+
158143
$$
159144
W_{\text{strategy, validator balance}} = \dfrac{ObligatedBalance[\text{validator balance}][\text{strategy}]}{TotalBAppBalance[\text{validator balance}]}
160145
$$
161-
:::
162146

163147
6. **Combine into the Final Weight**: With the per-token weights, the final step is to compute a final weight for the participant using a **combination function**. Such function is defined by the bApp and can be tailored to its specific needs. Traditional examples include the arithmetic mean, geometric mean, and harmonic mean.
164148

165149

166-
**Example**: Let's consider a bApp that uses tokens $A$ and $B$, and considers $A$ to be twice as important as $B$. Then, it could use the following weighted harmonic mean as its combination function:
150+
**Example**: Let's consider a bApp that uses tokens $A$ and $B$, and considers $A$ to be twice as important as $B$. Then, it could use the following weighted harmonic mean as its combination function:
167151

168-
$$
169-
W^{\text{final}}_{\text{strategy}} = c_{\text{final}} \times \dfrac{1}{\dfrac{2/3}{W_{\text{strategy, A}}} + \dfrac{1/3}{W_{\text{strategy, B}}}}
170-
$$
152+
$$
153+
W^{\text{final}}_{\text{strategy}} = c_{\text{final}} \times \dfrac{1}{\dfrac{2/3}{W_{\text{strategy, A}}} + \dfrac{1/3}{W_{\text{strategy, B}}}}
154+
$$
171155

172-
where $c_{\text{final}}$ is a normalization constant computed as
156+
where $c_{\text{final}}$ is a normalization constant computed as
173157

174-
$$
175-
c_{\text{final}} = \left( \sum_{\text{strategy}} \dfrac{1}{\dfrac{2/3}{W_{\text{strategy, A}}} + \dfrac{1/3}{W_{\text{strategy, B}}}} \right)^{-1}
176-
$$
158+
$$
159+
c_{\text{final}} = \left( \sum_{\text{strategy}} \dfrac{1}{\dfrac{2/3}{W_{\text{strategy, A}}} + \dfrac{1/3}{W_{\text{strategy, B}}}} \right)^{-1}
160+
$$
177161

162+
<!-- [At the following page](./participant-weight-example.md), you can find a coded example of how to combine Subgraph data with the logic described above. -->
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
---
2+
sidebar_label: 'Participant Weight Example'
3+
sidebar_position: 3
4+
unlisted: true
5+
---
6+
7+
# Participant Weight Script
8+
9+
The script below uses the logic described in the [related section of the Based Application Development page](based-application-depvelopment.md/#3-participant-weight), fetching the data from the Based Application Subgraph, and returns the Weight for all Strategies that have opted in to a given Based Application
10+
11+
```typescript
12+
import fetch from "node-fetch";
13+
14+
// Define the GraphQL endpoint URL
15+
const url = "https://api.studio.thegraph.com/query/53804/ssv-bapps-subgraph/version/latest";
16+
17+
// Define the GraphQL query - Update operators and account address to query different clusters
18+
const query = `{
19+
bapp(id: "0xaA184b86B4cdb747F4A3BF6e6FCd5e27c1d92c5a") {
20+
# this is a mapping table, representing the many-to-many relationship between bapps and strategies
21+
strategies {
22+
obligations {
23+
token
24+
percentage
25+
}
26+
# this is the actual strategy entity
27+
strategy {
28+
balances {
29+
balance
30+
token
31+
}
32+
id
33+
owner {
34+
delegators {
35+
percentage
36+
id
37+
}
38+
}
39+
}
40+
}
41+
bAppTokens {
42+
sharedRiskLevel
43+
token
44+
}
45+
}
46+
}`
47+
48+
// Function to fetch data
49+
async function fetchData() {
50+
try {
51+
// Make the HTTP request to the GraphQL endpoint
52+
const response = await fetch(url, {
53+
method: 'POST',
54+
headers: {
55+
'Content-Type': 'application/json',
56+
},
57+
body: JSON.stringify({ query })
58+
});
59+
60+
// Parse the response data
61+
const responseData = await response.json();
62+
63+
// ➡️ 1. **Gather Obligated Balances**
64+
// build a map that links each token with the mapping of a strategy and their related obligated balance
65+
let strategiesObligatedBalancesPerToken: Map<string, Map<number, number>> = new Map();
66+
67+
// build the two separate mappings of obligations per token, balances per token
68+
// calculate the actual balance obligated for each token
69+
// and add the entry to the global mapping
70+
for (let strategy of response.data.data.bapp.strategies) {
71+
let obligationsPerToken: Map<string, number> = new Map(strategy.obligations.map(
72+
(obligation) => return [token, percentage]
73+
))
74+
let balancesPerToken: Map<string, number> = new Map(strategy.strategy.balances.map(
75+
(obligation) => return [token, balance]
76+
))
77+
78+
obligationsPerToken.keys().map(
79+
(token) => {
80+
strategiesObligatedBalancesPerToken.set(token) = new Map([strategy.id, obligationsPerToken.get(token) * balancesPerToken.get(token)])
81+
}
82+
)
83+
}
84+
85+
// ➡️ 2. **Sum Obligations**
86+
let totalBAppBalancePerToken: Map<string, number> = new Map();
87+
88+
strategiesObligatedBalancesPerToken.entries().map(
89+
(token, strategyObligationsPerToken) => {
90+
totalBAppBalancePerToken.set(token) = strategyObligationsPerToken.values().reduce((accumulator, currentValue) => accumulator + currentValue, 0);
91+
}
92+
)
93+
94+
// ➡️ 3. **Calculate Risk**
95+
let riskPerTokenPerStrategy: Map<string, Map<number, number>>
96+
// ➡️ 4. **Compute Risk-Aware Weights**
97+
let cToken =
98+
// ➡️ 5. **Gather Obligated Validator Balances**
99+
// ➡️ 6. **Combine into the Final Weight**
100+
101+
102+
103+
104+
105+
} catch (error) {
106+
// Log any errors that occur during the fetch
107+
console.error("Error fetching data:", error);
108+
}
109+
}
110+
111+
// Run the fetchData function
112+
fetchData();
113+
```

docs/based-applications/developers/smart-contracts/README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ This smart contract is under development and as such, it is only deployed on Hol
1515

1616

1717
#### Holesky Testnet
18-
<!-- TODO missing deployment address -->
1918
| Contract | Address |
2019
|-----------------|-------------------------------------------------------------------------------------------------------------|
2120
| BasedAppManager | [`0x9B3345F3B1Ce2d8655FC4B6e2ed39322d52aA317`](https://holesky.etherscan.io/address/0x9B3345F3B1Ce2d8655FC4B6e2ed39322d52aA317) |
@@ -24,5 +23,4 @@ This smart contract is under development and as such, it is only deployed on Hol
2423
#### ABI
2524

2625
<!-- TODO missing ABI -->
27-
* [Mainnet](https://github.com/ssvlabs/based-applications/tree/contract-abi/docs/mainnet/v1.1.0/abi)
2826
* [Testnet](https://github.com/ssvlabs/based-applications/tree/contract-abi/docs/testnet/v1.1.0/abi)

docs/based-applications/developers/smart-contracts/based-app-middleware-example.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
---
22
sidebar_label: 'Based App Middleware Example'
33
sidebar_position: 2
4+
unlisted: true
45
---
56

67
# :warning: PAGE UNDER CONSTRUCTION :warning:

docs/based-applications/developers/smart-contracts/troubleshooting.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,4 @@ The best way to investigate this issue is to inspect the 4-byte selector for the
1212

1313
A useful tool that is able to do this comparison, is [tenderly](https://dashboard.tenderly.co/explorer), thanks to the fact that ssv.network's Smart Contracts have been verified.
1414

15-
<!-- TODO fix address -->
16-
Here is the [SSVNetwork contract, for example](https://dashboard.tenderly.co/contract/holesky/0x).
15+
Here is the [`BasedAppManager` contract, for example](https://dashboard.tenderly.co/contract/holesky/0x9B3345F3B1Ce2d8655FC4B6e2ed39322d52aA317).

docusaurus.config.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,17 @@ const config: Config = {
3939
sidebarPath: './sidebars.ts',
4040
remarkPlugins: [remarkMath],
4141
rehypePlugins: [rehypeKatex],
42-
43-
// Please change this to your repo.
44-
// Remove this to remove the "edit this page" links.
4542
editUrl:
46-
'https://github.com/ssvlabs/gitbook-docs/tree/main/packages/create-docusaurus/templates/shared/',
43+
'https://github.com/ssvlabs/gitbook-docs/tree/main/',
44+
4745
},
4846
theme: {
4947
customCss: './src/css/custom.css',
5048
},
49+
gtag: {
50+
trackingID: 'G-PYFERXZQP7',
51+
anonymizeIP: true,
52+
},
5153
} satisfies Preset.Options,
5254
],
5355
],

0 commit comments

Comments
 (0)