Merge branch 'master' into feature/store-models-in-service
# Conflicts: # app/controllers/index.js # tests/unit/controllers/index-test.js
This commit is contained in:
@@ -8,7 +8,7 @@ export default Component.extend({
|
|||||||
|
|
||||||
// Default attributes used by reset
|
// Default attributes used by reset
|
||||||
attributes: {
|
attributes: {
|
||||||
recipientId: null,
|
contributorId: null,
|
||||||
kind: 'community',
|
kind: 'community',
|
||||||
amount: null,
|
amount: null,
|
||||||
description: null,
|
description: null,
|
||||||
@@ -22,7 +22,7 @@ export default Component.extend({
|
|||||||
|
|
||||||
contributors: [],
|
contributors: [],
|
||||||
|
|
||||||
isValidRecipient: isPresent('recipientId'),
|
isValidRecipient: isPresent('contributorId'),
|
||||||
isValidAmount: computed('amount', function() {
|
isValidAmount: computed('amount', function() {
|
||||||
return parseInt(this.get('amount'), 10) > 0;
|
return parseInt(this.get('amount'), 10) > 0;
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<form {{action "submit" on="submit"}}>
|
<form {{action "submit" on="submit"}}>
|
||||||
<p>
|
<p>
|
||||||
<select required onchange={{action (mut recipientId) value="target.value"}}>
|
<select required onchange={{action (mut contributorId) value="target.value"}}>
|
||||||
<option value="" selected disabled hidden>Contributor</option>
|
<option value="" selected disabled hidden>Contributor</option>
|
||||||
{{#each contributors as |contributor|}}
|
{{#each contributors as |contributor|}}
|
||||||
<option value={{contributor.id}} selected={{eq recipientId contributor.id}}>{{contributor.github_username}}</option>
|
<option value={{contributor.id}} selected={{eq contributorId contributor.id}}>{{contributor.github_username}}</option>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</select>
|
</select>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -42,10 +42,9 @@ export default Controller.extend({
|
|||||||
this.get('proposals').pushObject(proposal);
|
this.get('proposals').pushObject(proposal);
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleProposalExecuted(proposalId, recipientId, amount) {
|
_handleProposalExecuted(proposalId, contributorId, amount) {
|
||||||
// TODO: check if proposalId is already a string
|
|
||||||
let proposal = this.get('proposals')
|
let proposal = this.get('proposals')
|
||||||
.findBy('id', proposalId.toString());
|
.findBy('id', proposalId);
|
||||||
|
|
||||||
if (proposal.get('isExecuted')) {
|
if (proposal.get('isExecuted')) {
|
||||||
Ember.Logger.debug('[index] proposal already executed, not adding from event');
|
Ember.Logger.debug('[index] proposal already executed, not adding from event');
|
||||||
@@ -57,13 +56,13 @@ export default Controller.extend({
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.get('contributors')
|
this.get('contributors')
|
||||||
.findBy('id', recipientId.toString())
|
.findBy('id', contributorId)
|
||||||
.incrementProperty('balance', amount);
|
.incrementProperty('balance', amount);
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleProposalVoted(proposalId, voter, totalVotes) {
|
_handleProposalVoted(proposalId, voter, totalVotes) {
|
||||||
this.get('proposals')
|
this.get('proposals')
|
||||||
.findBy('id', proposalId.toString())
|
.findBy('id', proposalId)
|
||||||
.setProperties({ 'votesCount': totalVotes });
|
.setProperties({ 'votesCount': totalVotes });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export default Controller.extend({
|
|||||||
actions: {
|
actions: {
|
||||||
save(proposal) {
|
save(proposal) {
|
||||||
// contributorIpfsHash is needed for the proposal ipfs data. I'm not happy to do this here but I think to load all the contributors in addProposal again is a bit too much. I hope we can refactor it later.
|
// contributorIpfsHash is needed for the proposal ipfs data. I'm not happy to do this here but I think to load all the contributors in addProposal again is a bit too much. I hope we can refactor it later.
|
||||||
let contributor = this.get('contributors').findBy('id', proposal.recipientId);
|
let contributor = this.get('contributors').findBy('id', proposal.contributorId);
|
||||||
proposal.contributorIpfsHash = contributor.get('ipfsHash');
|
proposal.contributorIpfsHash = contributor.get('ipfsHash');
|
||||||
|
|
||||||
return this.get('kredits').addProposal(proposal)
|
return this.get('kredits').addProposal(proposal)
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export default class Operator extends Base {
|
|||||||
.add(json)
|
.add(json)
|
||||||
.then((ipfsHashAttr) => {
|
.then((ipfsHashAttr) => {
|
||||||
let proposal = [
|
let proposal = [
|
||||||
proposalAttr.recipientId,
|
proposalAttr.contributorId,
|
||||||
proposalAttr.amount,
|
proposalAttr.amount,
|
||||||
ipfsHashAttr.ipfsHash,
|
ipfsHashAttr.ipfsHash,
|
||||||
ipfsHashAttr.hashFunction,
|
ipfsHashAttr.hashFunction,
|
||||||
|
|||||||
+35
-10
@@ -27,22 +27,44 @@ export default class Kredits {
|
|||||||
this.ipfsConfig = ipfsConfig;
|
this.ipfsConfig = ipfsConfig;
|
||||||
this.ipfs = new IPFS(ipfsConfig);
|
this.ipfs = new IPFS(ipfsConfig);
|
||||||
|
|
||||||
let registryContract = this.initRegistryContract(provider);
|
return this.ipfs._ipfsAPI.id().catch((error) => {
|
||||||
|
throw new Error(`IPFS node not available; config: ${JSON.stringify(ipfsConfig)} - ${error.message}`);
|
||||||
|
}).then(() => {
|
||||||
|
|
||||||
let addresses = Object.keys(contracts).reduce((mem, name) => {
|
let registryContract = this.initRegistryContract(provider);
|
||||||
let contractName = capitalize(name);
|
|
||||||
mem[contractName] = registryContract.functions.getProxyFor(contractName);
|
|
||||||
return mem;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
return RSVP.hash(addresses)
|
let addresses = Object.keys(contracts).reduce((mem, name) => {
|
||||||
.then((addresses) => {
|
let contractName = capitalize(name);
|
||||||
return new Kredits(provider, signer, addresses);
|
mem[contractName] = registryContract.functions.getProxyFor(contractName).catch((error) => {
|
||||||
});
|
throw new Error(`Failed to get address for ${contractName} from registry at ${registryContract.address}
|
||||||
|
- correct registry? does it have version entry? - ${error.message}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return mem;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
return RSVP.hash(addresses)
|
||||||
|
.then((addresses) => {
|
||||||
|
return new Kredits(provider, signer, addresses);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static initRegistryContract(provider) {
|
static initRegistryContract(provider) {
|
||||||
let address = addresses['Registry'][provider.chainId];
|
let address = addresses['Registry'][provider.chainId];
|
||||||
|
if (!address) {
|
||||||
|
throw new Error(`Registry address not found; invalid network?
|
||||||
|
requested network: ${provider.chainId}
|
||||||
|
supported networks: ${Object.keys(addresses['Registry'])}
|
||||||
|
`);
|
||||||
|
}
|
||||||
|
provider.getCode(address).then((code) => {
|
||||||
|
// not sure if we always get the same return value of the code is not available
|
||||||
|
// that's why checking if it is < 5 long
|
||||||
|
if (code === '0x00' || code.length < 5) {
|
||||||
|
throw new Error(`Registry not found at ${address} on network ${provider.chainId}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
let abi = abis['Registry'];
|
let abi = abis['Registry'];
|
||||||
console.log('Initialize registry contract:', address, abi, provider);
|
console.log('Initialize registry contract:', address, abi, provider);
|
||||||
return new ethers.Contract(address, abi, provider);
|
return new ethers.Contract(address, abi, provider);
|
||||||
@@ -69,6 +91,9 @@ export default class Kredits {
|
|||||||
|
|
||||||
let contractName = capitalize(name);
|
let contractName = capitalize(name);
|
||||||
let address = this.addresses[contractName];
|
let address = this.addresses[contractName];
|
||||||
|
if (!address || !abis[contractName]) {
|
||||||
|
throw new Error(`Address or ABI not found for ${contractName}`);
|
||||||
|
}
|
||||||
let contract = new ethers.Contract(address, abis[contractName], this.signer);
|
let contract = new ethers.Contract(address, abis[contractName], this.signer);
|
||||||
this.contracts[name] = new contracts[contractName](contract);
|
this.contracts[name] = new contracts[contractName](contract);
|
||||||
|
|
||||||
|
|||||||
@@ -51,5 +51,4 @@ export default class IPFS {
|
|||||||
return multihashes.encode(digest, hashData.hashFunction, hashData.hashSize);
|
return multihashes.encode(digest, hashData.hashFunction, hashData.hashSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ export default EmberObject.extend({
|
|||||||
|
|
||||||
// Contract
|
// Contract
|
||||||
id: bignumber('idRaw', 'toString'),
|
id: bignumber('idRaw', 'toString'),
|
||||||
creatorAddress: null,
|
creatorAccount: null,
|
||||||
recipientId: bignumber('recipientIdRaw', 'toString'),
|
contributorId: bignumber('contributorIdRaw', 'toString'),
|
||||||
amount: bignumber('amountRaw', 'toNumber'),
|
amount: bignumber('amountRaw', 'toNumber'),
|
||||||
votesCount: bignumber('votesCountRaw', 'toNumber'),
|
votesCount: bignumber('votesCountRaw', 'toNumber'),
|
||||||
votesNeeded: bignumber('votesNeededRaw', 'toNumber'),
|
votesNeeded: bignumber('votesNeededRaw', 'toNumber'),
|
||||||
@@ -28,7 +28,7 @@ export default EmberObject.extend({
|
|||||||
|
|
||||||
// Relationships
|
// Relationships
|
||||||
// TODO: Optimize it. We don't need to find the contributor every time we add a new one
|
// TODO: Optimize it. We don't need to find the contributor every time we add a new one
|
||||||
contributor: computed('recipientId', 'kredits.contributors.[]', function() {
|
contributor: computed('contributorId', 'kredits.contributors.[]', function() {
|
||||||
return this.get('kredits.contributors').findBy('id', this.get('recipientId'));
|
return this.get('kredits.contributors').findBy('id', this.get('contributorId'));
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ export default Route.extend({
|
|||||||
transition.retry();
|
transition.retry();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}).catch((error) => {
|
||||||
|
console.log('Error initializing Kredits', error);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import computed from 'ember-computed';
|
import computed from 'ember-computed';
|
||||||
|
import ethers from 'npm:ethers';
|
||||||
|
|
||||||
export default function(dependentKey, converterMethod) {
|
export default function(dependentKey, converterMethod) {
|
||||||
return computed(dependentKey, {
|
return computed(dependentKey, {
|
||||||
@@ -6,6 +7,7 @@ export default function(dependentKey, converterMethod) {
|
|||||||
return this.get(dependentKey)[converterMethod]();
|
return this.get(dependentKey)[converterMethod]();
|
||||||
},
|
},
|
||||||
set (key, value) {
|
set (key, value) {
|
||||||
|
value = ethers.utils.bigNumberify(value);
|
||||||
this.set(dependentKey, value);
|
this.set(dependentKey, value);
|
||||||
return value[converterMethod]();
|
return value[converterMethod]();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,20 +12,12 @@ moduleFor('controller:index', 'Unit | Controller | index', {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let addFixtures = function(controller) {
|
let addFixtures = function(controller) {
|
||||||
controller.set('model', {
|
|
||||||
contributors: [],
|
|
||||||
proposals: []
|
|
||||||
});
|
|
||||||
|
|
||||||
[
|
[
|
||||||
{ github_username: "neo", github_uid: "318", balance: 10000 },
|
{ github_username: "neo", github_uid: "318", balance: 10000 },
|
||||||
{ github_username: "morpheus", github_uid: "843", balance: 15000 },
|
{ github_username: "morpheus", github_uid: "843", balance: 15000 },
|
||||||
{ github_username: "trinity", github_uid: "123", balance: 5000 },
|
{ github_username: "trinity", github_uid: "123", balance: 5000 },
|
||||||
{ github_username: "mouse", github_uid: "696", balance: 0 }
|
{ github_username: "mouse", github_uid: "696", balance: 0 }
|
||||||
].forEach(fixture => {
|
].forEach(fixture => {
|
||||||
// we expect a bignumer but I don't want to add the bignumber dependency here... so this is some hack to return an object that looks good enough for the test
|
|
||||||
let fakeBignumber = function(balance) { return { toNumber: function() { return balance; } }; };
|
|
||||||
fixture.balance = fakeBignumber(fixture.balance);
|
|
||||||
controller.get('kredits.contributors').push(Contributor.create(fixture));
|
controller.get('kredits.contributors').push(Contributor.create(fixture));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user