Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
O
openzeppelin-contracts-upgradeable
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
俞永鹏
openzeppelin-contracts-upgradeable
Commits
80e591f4
Commit
80e591f4
authored
Aug 28, 2017
by
Francisco Giordano
Committed by
Martín Triay
Oct 04, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add TokenVesting contract
parent
5cf50367
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
140 additions
and
0 deletions
+140
-0
TokenVesting.sol
contracts/token/TokenVesting.sol
+82
-0
TokenVesting.js
test/TokenVesting.js
+58
-0
No files found.
contracts/token/TokenVesting.sol
0 → 100644
View file @
80e591f4
pragma solidity ^0.4.11;
import './ERC20Basic.sol';
import '../ownership/Ownable.sol';
import '../math/Math.sol';
import '../math/SafeMath.sol';
/**
* @title TokenVesting
* @dev A token holder contract that can release its token balance gradually like a
* typical vesting scheme, with a cliff and vesting period. Revokable by the owner.
*/
contract TokenVesting is Ownable {
using SafeMath for uint256;
// beneficiary of tokens after they are released
address beneficiary;
uint256 cliff;
uint256 start;
uint256 end;
mapping (address => uint256) released;
/**
* @dev Creates a vesting contract that vests its balance of any ERC20 token to the
* _beneficiary, gradually in a linear fashion until _end. By then all of the balance
* will have vested.
* @param _beneficiary address of the beneficiary to whom vested tokens are transferred
* @param _cliff timestamp of the moment when tokens will begin to vest
* @param _end timestamp of the moment when all balance will have been vested
*/
function TokenVesting(address _beneficiary, uint256 _cliff, uint256 _end) {
beneficiary = _beneficiary;
cliff = _cliff;
end = _end;
start = now;
}
/**
* @notice Transfers vested tokens to beneficiary.
* @param token ERC20 token which is being vested
*/
function release(ERC20Basic token) {
uint256 vested = vestedAmount(token);
require(vested > 0);
token.transfer(beneficiary, vested);
released[token] = released[token].add(vested);
}
/**
* @notice Allows the owner to revoke the vesting. Tokens already vested remain in the contract.
* @param token ERC20 token which is being vested
*/
function revoke(ERC20Basic token) onlyOwner {
uint256 balance = token.balanceOf(this);
uint256 vested = vestedAmount(token);
token.transfer(owner, balance - vested);
}
/**
* @dev Calculates the amount that has already vested.
* @param token ERC20 token which is being vested
*/
function vestedAmount(ERC20Basic token) constant returns (uint256) {
if (now < cliff) {
return 0;
} else {
uint256 currentBalance = token.balanceOf(this);
uint256 totalBalance = currentBalance.add(released[token]);
uint256 vested = totalBalance.mul(now - start).div(end - start);
return Math.min256(currentBalance, vested);
}
}
}
test/TokenVesting.js
0 → 100644
View file @
80e591f4
const
BigNumber
=
web3
.
BigNumber
require
(
'chai'
)
.
use
(
require
(
'chai-as-promised'
))
.
use
(
require
(
'chai-bignumber'
)(
BigNumber
))
.
should
();
import
EVMThrow
from
'./helpers/EVMThrow'
import
latestTime
from
'./helpers/latestTime'
;
import
{
increaseTimeTo
,
duration
}
from
'./helpers/increaseTime'
;
const
MintableToken
=
artifacts
.
require
(
'MintableToken'
);
const
TokenVesting
=
artifacts
.
require
(
'TokenVesting'
);
contract
(
'TokenVesting'
,
function
([
_
,
owner
,
beneficiary
])
{
const
amount
=
new
BigNumber
(
1000
);
beforeEach
(
async
function
()
{
this
.
token
=
await
MintableToken
.
new
({
from
:
owner
});
this
.
cliff
=
latestTime
()
+
duration
.
years
(
1
);
this
.
end
=
latestTime
()
+
duration
.
years
(
2
);
this
.
vesting
=
await
TokenVesting
.
new
(
beneficiary
,
this
.
cliff
,
this
.
end
,
{
from
:
owner
});
this
.
start
=
latestTime
();
// gets the timestamp at construction
await
this
.
token
.
mint
(
this
.
vesting
.
address
,
amount
,
{
from
:
owner
});
});
it
(
'cannot be released before cliff'
,
async
function
()
{
await
this
.
vesting
.
release
(
this
.
token
.
address
).
should
.
be
.
rejectedWith
(
EVMThrow
);
});
it
(
'can be released after cliff'
,
async
function
()
{
await
increaseTimeTo
(
this
.
cliff
+
duration
.
weeks
(
1
));
await
this
.
vesting
.
release
(
this
.
token
.
address
).
should
.
be
.
fulfilled
;
});
it
(
'should release proper amount after cliff'
,
async
function
()
{
await
increaseTimeTo
(
this
.
cliff
);
const
{
receipt
}
=
await
this
.
vesting
.
release
(
this
.
token
.
address
);
const
releaseTime
=
web3
.
eth
.
getBlock
(
receipt
.
blockNumber
).
timestamp
;
const
balance
=
await
this
.
token
.
balanceOf
(
beneficiary
);
balance
.
should
.
bignumber
.
equal
(
amount
.
mul
(
releaseTime
-
this
.
start
).
div
(
this
.
end
-
this
.
start
).
floor
());
});
it
(
'should have released all after end'
,
async
function
()
{
await
increaseTimeTo
(
this
.
end
);
await
this
.
vesting
.
release
(
this
.
token
.
address
);
const
balance
=
await
this
.
token
.
balanceOf
(
beneficiary
);
balance
.
should
.
bignumber
.
equal
(
amount
);
});
});
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment