This project comprehends a set of smart contracts that allow users to make KEY deposits for getting
access to services and features. The base contract
DepositVault serves as the base for more
complex functionality to be implemented, such as staking and escrow payments.
DepositVault contract implements basic "deposit" functionality. The contract works as a "deposit registry", keeping track of different deposits made by different addresses and linked to different services provided by different owners. The following is a list of features:
Addresses are able to "deposit" KEY associated to a given Service Owner address and a serviceID 32-byte string.
Deposited tokens can only be retrieved by the original sender anytime.
depositmethod to work, the sender has to first invoke
approve(depositVaultAddress, maxAmount)on the token contract , passing the deposit vault contract address and the corresponding deposit amount (including all decimal places). This is to allow the deposit contract to spend funds (up to the limit set) on behalf of its owner. After approval,
depositcan be invoked by specifying an
amount(with all decimal places), a serviceOwner address and a serviceID. For "global" services not tied to any particular provider, the "zero address" can be used as the
If multiple deposits need to be done, sender can make one big approval that sums up to the desired total deposit amount. Thus the users don't need to spend extra gas by having to approve each time.
DepositVault base contract
Core deposit functionality is implemented by the
DepositVault contract, which features a global array of balances:
balances[depositor][serviceOwner][serviceID]: this mapping stores all deposit balances for each depositor address for each different service owner under a specific serviceID.
deposit(amount, serviceOwner, serviceID): On invoking this function, an
amountof tokens is deducted from the sender address balance and added to the deposit balance for a particular
serviceOwneraddress. For the contract to be able to deduct tokens on behalf of the sender, sender must previously call the approve method on the token contract with at least the
amountintended for deposit. Successful execution triggers the event
withdraw(serviceOwner, serviceID): a deposit sender can invoke the
withdrawfunction anytime by specifying a
serviceID, in which case the total deposit for that service is sent back to the depositor address. Successful execution of this method triggers the event
KEYDeposited(amount, from, serviceOwner, serviceID): Emitted when an address has successfully deposited an amount of KEY to a particular service.
KEYWithdrawn(amount, from, serviceOwner, serviceID): Emitted when a depositor has withdrawn tokens previously deposited for a certain service.
Specialized DepositVault implementations
As previously mentioned,
DepositVault serves as the most simple case of deposit registry functionality, from which the following "specialized" implementations derive, having the same basic capabilites plus some additional features:
Implements an optional "timelock" on deposits. For this end, the service owner can set a "lock period" upon any serviceID. Any deposit made by an address on such serviceID will reset the counter for the period set on that deposit. Deposit sender cannot withdraw before the period is fulfilled.
This contract is pausable, meaning that the contract owner can at some point suspend its activity in case there's a migration going on and the contract is becoming "deprecated". When the contract is paused, no new deposits can be made, and withdrawals are enabled regardless of their timelock status.
releaseDates[depositor][serviceOwner][serviceID]: keeps track of the release dates for all deposits, stored as a datetime in Unix format. This value is set at deposit time, if there's a lock period that corresponds to the specific service. If no timelock has been set for the corresponding service, it'll have the default value 0.
lockPeriods[serviceOwner][serviceID]: stores all the set lock periods for specific services by their corresponding service owner. If no timelock has been set for the given service, it'll have the default value 0.
setLockPeriod(serviceID, period): At any point, any Ethereum address can set a lock period (in seconds) for a
serviceIDthat holds or will hold deposits under the caller address as its service owner.
withdraw methods work as implemented on the
DepositVault contract, but have been
overwritten for adding and checking timelock states on deposits respectively. Timelock check on withdrawal is overriden if the contract is paused.
LockPeriodSet(serviceOwner, serviceID, period): triggered when a lock
periodis set to a
RefundableDepositVault is a type of
LockedDepositVault, with the addition of a
refund method that a service owner can invoke anytime to force a refund of tokens to the original depositor, regardless of its timelock status.
refund(depositor, serviceID): refunds deposited token to their original sender. Successful execution triggers a
PaymentRefunded(amount, depositor, serviceOwner, serviceID)
RefundableEscrow is a slightly different type of deposit contract, in that it's made to handle "deferred payments", meaning that the tokens can be released to the service owner when the depositor considers the transaction conditions have been met.
This contract is pausable, meaning that the contract owner can at some point suspend its activity in case there's a migration going on and the contract is becoming "deprecated". When the contract is paused, no new deposits can be made, and withdrawals are enabled.
withdraw(serviceOwner, serviceID): In this version, withdrawals are disabled by default, being available only if the contract is paused.
deposit(amount, serviceOwner, serviceID): works exactly as in
DepositVault, with the difference that
0x000..cannot be used as a service owner address.
release(serviceOwner, serviceID): A depositor can release the deposited funds on a
serviceIDto be sent to the corresponding
refund(depositor, serviceID): A service owner can "roll-back" the payment by refunding the tokens to the depositor.
PaymentMade(amount, sender, serviceOwner, serviceID)
PaymentReleased(amount, sender, serviceOwner, serviceID)
PaymentRefunded(amount, sender, serviceOwner, serviceID)
The smart contracts are being implemented in Solidity
- NodeJS, version 9.5+ (I use
nvmto manage Node versions —
brew install nvm.)
- truffle, which is a comprehensive framework for Ethereum development.
npm install -g truffle— this should install Truffle v4+. Check that with
- Access to the KYC_Chain Jira
or with code coverage
npm run test:cov
From within Truffle
truffle development environment
then from the prompt you can run
compile migrate test
as well as other Truffle commands. See truffleframework.com for more.
We provide the following linting options
npm run lint:sol— to lint the Solidity files, and
Please see the contributing notes.