Closed timmoreton closed 4 years ago
Some notes based on latest call.
We will have three main roles:
We will have VestingFactory contract, spawning and keeping track of VestingInstance contracts. The VestingInstance will govern the rules of the Vesting. Some notable nuances discussed:
createVestingInstance
instead of start
withdraw
function that will check and allow you to withdraw up to amount specified by the schedule params. This function will not be the same as the withdraw
proxy function of the LockedGold, discussed belowrevoke
- will have just one parameter - when the revocation becomes active revokeTime
. If the parameter revokeTime is less than the current block.timestamp the block.timestamp is used for revokeTime
. vestingRevokedFrom
is the same as revokeTime
onlyBeneficiary
proxy functions to the stateful methods of LockedGold
(lock, unlock withdraw) and Account
(authorize etc.) contracts.vesting:create
CLI function will probably not be neededThanks @Perseverance, that all looks good to me. I've made some changes to the initial spec after reading it more carefully. Most notably:
Accounts.sol
and LockedGold.sol
. Other actions, like voting, can be done by calling Accounts.authorizeVoteSigner
to authorize a separate voting key, which the beneficiary
can use for voting without going through the VestingInstance
.VestingInstance
balance that can be withdrawn per period. This would mean that the balance would be drawn down asymptotically approaching zero, which is not what we want. Instead, we should specify an amount x
of the initial amount that can be withdrawn per period, and satisfy the following equality:
x/totalInitialAmount = amountWithdrawable/currentVestingInstanceBalance
Rather than an amount, we could also specify x
as a fraction of the initial amount, whichever makes the implementation easierPlease take a look at the updated spec and let me know if any of the changes don't make sense
Should we create the VestingInstances as proxied contracts, with the revoker being able to update the proxy? These VestingInstances we create might be holding a lot of Celo Gold, so any bugs would be great cause for concern.
Instead of revoke(timestamp)
we have revoke()
which revokes now. On revoking, the contract will record the owed amount for the beneficiary that he can later withdraw.
After revoking the beneficiary should only be able to call withdraw
and the revoke should be able to call the other methods to interact with LockedGold and Accounts
After revoking, the revoker is responsible for calling the necessary revokeVote, unlock, withdrawLockedGold combinations to actually unlock the locked gold and transfer it to the VestingInstance.
After revoking, the beneficiary can call withdraw
to extract what it's owed to him. It will only be able to withdraw whatever it's owed and it's currently in the contract balance. It can make many calls. To extract the full amount it will have to wait for locked gold to be transfered to the contract such that contract balance >= owed gold
When calling revoke, no funds are transfered
After revoking, and after all the locked gold has been transfered to the contract, the revoker can call refundAndFinalize()
which will (a) transfer remaining funds to revoker (b) transfer remaining owed money to the beneficiary (c) destroy the vesting instance contract
If the contract is never revoked, then when the beneficiary withdraws all the gold from the vesting schedule, the call should also destroy the vesting instance contract.
Expected Behavior
We want to be able to include in the genesis block a contract (call it
VestingFactory
)While vesting, funds should be able to be locked using the
LockedGold
contract so that they can be used for voting for validators, in on-chain governance, and earn compound rewards. To do this,VestingFactory
might have a functioncreateVesting()
that creates a new contract, owned by a specifiedbeneficiary
, that exposes wrappers for the public functions ofLockedGold
andAccounts
.The beneficiary will be able to call
LockedGold.lock
to lock up gold, andAccounts.authorize*()
to specify keys that can be used for other governance actions (e.g. voting, running a validator). At any time, thebeneficiary
mayunlock
locked gold to return it to the vesting contract. Gold in the vesting contract may be transferred to thebeneficiary
pursuant to the vesting contract'sSchedule
.Note that we may not need to support wrappers around
Validators
,Governance
, andElection
, since the beneficiary will be able to authorize other keys that can perform those actions.The
Schedule
will be composed of the following parameters:vestingCliff
,vestAmountPerPeriod
,vestingStartTime
,vestPeriodSec
,totalAmount
, as per belowThe user can withdraw
VestingInstance.balance * (vestAmountPerPeriod * ((now - vestingStartTime)/vestPeriodSec)) / totalAmount
, providednow > vestingCliff + vestingStartTime
. This allows users to withdraw their rewards pro rata according to the schedule, and supports continuous (e.g. monthly) vesting.The data in
VestingFactory
will need to comprise a map:address -> Schedule
such that for a givenaddress
we have:revokable
As we go we'll also need to track:
withdrawnAmount
, initially zero.vestingRevokedFrom
, initially zero but can be set to revocation time (see below)Once the original vesting schedule would be complete, i.e
vestAmountPerPeriod*(now-vestingStartTime)/vestPeriodSec>=totalAmount
, all funds may be withdrawn.Further requirement for revocation: the Celo Foundation may need to revoke vesting schedule instances. Each
Schedule
should be eitherrevocable
or not.VestingFactory should also take two parameters:
revoker
the only address that can callrevoke(address, vestingEndTime)
refundDestination
an address that then receives refundsTo revoke a schedule that hasn't started, the
VestingFactory
should support arevoke(vestingEndTime)
function. Can only be called once. This should have no effect if address has aSchedule
that isrevokable=false
. Otherwise, if they have not called 'vesting:start', then setvestingRevokedFrom
and calculate the portion to return to transfer torefundDestination
. All rewards are retained by the user. The vesting instance contracts should support a similar function.We want support for this contract in ContractKit, and in the CLI, as a new set of methods,
vesting:authorize
,vesting:lock
,vesting:unlock
, etc.Requirement for pause:
If a grant is
revokable
, then therevoker
can also pause withdrawals for a certain period, up to 365 days. This does not affect the underlying timing of vesting, it only affects whether withdrawals can be made. We would need something like apause(seconds)
method only callable byrevoker
, then onwithdraw
check that a pause is not currently in place.Current Behavior
No support for this.