Skip to content

Commit 3979fdd

Browse files
swarna1101nikerzetic-aflabs
authored andcommitted
fix: format the guide
1 parent 17efdec commit 3979fdd

File tree

1 file changed

+69
-45
lines changed

1 file changed

+69
-45
lines changed

docs/fdc/guides/proof-of-reserves.mdx

+69-45
Original file line numberDiff line numberDiff line change
@@ -9,41 +9,46 @@ unlisted: false
99
---
1010

1111
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.
1313

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.
1515
We will first describe what issue the app is addressing, and then provide a detailed walkthrough through its source code.
1616
All the code for this project is available on GitHub, in the [Flare Hardhat Starter](https://github.com/flare-foundation/flare-hardhat-starter) repository.
1717

18-
## The task
18+
## The problem
1919

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.
2222

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.
2825

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:
3327

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.
3631

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.
3834

39-
## Smart contracts
35+
This guide will walk through all the components needed to build the complete `proofOfReserves` verification system.
4036

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
4438

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.
4752

4853
```solidity title="contracts/proofOfReserves/Token.sol"
4954
// SPDX-License-Identifier: MIT
@@ -72,6 +77,8 @@ contract MyStablecoin is ERC20, ERC20Burnable, Ownable, ERC20Permit {
7277
Because we are building our app around `@openzeppelin`'s ERC20 token, we can later replace the token with any such instance.
7378
This means that we can easily modify our app to work with an arbitrary contract that inherits the `ERC20`.
7479

80+
### TokenStateReader Contract
81+
7582
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.
7683
It has a single method that takes an `ERC20` token instance and calls its `totalSupply` function.
7784
Then, it emits the `TotalTokenSupply` event with the token's address and total supply.
@@ -92,9 +99,18 @@ contract TokenStateReader {
9299
}
93100
```
94101

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`.
98114

99115
```solidity title="contracts/proofOfReserves/ProofOfReserves.sol"
100116
// SPDX-License-Identifier: MIT
@@ -141,23 +157,31 @@ contract ProofOfReserves is Ownable {
141157
}
142158
```
143159

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.
148165

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:
152173

153174
```solidity title="contracts/proofOfReserves/ProofOfReserves.sol"
154175
struct DataTransportObject {
155176
uint256 reserves;
156177
}
157178
```
158179

159-
With that, we simply decode the `abi_encoded_data` within the `IJsonAPi.Proof` struct, and access its `reserves` field.
160-
Of course, we must first validate the proof, but more on that later.
180+
This structure contains a single field to store the reserve amount received from the Web2 API.
181+
With this definition in place, we can now decode the `abi_encoded_data` within the `IJsonApi.Proof` struct and access its `reserves` field.
182+
Before accessing this data, we must first validate the proof - more on that later.
183+
184+
For processing JsonApi proofs, we implement the following function:
161185

162186
```solidity title="contracts/proofOfReserves/ProofOfReserves.sol:ProofOfReserves"
163187
function readReserves(IJsonApi.Proof calldata proof) private returns (uint256) {
@@ -227,21 +251,21 @@ We name the function appropriately.
227251

228252
## Process Overview
229253

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:
231256

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
235260
4. Save `MyStablecoin`, `TokenStateReader`, and `ProofOfReserves` addresses to `scripts/proofOfReserves/config.ts`
236261
5. Call the `broadcastTokenSupply` function of both `TokenStateReader` contracts with the corresponding `MyStablecoin` addresses
237262
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
239264

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.
242266

243267
:::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.
245269
:::
246270

247271
## Scripts
@@ -486,7 +510,7 @@ The steps are as follows:
486510
5. submitting the data and proofs to the `ProofOfReserves` contract
487511

488512
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).
490514
For a detailed breakdown of these functions, look at the Hardhat attestation type guides.
491515

492516
```typescript title="scripts/proofOfReserves/verifyProofOfReserves.ts"
@@ -535,7 +559,7 @@ To the response JSON, we will apply the following JQ filter.
535559
{reserves: .value | gsub(\",\";\"\") | sub(\"\\\\.\\\\d*\";\"\")}
536560
```
537561

538-
The filter removes all commas (separating thousands), and cuts away the decimal part.
562+
The filter removes all commas (separating thousands), and discards the decimal part (the period and everything after it).
539563
That way, the value we receive will truly be an integer.
540564

541565
We will encode the data as the `DataTransportObject` type, with the following abi signature (expanded to multiple lines for clarity's sake).

0 commit comments

Comments
 (0)