liquid-funding/js/liquidPledging.js

282 lines
8.7 KiB
JavaScript
Raw Normal View History

/* eslint-disable no-await-in-loop */
const LiquidPledgingAbi = require('../build/LiquidPledging.sol').LiquidPledgingAbi;
const LiquidPledgingCode = require('../build/LiquidPledging.sol').LiquidPledgingByteCode;
const LiquidPledgingMockAbi = require('../build/LiquidPledgingMock.sol').LiquidPledgingMockAbi;
const LiquidPledgingMockCode = require('../build/LiquidPledgingMock.sol').LiquidPledgingMockByteCode;
2017-09-16 04:05:50 +00:00
function checkWeb3(web3) {
if (typeof web3.version !== 'string' || !web3.version.startsWith('1.')) {
throw new Error('web3 version 1.x is required');
}
}
const estimateGas = (web3, method, opts) => {
if (opts.$noEstimateGas) return Promise.resolve(4700000);
if (opts.$gas || opts.gas) return Promise.resolve(opts.$gas || opts.gas);
return method.estimateGas(opts)
// eslint-disable-next-line no-confusing-arrow
.then(gas => opts.$extraGas ? gas + opts.$extraGas : Math.floor(gas * 1.1));
};
2017-09-20 09:44:34 +00:00
// if constant method, executes a call, otherwise, estimates gas and executes send
const execute = (web3, txObject, opts, cb) => {
const { _method } = txObject;
if (_method.constant) return txObject.call(opts);
// eslint-disable-next-line no-param-reassign
return estimateGas(web3, txObject, opts)
.then((gas) => {
Object.assign(opts, { gas });
return (cb) ? txObject.send(opts, cb) : txObject.send(opts);
});
2017-09-16 04:05:50 +00:00
};
2017-09-20 09:44:34 +00:00
const methodWrapper = (web3, method, ...args) => {
let cb;
let opts = {};
if (typeof args[args.length - 1] === 'function') cb = args.pop();
if (typeof args[args.length - 1] === 'object') opts = args.pop();
const txObject = method(...args);
return execute(web3, txObject, opts, cb);
};
2017-07-04 23:13:24 +00:00
2017-07-13 17:12:45 +00:00
module.exports = (test) => {
2017-09-16 04:05:50 +00:00
const $abi = (test) ? LiquidPledgingMockAbi : LiquidPledgingAbi;
const $byteCode = (test) ? LiquidPledgingMockCode : LiquidPledgingCode;
2017-07-13 17:12:45 +00:00
2017-09-16 04:05:50 +00:00
return class LiquidPledging {
2017-07-04 23:13:24 +00:00
constructor(web3, address) {
2017-09-16 04:05:50 +00:00
checkWeb3(web3);
this.$web3 = web3;
this.$address = address;
this.$contract = new web3.eth.Contract($abi, address);
this.$abi = $abi;
this.$byteCode = $byteCode;
// helpers
this.$toNumber = web3.utils.toBN;
this.$toDecimal = web3.utils.toDecimal;
this.notes = [];
this.managers = [];
2017-09-16 04:05:50 +00:00
2017-09-20 09:44:34 +00:00
Object.keys(this.$contract.methods)
.filter(key => !key.startsWith('0x'))
.forEach((key) => {
this[key] = (...args) => methodWrapper(web3, this.$contract.methods[key], ...args);
});
2017-09-16 04:05:50 +00:00
// set default from address
web3.eth.getAccounts()
.then((accounts) => {
this.$contract.options.from = (accounts.length > 0) ? accounts[0] : undefined;
});
}
async $getNote(idNote) {
const note = {
delegates: [],
};
2017-09-20 09:44:34 +00:00
const res = await this.getNote(idNote);
2017-09-16 04:05:50 +00:00
note.amount = this.$toNumber(res.amount);
note.owner = res.owner;
for (let i = 1; i <= this.$toDecimal(res.nDelegates); i += 1) {
const delegate = {};
2017-09-20 09:44:34 +00:00
const resd = await this.getNoteDelegate(idNote, i);
2017-09-16 04:05:50 +00:00
delegate.id = this.$toDecimal(resd.idDelegate);
delegate.addr = resd.addr;
delegate.name = resd.name;
note.delegates.push(delegate);
}
2017-09-16 04:05:50 +00:00
if (res.proposedProject) {
note.proposedProject = this.$toDecimal(res.proposedProject);
note.commmitTime = this.$toDecimal(res.commitTime);
}
2017-09-16 04:05:50 +00:00
if (res.oldNote) {
note.oldProject = this.$toDecimal(res.oldNote);
}
2017-09-16 04:05:50 +00:00
if (res.paymentState === '0') {
note.paymentState = 'NotPaid';
2017-09-16 04:05:50 +00:00
} else if (res.paymentState === '1') {
note.paymentState = 'Paying';
2017-09-16 04:05:50 +00:00
} else if (res.paymentState === '2') {
note.paymentState = 'Paid';
} else {
note.paymentState = 'Unknown';
}
return note;
2017-07-04 23:13:24 +00:00
}
async $getManager(idManager) {
const manager = {};
2017-09-20 09:44:34 +00:00
const res = await this.getNoteManager(idManager);
2017-09-16 04:05:50 +00:00
if (res.managerType === '0') {
manager.type = 'Donor';
} else if (res.managerType === '1') {
manager.type = 'Delegate';
} else if (res.managerType === '2') {
manager.type = 'Project';
} else {
2017-09-16 04:05:50 +00:00
manager.type = 'Unknown';
}
2017-09-16 04:05:50 +00:00
manager.addr = res.addr;
manager.name = res.name;
manager.commitTime = this.$toDecimal(res.commitTime);
if (manager.paymentState === 'Project') {
2017-09-16 04:05:50 +00:00
manager.parentProject = res.parentProject;
manager.canceled = res.canceled;
}
return manager;
}
async getState() {
const st = {
notes: [null],
managers: [null],
};
2017-09-20 09:44:34 +00:00
const nNotes = await this.numberOfNotes();
for (let i = 1; i <= nNotes; i += 1) {
const note = await this.$getNote(i);
st.notes.push(note);
}
2017-09-20 09:44:34 +00:00
const nManagers = await this.numberOfNoteManagers();
for (let i = 1; i <= nManagers; i += 1) {
const manager = await this.$getManager(i);
st.managers.push(manager);
}
return st;
2017-07-04 23:13:24 +00:00
}
2017-07-11 11:01:00 +00:00
generateDonorsState() {
const donorsState = [];
const getDonor = (idNote) => {
let note = this.notes[idNote];
while (note.oldNode) note = this.notes[idNote];
return note.owner;
};
// Add a donor structure to the list
const addDonor = (_list, idDonor) => {
const list = _list;
if (!list[idDonor]) {
list[idDonor] = {
idDonor,
notAssigned: {
notes: [],
delegates: [],
},
precommitedProjects: [],
commitedProjects: [],
};
}
};
// Add a delegate structure to the list
const addDelegate = (_list, idDelegate) => {
const list = _list;
if (!list[idDelegate]) {
list[idDelegate] = {
idDelegate,
name: this.managers[idDelegate].name,
notes: [],
delegtes: [],
};
}
};
const addProject = (_list, idProject) => {
const list = _list;
if (!list[idProject]) {
list[idProject] = {
idProject,
notes: [],
commitedProjects: [],
name: this.managers[idProject].name,
commitTime: this.managers[idProject].commitTime,
owner: this.managers[idProject].owner,
parentProject: this.managers[idProject].parentProject,
};
}
};
const addDelegateNote = (stDonor, idNote) => {
const note = this.notes[idNote];
stDonor.notAssigned.notes.push(idNote);
let list = stDonor.notAssigned.delegates;
for (let i = 0; i < note.delegationChain.length; i += 1) {
const idDelegate = note.delegationChain[i];
addDelegate(list, idDelegate);
list = list[idDelegate].delegates;
}
};
const addProjectNote = (stDonor, idNote) => {
const note = this.notes[idNote];
const projectList = [];
let n = note;
while (n.oldNode) {
projectList.unshift(n.owner);
n = this.notes[n.oldNode];
}
let list = stDonor.commitedProjects;
for (let j = 0; j < projectList.length; j += 1) {
addProject(list, projectList[j]);
list[projectList[j]].notes.push(idNote);
list = list[projectList[j]].commitedProjects;
}
};
for (let i = 0; i < this.notes; i += 1) {
const idNote = this.notes[i];
const idDonor = getDonor(idNote);
addDonor(donorsState, idDonor);
const stDonor = donorsState[idDonor];
const note = this.notes[idNote];
if ((note.owner === idDonor) && (note.precommitedProject === 0)) {
addDelegateNote(stDonor, idNote);
} else if ((note.owner === idDonor) && (note.precommitedProject !== 0)) {
addProject(stDonor.precommitedProjects, note.precommitedProject);
stDonor.precommitedProjects[note.precommitedProject].notes.push(idNote);
} else {
addProjectNote(stDonor, idNote);
2017-07-11 11:01:00 +00:00
}
}
2017-07-11 11:01:00 +00:00
this.donorsState = donorsState;
2017-07-11 11:01:00 +00:00
}
2017-09-16 04:05:50 +00:00
static new(web3, vault, opts = {}) {
const deploy = new web3.eth.Contract($abi)
2017-09-20 09:44:34 +00:00
.deploy({
data: $byteCode,
arguments: [vault],
});
2017-09-16 04:05:50 +00:00
const getAccount = () => {
if (opts.from) return Promise.resolve(opts.from);
return web3.eth.getAccounts()
// eslint-disable-next-line no-confusing-arrow
.then(accounts => (accounts.length > 0) ? accounts[0] : undefined);
};
return getAccount()
.then(account => Object.assign(opts, { from: account }))
2017-09-20 09:44:34 +00:00
.then(() => execute(web3, deploy, opts))
2017-09-16 04:05:50 +00:00
.then(contract => new LiquidPledging(web3, contract.options.address));
}
2017-07-13 17:12:45 +00:00
};
2017-07-11 11:01:00 +00:00
};