You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardexpand all lines: docs/fdc/guides/proof-of-reserves.mdx
+69-45
Original file line number
Diff line number
Diff line change
@@ -9,41 +9,46 @@ unlisted: false
9
9
---
10
10
11
11
This is a guide on how to build a simple dApp using the [Flare Data Connector](/fdc/overview).
12
-
It demonstrates how multiple attestation types, namely the EVMTransaction and JsonApi, can be combined within the same app.
12
+
It demonstrates how multiple attestation types, namely the [EVMTransaction](/fdc/attestation-types/evm-transaction) and [JsonApi](/fdc/attestation-types/json-api), can be combined within the same app.
13
13
14
-
The app that we will be building is called `proofOfReserves`.
14
+
The app that we will be building is called `proofOfReserves`, which enables on-chain verification that a stablecoin's circulating supply is backed by sufficient off-chain reserves.
15
15
We will first describe what issue the app is addressing, and then provide a detailed walkthrough through its source code.
16
16
All the code for this project is available on GitHub, in the [Flare Hardhat Starter](https://github.com/flare-foundation/flare-hardhat-starter) repository.
17
17
18
-
## The task
18
+
## The problem
19
19
20
-
A stablecoin is a type of token with a fixed value.
21
-
One token is guaranteed to always be exchangeable, for example, for one dollar.
20
+
Stablecoins are cryptographic tokens designed to maintain a fixed value, typically pegged to a fiat currency like the US dollar.
21
+
To maintain trust in the system, the issuing institution must hold sufficient reserves to back the tokens in circulation.
22
22
23
-
The institution backing the token provides a public Web2 API, listing its dollar reserves.
24
-
Meanwhile, they also issue tokens on multiple chains.
25
-
We want to compare the total token supply, across all chains, with the claimed dollar reserve value.
26
-
If the sum of tokens exceeds the claimed reserve amount, the institution is overdrafting its tokens.
27
-
That is why we call the app `proofOfReserves`.
23
+
The `proofOfReserves` application demonstrates how to verify that a stablecoin issuer maintains adequate off-chain dollar reserves to cover all tokens in circulation across multiple blockchains.
24
+
This verification creates transparency and helps prevent situations where more tokens exist than the backing reserves can support.
28
25
29
-
Here, we are facing several challenges.
30
-
First, how do we acquire data from a public Web2 API?
31
-
Second, how can we convert the state data of a contract to an event?
32
-
And thirdly, how can we collect the event data from another chain?
26
+
Implementing this verification system presents three technical challenges:
33
27
34
-
The answer to the first and the last question is FDC.
35
-
The answer to the second is, that we deploy a contract that, upon being prompted, reads the state data and emits an event with the data included.
28
+
1.**Accessing off-chain data**: We need to query a Web2 API that reports the institution's official dollar reserves.
29
+
2.**Reading on-chain state**: We need to access the total token supply data from various blockchain networks.
30
+
3.**Cross-chain data collection**: We need to aggregate token supply information across multiple chains.
36
31
37
-
This is all the information we need to write our `proofOfReserves` example.
32
+
The [Flare Data Connector (FDC)](/fdc/overview) provides solutions for both accessing Web2 APIs through the [JsonApi](/fdc/attestation-types/json-api) attestation type and collecting cross-chain data via the [EVMTransaction](/fdc/attestation-types/evm-transaction) attestation type.
33
+
For reading on-chain state, we deploy a dedicated contract that reads the token supply and emits this data as an event.
38
34
39
-
## Smart contracts
35
+
This guide will walk through all the components needed to build the complete `proofOfReserves` verification system.
40
36
41
-
To implement our proof of reserves example we will create three contracts.
42
-
If this were production code, we would only need two.
43
-
But since this is a guide and because we want to be able to play with token supply values, we will also deploy our own stablecoin.
37
+
## Smart Contract Architecture
44
38
45
-
The code that defines the token is as follows.
46
-
It is an ERC20 token that is burnable, ownable, and permits the owner to mint more tokens.
39
+
For our proof of reserves implementation, we'll create three distinct smart contracts:
40
+
41
+
1.`MyStablecoin`: A custom ERC20 token for testing
42
+
2.`TokenStateReader`: A utility contract that reads and broadcasts token supply data
43
+
3.`ProofOfReserves`: The main verification contract that processes attestation proofs
44
+
45
+
Note that in a production environment, we would typically only need two contracts - the main verification contract and a state reader.
46
+
However, since this is a guide and we want flexibility to experiment with different token supply values, we'll also deploy our own stablecoin.
47
+
48
+
### Stablecoin Contract
49
+
50
+
Let's start with the stablecoin implementation.
51
+
This contract creates an ERC20-compatible token with additional functionality for burning tokens and controlled minting.
Because we are building our app around `@openzeppelin`'s ERC20 token, we can later replace the token with any such instance.
73
78
This means that we can easily modify our app to work with an arbitrary contract that inherits the `ERC20`.
74
79
80
+
### TokenStateReader Contract
81
+
75
82
The second contract we need to write is the one that reads the total token supply of a given token and emits an event that exposes both the token address and its total supply.
76
83
It has a single method that takes an `ERC20` token instance and calls its `totalSupply` function.
77
84
Then, it emits the `TotalTokenSupply` event with the token's address and total supply.
@@ -92,9 +99,18 @@ contract TokenStateReader {
92
99
}
93
100
```
94
101
95
-
The last contract left to define will check whether the claimed dollar reserves exceed the sum of total token supplies.
96
-
Its main function, `verifyReserves`, will take two arguments: an `IJsonApi.Proof` struct, and an array of `IEVMTransaction.Proof` structs.
97
-
Then, if the sum of total token supplies is less than the claimed reserves it will return `true`, and `false` otherwise.
102
+
### ProofOfReserves Contract
103
+
104
+
The final component in our implementation is the `ProofOfReserves` contract, which performs the actual verification of reserve adequacy.
105
+
This contract evaluates whether the claimed dollar reserves are sufficient to back all tokens in circulation across different blockchains.
106
+
107
+
The core functionality is contained in the `verifyReserves` function, which accepts two parameters:
108
+
109
+
- An `IJsonApi.Proof` struct containing attested data from the Web2 API about dollar reserves
110
+
- An array of `IEVMTransaction.Proof` structs containing attested data about token supplies from various blockchains
111
+
112
+
The function aggregates the total token supply from all chains and compares it against the claimed reserves.
113
+
If sufficient reserves exist (i.e., if the total token supply is less than or equal to the claimed reserves), the function returns `true`; otherwise, it returns `false`.
@@ -141,23 +157,31 @@ contract ProofOfReserves is Ownable {
141
157
}
142
158
```
143
159
144
-
At the top of the contract, we see two events and several variables.
145
-
The `GoodPair` and `BadPair` events, as well as the `debugTokenReserves` and `debugClaimedReserves` are there for debugging purposes - they will allow us to check those values in the [explorer](https://coston2-explorer.flare.network/).
146
-
The `tokenStateReaders` mapping connects each stablecoin to its corresponding `tokenStateReader` contract; it serves as the registry of the official readers.
147
-
Therefore, it will only be modifiable by the owner of the `ProofOfReserves` contract (the `updateAddress` function).
160
+
The contract defines several important components:
161
+
162
+
-**Event Declarations**: The `GoodPair` and `BadPair` events are used for debugging and monitoring purposes, allowing us to trace token supply validation in block explorers like the [Coston2 Explorer](https://coston2-explorer.flare.network/).
163
+
164
+
-**Debug Variables**: The `debugTokenReserves` and `debugClaimedReserves` state variables store the latest values from the verification process, providing transparency and easier troubleshooting.
148
165
149
-
Before we can write the readReserves function for the `IJsonAPi.Proof` type, we need to define a `DataTransportObject` struct, as we did in the [JsonApi attestation type guide](/fdc/guides/json-api).
150
-
This will later allow us to specify how data from the Web2 API will be stored.
151
-
In this case, this will be a single `uint256` field.
166
+
-**Registry Mapping**: The `tokenStateReaders` mapping serves as a registry that associates each `TokenStateReader` contract with its corresponding stablecoin token.
167
+
This mapping ensures we only process events from authorized reader contracts.
168
+
169
+
-**Access Control**: The `updateAddress` function, protected by the `onlyOwner` modifier, provides a secure mechanism to update the registry mapping.
170
+
171
+
To properly decode data from the [JsonApi](/fdc/attestation-types/json-api) attestation, we need to define a data structure that matches our expected format.
172
+
Following patterns from the [JsonApi attestation type guide](/fdc/guides/json-api), we create a simple `DataTransportObject` struct:
function readReserves(IJsonApi.Proof calldata proof) private returns (uint256) {
@@ -227,21 +251,21 @@ We name the function appropriately.
227
251
228
252
## Process Overview
229
253
230
-
We can also replace the Coston and Coston2 chains with an arbitrary EVM chain.
254
+
This guide demonstrates deployment on Flare's Coston and Coston2 testnets, but the same approach can be adapted for any EVM chain.
255
+
The complete process follows these sequential steps:
231
256
232
-
1. Deploy and verify `MyStablecoin` contract on Coston and Coston2 chains
233
-
2. Deploy and verify `TokenStateReader` contract on Coston and Coston2
234
-
3. Deploy and verify `ProofOfReserves` contract on Coston2
257
+
1. Deploy and verify the `MyStablecoin` contract on both Coston and Coston2 chains
258
+
2. Deploy and verify the `TokenStateReader` contract on both Coston and Coston2 chains
259
+
3. Deploy and verify the `ProofOfReserves` contract on Coston2 chain only
235
260
4. Save `MyStablecoin`, `TokenStateReader`, and `ProofOfReserves` addresses to `scripts/proofOfReserves/config.ts`
236
261
5. Call the `broadcastTokenSupply` function of both `TokenStateReader` contracts with the corresponding `MyStablecoin` addresses
237
262
6. Save transaction hashes of both function calls to `scripts/proofOfReserves/config.ts`
238
-
7. Request attestation from the FDC, and call `verifyReserves` function of the `ProofOfReserves` with the received data
263
+
7. Request attestation from the [FDC](/fdc/overview), and call `verifyReserves` function of the `ProofOfReserves` with the received data
239
264
240
-
File names of our scripts will reflect these steps.
241
-
At the end of the guide, we will repeat the list with file names instead.
265
+
Throughout this guide, we'll provide separate scripts for each step above, with filenames that clearly indicate their purpose.
242
266
243
267
:::warning
244
-
We deploy the `ProofOfReserves` on the Coston2 chain only.
268
+
While we deploy stablecoin and reader contracts on both chains, the `ProofOfReserves`contract is deployed only on the Coston2 chain, which serves as our verification hub.
245
269
:::
246
270
247
271
## Scripts
@@ -486,7 +510,7 @@ The steps are as follows:
486
510
5. submitting the data and proofs to the `ProofOfReserves` contract
487
511
488
512
We first import the addresses from the `scripts/proofOfReserves/config.ts` file, and certain settings from environmental variables.
489
-
In this scripts, we also heavily utilize helper functions shipped with the `flare-hardhat-starter` repository, (the `scripts/fdcExample/Base.ts` file).
513
+
In these scripts, we also heavily utilize helper functions shipped with the `flare-hardhat-starter` repository, (the `scripts/fdcExample/Base.ts` file).
490
514
For a detailed breakdown of these functions, look at the Hardhat attestation type guides.
0 commit comments