Skip to content

Commit

Permalink
Merge 9eea949 into 63defd8
Browse files Browse the repository at this point in the history
  • Loading branch information
wjmelements committed Oct 23, 2018
2 parents 63defd8 + 9eea949 commit 6a92704
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 87 deletions.
28 changes: 10 additions & 18 deletions apps/finance/contracts/Finance.sol
Expand Up @@ -61,7 +61,6 @@ contract Finance is EtherTokenConstant, IsContract, AragonApp {
uint64 interval;
uint64 maxRepeats;
uint64 repeats;
string reference;
}

// Order optimized for storage
Expand All @@ -74,7 +73,6 @@ contract Finance is EtherTokenConstant, IsContract, AragonApp {
uint64 paymentRepeatNumber;
uint64 date;
uint64 periodId;
string reference;
}

struct TokenStatement {
Expand Down Expand Up @@ -114,8 +112,8 @@ contract Finance is EtherTokenConstant, IsContract, AragonApp {

event NewPeriod(uint64 indexed periodId, uint64 periodStarts, uint64 periodEnds);
event SetBudget(address indexed token, uint256 amount, bool hasBudget);
event NewPayment(uint256 indexed paymentId, address indexed recipient, uint64 maxRepeats);
event NewTransaction(uint256 indexed transactionId, bool incoming, address indexed entity, uint256 amount);
event NewPayment(uint256 indexed paymentId, address indexed recipient, uint64 maxRepeats, string reference);
event NewTransaction(uint256 indexed transactionId, bool incoming, address indexed entity, uint256 amount, string reference);
event ChangePaymentState(uint256 indexed paymentId, bool inactive);
event ChangePeriodDuration(uint64 newDuration);
event PaymentFailure(uint256 paymentId);
Expand Down Expand Up @@ -243,7 +241,7 @@ contract Finance is EtherTokenConstant, IsContract, AragonApp {
require(settings.budgets[_token] >= _amount || !settings.hasBudget[_token], ERROR_BUDGET);

paymentId = paymentsNextIndex++;
emit NewPayment(paymentId, _receiver, _maxRepeats);
emit NewPayment(paymentId, _receiver, _maxRepeats, _reference);

Payment storage payment = payments[paymentId];
payment.token = _token;
Expand All @@ -252,7 +250,6 @@ contract Finance is EtherTokenConstant, IsContract, AragonApp {
payment.initialPaymentTime = _initialPaymentTime;
payment.interval = _interval;
payment.maxRepeats = _maxRepeats;
payment.reference = _reference;
payment.createdBy = msg.sender;

if (nextPaymentTime(paymentId) <= getTimestamp64()) {
Expand Down Expand Up @@ -405,7 +402,6 @@ contract Finance is EtherTokenConstant, IsContract, AragonApp {
uint64 initialPaymentTime,
uint64 interval,
uint64 maxRepeats,
string reference,
bool inactive,
uint64 repeats,
address createdBy
Expand All @@ -421,7 +417,6 @@ contract Finance is EtherTokenConstant, IsContract, AragonApp {
maxRepeats = payment.maxRepeats;
repeats = payment.repeats;
inactive = payment.inactive;
reference = payment.reference;
createdBy = payment.createdBy;
}

Expand All @@ -437,8 +432,7 @@ contract Finance is EtherTokenConstant, IsContract, AragonApp {
address token,
address entity,
bool isIncoming,
uint64 date,
string reference
uint64 date
)
{
Transaction storage transaction = transactions[_transactionId];
Expand All @@ -451,7 +445,6 @@ contract Finance is EtherTokenConstant, IsContract, AragonApp {
amount = transaction.amount;
paymentId = transaction.paymentId;
paymentRepeatNumber = transaction.paymentRepeatNumber;
reference = transaction.reference;
}

function getPeriod(uint64 _periodId)
Expand Down Expand Up @@ -597,7 +590,7 @@ contract Finance is EtherTokenConstant, IsContract, AragonApp {
payment.amount,
_paymentId,
payment.repeats,
"" // since paymentId is saved, the payment reference can be fetched
""
);
}
}
Expand Down Expand Up @@ -666,22 +659,21 @@ contract Finance is EtherTokenConstant, IsContract, AragonApp {

uint256 transactionId = transactionsNextIndex++;
Transaction storage transaction = transactions[transactionId];
transaction.periodId = periodId;
transaction.token = _token;
transaction.entity = _entity;
transaction.isIncoming = _incoming;
transaction.amount = _amount;
transaction.paymentId = _paymentId;
transaction.paymentRepeatNumber = _paymentRepeatNumber;
transaction.isIncoming = _incoming;
transaction.token = _token;
transaction.entity = _entity;
transaction.date = getTimestamp64();
transaction.reference = _reference;
transaction.periodId = periodId;

Period storage period = periods[periodId];
if (period.firstTransactionId == NO_TRANSACTION) {
period.firstTransactionId = transactionId;
}

emit NewTransaction(transactionId, _incoming, _entity, _amount);
emit NewTransaction(transactionId, _incoming, _entity, _amount, _reference);
}

function _tryTransitionAccountingPeriod(uint256 _maxTransitions) internal returns (bool success) {
Expand Down
44 changes: 23 additions & 21 deletions apps/finance/test/finance.js
Expand Up @@ -7,6 +7,8 @@ const MiniMeToken = artifacts.require('MiniMeToken')

const getContract = name => artifacts.require(name)

const getEventData = (receipt, event, arg) => receipt.logs.filter(log => log.event == event)[0].args[arg]

contract('Finance App', accounts => {
let daoFact, financeBase, finance, vaultBase, vault, token1, token2, executionTarget, etherToken = {}

Expand Down Expand Up @@ -162,9 +164,9 @@ contract('Finance App', accounts => {

it('records ERC20 deposits', async () => {
await token1.approve(finance.address, 5)
await finance.deposit(token1.address, 5, 'ref')
const receipt = await finance.deposit(token1.address, 5, 'ref')

const [periodId, amount, paymentId, paymentRepeatNumber, token, entity, incoming, date, ref] = await finance.getTransaction(1)
const [periodId, amount, paymentId, paymentRepeatNumber, token, entity, incoming, date] = await finance.getTransaction(1)

// vault has 100 token1 initially
assert.equal((await token1.balanceOf(vault.address)).toString(), 100 + 5, 'deposited tokens must be in vault')
Expand All @@ -176,7 +178,7 @@ contract('Finance App', accounts => {
assert.equal(entity, accounts[0], 'entity should be correct')
assert.isTrue(incoming, 'tx should be incoming')
assert.equal(date, 1, 'date should be correct')
assert.equal(ref, 'ref', 'ref should be correct')
assert.equal(getEventData(receipt, 'NewTransaction', 'reference'), 'ref', 'ref should be correct')
})

it('fails on no value ERC20 deposits', async () => {
Expand All @@ -192,7 +194,7 @@ contract('Finance App', accounts => {

const transactionId = receipt.logs.filter(log => log.event == 'NewTransaction')[0].args.transactionId

const [periodId, amount, paymentId, paymentRepeatNumber, token, entity, incoming, date, ref] = await finance.getTransaction(transactionId)
const [periodId, amount, paymentId, paymentRepeatNumber, token, entity, incoming, date] = await finance.getTransaction(transactionId)

assert.equal(await vault.balance(ETH), VAULT_INITIAL_ETH_BALANCE + sentWei, 'deposited ETH must be in vault')
assert.equal(periodId, 0, 'period id should be correct')
Expand All @@ -203,15 +205,15 @@ contract('Finance App', accounts => {
assert.equal(entity, accounts[0], 'entity should be correct')
assert.isTrue(incoming, 'tx should be incoming')
assert.equal(date, 1, 'date should be correct')
assert.equal(ref, reference, 'ref should be correct')
assert.equal(getEventData(receipt, 'NewTransaction', 'reference'), reference, 'ref should be correct')
})

it('records ETH deposits using fallback', async () => {
const sentWei = 10
const receipt = await finance.send(sentWei)
const transactionId = receipt.logs.filter(log => log.event == 'NewTransaction')[0].args.transactionId

const [periodId, amount, paymentId, paymentRepeatNumber, token, entity, incoming, date, ref] = await finance.getTransaction(transactionId)
const [periodId, amount, paymentId, paymentRepeatNumber, token, entity, incoming, date] = await finance.getTransaction(transactionId)

assert.equal(await vault.balance(ETH), VAULT_INITIAL_ETH_BALANCE + sentWei, 'deposited ETH must be in vault')
assert.equal(periodId, 0, 'period id should be correct')
Expand All @@ -222,7 +224,7 @@ contract('Finance App', accounts => {
assert.equal(entity, accounts[0], 'entity should be correct')
assert.isTrue(incoming, 'tx should be incoming')
assert.equal(date, 1, 'date should be correct')
assert.equal(ref, 'Ether transfer to Finance app', 'ref should be correct')
assert.equal(getEventData(receipt, 'NewTransaction', 'reference'), 'Ether transfer to Finance app', 'ref should be correct')
})

context('locked tokens', () => {
Expand All @@ -239,9 +241,9 @@ contract('Finance App', accounts => {
})

it('are recovered using Finance#recoverToVault', async () => {
await finance.recoverToVault(token1.address)
const receipt = await finance.recoverToVault(token1.address)

const [periodId, amount, paymentId, paymentRepeatNumber, token, entity, incoming, date, ref] = await finance.getTransaction(1)
const [periodId, amount, paymentId, paymentRepeatNumber, token, entity, incoming, date] = await finance.getTransaction(1)

let finalBalance = await token1.balanceOf(vault.address)
assert.equal(finalBalance.toString(), initialBalance.plus(5).toString(), 'deposited tokens must be in vault')
Expand All @@ -254,7 +256,7 @@ contract('Finance App', accounts => {
assert.equal(entity, finance.address, 'entity should be correct')
assert.isTrue(incoming, 'tx should be incoming')
assert.equal(date, 1, 'date should be correct')
assert.equal(ref, 'Recover to Vault', 'ref should be correct')
assert.equal(getEventData(receipt, 'NewTransaction', 'reference'), 'Recover to Vault', 'ref should be correct')
})

it('fail to be recovered using AragonApp#transferToVault', async () => {
Expand Down Expand Up @@ -284,9 +286,9 @@ contract('Finance App', accounts => {
})

it('is recovered using Finance#recoverToVault', async () => {
await finance.recoverToVault(ETH)
const receipt = await finance.recoverToVault(ETH)

const [periodId, amount, paymentId, paymentRepeatNumber, token, entity, incoming, date, ref] = await finance.getTransaction(1)
const [periodId, amount, paymentId, paymentRepeatNumber, token, entity, incoming, date] = await finance.getTransaction(1)

assert.equal(await vault.balance(ETH), VAULT_INITIAL_ETH_BALANCE + lockedETH, 'recovered ETH must be in vault')
assert.equal((await getBalance(finance.address)).toNumber(), 0, 'finance shouldn\'t have ETH')
Expand All @@ -298,7 +300,7 @@ contract('Finance App', accounts => {
assert.equal(entity, finance.address, 'entity should be correct')
assert.isTrue(incoming, 'tx should be incoming')
assert.equal(date, 1, 'date should be correct')
assert.equal(ref, 'Recover to Vault', 'ref should be correct')
assert.equal(getEventData(receipt, 'NewTransaction', 'reference'), 'Recover to Vault', 'ref should be correct')
})

it('fails to be recovered using AragonApp#transferToVault', async () => {
Expand Down Expand Up @@ -370,17 +372,17 @@ contract('Finance App', accounts => {
it('records payment', async () => {
const amount = 10
// repeats up to 10 times every 2 seconds
await finance.newPayment(token1.address, recipient, amount, time, 2, 10, 'ref')
const receipt = await finance.newPayment(token1.address, recipient, amount, time, 2, 10, 'ref')

const [token, receiver, txAmount, initialTime, interval, maxRepeats, ref, disabled, repeats, createdBy] = await finance.getPayment(1)
const [token, receiver, txAmount, initialTime, interval, maxRepeats, disabled, repeats, createdBy] = await finance.getPayment(1)

assert.equal(token, token1.address, 'token address should match')
assert.equal(receiver, recipient, 'receiver should match')
assert.equal(amount, txAmount, 'amount should match')
assert.equal(initialTime, time, 'time should match')
assert.equal(interval, 2, 'interval should match')
assert.equal(maxRepeats, 10, 'max repeats should match')
assert.equal(ref, 'ref', 'ref should match')
assert.equal(getEventData(receipt, 'NewPayment', 'reference'), 'ref', 'ref should match')
assert.isFalse(disabled, 'should be enabled')
assert.equal(repeats, 1, 'should be on repeat 1')
assert.equal(createdBy, accounts[0], 'should have correct creator')
Expand Down Expand Up @@ -413,11 +415,11 @@ contract('Finance App', accounts => {
const amount = 10

// interval 0, repeat 1 (single payment)
await finance.newPayment(token1.address, recipient, amount, time, 0, 1, 'ref')
const receipt = await finance.newPayment(token1.address, recipient, amount, time, 0, 1, 'ref')

assert.equal((await token1.balanceOf(recipient)).toString(), amount, 'recipient should have received tokens')

const [periodId, txAmount, paymentId, paymentRepeatNumber, token, entity, isIncoming, date, ref] = await finance.getTransaction(1)
const [periodId, txAmount, paymentId, paymentRepeatNumber, token, entity, isIncoming, date] = await finance.getTransaction(1)
assert.equal(periodId, 0, 'period id should be correct')
assert.equal(txAmount, amount, 'amount should match')
assert.equal(paymentId, 0, 'payment id should be 0 for single payment')
Expand All @@ -426,7 +428,7 @@ contract('Finance App', accounts => {
assert.equal(entity, recipient, 'receiver should match')
assert.isFalse(isIncoming, 'single payment should be outgoing')
assert.equal(date.toNumber(), time, 'date should be correct')
assert.equal(ref, 'ref', 'ref should match')
assert.equal(getEventData(receipt, 'NewTransaction', 'reference'), 'ref', 'ref should match')
})

it('can decrease budget after spending', async () => {
Expand Down Expand Up @@ -473,7 +475,7 @@ contract('Finance App', accounts => {
const repeatNum = index + 1

const transactionId = receipt.logs.filter(log => log.event == 'NewTransaction')[0].args.transactionId
const [periodId, txAmount, paymentId, paymentRepeatNumber, token, entity, incoming, date, ref] = await finance.getTransaction(transactionId)
const [periodId, txAmount, paymentId, paymentRepeatNumber, token, entity, incoming, date] = await finance.getTransaction(transactionId)

assert.equal(txAmount, amount, 'amount should be correct')
assert.equal(paymentId, 1, 'payment id should be 1')
Expand Down Expand Up @@ -584,7 +586,7 @@ contract('Finance App', accounts => {

const receipt = await finance.send(sentWei, { gas: 3e5 })
const transactionId = receipt.logs.filter(log => log.event == 'NewTransaction')[0].args.transactionId
const [periodId, amount, paymentId, paymentRepeatNumber, token, entity, incoming, date, ref] = await finance.getTransaction(transactionId)
const [periodId, amount, paymentId, paymentRepeatNumber, token, entity, incoming, date] = await finance.getTransaction(transactionId)

assert.equal(amount, sentWei, 'app should have received ETH and sent it to vault')
assert.equal((await getBalance(vault.address)).toNumber(), prevVaultBalance + sentWei, 'app should have received ETH and sent it to vault')
Expand Down
22 changes: 7 additions & 15 deletions apps/survey/contracts/Survey.sol
Expand Up @@ -50,14 +50,12 @@ contract Survey is AragonApp {
}

struct SurveyStruct {
address creator;
uint64 startDate;
uint64 snapshotBlock;
uint64 minParticipationPct;
uint256 options;
uint256 votingPower; // total tokens that can cast a vote
uint256 participation; // tokens that casted a vote
string metadata;

// Note that option IDs are from 1 to `options`, due to ABSTAIN_VOTE taking 0
mapping (uint256 => uint256) optionPower; // option ID -> voting power for option
Expand All @@ -72,7 +70,7 @@ contract Survey is AragonApp {
mapping (uint256 => SurveyStruct) internal surveys;
uint256 public surveysLength;

event StartSurvey(uint256 indexed surveyId);
event StartSurvey(uint256 indexed surveyId, address indexed creator, string metadata);
event CastVote(uint256 indexed surveyId, address indexed voter, uint256 option, uint256 stake, uint256 optionPower);
event ResetVote(uint256 indexed surveyId, address indexed voter, uint256 option, uint256 previousStake, uint256 optionPower);
event ChangeMinParticipation(uint64 minParticipationPct);
Expand Down Expand Up @@ -130,18 +128,18 @@ contract Survey is AragonApp {
* @return surveyId id for newly created survey
*/
function newSurvey(string _metadata, uint256 _options) external auth(CREATE_SURVEYS_ROLE) returns (uint256 surveyId) {
uint256 votingPower = token.totalSupplyAt(survey.snapshotBlock);
require(votingPower > 0, ERROR_NO_VOTING_POWER);

surveyId = surveysLength++;
SurveyStruct storage survey = surveys[surveyId];
survey.creator = msg.sender;
survey.startDate = getTimestamp64();
survey.options = _options;
survey.metadata = _metadata;
survey.snapshotBlock = getBlockNumber64() - 1; // avoid double voting in this very block
survey.votingPower = token.totalSupplyAt(survey.snapshotBlock);
require(survey.votingPower > 0, ERROR_NO_VOTING_POWER);
survey.minParticipationPct = minParticipationPct;
survey.options = _options;
survey.votingPower = votingPower;

emit StartSurvey(surveyId);
emit StartSurvey(surveyId, msg.sender, _metadata);
}

/**
Expand Down Expand Up @@ -262,7 +260,6 @@ contract Survey is AragonApp {
surveyExists(_surveyId)
returns (
bool _open,
address _creator,
uint64 _startDate,
uint64 _snapshotBlock,
uint64 _minParticipationPct,
Expand All @@ -274,7 +271,6 @@ contract Survey is AragonApp {
SurveyStruct storage survey = surveys[_surveyId];

_open = _isSurveyOpen(survey);
_creator = survey.creator;
_startDate = survey.startDate;
_snapshotBlock = survey.snapshotBlock;
_minParticipationPct = survey.minParticipationPct;
Expand All @@ -283,10 +279,6 @@ contract Survey is AragonApp {
_options = survey.options;
}

function getSurveyMetadata(uint256 _surveyId) public view surveyExists(_surveyId) returns (string) {
return surveys[_surveyId].metadata;
}

/* solium-disable-next-line function-order */
function getVoterState(uint256 _surveyId, address _voter)
external
Expand Down

0 comments on commit 6a92704

Please sign in to comment.