owned this note
owned this note
Published
Linked with GitHub
==moved to notion: https://www.notion.so/iden3/Withdraw-multi-token-c7a15544a10a423ca1f74b3f1b2a6691==
# Withdraw-multi-token
## Summary
- User to withdraw different tokens at the same time
## Abstract
- Now, when a user wants to withdraw tokens from L2, the user has to make two calls:
- `L2 Exit`: prepare the tokens that the user wants to withdraw
- `L1 Withdraw`: pass it to L1
- So the user has to pay for each call he wants to make
- In this way, we achieve that the second call can be made only once for a set of tokens:
- make a `L2 exit` for each token that the user wants to withdraw
- `L1 withdraw` a group of tokens
## Motivation
- The objective is that the user can save money when making a withdraw by implementing this improvement, the user will be able to withdraw several tokens in the same call and will not have to make a withdraw for each token
- This approach takes advantatge that zk-proof is constant regardless number of tokens withdrawn. Hence, we implement a function that is able to withdraw N tokens at the same time. Users will safe a lot of gas taking into account exit-tree removal and multi-token all together
## Specification
### circuit
- This circuit is used to prove
- for each token
- there is a concrete exit balance in the state tree
- accounts should have the same ethereum address from which we want to withdraw
- If the proof is valid, user will be able to withdraw funds from the Hermez Contract
#### Description
Two options are proposed:
- A: circuit with `nTokens` and skip `idx = 0`:
- the user will make a withdraw with `nTokens` always
- if there is a token that the user does not want to withdraw, it should be set `idx = 0`
- if `idx = 0` the contract and the circuit should not do anything
- B: several circuits with `nTokens` and force always verify idx:
- if user makes a withdraw with 2 tokens --> verifier with `nTokens = 2`
```
template WithdrawMultiToken(nLevels, nTokens) {
// private inputs
signal private input rootState;
signal private input ethAddr;
signal private input tokenIDs[nTokens];
signal private input nonces[nTokens];
signal private input balances[nTokens];
signal private input idxs[nTokens];
signal private input exitBalances[nTokens];
signal private input accumulatedHashes[nTokens];
signal private input signs[nTokens];
signal private input ays[nTokens];
signal private input siblingsStates[nTokens][nLevels + 1];
}
```
- check for each token if account state is on state tree root
- compute hash global inputs
> The A option has been chosen: less security holes and less constraints/gas consumption
#### Inputs
- `rootState`: state-tree root for all tokens (exit is accumulative)
- `ethAddr`: ethereum address present across all accounts (smart contract: msg.sender)
- `ays[nTokens]` & `signs[nTokens]`: bjj account state information
- `tokensIds[nTokens]`: array tokensID of to withdraw (smart constract)
- `nonces[nTokens]`: array nonces of accounts to withdraw
- `balances[nTokens]`: array balance of accounts to withdraw
- `idxs[nTokens]`: array idx of accounts to withdraw
- `exitBalances[nTokens]`: array exit balance of each idx to withdraw (smart contract)
- `accumulatedHashes[nTokens]`: array accumulated hash of accounts to withdraw
- `siblingsStates[nTokens][nLevels + 1];`: array siblings of accounts to withdraw
### Hermez smart contract
- Only one withdraw function will remain: `withdrawMultiToken`
- add `withdraw-multi-token` function
- delete `withdrawCircuit` function
> If user wants to withdraw only one token, the arrays will have `length = 1`
- Check length
- Must be checked before withdrawing:
- `If (instantWithdraw[i])` --> in case of instant withdraw, assegur that is available (`instantWithdraws` is an Array)
- If for a token it is not available, revert tx
- Check `amountWithdraw > amountExit - exitAccumulateMap` for each token
- Update `exitAccumulateMap` for each token
- If `amountWithdraw < amountExit - exitAccumulateMap`, revert tx
- Check this information in a loop, if there are repeated tokens, there is enought amount for all withdraws
- input --> encodePacket --> `_getInputWithdraw` (in `HermezHelpersV2.sol`) :
- `rootState`
- `ethAddr`
- `tokensIds[nTokens]`
- `amountExits[nTokens]`
- `idxs[nTokens]`
- VerifyProof
- `_withdrawFunds` for each tokenID
- WithdrawEvent:
```
event WithdrawEvent(
uint192 indexed amountWithdraw,
uint48 indexed idx,
bool indexed instantWithdraw
);
```
- For example:
```
function withdrawMultiToken(
uint256[2] calldata proofA,
uint256[2][2] calldata proofB,
uint256[2] calldata proofC,
uint32[] memory tokenIDs,
uint192[] memory amountExits,
uint192[] memory amountWithdraws,
uint32 batchNum,
uint48[] memory idxs,
bool[] memory instantWithdraws
) external;
for (uint256 i = 0; i < nTokens; i++) {
_withdrawFunds(
amountWithdraws[i],
tokenIDs[i],
instantWithdraws[i]
);
emit WithdrawEvent(
amountWithdraws[i],
idxs[i],
instantWithdraws[i]
);
}
```