What and why
ERC900 defines a standard interface for staking and unstaking tokens in a smart contract, as well as getting information about the state of a holder’s stake and the total amount of tokens staked to the contract.
However, ERC900 doesn’t define what can happen once someone has staked their tokens. We started thinking about stake locking to standardize how other interesting usecases could be built on top of a user depositing their tokens to the contract. Stake locking allows a staker to put a limit on their ability to transfer tokens. This unlocks these two important properties:
Anti-sybil protection: the fact that a token is fungibile means that a token unit is indistiguisible from any other token units. Token units don’t have a serial number, so it becomes impossible to check if a particular token has been used more than once for a particular task. This is particulary important for token-weighted voting, one token could potentially be used to vote more than once (if the owner of the token transfers it to another account) if no extra protections are in place. By locking one’s tokens for some amount of time, those tokens cannot have been transferred, therefore it ensures integrity to applications that need to make sure that one token cannot be used more than once.
Slashing potential: a lot of interesting applications for staking tokens are built on the fact that a part or the totality of one’s tokens could potentially be lost if they were to act in a bad way.
On the previous iteration of the Staking app, locks were used to prevent sybil attacks (by preventing tokens from moving). Having to use locks for this started being a challenge when apps would need to set many locks to prevent tokens from being transferred during different timespans, we implemented something called overlocking and we started realizing that the previous approach was falling short when used for more complex applications, such as implementing a TCR (which needed multiple Staking apps to circumvent some limitations).
A solution that doesn’t require locking is using ERC900 checkpointing, which allows to get the staked balance of a staker at the end of particular block number. Because staked tokens cannot be owned by two different accounts at a given block height, applications that need to ensure that the same tokens aren’t used twice, can check staked balances at a block number in the past. An example of applications for this would be stake voting (preventing double voting) or distributing inflation rewards to stakers.
An alternative approach would be to not add checkpointing to the Staking contract, but offload it to a non-transferable IOU token with checkpointing functionality (MiniMe). When someone stakes, tokens can be minted for the holder, which represent that they have a given stake in the Staking contract. If the staker is slashed or unstakes, an equal amount of the IOU token gets burned from the staker’s balance. This IOU token could directly be used with any MiniMe compatible apps.
While the above works for some applications that just need to check the staked balance, it is not enough for usecases where the staked balance needs to be ‘cached’ by the contract for some reason (for example our liquid democracy implementation). A potential solution would be to add stake change hooks that a staker can set up in their account, so whenever their staked balance changes, functions in other smart contracts would be called. This wouldn’t be a problem for staker initiated changes (staking or unstaking), but for external changes (as a result of slashing for example) it could be problematic as whoever triggers slashing would be paying for the computation executed in the hook.
If anti-sybil can be solved with the mechanisms described on top, then locks are only needed when there is potential for slashing and for that reason tokens must not be transferred while they could be slashed.
A work in progress spec for how stake locking could look like:
The core idea is that every lock has a
manager (looking for a better word here), after the lock is created, the manager has control over the lock, including modifying the lock amount (by decreasing it), transferring locked funds to another staker or lock, changing the data associated with the lock and even changing the manager. Lock managers have complete control over the funds in a lock, but the ownership of the funds in the staking contract is maintained by the staker.
Managers will be smart contracts in most cases, which have well-defined rules for when a lock can be removed, funds transferred or the manager changed to another contract that will take over managing the lock.
By setting managers at the lock level, rather than global authorized entities with the
MOVE_TOKENS role as in the previous implementation, a Staking app instance is much more trustless than before, and users can choose what manager has control over any lock, allowing to have many ways to resolve agreements and different types of agreements running at the same time over a unique staking pool.
Time-locks as supported in the previous iteration can also be built using managed locks. By taking advantage of the
data payload that locks can have associated with them, a very simple TimeLock manager can be built:
Aragon Network v1: staking, governance and agreements
With this new spec, the Aragon Network v1 core component would be a Staking app, where stakers can create locks for different types of agreements, which can be resolved with different mechanisms. Staked funds, locked or unlocked, can be used to participate in governance decisions of the Aragon Network.
Resolution agnostic agreements
Agreements could be created using staked funds by locking funds and setting a manager that will unlock funds based on how the agreement is resolved. This has the advantage that we don’t need to commit to a version of the Aragon Court early on, nor wait until the fully fledged Aragon Court is ready (see simulations with the latest research) for users and DAOs to start creating agreements collateralized by ANT.
It also means that other types of agreements, that don’t necessarily need to use a decentralized court for resolution, can be created, while the locked tokens can still be used for participating in governance decisions.
An example of this would be a simple escrow contract between two parties, which a designated arbiter can resolve:
For the specific Aragon Court implementation as defined in the whitepaper, a lock would be created per agreement with the minimum liability of the agreement. Maximum liability which can be shared between agreements, would be another unique lock managed by the Aragon Court. When creating a new agreement, it is possible that funds from the maximum liability lock need to be locked in the minimum liability of the new agreement. Under the new spec, an undercollateralized agreement could be created, and then the court could transfer funds from the maximum liability lock to collateralize the new agreement, by transferring tokens between locks.
Stake-based liquid democracy
With the current naïve implementation of liquid democracy (https://github.com/aragonlabs/liquid-democracy/pull/1) the stake change hooks would be problematic, as whenever a delegator’s stake changes the increment or decrement on balance would need to be propagated up the delegation chain (as in the current implementation each step in the delegation chain has the sum of all delegated tokens for cheap tallying). In the worst case (delegation chain depth of 20), the cost for this update would be around 500k gas (~20k + 5k gas per step) which would need to be paid by the slasher. If the staker has different delegation chains for different topics, the gas cost would increase linearly with the number of topics.
The combination of LD with this new Staking implementation, creates even more potential griefing attacks that need to be evaluated, as creating artificially long delegation chains can impact slashing. I’m not sure on-chain tallying of LD as we are doing at the moment will be feasible, but needs further thinking and research.
Work in progress
Our thinking on staking and locking, and its implementation on the Aragon Network is quickly evolving. Some areas that need more work:
- Figuring out whether stake change hooks make sense at all, or how to implement LD using the new Staking app.
- Making sure the experience for DAOs Staking and creating locks and agreements is great, taking it into account when working on the Actor app