# MACI feature: top-up voice credits From Barry: For MACI topups i think its best to have a smart contract que that uses the (batch deposit mech) and then have the cooridnator produce a ZKP that they have added the balance to the leaf they specified. If they refuse to add the deposit the round stops and after a deadline passes the users are able to wtihdraw their funds. We should consider this for malicious coordinators trying to lock users funds inside. ## Problem statement Let's say I sign up to MACI and use all my voice credits. Now I have to sign up again. There's no way to put more voice credits to this leaf. For some apps, this is a problem. For QHP, we want to give users their voice credits back every week. So we need a way to top-up voice credits. 1) Top up an arbitrary amount of voice credits for an arbitrary user 2) Increase each user's voice credits by some constant or arbitrary amount The voice credit balance is part of the user's state leaf. Each state leaf is a hash of the following information: - Public key - Vote option tree root - Voice credit balance - Nonce ## Potential solutions ### 1. Update the state tree using a snark Like the `UpdateStateTree` circuit, we could have a snark which: - Accepts as inputs: 1. The state index 2. The state root 3. The original state leaf data 4. The new voice credit balance 5. A Merkle proof from the original state leaf to the state root - Outputs: 1. A new state root The contract will verify this proof and update the state root if it is valid. There can be another circuit which updates a batch of state leaves in a single transaction. The downside to this solution is that it requires the coordinator to do a lot of computationally intensive work, and to pay a lot of gas to execute the transactions. The upside is that no changes are needed to the current architecture. Estimate implementation time (full-time): 1 week > [name=barryWhiteHat] we could charge a fee to allow cover proving / gas costs. ### 2. Store encrypted voice credit balances in a separate contract mapping This solution seeks to reduce the proof-generation computational load on the coordinator, but it requires a deep change to the MACI architecture. We have a new contract storage mapping which which associates state leaf indices with encrypted and salted voice credit balances. The encryption keys and salt values are only known to the coordinator. Each key may be an ECDH key generated using the coordinator's public key and the user's private key, but it is still clear whether the user should use a separate private key from the one they use to sign commands, or if they should use the same one. To update a user's voice credit balance, the coordinator supplies a snark proof of the following: - Accepts as inputs: 1. Encryption key (private) 2. Salt (private) 3. Encrypted original voice credit balance (public) 4. New voice credit balance (private) - Outputs: 1. New ciphertext If the proof is valid, the contract function stores the new ciphertext in the mapping. This can also be done in batches. A change is required to the `UpdateStateTree` circuit. - Accepts as inputs: 1. Voice credit balance encryption key (private) 2. Encrypted original voice credit balance (public) - Outputs: 1. Encrypted new voice credit balance Each state leaf no longer stores the voice credit balance. The `UpdateStateTree` circuit decrypts the encrypted balance, updates the vote option tree, and modifies the voice credit balance depending on how the user spent their votes. It then encrypts and outputs the new voice credit balance, and updates the mapping. The downside to this approach is that it increases complexity of the system. Moreover, each invocation of `batchProcessMessage()` will be more expensive as it has to update the storage mapping (5k gas per user). The upside is that voice credit top-ups are now less expensive. Furthermore, it is possible to (publicly) give all users the same number of voice credits by storing the same ciphertext to all mapping indices. Estimate implementation time (full-time): 3 weeks ## 3. Store a spent balance in the state tree and a total balance in a separate tree Barry: i like having seperate trees one for balance and another that says how much has been spent. so i can spend `total_deposit - already_spent` where `already_spent` is stored in the leaf and `total_deposit` is a append only tree that maps `(leaf_index -> amount)`