-
Notifications
You must be signed in to change notification settings - Fork 107
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Create VentureEth.sol, add tests, add README.md
- Loading branch information
vsfalliance
committed
Jan 25, 2020
1 parent
cb01bd5
commit 41fdafb
Showing
4 changed files
with
189 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
pragma solidity ^0.5.10; | ||
|
||
import "@openzeppelin/contracts/token/ERC20/ERC20Mintable.sol"; | ||
import "@openzeppelin/contracts/math/SafeMath.sol"; | ||
import "../../issuance/IssuanceEth.sol"; | ||
import "../../token/ERC20DividendableEth.sol"; | ||
|
||
|
||
/** | ||
* @title VentureEth | ||
* @notice Implements a venture | ||
* | ||
* 1. Use `setIssuePrice` to determine how many ether (in wei) do investors | ||
* have to pay for each issued token. | ||
* 2. Use `openIssuance` to allow investors to invest. | ||
* 3. Investors can `invest` their ether at will. | ||
* 4. Investors can also `cancelInvestment` and get their ether back. | ||
* 5. The contract owner can `cancelAllInvestments` to close the investment phase. | ||
* In this case `invest` is not available, but `cancelInvestment` is. | ||
* 6. Use `startDistribution` to close the investment phase. | ||
* 7. Investors can only `withdraw` their issued tokens now. | ||
* 8. Owner can use `transferFunds` to send collected ether to a wallet. | ||
* 9. | ||
* 10. | ||
*/ | ||
contract VentureEth is ERC20Mintable, ERC20DividendableEth, IssuanceEth { | ||
|
||
constructor() public ERC20Mintable() | ||
ERC20DividendableEth() IssuanceEth(address(this)) { | ||
_createState("ENDED"); | ||
_createTransition("LIVE", "ENDED"); | ||
_createTransition("FAILED", "ENDED"); | ||
addMinter(address(this)); | ||
} | ||
|
||
modifier afterIssuance { | ||
require( | ||
currentState == "ENDED", | ||
"Issuance must have ended." | ||
); | ||
_; | ||
} | ||
|
||
/** | ||
* @notice Send ether to this function in orther to disburse dividends. Venture must be live. | ||
*/ | ||
function increasePool() external payable afterIssuance { | ||
totalDividends = totalDividends.add(msg.value); | ||
totalDividendPoints = totalDividends | ||
.mul(pointMultiplier).div(this.totalSupply()); | ||
} | ||
|
||
/** | ||
* @notice Function to transfer all collected tokens to the wallet of the owner. | ||
*/ | ||
function transferFunds(address payable _wallet) public onlyOwner { | ||
super.transferFunds(_wallet); | ||
_transition("ENDED"); | ||
} | ||
|
||
/** | ||
* @dev Function to update an account | ||
* @param account The account to update | ||
* @notice Will revert if account need not be updated, or venture is not live. | ||
*/ | ||
function updateAccount(address payable account) public afterIssuance { | ||
super.updateAccount(account); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
import { should } from 'chai'; | ||
|
||
// tslint:disable-next-line:no-var-requires | ||
const { balance, BN, constants, ether, expectEvent, expectRevert, send } = require('@openzeppelin/test-helpers'); | ||
|
||
import { VentureEthInstance } from '../../../types/truffle-contracts'; | ||
|
||
const VentureEth = artifacts.require( | ||
'VentureEth.sol', | ||
) as Truffle.Contract<VentureEthInstance>; | ||
|
||
|
||
should(); | ||
|
||
contract('VentureEth - before issuance', (accounts) => { | ||
|
||
const [user1, investor1, investor2] = accounts; | ||
|
||
let ventureEth: VentureEthInstance; | ||
|
||
beforeEach(async () => { | ||
ventureEth = await VentureEth.new(); | ||
}); | ||
|
||
/** | ||
* @test {VentureEth#increasePool} | ||
*/ | ||
it('cannot increase pool when state is not "LIVE"', async () => { | ||
await expectRevert( | ||
ventureEth.increasePool({ from: user1, value: ether('6').toString()}), | ||
'Issuance must have ended.', | ||
); | ||
}); | ||
|
||
/** | ||
* @test {VentureEth#updateAccount} | ||
*/ | ||
it('cannot update account when state is not "LIVE"', async () => { | ||
await expectRevert( | ||
ventureEth.updateAccount(investor1), | ||
'Issuance must have ended.', | ||
); | ||
}); | ||
}); | ||
|
||
|
||
contract('VentureEth - after issuance', (accounts) => { | ||
|
||
const [wallet, user1, investor1, investor2] = accounts; | ||
|
||
let ventureEth: VentureEthInstance; | ||
|
||
beforeEach(async () => { | ||
ventureEth = await VentureEth.new(); | ||
await ventureEth.setIssuePrice(5); | ||
await ventureEth.openIssuance(); | ||
await ventureEth.invest({ from: investor1, value: ether('0.5').toString() }); | ||
await ventureEth.invest({ from: investor2, value: ether('0.1').toString() }); | ||
await ventureEth.startDistribution(); | ||
(bytes32ToString(await ventureEth.currentState())).should.be.equal('LIVE'); | ||
await ventureEth.withdraw({ from: investor1 }); | ||
await ventureEth.withdraw({ from: investor2 }); | ||
BN(await ventureEth.balanceOf(investor1)).should.be.bignumber.equal(ether('0.1')); | ||
BN(await ventureEth.balanceOf(investor2)).should.be.bignumber.equal(ether('0.02')); | ||
const tracker = await balance.tracker(wallet, 'wei'); | ||
await tracker.get(); | ||
await ventureEth.transferFunds(wallet); | ||
BN(await tracker.delta()).should.be.bignumber.gte(ether('0.5')).and.bignumber.lte(ether('0.6')); | ||
}); | ||
|
||
/** | ||
* @test {VentureEth#updateAccount} and {VentureEth#increasePool} | ||
*/ | ||
it('updateAccount can succesfully update an account', async () => { | ||
const tracker1 = await balance.tracker(investor1, 'ether'); | ||
const tracker2 = await balance.tracker(investor2, 'ether'); | ||
await tracker1.get(); | ||
await tracker2.get(); | ||
await ventureEth.increasePool({ from: user1, value: ether('6').toString()}); | ||
await ventureEth.updateAccount(investor1); | ||
await ventureEth.updateAccount(investor2); | ||
(await tracker1.delta()).should.be.bignumber.equal('5'); | ||
(await tracker2.delta()).should.be.bignumber.equal('1'); | ||
}); | ||
|
||
/** | ||
* @test {VentureEth#updateAccount} and {VentureEth#increasePool} | ||
*/ | ||
it('more updateAccount usage, including a revert', async () => { | ||
const tracker1 = await balance.tracker(investor1, 'ether'); | ||
const tracker2 = await balance.tracker(investor2, 'ether'); | ||
await tracker1.get(); | ||
await tracker2.get(); | ||
await ventureEth.increasePool({ from: user1, value: ether('6').toString()}); | ||
await ventureEth.updateAccount(investor1); | ||
(await tracker1.delta()).should.be.bignumber.equal('5'); | ||
await expectRevert(ventureEth.updateAccount(investor1), 'Account need not be updated now.'); | ||
await ventureEth.increasePool({ from: user1, value: ether('6').toString()}); | ||
await ventureEth.updateAccount(investor2); | ||
(await tracker2.delta()).should.be.bignumber.equal('2'); | ||
}); | ||
}); | ||
|
||
function bytes32ToString(text: string) { | ||
return web3.utils.toAscii(text).replace(/\0/g, ''); | ||
} | ||
|