This repository has been archived by the owner on Jul 24, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Increased time cannot be reseted according to trufflesuite/ganache-cli-archive#390
- Loading branch information
Showing
2 changed files
with
199 additions
and
0 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
pragma solidity ^0.4.15; | ||
|
||
import "./ERC20Token.sol"; | ||
|
||
contract Question { | ||
uint public constant version = 1; | ||
|
||
struct Charity { | ||
string name; | ||
address addr; | ||
} | ||
|
||
ERC20Interface token; | ||
Charity[] public charities; | ||
string public question; | ||
string public twitterAccount; | ||
uint public deadline; | ||
string public tweetUrl; | ||
mapping(address => uint256) public donorDonations; | ||
uint public donorCount; | ||
uint256 public donations; | ||
|
||
modifier beforeDeadline() { | ||
require(now < deadline); | ||
_; | ||
} | ||
|
||
function getCharitiesCount() constant returns (uint) { | ||
return charities.length; | ||
} | ||
|
||
function Question(ERC20Interface _token, string _question, string _twitterAccount, uint _deadline) { | ||
token = _token; | ||
require(bytes(_question).length != 0); | ||
require(bytes(_twitterAccount).length != 0); | ||
// todo check twitter account more carefully | ||
require(now < _deadline); | ||
|
||
charities.push(Charity({ name: 'Test charity 1', | ||
addr: 0xfA491DF8780761853D127A9f7b2772D688A0E3B5 })); | ||
charities.push(Charity({ name: 'Test charity 2', | ||
addr: 0x45992982736870Fe45c41049C5F785d4E4cc38Ec })); | ||
charities.push(Charity({ name: 'Test charity 3', | ||
addr: 0xfA491DF8780761853D127A9f7b2772D688A0E3B5 })); | ||
charities.push(Charity({ name: 'Test charity 4', | ||
addr: 0x45992982736870Fe45c41049C5F785d4E4cc38Ec })); | ||
|
||
question = _question; | ||
twitterAccount = _twitterAccount; | ||
deadline = _deadline; | ||
} | ||
|
||
function increase(uint256 amount) beforeDeadline { | ||
require(token.transferFrom(msg.sender, this, amount)); | ||
if (0 == donorDonations[msg.sender]) donorCount += 1; | ||
donations += amount; | ||
donorDonations[msg.sender] += amount; | ||
} | ||
|
||
function answer(string _tweetUrl) beforeDeadline { | ||
require(bytes(_tweetUrl).length != 0); | ||
// todo check tweet more carefully, get charity id | ||
tweetUrl = _tweetUrl; | ||
assert(token.transfer(charities[0].addr, donations)); | ||
} | ||
|
||
function revertDonation() { | ||
require(bytes(tweetUrl).length == 0); | ||
require(now >= deadline); | ||
require(donorDonations[msg.sender] != 0); | ||
assert(token.transfer(msg.sender, donorDonations[msg.sender])); | ||
donorCount -= 1; | ||
donations -= donorDonations[msg.sender]; | ||
donorDonations[msg.sender] = 0; | ||
} | ||
} |
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,123 @@ | ||
/* global artifacts contract it assert web3 */ | ||
|
||
const { assertError } = require('./common'); | ||
|
||
const ERC20Token = artifacts.require('ERC20Token'); | ||
const Question = artifacts.require('Question'); | ||
|
||
const increaseTime = (seconds = 0) => web3.currentProvider.send({ | ||
jsonrpc: '2.0', method: 'evm_increaseTime', params: [seconds] }).result; | ||
|
||
// https://github.com/ethereumjs/testrpc/issues/390 | ||
const increasedSeconds = increaseTime(); | ||
const testBeforeNowDate = Math.floor(Date.now() / 1000) + (increasedSeconds - 5); | ||
const testAfterNowDate = Math.floor(Date.now() / 1000) + (increasedSeconds + 5); | ||
const testQuestion = 'test_question'; | ||
const testAccount = 'test_account'; | ||
const testAnswer = 'test_answer'; | ||
|
||
contract('Question', (accounts) => { | ||
it('can\'t be deployed with unset question', () => | ||
Question.new(ERC20Token.address, '', testAccount, testAfterNowDate) | ||
.then(assert.fail, assertError)); | ||
|
||
it('can\'t be deployed with unset account', () => | ||
Question.new(ERC20Token.address, testQuestion, '', testAfterNowDate) | ||
.then(assert.fail, assertError)); | ||
|
||
it('can\'t be deployed with deadline before current date', () => | ||
Question.new(ERC20Token.address, testQuestion, testAccount, testBeforeNowDate) | ||
.then(assert.fail, assertError)); | ||
|
||
it('should be deployable', () => | ||
Question.new(ERC20Token.address, testQuestion, testAccount, testAfterNowDate) | ||
.then(instance => | ||
Promise.all([ | ||
instance.version.call().then(c => assert.equal(c, 1)), | ||
instance.getCharitiesCount.call().then(c => assert.equal(c, 4)), | ||
instance.question.call().then(q => assert.equal(q, testQuestion)), | ||
instance.twitterAccount.call().then(t => assert.equal(t, testAccount)), | ||
instance.deadline.call().then(d => assert.equal(d, testAfterNowDate)), | ||
]))); | ||
|
||
it('can\'t increase after deadline', () => | ||
Question.new(ERC20Token.address, testQuestion, testAccount, testBeforeNowDate) | ||
.then(question => question.increase(0)) | ||
.then(assert.fail, assertError)); | ||
|
||
const newDonatedQuestion = amount => | ||
Promise.all([ | ||
Question.new(ERC20Token.address, testQuestion, testAccount, testAfterNowDate), | ||
ERC20Token.deployed(), | ||
]) | ||
.then(([question, token]) => | ||
token.approve(question.address, amount) | ||
.then(() => question.increase(amount)) | ||
.then(() => question)); | ||
|
||
it('increase', () => { | ||
const amount = 1; | ||
return newDonatedQuestion(amount) | ||
.then(question => | ||
Promise.all([ | ||
question.donorDonations.call(accounts[0]).then(d => assert.equal(d, amount)), | ||
question.donorCount.call().then(c => assert.equal(c, 1)), | ||
question.donations.call().then(d => assert.equal(d, amount)), | ||
])); | ||
}); | ||
|
||
it('can\'t answer after deadline', () => | ||
Question.new(ERC20Token.address, testQuestion, testAccount, testBeforeNowDate) | ||
.then(question => question.answer(testAnswer)) | ||
.then(assert.fail, assertError)); | ||
|
||
it('answer', () => | ||
newDonatedQuestion(1) | ||
.then(question => | ||
question.answer(testAnswer) | ||
.then(() => question.tweetUrl.call())) | ||
.then(t => assert.equal(t, testAnswer))); | ||
|
||
it('answer with transfer to charity', () => { | ||
const amount = 1; | ||
return Promise.all([ | ||
newDonatedQuestion(amount), | ||
ERC20Token.deployed(), | ||
]) | ||
.then(([question, token]) => | ||
question.charities.call(0) | ||
.then(([, charityAddress]) => | ||
token.balanceOf.call(charityAddress) | ||
.then(charityBalance => | ||
question.answer(testAnswer) | ||
.then(() => token.balanceOf.call(charityAddress)) | ||
.then(newCharityBalance => | ||
assert.equal(newCharityBalance.comparedTo(charityBalance.plus(amount)), 0))))); | ||
}); | ||
|
||
it('can\'t revert donation before deadline', () => { | ||
const amount = 1; | ||
return newDonatedQuestion(amount) | ||
.then(question => question.revertDonation()) | ||
.then(assert.fail, assertError); | ||
}); | ||
|
||
it('revert donation', () => { | ||
const amount = 1; | ||
return Promise.all([ | ||
newDonatedQuestion(amount) | ||
.then((token) => { | ||
increaseTime(10); | ||
return token; | ||
}), | ||
ERC20Token.deployed(), | ||
]) | ||
.then(([question, token]) => | ||
token.balanceOf.call(accounts[0]) | ||
.then(accountBalance => | ||
question.revertDonation() | ||
.then(() => token.balanceOf.call(accounts[0])) | ||
.then(newAccountBalance => | ||
assert.equal(newAccountBalance.comparedTo(accountBalance.plus(amount)), 0)))); | ||
}); | ||
}); |