From eb0a98572bd9e887a94591eb35aeb9ff5c238e79 Mon Sep 17 00:00:00 2001 From: skoupidi Date: Wed, 11 Mar 2026 14:41:04 +0200 Subject: [PATCH] doc/spec/contract/vesting: formal definitions added --- doc/src/SUMMARY.md | 3 + doc/src/spec/contract/vesting/concepts.md | 60 +++++ doc/src/spec/contract/vesting/model.md | 82 ++++++ doc/src/spec/contract/vesting/scheme.md | 305 ++++++++++++++++++++++ doc/src/spec/contract/vesting/vesting.md | 103 +++----- 5 files changed, 492 insertions(+), 61 deletions(-) create mode 100644 doc/src/spec/contract/vesting/concepts.md create mode 100644 doc/src/spec/contract/vesting/model.md create mode 100644 doc/src/spec/contract/vesting/scheme.md diff --git a/doc/src/SUMMARY.md b/doc/src/SUMMARY.md index 5d9c658ea..5d84bd8f8 100644 --- a/doc/src/SUMMARY.md +++ b/doc/src/SUMMARY.md @@ -102,6 +102,9 @@ - [Concepts](spec/contract/deploy/concepts.md) - [Scheme](spec/contract/deploy/scheme.md) - [Vesting](spec/contract/vesting/vesting.md) + - [Concepts](spec/contract/vesting/concepts.md) + - [Model](spec/contract/vesting/model.md) + - [Scheme](spec/contract/vesting/scheme.md) # P2P API Tutorial diff --git a/doc/src/spec/contract/vesting/concepts.md b/doc/src/spec/contract/vesting/concepts.md new file mode 100644 index 000000000..b1dff1697 --- /dev/null +++ b/doc/src/spec/contract/vesting/concepts.md @@ -0,0 +1,60 @@ +# Concepts + +The vesting process is divided in a few steps that are outlined below: + +* **Vest:** a vesting configuration is submitted to the blockchain. +* **Withdraw:** vestee can withdraw some amount of their vested coin. +* **Forfeit:** vesting authority forfeits a specific vesting. +* **Exec:** overlay function over `Withdraw` and `Forfeit`, used as the + spend hook binding the coins to these contract calls. + +## Vest + +Vesting authority submits a vesting configuration on-chain, along with +a chained transfer call burning the to-be-vested input coins, which +must be for the same token, and minting a new coin with their total +amount for a shared secret address, using the contracts' `Exec` call +spend-hook, effectivelly becoming usable only withing the vesting +contract context. + +> Note: There is a limitation though; the vested coin can only be +> controlled by a single address. To overcome this, when the vesting +> authority creates the vested coin, instead of using the recipients +> actual address, it generates a new random one, which is shared with +> the vestee(in a safe off-chain manner), so the coin can be controlled +> by both parties. + +> Note: Since vesting requires a 1-1 vested coin to config matching, it +> means that those coins can be tracked by the vesting configuration +> bulla. It doesn't affect rest anonimity, since it's specific to the +> vesting contract flow and no other information can be derived by it. + +## Withdraw + +After some time has passed, the vestee can withdraw some amount from +their vested coin, which is done by a chained transfer call burning the +existing vested coin and creating two output coins; one which will be a +normal coin for a withdrawal address, and a second one representing the +remaining balance using the spend hook of the vesting contract. This +call is responsible to define the available-to-withdraw amount, along +with ensuring the chained transfer call second output correctly +represents the remaining balance vested coin. We don't care if that +becomes a zero value coin, since it won't be usable anymore, and we +want all our outputs to look the same, so the final withdrawl cannot be +tracked. + +> Note: A medatada leak exists though; the final withdrawl cannot be +> conventionally tracked, since nobody but the parties knows when the +> remaining balance coin becomes a zero value one, but someone tracking +> all the withdrawls calls for a specific vesting configuration can +> assume that the vesting has ended, if no other withdrawl is observed +> after some time period. Still, they can't prove that the vesting has +> concluded without access to the vesting information and/or the shared +> secret address. + +## Forfeit + +With this call, a vesting authority is able to forfeit a specific +vesting, by removing the vesting configuration, burning the remaining +balance vested coin and mint a new one to a recipient address, using a +chained transfer call. diff --git a/doc/src/spec/contract/vesting/model.md b/doc/src/spec/contract/vesting/model.md new file mode 100644 index 000000000..b16aa5138 --- /dev/null +++ b/doc/src/spec/contract/vesting/model.md @@ -0,0 +1,82 @@ +# Model + +Let $\t{Bulla}$ be defined as in the section [Bulla Commitments][1]. + +Let $β„™β‚š, π”½β‚š, \mathcal{X}, \mathcal{Y}, \t{𝔹⁢⁴2π”½β‚š}$ be defined as in the +section [Pallas and Vesta][2]. + +Let $\t{Coin}$ be defined as in the section [Coin][3]. + +## Vesting Configuration + +The vesting configuration contains the main parameters that define the +vesting operation: + +* The vesting authority public key $VAPK$ controls the vesting + configuration. +* The vestee public key $VPK$ for withdrawls. +* The shared secret public key $SPK$ controls who can use the vested + coin. +* Token $t$ is the token type of the to-be-vested input coins. +* Total $T$ is the total amount of the to-be-vested input coins. +* Cliff $C$ is the amount unlocked at the start blockwindow $S$. +* Start $S$ and end $E$ are the blockwindows defining when vesting + starts and ends. +* Blockwindow value $V$ is the amount unlocked on each blockwindow. + +Define the vesting configuration $VC$ params: +$$ \begin{aligned} + \t{Params}_\t{VC}.\t{VAPK} &∈ β„™β‚š \\ + \t{Params}_\t{VC}.\t{VPK} &∈ β„™β‚š \\ + \t{Params}_\t{VC}.\t{SPK} &∈ β„™β‚š \\ + \t{Params}_\t{VC}.Ο„ &∈ π”½β‚š \\ + \t{Params}_\t{VC}.T &∈ ℕ₆₄ \\ + \t{Params}_\t{VC}.C &∈ ℕ₆₄ \\ + \t{Params}_\t{VC}.S &∈ ℕ₆₄ \\ + \t{Params}_\t{VC}.E &∈ ℕ₆₄ \\ + \t{Params}_\t{VC}.V &∈ ℕ₆₄ +\end{aligned} $$ + +```rust +TODO: add model definition path +``` + +$$ \t{Bulla}_\t{VC} : \t{Params}_\t{VC} Γ— π”½β‚š β†’ π”½β‚š $$ +$$ \begin{aligned} +\t{Bulla}_\t{VC}(p, b_\t{VC}) = \t{Bulla}( \\ +\mathcal{X}(p.\t{VAPK}), \mathcal{Y}(p.\t{VAPK}), \\ +\mathcal{X}(p.\t{VPK}), \mathcal{Y}(p.\t{VPK}), \\ +\mathcal{X}(p.\t{SPK}), \mathcal{Y}(p.\t{SPK}), \\ +p.Ο„, \\ +ℕ₆₄2π”½β‚š(p.T), \\ +ℕ₆₄2π”½β‚š(p.C), \\ +ℕ₆₄2π”½β‚š(p.S), \\ +ℕ₆₄2π”½β‚š(p.E), \\ +ℕ₆₄2π”½β‚š(p.V), \\ +b_\t{VC} \\ +) +\end{aligned} $$ + +> Note: Since a vesting configuration bulla is derived using a random +> blinding factor, it's safe to use the same parameters to generate +> different vesting configurations. + +## Blockwindow + +Time limits on vesting configurations are expressed in 1 day windows. +Since proofs cannot guarantee which block they get into, we therefore +must modulo the block height a certain number which we use in the +proofs. + +```rust +TODO: add definition path +``` + +which can be used like this: +```rust +TODO: add usage example path +``` + +[1]: ../../crypto-schemes.md#bulla-commitments +[2]: ../../crypto-schemes.md#pallas-and-vesta +[3]: ../money/model.md#coin diff --git a/doc/src/spec/contract/vesting/scheme.md b/doc/src/spec/contract/vesting/scheme.md new file mode 100644 index 000000000..83a9b144d --- /dev/null +++ b/doc/src/spec/contract/vesting/scheme.md @@ -0,0 +1,305 @@ +# Scheme + + + +Let $\t{Params}_\t{VC}, \t{Bulla}_\t{VC}$ be defined as in +[Vesting Configuration Model](model.md). + +Let $\t{Coin}$ be defined as in the section [Coin][1]. + +Let $β„™β‚š, π”½β‚š, \mathcal{X}, \mathcal{Y}, \t{𝔹⁢⁴2π”½β‚š}$ be defined as in the +section [Pallas and Vesta][2]. + +Let $tβ‚€ = \t{BlockWindow} ∈ π”½β‚š$ be the current blockwindow as defined +in [Blockwindow](model.md#blockwindow). + +Let $\t{PoseidonHash}$ be defined as in the section +[PoseidonHash Function](../../crypto-schemes.md#poseidonhash-function). + +Let $\t{ElGamal.Encrypt}, \t{ElGamalEncNote}β‚–$ be defined as in the +section [Verifiable In-Band Secret Distribution][3]. + +Denote the Vesting contract ID by $\t{CID}_\t{V} ∈ π”½β‚š$ and its `Exec` +function spend hook by $\t{SH}_\t{V} ∈ π”½β‚š$. + +## Vest + +This function creates a vesting configuration bulla $ℬ_\t{VC}$. We +commit to the vesting configuration params and then add the bulla to +the set, along with the vested coin $\t{Coin}$ minted by the child +`Money::transfer()` call. Each vesting configuration keeps track of its +minted coins, to ensure that only those can be burned in next actions, +creating a sequence of coins, enabling the contract to keep track of +remaining balances anonymously. Additionally, we verify the minted +vesting coin is encrypted for the configuration shared secret key, +ensuring both parties have access to it. + +* Wallet builder: `TODO: add client path` +* WASM VM code: `TODO: add entrypoint path` +* ZK proof: `TODO: add proof path` + +### Function Params + +Define the vest function params +$$ \begin{aligned} + ℬ_\t{VC} &∈ \t{im}(\t{Bulla}_\t{VC}) \\ + \t{SPK} &∈ β„™β‚š +\end{aligned} $$ + +```rust +TODO: Add call params path +``` + +### Contract Statement + +**Vesting configuration bulla uniqueness**   whether $ℬ_\t{VC}$ +already exists. If yes then fail. + +Let there be a prover auxiliary witness inputs: +$$ \begin{aligned} + VAx &∈ π”½β‚š \\ + VPK &∈ π”½β‚š \\ + Sx &∈ π”½β‚š \\ + Ο„ &∈ π”½β‚š \\ + T &∈ ℕ₆₄ \\ + C &∈ ℕ₆₄ \\ + S &∈ ℕ₆₄ \\ + E &∈ ℕ₆₄ \\ + V &∈ ℕ₆₄ \\ + b_\t{VC} &∈ π”½β‚š \\ + b_\t{Coin} &∈ π”½β‚š +\end{aligned} $$ + +Attach a proof $Ο€$ such that the following relations hold: + +**Proof that start blockwindow is greater than current blockwindow** +  $S > tβ‚€$. + +**Proof that end blockwindow is greater than start blockwindow**   +$E > S$. + +**Proof that total is greater than cliff**   $T >= C$. + +**Proof that blockwindow value is valid**   $T == (E - S) * V + +C$. + +**Proof of vesting authority public key ownership**   $\t{VAPK} = +\t{DerivePubKey}(VAx)$. + +**Proof of shared secret public key ownership**   $\t{SPK} = +\t{DerivePubKey}(Sx)$. + +**Vesting configuration bulla integrity**   $ℬ = +\t{Bulla}_\t{VC}(\mathcal{X}(p.\t{VAPK}), \mathcal{Y}(p.\t{VAPK}), +\mathcal{X}(p.\t{VPK}), \mathcal{Y}(p.\t{VPK}), +\mathcal{X}(p.\t{SPK}), \mathcal{Y}(p.\t{SPK}), t, T, C, S, E, V, +b_\t{VC})$ + +**Minted vested coin integrity**   $Coin = +\t{PoseidonHash}(\mathcal{X}(p.\t{SPK}), \mathcal{Y}(p.\t{SPK}), T, t, +\t{CID}_\t{V}, \t{SH}_\t{V}, ℬ, b_\t{Coin})$ + +**Verifiable vested coin note encryption**   +let $𝐧 = (c.v, c.Ο„, c.\t{SH}, c.\t{UD}, c.n)$, and verify +$a = \t{ElGamal}.\t{Encrypt}(𝐧, \t{esk}, d.\t{SPK})$. + +### Signatures + +There should be a single signature attached, which uses +$\t{SPK}$ as the signature public key. + +## Withdraw + +This function enables the vestee to withdraw the corresponding unlocked +value up to that blockwindow. The child `Money::transfer()` call must +contain a single input, the vested coin we burn, and two outputs. The +first one being the withdrawed one while the second one is the +remaining vested balance coin. Both coins values are verified by the +vesting configuration rules, and we store the second one as the current +vested coin, to burn in next actions. Additionally, we verify the +second/vested coin is encrypted for the configuration shared secret +key, ensuring both parties have access to it. + +* Wallet builder: `TODO: add client path` +* WASM VM code: `TODO: add entrypoint path` +* ZK proof: `TODO: add proof path` + +### Function Params + +Define the withdraw function params +$$ \begin{aligned} + ℬ_\t{VC} &∈ \t{im}(\t{Bulla}_\t{VC}) \\ + \t{SPK} &∈ β„™β‚š +\end{aligned} $$ + +```rust +TODO: Add call params path +``` + +### Contract Statement + +**Vesting configuration bulla existance**   whether $ℬ_\t{VC}$ +exists. If no then fail. + +**Burned vested coin existance**   whether the burned coin +$\t{BCoin}$ matches the vesting configuration record one. If no then +fail. + +Let there be a prover auxiliary witness inputs: +$$ \begin{aligned} + VAPK &∈ π”½β‚š \\ + Vx &∈ π”½β‚š \\ + Sx &∈ π”½β‚š \\ + Ο„ &∈ π”½β‚š \\ + T &∈ ℕ₆₄ \\ + C &∈ ℕ₆₄ \\ + S &∈ ℕ₆₄ \\ + E &∈ ℕ₆₄ \\ + V &∈ ℕ₆₄ \\ + b_\t{VC} &∈ π”½β‚š \\ + Bv &∈ ℕ₆₄ \\ + b_\t{BCoin} &∈ π”½β‚š \\ + x_c &∈ π”½β‚š \\ + Cv &∈ ℕ₆₄ \\ + b_\t{Coin} &∈ π”½β‚š +\end{aligned} $$ + +Attach a proof $Ο€$ such that the following relations hold: + +**Proof of vestee public key ownership**   $\t{VPK} = +\t{DerivePubKey}(Vx)$. + +**Proof of shared secret public key ownership**   $\t{SPK} = +\t{DerivePubKey}(Sx)$. + +**Vesting configuration bulla integrity**   $ℬ = +\t{Bulla}_\t{VC}(\mathcal{X}(p.\t{VAPK}), \mathcal{Y}(p.\t{VAPK}), +\mathcal{X}(p.\t{VPK}), \mathcal{Y}(p.\t{VPK}), +\mathcal{X}(p.\t{SPK}), \mathcal{Y}(p.\t{SPK}), t, T, C, Cb, S, E, V, +b_\t{VC})$ + +**Proof that current blockwindow is greater than start blockwindow** +  $tβ‚€ >= S$. + +TODO: cond_select statement to pick current or end blockwindow + +**Proof of withdraw amount correctness**   +$$ \begin{aligned} +CurrentBlockwindow = CondSelect(BlockwindowCond, tβ‚€, E); \\ +BlockwindowsPassed = CurrentBlockwindow - S; \\ +Available = (BlockwindowsPassed * V) + C; \\ +Withdrawn = T - Bv; \\ +WithdrawlCoinValue = Available - Withdrawn; \\ +VestingChangeValue = T - (Withdrawn + WithdrawlCoinValue); +\end{aligned} $$ + +Verify the child `Money::transfer()` call correctnes: + +**Burned vested coin integrity**   $BCoin = +\t{PoseidonHash}(\mathcal{X}(p.\t{SPK}), \mathcal{Y}(p.\t{SPK}), +Bv, t, \t{CID}_\t{V}, \t{SH}_\t{V}, ℬ, b_\t{Coin})$ + +**Burned vested coin nullifier integrity**   $\cN = +\t{PoseidonHash}(x_c, BCoin)$ + +**Minted vested coin integrity**   $Coin = +\t{PoseidonHash}(\mathcal{X}(p.\t{SPK}), \mathcal{Y}(p.\t{SPK}), +VestingChangeValue, t, \t{CID}_\t{V}, \t{SH}_\t{V}, ℬ, b_\t{Coin})$ + +**Verifiable vested coin note encryption**   +let $𝐧 = (c.v, c.Ο„, c.\t{SH}, c.\t{UD}, c.n)$, and verify +$a = \t{ElGamal}.\t{Encrypt}(𝐧, \t{esk}, d.\t{SPK})$. + +### Signatures + +There should be a single signature attached, which uses +$\t{SPK}$ as the signature public key. + +## Forfeit + +This function enables the vesting authority to forfeit a vesting +configuration, withdrawing the rest of vested value. The child +`Money::transfer()` call must containg a single input, the vested coin +we burn, and a single output, the newlly minted coin. Both coins values +are verified by the vesting configuration rules, and we remove the +vesting configuration bulla $ℬ_\t{VC}$ entry from the set. + +* Wallet builder: `TODO: add client path` +* WASM VM code: `TODO: add entrypoint path` +* ZK proof: `TODO: add proof path` + +### Function Params + +Define the vest function params +$$ \begin{aligned} + ℬ_\t{VC} &∈ \t{im}(\t{Bulla}_\t{VC}) \\ + \t{SPK} &∈ β„™β‚š +\end{aligned} $$ + +```rust +TODO: Add call params path +``` + +### Contract Statement + +**Vesting configuration bulla existance**   whether $ℬ_\t{VC}$ +exists. If no then fail. + +**Burned vested coin existance**   whether the burned coin +$\t{BCoin}$ matches the vesting configuration record one. If no then +fail. + +Let there be a prover auxiliary witness inputs: +$$ \begin{aligned} + VAx &∈ π”½β‚š \\ + VPK &∈ π”½β‚š \\ + Sx &∈ π”½β‚š \\ + Ο„ &∈ π”½β‚š \\ + T &∈ ℕ₆₄ \\ + C &∈ ℕ₆₄ \\ + S &∈ ℕ₆₄ \\ + E &∈ ℕ₆₄ \\ + V &∈ ℕ₆₄ \\ + b_\t{VC} &∈ π”½β‚š + Bv &∈ ℕ₆₄ \\ + b_\t{BCoin} &∈ π”½β‚š \\ + x_c &∈ π”½β‚š +\end{aligned} $$ + +Attach a proof $Ο€$ such that the following relations hold: + +**Proof of vesting authority public key ownership**   $\t{VAPK} = +\t{DerivePubKey}(VAx)$. + +**Proof of shared secret public key ownership**   $\t{SPK} = +\t{DerivePubKey}(Sx)$. + +**Vesting configuration bulla integrity**   $ℬ = +\t{Bulla}_\t{VC}(\mathcal{X}(p.\t{VAPK}), \mathcal{Y}(p.\t{VAPK}), +\mathcal{X}(p.\t{VPK}), \mathcal{Y}(p.\t{VPK}), +\mathcal{X}(p.\t{SPK}), \mathcal{Y}(p.\t{SPK}), t, T, C, S, E, V, +b_\t{VC})$ + +**Proof of forfeit amount correctness**   $ForfeitValue = T - Bv$ + +Verify the child `Money::transfer()` call correctnes: + +**Burned vested coin integrity**   $BCoin = +\t{PoseidonHash}(\mathcal{X}(p.\t{SPK}), \mathcal{Y}(p.\t{SPK}), +ForfeitValue, t, \t{CID}_\t{V}, \t{SH}_\t{V}, ℬ, b_\t{Coin})$ + +**Burned vested coin nullifier integrity**   $\cN = +\t{PoseidonHash}(x_c, BCoin)$ + +**Minted coin integrity**   $Coin = +\t{PoseidonHash}(\mathcal{X}(p.\t{SPK}), \mathcal{Y}(p.\t{SPK}), +ForfeitValue, t, \t{CID}_\t{V}, \t{SH}_\t{V}, ℬ, b_\t{Coin})$ + +### Signatures + +There should be a single signature attached, which uses +$\t{SPK}$ as the signature public key. + +[1]: ../money/model.md#coin +[2]: ../../crypto-schemes.md#pallas-and-vesta +[3]: ../../crypto-schemes.md#verifiable-in-band-secret-distribution diff --git a/doc/src/spec/contract/vesting/vesting.md b/doc/src/spec/contract/vesting/vesting.md index cdb6afd56..4fd91394d 100644 --- a/doc/src/spec/contract/vesting/vesting.md +++ b/doc/src/spec/contract/vesting/vesting.md @@ -1,67 +1,48 @@ # Vesting +``` +status: draft +``` + ## Abstract -We want to create a fully anonymous vesting contract, in which all the vesting information is private. -What we need, is a vesting authority, which initially submits coins to be vested, along with the vesting -configuration. When this happens, all input coins, which must be for the same token, get burned, and a new -coin is minted for the vested public key, which uses the spend hook of the vesting contract, effectivelly -becoming usable only withing the vesting contract context. After some time has passed, the vestee can -withdraw some coins, which is done by burning the existing vested coin, and creates two output coins; -one representing the remaining balance using the spend hook of the vesting contract and a second one -which will be a normal coin for a withdrawal address(DAOs can be recipients too). +This contract implements fully anonymous vesting, in which all the +vesting information is private. Anyone can become a vesting authority, +submitting coins to-be-vested for another user(or a DAO), the vestee. +After some time has passed, the vestee can withdraw a chunk of the +vested coin value. The vesting authority is also able to forfeit a +vesting at any time, retrieving the remaining vested coin balance. -The vesting authority must also be able to forfeit the configured vesting. There is a limitation though; -the vested coin can only be controlled by a single address. To overcome this, when the vesting authority -creates the vested coin, instead of using the recipients actual address, it generates a new random one, -which is shared with the vestee(in a safe off-chain manner), so the coin can be controlled by both parties. -When the vestee withdraws some funds, the new remaining balance token must use the same shared secret key. -We don't care if that becomes a zero value coin, since it won't be usable anymore, and we want all our -outputs to look the same, so the final withdrawl cannot be tracked. - -## Vesting configuration - -The vesting contract uses 1 day block windows as its time measurement, similar to the DAO contract. - -The configuration structure contains the following: - 1. auth_public_x: The vesting autority public key X coord - 2. auth_public_y: The vesting autority public key Y coord - 3. shared_public_x: The shared vestee public key X coord - 4. shared_public_y: The shared vestee public key Y coord - 5. cliff: Amount unlocked at the cliff timestamp. - 6. cliff_window: Vesting contract cliff block window. - 7. start_window: Block window when the tokens start vesting. - 8. end_window: Block window when all the tokens are fully vested. - -The above information get hashed by poseidon to produce the VestingBulla, which is used as the on-chain -identifier of this specific configuration. - -## Contract calls - -TODO: describe all the checks for each call - -### Vest -Vesting authority submits a vesting configuration on-chain, burns the to-be-vested input coins and mints -a new coin with their total amount for the shared secret address, using the contracts' spend-hook. - -### Withdraw -This call is responsible to define the available to withdraw amount, along with checking the first output -correctly represents the shared secret and uses contract spend-hook. In this call, input coin value -commitment must match the addition of the output coin value commitments. Also we check the next call is a -normal money transfer call, which executes the actual burn and mint functions. - -### ExecWithdraw -This is an overlay function, acting as the parent of a Withdraw and money Transfer calls combination, to -bound them together into a single atomic action, and define the input spendhook that must be used in the -transfer call. - -### Forfeit -With this call, the vest autority is able to forfeit a specific vesting, by removing the configuration, -burning the existing vest coin and mint a new one to a recipient address, using a normal money transfer. -Input and output coin values must be identical. - -### ExecForfeit -This is an overlay function, acting as the parent of a Forfeit and money Transfer calls combination, to -bound them together into a single atomic action, and define the input spendhook that must be used in the -transfer call. +- [Concepts](concepts.md) +- [Model](model.md) +- [Scheme](scheme.md) +> Open questions: +> 1. Do we need a separate cliff time? If its set thats the start time +> so no real need to keep them both we can assume start == cliff. +> 2. Is using the shared key for signatures safe and needed? +> 3. Should vesting configurations be grouped by authority so is easier +> UX to manage them? +> 4. Is the vested coin encryption verification formula correct? +> 5. Do we need to check both coins in withdraw transfer in the proof or +> its fine since transfer itself enforces them? +> 6. Vesting requires 1-1 vested coin to config matching, which means +> vested coin is trackable as they are used during the vesting process. +> Does that break any anonymity properties? Withdrawed coins cannot be +> tracked, just the vested coin. +> 7. We need to figure out a way to handle withdrawls after end +> blockwindow has passed. We can use `cond_select` where both prover +> and verifier pass the condition checl `current >= end` and in the +> proof we pick current blockwindow or end blockwindow based on that. +> But this require the verifier to know the end blockwindow, unless we +> find a way the condition check can be done without revealing it. +> Another option is to have an explicit `WithdrawAfterEnd` to withdraw +> remaining balance after end blockwindow has passed. We already have +> the metadata leak of ending tracking assumption, so perhaps its +> worthy to sacrifice it. +> 8. Withdrawl calcs correctness? They can also be simplified further +> for proof optimization. +> 9. All calls use the same parameters. Unless we need something in any +> of them they will be the same structure in the final code. +> 10. Do we need to check both coins in forfeit transfer in the proof or +> its fine since transfer itself enforces them?