From f25c74c7e91c4d32417aac2b514e09538589c9cd Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Sun, 28 Apr 2019 14:14:27 +0100 Subject: [PATCH 1/5] Add helper functions for confirmation status --- app/helpers/contribution-status.js | 20 ++++++++++++++++++ app/helpers/is-confirmed-contribution.js | 15 +++++++++++++ tests/unit/helpers/contribution-status.js | 21 +++++++++++++++++++ .../unit/helpers/is-confirmed-contribution.js | 21 +++++++++++++++++++ 4 files changed, 77 insertions(+) create mode 100644 app/helpers/contribution-status.js create mode 100644 app/helpers/is-confirmed-contribution.js create mode 100644 tests/unit/helpers/contribution-status.js create mode 100644 tests/unit/helpers/is-confirmed-contribution.js diff --git a/app/helpers/contribution-status.js b/app/helpers/contribution-status.js new file mode 100644 index 0000000..79e4bbb --- /dev/null +++ b/app/helpers/contribution-status.js @@ -0,0 +1,20 @@ +import Helper from '@ember/component/helper'; +import { inject as service } from '@ember/service'; +import { alias } from '@ember/object/computed'; + +export default Helper.extend({ + + kredits: service(), + currentBlock: alias('kredits.currentBlock'), + + compute([contribution]) { + if (contribution.vetoed) { + return 'vetoed'; + } else if (contribution.confirmedAt > this.currentBlock) { + return 'unconfirmed'; + } else { + return 'confirmed' + } + } + +}); diff --git a/app/helpers/is-confirmed-contribution.js b/app/helpers/is-confirmed-contribution.js new file mode 100644 index 0000000..0f63b76 --- /dev/null +++ b/app/helpers/is-confirmed-contribution.js @@ -0,0 +1,15 @@ +import Helper from '@ember/component/helper'; +import { inject as service } from '@ember/service'; +import { alias } from '@ember/object/computed'; + +export default Helper.extend({ + + kredits: service(), + currentBlock: alias('kredits.currentBlock'), + + compute([contribution]) { + return !contribution.vetoed && + (contribution.confirmedAt <= this.currentBlock); + } + +}); diff --git a/tests/unit/helpers/contribution-status.js b/tests/unit/helpers/contribution-status.js new file mode 100644 index 0000000..785b56c --- /dev/null +++ b/tests/unit/helpers/contribution-status.js @@ -0,0 +1,21 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Helper | contribution-status', function (hooks) { + setupTest(hooks); + + test('returns the appropriate status', function (assert) { + const contributionStatus = this.owner.factoryFor('helper:contribution-status').create(); + const kredits = this.owner.lookup('service:kredits'); + + kredits.set('currentBlock', 23000); + + const contributionUnconfirmed = { confirmedAt: 23001, vetoed: false }; + const contributionConfirmed = { confirmedAt: 21000, vetoed: false }; + const contributionVetoed = { confirmedAt: 23001, vetoed: true }; + + assert.eq(contributionStatus.compute([contributionUnconfirmed]), 'unconfirmed'); + assert.eq(contributionStatus.compute([contributionConfirmed]), 'confirmed'); + assert.eq(contributionStatus.compute([contributionVetoed]), 'vetoed'); + }); +}); diff --git a/tests/unit/helpers/is-confirmed-contribution.js b/tests/unit/helpers/is-confirmed-contribution.js new file mode 100644 index 0000000..3db7534 --- /dev/null +++ b/tests/unit/helpers/is-confirmed-contribution.js @@ -0,0 +1,21 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'ember-qunit'; + +module('Unit | Helper | contribution-status', function (hooks) { + setupTest(hooks); + + test('returns the appropriate status', function (assert) { + const contributionStatus = this.owner.factoryFor('helper:contribution-status').create(); + const kredits = this.owner.lookup('service:kredits'); + + kredits.set('currentBlock', 23000); + + const contributionUnconfirmed = { confirmedAt: 23001, vetoed: false }; + const contributionConfirmed = { confirmedAt: 21000, vetoed: false }; + const contributionVetoed = { confirmedAt: 23001, vetoed: true }; + + assert.notOk(contributionStatus.compute([contributionUnconfirmed]), 'unconfirmed'); + assert.notOk(contributionStatus.compute([contributionVetoed]), 'vetoed'); + assert.ok(contributionStatus.compute([contributionConfirmed]), 'confirmed'); + }); +}); From c6a37f7e94b08fb6f23718e754523ce0ab3b78e5 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Sun, 28 Apr 2019 14:39:50 +0100 Subject: [PATCH 2/5] Refactor and add new button styles --- app/styles/_buttons.scss | 30 +++++++++++++++++++ app/styles/app.scss | 17 +---------- app/styles/components/_contribution-list.scss | 22 +++++++------- app/styles/components/_proposal-list.scss | 6 ---- 4 files changed, 41 insertions(+), 34 deletions(-) create mode 100644 app/styles/_buttons.scss diff --git a/app/styles/_buttons.scss b/app/styles/_buttons.scss new file mode 100644 index 0000000..8a6956a --- /dev/null +++ b/app/styles/_buttons.scss @@ -0,0 +1,30 @@ +button, input[type=submit] { + display: inline-block; + padding: 0.6rem 2rem; + background-color: rgba(22, 21, 40, 0.6); + border: 1px solid rgba(22, 21, 40, 1); + border-radius: 3px; + color: $primary-color; + font-weight: 500; + text-transform: uppercase; + cursor: pointer; + letter-spacing: 0.1em; + + &:hover { + background-color: rgba(22, 21, 40, 0.8); + } + + &.small { + font-size: 0.8rem; + padding: 0.2rem 0.8rem; + } + + &.danger { + color: $red; + background-color: rgba(40, 21, 21, 0.6); + + &:hover { + background-color: rgba(40, 21, 21, 0.8); + } + } +} diff --git a/app/styles/app.scss b/app/styles/app.scss index 84ec881..69555ef 100644 --- a/app/styles/app.scss +++ b/app/styles/app.scss @@ -90,22 +90,6 @@ section { } } -button, input[type=submit] { - display: inline-block; - border: 1px solid rgba(22, 21, 40, 1); - background-color: rgba(22, 21, 40, 0.6); - color: $primary-color; - border-radius: 3px; - font-weight: 500; - text-transform: uppercase; - cursor: pointer; - letter-spacing: 0.1em; - - &:hover { - background-color: rgba(22, 21, 40, 0.8); - } -} - @media (min-width: 550px) { section { h2 { @@ -114,6 +98,7 @@ button, input[type=submit] { } } +@import "buttons"; @import "components/topbar"; @import "components/loading-spinner"; @import "components/contributor-list"; diff --git a/app/styles/components/_contribution-list.scss b/app/styles/components/_contribution-list.scss index c865532..4cc0636 100644 --- a/app/styles/components/_contribution-list.scss +++ b/app/styles/components/_contribution-list.scss @@ -20,6 +20,10 @@ ul.contribution-list { font-size: 1.2rem; border-bottom: 1px solid rgba(255,255,255,0.2); + &.unconfirmed { + grid-template-columns: auto 5rem 5rem; + } + &:first-of-type { border-top: 1px solid rgba(255,255,255,0.2); } @@ -34,13 +38,13 @@ ul.contribution-list { text-align: right; } - &.description { - grid-column-start: span 2; - } + // &.description { + // grid-column-start: span 2; + // } - &.voting { - grid-column-start: span 2; - } + // &.voting { + // grid-column-start: span 2; + // } } span { @@ -92,12 +96,6 @@ ul.contribution-list { color: $primary-color; margin-right: 0.5rem; } - - button { - height: 2rem; - line-height: 2rem; - padding: 0 0.6rem; - } } } diff --git a/app/styles/components/_proposal-list.scss b/app/styles/components/_proposal-list.scss index 2599a0b..2527ad2 100644 --- a/app/styles/components/_proposal-list.scss +++ b/app/styles/components/_proposal-list.scss @@ -73,12 +73,6 @@ ul.proposal-list { color: $primary-color; margin-right: 0.5rem; } - - button { - height: 2rem; - line-height: 2rem; - padding: 0 0.6rem; - } } } From 9821c8b2ea43ddcd757037ace19ba3f90d4f68df Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Sun, 28 Apr 2019 14:41:16 +0100 Subject: [PATCH 3/5] Veto contributions --- .template-lintrc.js | 6 +++- app/components/contribution-list/component.js | 22 +++++++------- app/components/contribution-list/template.hbs | 9 +++++- app/controllers/index.js | 8 ++--- app/services/kredits.js | 15 ++++++++-- app/styles/components/_contribution-list.scss | 29 +++++++++---------- 6 files changed, 54 insertions(+), 35 deletions(-) diff --git a/.template-lintrc.js b/.template-lintrc.js index b45e96f..02bee12 100644 --- a/.template-lintrc.js +++ b/.template-lintrc.js @@ -1,5 +1,9 @@ 'use strict'; module.exports = { - extends: 'recommended' + extends: 'recommended', + + rules: { + 'simple-unless': false + } }; diff --git a/app/components/contribution-list/component.js b/app/components/contribution-list/component.js index c490f86..f85da1d 100644 --- a/app/components/contribution-list/component.js +++ b/app/components/contribution-list/component.js @@ -5,16 +5,16 @@ export default Component.extend({ tagName: 'ul', classNames: ['contribution-list'], - // actions: { - // - // veto (contributionId) { - // if (this.contractInteractionEnabled) { - // this.vetoContribution(contributionId); - // } else { - // window.alert('Only members can veto contributions. Please ask someone to set you up.'); - // } - // } - // - // } + actions: { + + veto (contributionId) { + if (this.contractInteractionEnabled) { + this.vetoContribution(contributionId); + } else { + window.alert('Only members can veto contributions. Please ask someone to set you up.'); + } + } + + } }); diff --git a/app/components/contribution-list/template.hbs b/app/components/contribution-list/template.hbs index d53ad52..3a4aa90 100644 --- a/app/components/contribution-list/template.hbs +++ b/app/components/contribution-list/template.hbs @@ -1,5 +1,5 @@ {{#each contributions as |contribution|}} -
  • +
  • {{user-avatar contributor=contribution.contributor}} ({{contribution.kind}}) @@ -14,5 +14,12 @@

    {{contribution.amount}}₭S

    + {{#unless contribution.vetoed}} + {{#unless (is-confirmed-contribution contribution)}} +

    + +

    + {{/unless}} + {{/unless}}
  • {{/each}} \ No newline at end of file diff --git a/app/controllers/index.js b/app/controllers/index.js index 825a03d..d871450 100644 --- a/app/controllers/index.js +++ b/app/controllers/index.js @@ -33,10 +33,10 @@ export default Controller.extend({ actions: { - vetoContribution (/* contributionId */) { - // this.kredits.vote(proposalId).then(transaction => { - // window.confirm('Vote submitted to Ethereum blockhain: '+transaction.hash); - // }); + vetoContribution (contributionId) { + this.kredits.veto(contributionId).then(transaction => { + window.confirm('Veto submitted to Ethereum blockhain: '+transaction.hash); + }); }, confirmProposal (proposalId) { diff --git a/app/services/kredits.js b/app/services/kredits.js index 12cd42c..f3358d1 100644 --- a/app/services/kredits.js +++ b/app/services/kredits.js @@ -52,9 +52,10 @@ export default Service.extend({ }); } - function instantiateWithAccount (web3Provider, context) { + async function instantiateWithAccount (web3Provider, context) { console.debug('[kredits] Using user-provided instance, e.g. from Mist browser or Metamask'); ethProvider = new ethers.providers.Web3Provider(web3Provider); + // const network = await ethProvider.getNetwork(); ethProvider.listAccounts().then(accounts => { context.set('currentUserAccounts', accounts); const ethSigner = accounts.length === 0 ? null : ethProvider.getSigner(); @@ -183,12 +184,22 @@ export default Service.extend({ console.debug('[kredits] vote for', proposalId); return this.kredits.Proposal.functions.vote(proposalId) - .then((data) => { + .then(data => { console.debug('[kredits] vote response', data); return data; }); }, + veto(contributionId) { + console.debug('[kredits] veto against', contributionId); + + return this.kredits.Contribution.functions.veto(contributionId) + .then(data => { + console.debug('[kredits] veto response', data); + return data; + }); + }, + getCurrentUser: computed('kredits.provider', function() { if (isEmpty(this.currentUserAccounts)) { return RSVP.resolve(); diff --git a/app/styles/components/_contribution-list.scss b/app/styles/components/_contribution-list.scss index 4cc0636..22452dc 100644 --- a/app/styles/components/_contribution-list.scss +++ b/app/styles/components/_contribution-list.scss @@ -20,14 +20,6 @@ ul.contribution-list { font-size: 1.2rem; border-bottom: 1px solid rgba(255,255,255,0.2); - &.unconfirmed { - grid-template-columns: auto 5rem 5rem; - } - - &:first-of-type { - border-top: 1px solid rgba(255,255,255,0.2); - } - p { align-self: center; margin: 0; @@ -37,14 +29,6 @@ ul.contribution-list { &.kredits-amount, &.voting { text-align: right; } - - // &.description { - // grid-column-start: span 2; - // } - - // &.voting { - // grid-column-start: span 2; - // } } span { @@ -96,6 +80,19 @@ ul.contribution-list { color: $primary-color; margin-right: 0.5rem; } + + &:first-of-type { + border-top: 1px solid rgba(255,255,255,0.2); + } + + &.unconfirmed { + grid-template-columns: auto 5rem 5rem; + } + + &.vetoed { + text-decoration: line-through; + opacity: 0.6; + } } } From 00b7b380b918e2aade6d258fa4da5c11c08209e6 Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Sun, 28 Apr 2019 15:06:00 +0100 Subject: [PATCH 4/5] Fix veto tx failing Still have to set the gas limit for most functions in order for them to work. :/ --- app/services/kredits.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/services/kredits.js b/app/services/kredits.js index f3358d1..740c4d8 100644 --- a/app/services/kredits.js +++ b/app/services/kredits.js @@ -193,7 +193,7 @@ export default Service.extend({ veto(contributionId) { console.debug('[kredits] veto against', contributionId); - return this.kredits.Contribution.functions.veto(contributionId) + return this.kredits.Contribution.functions.veto(contributionId, { gasLimit: 300000 }) .then(data => { console.debug('[kredits] veto response', data); return data; From e1737392a78706106b006b3c0801e8eb2350914a Mon Sep 17 00:00:00 2001 From: Sebastian Kippe Date: Sun, 28 Apr 2019 15:26:26 +0100 Subject: [PATCH 5/5] Mark contributions as vetoed on incoming event --- app/components/contribution-list/template.hbs | 2 +- app/controllers/index.js | 4 +-- app/services/kredits.js | 19 ++++++++---- app/styles/components/_contribution-list.scss | 29 ++++++++++--------- 4 files changed, 31 insertions(+), 23 deletions(-) diff --git a/app/components/contribution-list/template.hbs b/app/components/contribution-list/template.hbs index 3a4aa90..29a5760 100644 --- a/app/components/contribution-list/template.hbs +++ b/app/components/contribution-list/template.hbs @@ -1,5 +1,5 @@ {{#each contributions as |contribution|}} -
  • +
  • {{user-avatar contributor=contribution.contributor}} ({{contribution.kind}}) diff --git a/app/controllers/index.js b/app/controllers/index.js index d871450..9a7bd1f 100644 --- a/app/controllers/index.js +++ b/app/controllers/index.js @@ -35,13 +35,13 @@ export default Controller.extend({ vetoContribution (contributionId) { this.kredits.veto(contributionId).then(transaction => { - window.confirm('Veto submitted to Ethereum blockhain: '+transaction.hash); + console.debug('[controllers:index] Veto submitted to Ethereum blockhain: '+transaction.hash); }); }, confirmProposal (proposalId) { this.kredits.vote(proposalId).then(transaction => { - window.confirm('Vote submitted to Ethereum blockhain: '+transaction.hash); + console.debug('[controllers:index] Vote submitted to Ethereum blockhain: '+transaction.hash); }); }, diff --git a/app/services/kredits.js b/app/services/kredits.js index 740c4d8..97a85c0 100644 --- a/app/services/kredits.js +++ b/app/services/kredits.js @@ -220,23 +220,30 @@ export default Service.extend({ return this.proposals.findBy('id', proposalId.toString()); }, - findContributionById(contributionId) { - return this.contributions.findBy('id', contributionId.toString()); - }, - // Contract events addContractEventHandlers() { - // Proposal events + this.kredits.Contribution + .on('ContributionVetoed', this.handleContributionVetoed.bind(this)) + this.kredits.Proposal .on('ProposalCreated', this.handleProposalCreated.bind(this)) .on('ProposalVoted', this.handleProposalVoted.bind(this)) .on('ProposalExecuted', this.handleProposalExecuted.bind(this)); - // Token events this.kredits.Token .on('Transfer', this.handleTransfer.bind(this)); }, + handleContributionVetoed(contributionId) { + console.debug('[kredits] ContributionVetoed event received for ', contributionId); + const contribution = this.contributions.findBy('id', contributionId); + console.debug('[kredits] contribution', contribution); + + if (contribution) { + contribution.set('vetoed', true); + } + }, + handleProposalCreated(proposalId) { let proposal = this.findProposalById(proposalId); diff --git a/app/styles/components/_contribution-list.scss b/app/styles/components/_contribution-list.scss index 22452dc..71367b9 100644 --- a/app/styles/components/_contribution-list.scss +++ b/app/styles/components/_contribution-list.scss @@ -13,13 +13,27 @@ ul.contribution-list { li { display: grid; - grid-template-columns: auto 5rem; + grid-template-columns: auto 5rem 5rem; grid-row-gap: 0.5rem; padding: 1rem 1.2rem; background-color: rgba(255,255,255,0.1); font-size: 1.2rem; border-bottom: 1px solid rgba(255,255,255,0.2); + &:first-of-type { + border-top: 1px solid rgba(255,255,255,0.2); + } + + &.confirmed { + grid-template-columns: auto 5rem; + } + + &.vetoed { + grid-template-columns: auto 5rem; + text-decoration: line-through; + opacity: 0.6; + } + p { align-self: center; margin: 0; @@ -80,19 +94,6 @@ ul.contribution-list { color: $primary-color; margin-right: 0.5rem; } - - &:first-of-type { - border-top: 1px solid rgba(255,255,255,0.2); - } - - &.unconfirmed { - grid-template-columns: auto 5rem 5rem; - } - - &.vetoed { - text-decoration: line-through; - opacity: 0.6; - } } }