The Vault Contract: Open Sourced by Giveth
The Vault Contract will be a safe contract for storing ether and automating payments once it is battle tested.
Want to learn about the Vault the easy way?Join our Slack and ask us anything you want to know!
Security Focused Without Delaying for Idealism
The Giveth Core Team’s first milestone is to build a system of smart contracts for secure, automated payments, which is surprisingly lacking in this space. We designed the Vault Contract to store ether as securely as we could imagine. We are hyper-conscious of security issues, as most of our team had a front row seat for The DAO Hack and frankly I would argue we are more paranoid than anyone about smart contract security (my PTSDAO comes out every time I see a call function).
However that paranoia should not slow down experimentation and open source development. The only way for a contract to become trusted is for it to be used! Giveth has been using this contract for months to manage its own payments and to better understand what working with this contract is like so we can improve it.
The Vault Contract has exceeded expectations! It gives the same security vs. idealism trade off choice to any DApp that deploys it. Sadly most security features add centralization to DApp design, but with Giveth’s Vault Contract all the security features are able to be removed allowing the DApp to become more decentralized as trust is earned over time.
What does the Vault Contract do?
The Vault Contract is designed to be a safe contract for storing and automating payments.
It is equipped with many *optional* and adjustable safety features, like variable time delays, a whitelist of approved spenders, and an escape hatch if needed. It is an ideal contract for DApps to use to store their ether safely in the case that other more complex portions of their smart contracts have unexpected flaws.
When starting to use this contract, we encourage all projects to enable all the safety features and test them out to see if they add value to your project. As trust in the DApp is built, the safety features can be removed or automated away.
The Vault Contract is designed to allow for a step-by-step decentralization process as trust in the code base is built over time.
Example Payment Workflow
Once a Vault is deployed and filled with ether, a successful payment from a Vault will require 3 steps:
STEP 1: The `owner` adds `approvedSpenders` to the whitelist.
STEP 2: An `approvedSpender` will authorize a payment.
STEP 2.5: The payment will have to wait out the specified `timeDelay`.
STEP 3: The payment’s recipient can call `collectAuthorizedPayment()` to be sent the ether
The Vault Contract’s Security Features
1. Whitelist: Only addresses that have been pre-approved by the `owner` can authorize a payment, this is NOT an optional feature. The `owner` can remove addresses from the whitelist as well (The `owner` role however IS optional, after it has added `authorizedSpenders` to the whitelist, it can be set to 0x0).
2. Time-Based Failsafes: Authorized Payments cannot be collected until the `earliestPayTime` has passed. The minimum `earliestPayTime` is set when deploying the Vault (and can be set to 0 to allow immediate payments) but it can be extended by:
A. The `owner` (only affects future authorized payments)
B. The `approvedSpender` when authorizing a payment.
C. The `securityGuard` anytime after the payment has been authorized.
3. Canceling Authorized Payments: The ‘owner’ can cancel any authorized payment.
4. Escape Hatch: If there seems to be a critical issue, the `owner` or the `escapeCaller` can call the `escapeHatch()` to send the ether in the Vault to a trusted multisig (specified when deploying the Vault and of course this is also a completely optional feature).
Is the Vault Ready to Store Millions of Ether?
NO! In fact, as far as we are concerned there’s only one contract in the ecosphere proven safe enough to hold large amounts of funds. We have deployed a version of Ethereum foundation’s multisig (used by The DAO’s Curators and nearly every other major Ethereum project) to hold our donations as it has publicly held millions of dollars without issue.
The Vault contract is at an alpha stage, and is ready for critical peer review. Giveth’s Core Team is using the Vault contract currently to handle our own payments to bring transparency to our platform, but we keep most of our ether in this multisig as a safety precaution and only send to the Vault just before the payment is executed (it’s not THAT much money… really I am just paranoid. OH! But don’t send donations straight to our multisig! Send donations to 0xB94c53B0E67FABac3d97173482663Ef597D4174a and you will receive Giveth Tokens! Make sure to set a gas limit of 133,333 gas or more when donating to Giveth Campaigns).
Once tested and optimized, we will build a UI for the Vault and release it to the community for general use.
The Vault can only hold ether, but eventually we will add token functionality, Jordi already wrote the PR.
If you are looking at other Vault-like contracts, Alex Van de Sande wrote a really cool one, DappHub has a few options, and Malte Moeser, Dr. Ittay Eyal, and Dr. Emin Gün Sirer designed the MES Vault for Bitcoin as well.
WARNING: The rest of this post is a bit technical and meant for developers that want to dive in. It is pretty much just a revision of the Vault’s ReadMe and best read side-by-side with the code itself.
Who owns the Vault?
There are several important roles in the Vault Contract, each role is defined as an Ethereum address, so it can be a normal account, a multisig, an oracle, or even a DAO. The most important role for the Vault Contract is `owner`.
The `owner` is in charge of the Vault, they can add addresses to the whitelist of `approvedSpenders`, cancel authorized payments, change the `timeLock` delay, call the `escapeHatch()` and reassign the roles of `escapeCaller` and `securityGuard` (to understand all this keep reading). The `owner` by default is set as the address that deploys the Vault, but the `owner` can reassign its role to any account/contract or even to `0x000000000000000000000000000` to decentralize the Vault contract completely. The only things the `owner` can’t do in the Vault is change `escapeDestination` and `absoluteMinTimeLock`, these are set in the constructor and cannot be changed.
What do you need to define when deploying your own Vault Contract?
In the constructor of the Vault, you assign:
`_escapeCaller`: The account/contract (ideally one account given to multiple trusted individuals) given the power to call `escapeHatch()` and empty the Vault to a trusted destination in the case of an emergency; the `owner` can do everything the `escapeCaller` can do and can reassign the `escapeCaller` if necessary. The escape hatch is optional and can be removed by setting the `_escapeCaller` to 0x0.
`_escapeDestination`: The account/contract (ideally a trusted multisig that does not include anyone holding the key for `escapeCaller`) that receives the ether in the vault in the case of an emergency and the function `escapeHatch()` is called.
`_absoluteMinTimeLock`: The absolute minimum number of seconds needed to elapse before an authorized payment from the vault can be executed (giving time for `escapeHatch()` to be called or for the `owner` to reject the payment).
`_timeLock`: The default number of seconds needed to elapse before an authorized payment from the vault can be executed.
`_securityGuard`: The account/contract (ideally one account given to several trusted individuals) given the power to delay payments in the case of payment disputes; the `securityGuard` can do nothing other than delay the authorized payment’s execution. The Security Guard feature is optional and can be removed by setting the `_securityGuard` to 0x0.
`_maxSecurityGuardDelay`: The absolute maximum number of seconds that `securityGuard` is able to delay an authorized payment (giving time for the escape hatch to be called or for the `owner` to reject the payment). The `securityGuard` adds this delay to `earliestPayTime`.
How do you add funds to the Vault?
This version of the Vault only holds ether. If tokens are sent to the Vault, at this stage, they will be lost. Anyone can of course send ether directly to the Vault; however, on the Giveth platform, we recommend Campaigns have their Donors send ether to their token contract to generate tokens for accounting and governance purposes and then that token contract relays the ether to the Vault by calling the Vault’s `receiveEther()` function.
How does the Vault send ether?
Ether payments can be authorized by any address added to the Vault’s whitelist (the `allowedSpenders` mapping).
The `owner` can add or remove addresses from the whitelist as they wish by calling `authorizeSpender(address _spender, bool _authorize)` where `_authorize` is set to `true` if the owner wants to add `_spender` to the whitelist or is set `false` if the owner wants to remove `_spender` from the whitelist.
The addresses on the whitelist will almost certainly be open source contracts, and in Giveth’s case, the Milestone Tracker Contract will be the most common. These contracts will call `authorizePayment()` when they want the vault to send a payment. This function gives each authorized payment an ID number (`idPayment`) and requires 4 parameters to bring transparency to each payment:
`_description`: A brief description of the payment.
`_recipient`: The address that can call `collectAuthorizedPayment()` (ther recipient of the payment).
`_amount`: The amount to be paid (in wei).
`_paymentDelay`: The number of seconds the authorized payment is to be delayed before being executed, if this value is less than the default `timeLock` then `timeLock` determines the number of seconds the payment is delayed.
The authorized payment can be collected by the recipient of the payment by calling `collectAuthorizedPayment()` (I know creative function names all around).
What happens if a whitelisted address goes rogue and authorizes a fraudulent payment?
The the `owner`, the`escapeCaller`, and the `securityGuard` are given special abilities that can be used to protect the vault from malicious attacks. We recommend that these roles start out as identity-verified accounts that share a communication channel (much like the Curators for The DAO), but these roles can be easily automated by assigning them to contracts/oracles or even removed completely by setting them to 0x0.
The `timelock` is the first line of defense, after a payment is authorized there is a default amount of time that the recipient has to wait before they can collect their payment, this is defined by `earliestPayTime` (in UNIX time).
If anything looks questionable, the `securityGuard` can call `delayPayment()` to extend the `earliestPayTime`, delaying to the payment to give the `owner` and the`escapeCaller` extra time to investigate. The `securityGuard` is a helper role for the case that a decentralized entity is acting as an `owner` so that if there is a questionable payment, the entity can have extra time to use its governance protocols.
If the `owner` doesn’t think an authorized payment should be made, they can call `cancelPayment()`. If there is an emergency, or even just a desire to upgrade to a new Vault Contract, either the `owner` or the`escapeCaller` can call the `escapeHatch()` which sends all the ether in the Vault to the `escapeDestination`.
Can I use the Vault Contract in my project?
Absolutely, all of Giveth’s Smart Contracts are made to be used! Please use it, modify it and if you need any help, sign up to our Slack and we will help you dive in!