summa-solvency
Last updated
Last updated
This section describes how to use backend to perform a full .
First of all, it is essential to determine three key parameters:
The number of currencies that will be handled simultaneously in a single Proof of Solvency - N_CURRENCIES
The byte range in which the balances part of the liabilities - N_BYTES
The number of users to be included in the Proof of Solvency expressed as the number of levels in the Merkle Sum Tree -LEVELS
These parameters are crucial as they significantly influence the proof size and the computation time required.
For instance, if a Custodian decides to handle ten currencies in a single proof, the proof size will be larger, and generating each proof will take more time than a single currency proof. However, this approach enhances user experience since users won't need to verify ten different proofs. In the backend, this translates into the number of currencies supported in a single Merkle Sum Tree.
The byte range parameter also influences the proof size and generation time. However, there is one key difference: will fail if balances, input to the proof, exceeds the predefined byte range limit.
The number of users refers to the magnitude of the user base of the Custodian. This number has to be expressed as a power of two since the users are aggregated inside a Merkle Tree-like data structure.
So, before starting, the Custodian has to choose the generic parameters N_CURRENCIES
, N_BYTES
and LEVELS
.
systems require a Trusted Setup. Summa uses the with the polynomial commitment scheme. All Summa circuits must rely on a one-time universal (also known as a powers-of-tau ceremony).
To generate the proving artifacts, the Custodian must download the appropriate .ptau
file depending on their circuit size.
In this case, we are fetching a .ptau
for a circuit size equal to k=11
. If this doesn't make sense to you yet, this is completely fine. In the following step, you will learn how to set the appropriate circuit size.
The script can be run as follows:
Setting different (and higher) generic parameters might cause the following error
The best way to find out the smallest available size fits your circuit is through trial and error.
Follow the steps below to deploy the Summa contract:
Modify Key Parameters
Update Hardhat Configuration
Run Deploy Script
Execute the command below with the network name set in the previous step from the contracts
folder
As a result of running this script, Summa contract is deployed to network_name
and a deployments.json
file is created. This file includes the address of the deployed Summa Contract and is located at backend/src/contracts/deployments.json
.
Custodians can send ownership proofs of their address to the Summa contract using AddressOwnership
. To do this, the Custodian must create a CSV file containing their account addresses, asset types, and signed messages. This file is referred to as signature_csv
. Then, custodians can send a transaction containing ownership proofs as follows:
The signer
in the above code is an instance of SummaSigner
, which includes LocalWallet from ethers-rs, and is essential for signing Ethereum transactions for the Summa contract. It is used to sign transactions that send ownership proofs to the Summa contract. However, one of its internal components, LocalWallet, is considered an insecure wallet type for production use in ethers-rs.
The signer
is only used to submit proofs and commitments to Summa contract so it does not have to hold any of the Custodian funds. Note that since Summa contract is a Ownable
contract, the signer
has to be the same used to deploy the Summa contract. Otherwise, transactions will be reverted.
For generating liabilities commitment and user inclusion proofs, a custodian has to prepare a CSV file, referred to as entry.csv
, which contains all usernames and their N_CURRENCIES
balances. The csv file format looks like this:
The first column header must be the username, and the rest of the columns should follow the pattern balance_[Currency]_[Chain]. Assuming the CSV file is named asentry.csv
, build the Merkle Sum Tree as follows:
Now, the custodian can send the commitment transaction using the dispatch_commitment
method:
Internally, dispatch_commitment
sends a transaction that includes the mstRoot
and rootBalance
of the Merkle Sum Tree to the submitCommitment
function in the Summa Contract.
Now, custodians can generate inclusion proofs for their users using the round
, initiated from the previous step.
The get_proof_of_inclusion
method requires a user_index
, which corresponds to the index of the user's data in the Entry CSV file (entry.csv
from the previous section).
Custodians can then provide these inclusion proofs to their users.
The verification function also requires the user to pass the snapshot_time
which must match the timestamp
at which the Liabilities Commitment was submitted to the smart contract.
As demonstrated in the example above, custodians can provide an application to users to verify their inclusion proof locally on their machines.
Note that the verify_inclusion_proof
function in the Summa contract is a view function. This means that it does not consume gas or alter the state of the blockchain. Additionally, users can independently verify their proofs using public interfaces, such as Etherscan, for added transparency and trust.
When receiving the proof, the user should also verify that the leaf_hash
being verified matches the combination of their username and balances. balances
represent the balances of the user at snapshot_time
You can find pre-existing trusted setup files at . To download a specific file, you can use:
For the sake of the current example, let's assume that N_CURRENCIES
is 2, N_BYTES
is 8, and LEVELS
is 4 (namely, a maximum user base of 16 users). Also, let's consider that a ptau
file placed in the path
Custodians can manually modify these parameters and ptau
file path in
The script is provided to generate a solidity contract used by the users to verify their inclusion inside the liabilities Merkle Sum Tree.
After cloning the Repo
The script will generate a new InclusionVerifier.sol
and InclusionVerifier.yul
contracts in .
Given the generics parameters set, this error indicates that the circuit size is too small. To solve that, a .ptau
file with a higher k
must be , and the function must be adjusted accordingly.
In the previous section, the verifier contract files are generated, which are InclusionVerifier.sol
and InclusionVerifier.yul
. Both are needed to deploy the main , in particular, the InclusionVerifier.sol
is passed to the constructor of Summa.sol
Custodians need to modify certain parameters in the deploy script located at . These parameters must be equal to LEVELS
, N_CURRENCIES
, and N_BYTES
set above.
The Summa-solvency project provides a hardhat configuration file primarily for testing purposes. Custodians must update hardhat.config.ts
for deploying the contract with their own account and node. For guidance on configuring the hardhat config file, refer to .
Once the setup is completed, the Custodian can utilize summa-solvency
to perform a
The following steps can be performed via a working example in .
More secure signer structures, such as and , are available in ethers-rs, and custodians are advised to use these for enhanced security. For instance, to use a Ledger wallet instead of LocalWallet, modify the as shown below:
To initiate Round
, two additional parameters are needed: params_path
and timestamp
. params_path
is the path to the .ptau file, which should be the same as used in the . timestamp
is a UNIX timestamp that indicates the time when the liabilities snapshot (reflected in the entry.csv
file) was taken.
Building a Merkle Sum Tree on a single machine is a heavy task that can be parallelized and, therefore, sped up, using
Generating proofs for all the users at once can present some . Alternatively, the custodian can generate such proof only if the user queries it. Have a look at the for this!
Users who receive a proof for a specific round can use the verify_inclusion_proof
API provided by the backend. The term downloaded_inclusion_proof
refers to the proof that users have downloaded from custodians.
For details on handling downloaded_inclusion_proof
at the code level, please refer to the .