feat: approval and allocation in separate operations (#35)
This commit is contained in:
parent
9c5640605b
commit
af55ca0311
|
@ -12,13 +12,19 @@ import {
|
|||
removeContributor,
|
||||
forfeitAllocation,
|
||||
lastForfeited,
|
||||
allocate
|
||||
allocate,
|
||||
getAllowance,
|
||||
approve,
|
||||
resetAllowance,
|
||||
getSNTBalance
|
||||
} from '../services/Meritocracy';
|
||||
import { sortByAlpha } from '../utils';
|
||||
import moment from 'moment';
|
||||
|
||||
import './admin.scss';
|
||||
|
||||
const toBN = web3.utils.toBN;
|
||||
|
||||
class Admin extends React.Component {
|
||||
state = {
|
||||
contributorName: '',
|
||||
|
@ -32,7 +38,9 @@ class Admin extends React.Component {
|
|||
sortBy: 'label',
|
||||
tab: 'admin',
|
||||
sntPerContributor: 0,
|
||||
lastForfeited: null
|
||||
lastForfeited: null,
|
||||
allowance: '0',
|
||||
balance: '0',
|
||||
};
|
||||
|
||||
async componentDidMount() {
|
||||
|
@ -42,11 +50,18 @@ class Admin extends React.Component {
|
|||
this.setState({ busy: false, contributorList });
|
||||
|
||||
this.getLastForfeitDate();
|
||||
this.getAllowance();
|
||||
} catch (error) {
|
||||
this.setState({ errorMsg: error.message || error });
|
||||
}
|
||||
}
|
||||
|
||||
getAllowance = async () => {
|
||||
const allowance = await getAllowance();
|
||||
const balance = await getSNTBalance();
|
||||
this.setState({allowance, balance});
|
||||
}
|
||||
|
||||
onChange = (name, e) => {
|
||||
this.setState({ [name]: e.target.value });
|
||||
};
|
||||
|
@ -84,7 +99,50 @@ class Admin extends React.Component {
|
|||
|
||||
try {
|
||||
await allocate(sntAmount);
|
||||
this.setState({ busy: false, successMsg: 'Funds allocated!' });
|
||||
this.setState({ busy: false, successMsg: 'Funds allocated!'});
|
||||
this.getAllowance();
|
||||
} catch (error) {
|
||||
this.setState({ error: error.message || error, busy: false });
|
||||
}
|
||||
};
|
||||
|
||||
approve = async e => {
|
||||
e.preventDefault();
|
||||
|
||||
/* eslint-disable-next-line no-alert*/
|
||||
if (!confirm('Are you sure?')) return;
|
||||
|
||||
this.setState({ busy: true, successMsg: '', error: '' });
|
||||
|
||||
const { contributorList, sntPerContributor } = this.state;
|
||||
const sntAmount = web3.utils.toWei((contributorList.length * parseInt(sntPerContributor, 10)).toString(), 'ether');
|
||||
|
||||
try {
|
||||
await approve(sntAmount);
|
||||
this.setState({
|
||||
busy: false,
|
||||
successMsg: (contributorList.length * parseInt(sntPerContributor, 10)) + ' SNT approved for allocation',
|
||||
allowance: sntAmount
|
||||
});
|
||||
|
||||
this.getAllowance();
|
||||
} catch (error) {
|
||||
this.setState({ error: error.message || error, busy: false });
|
||||
}
|
||||
};
|
||||
|
||||
resetAllowance = async e => {
|
||||
e.preventDefault();
|
||||
|
||||
/* eslint-disable-next-line no-alert*/
|
||||
if (!confirm('Are you sure?')) return;
|
||||
|
||||
this.setState({ busy: true, successMsg: '', error: '' });
|
||||
|
||||
try {
|
||||
await resetAllowance();
|
||||
this.setState({ busy: false, successMsg: 'Allowance reset to 0', allowance: '0' });
|
||||
this.getAllowance();
|
||||
} catch (error) {
|
||||
this.setState({ error: error.message || error, busy: false });
|
||||
}
|
||||
|
@ -141,13 +199,23 @@ class Admin extends React.Component {
|
|||
successMsg,
|
||||
focusedContributorIndex,
|
||||
tab,
|
||||
sntPerContributor
|
||||
sntPerContributor,
|
||||
allowance,
|
||||
balance
|
||||
} = this.state;
|
||||
const currentContributor = focusedContributorIndex > -1 ? contributorList[focusedContributorIndex] : {};
|
||||
const nextForfeit = (lastForfeited ? lastForfeited * 1000 : new Date().getTime()) + 86400 * 6 * 1000;
|
||||
const nextForfeitDate =
|
||||
new Date(nextForfeit).toLocaleDateString() + ' ' + new Date(nextForfeit).toLocaleTimeString();
|
||||
|
||||
const totalSntForContributors = web3.utils.toWei(toBN(contributorList.length * parseInt(sntPerContributor || '0', 10)), "ether");
|
||||
|
||||
|
||||
const enoughBalance = toBN(balance).gte(toBN(totalSntForContributors));
|
||||
const shouldApprove = toBN(totalSntForContributors).gt(toBN(0)) && toBN(allowance).lt(toBN(totalSntForContributors));
|
||||
const shouldReset = toBN(allowance).gt(toBN(0)) && toBN(allowance).lt(toBN(totalSntForContributors));
|
||||
const canAllocate = toBN(totalSntForContributors).gt(toBN(0)) && toBN(allowance).gte(toBN(totalSntForContributors));
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Tabs className="home-tabs mb-3" activeKey={tab} onSelect={tab => this.setState({ tab })}>
|
||||
|
@ -214,7 +282,7 @@ class Admin extends React.Component {
|
|||
<Form.Group controlId="fundAllocation">
|
||||
<Form.Label>SNT per contributor</Form.Label>
|
||||
<Form.Text className="text-muted">
|
||||
Total: {contributorList.length * parseInt(sntPerContributor, 10) || 0} SNT
|
||||
Total: {contributorList.length * parseInt(sntPerContributor, 10) || 0} SNT, (Balance: {web3.utils.fromWei(balance, "ether")} SNT, Approved: {web3.utils.fromWei(allowance, "ether")} SNT)
|
||||
</Form.Text>
|
||||
<Input
|
||||
type="text"
|
||||
|
@ -225,9 +293,15 @@ class Admin extends React.Component {
|
|||
validations={[required, isNumber, higherThan.bind(null, 0)]}
|
||||
/>
|
||||
</Form.Group>
|
||||
<Button variant="primary" onClick={this.allocateFunds}>
|
||||
Allocate Funds
|
||||
</Button>
|
||||
{ enoughBalance && canAllocate && <Button variant="primary" disabled={busy} onClick={this.allocateFunds}>
|
||||
Allocate {contributorList.length * parseInt(sntPerContributor || '0', 10)} SNT
|
||||
</Button> }
|
||||
{ enoughBalance && shouldApprove && !shouldReset && <Button disabled={busy} variant="primary" onClick={this.approve}>
|
||||
Approve {contributorList.length * parseInt(sntPerContributor || '0', 10)} SNT
|
||||
</Button> }
|
||||
{ shouldApprove && shouldReset && <Button disabled={busy} variant="primary" onClick={this.resetAllowance}>
|
||||
Reset existing approval
|
||||
</Button> }
|
||||
</ValidatedForm>
|
||||
<hr className="mt-5 mb-5" />
|
||||
<ValidatedForm>
|
||||
|
|
|
@ -106,45 +106,63 @@ export function forfeitAllocation() {
|
|||
resolve(receipt);
|
||||
} catch (error) {
|
||||
const message = 'Error forfeiting allocation';
|
||||
console.error(message);
|
||||
console.error(error);
|
||||
reject(message);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function getSNTBalance() {
|
||||
return new Promise(async (resolve) => {
|
||||
const mainAccount = web3.eth.defaultAccount;
|
||||
resolve(await SNT.methods.balanceOf(mainAccount).call());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function getAllowance() {
|
||||
return new Promise(async (resolve) => {
|
||||
const mainAccount = web3.eth.defaultAccount;
|
||||
resolve(await SNT.methods.allowance(mainAccount, Meritocracy.options.address).call());
|
||||
});
|
||||
}
|
||||
|
||||
export function resetAllowance() {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const mainAccount = web3.eth.defaultAccount;
|
||||
try {
|
||||
const toSend = SNT.methods.approve(Meritocracy.options.address, '0');
|
||||
const gas = await toSend.estimateGas({ from: mainAccount });
|
||||
const receipt = await toSend.send({ from: mainAccount, gas: gas + 1000 });
|
||||
resolve(receipt);
|
||||
} catch(error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function approve(sntAmount) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const mainAccount = web3.eth.defaultAccount;
|
||||
try {
|
||||
const toSend = SNT.methods.approve(Meritocracy.options.address, sntAmount);
|
||||
const gas = await toSend.estimateGas({ from: mainAccount });
|
||||
const receipt = await toSend.send({ from: mainAccount, gas: gas + 1000 });
|
||||
resolve(receipt);
|
||||
} catch(error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function allocate(sntAmount) {
|
||||
return new Promise(async (resolve, reject) => {
|
||||
const mainAccount = web3.eth.defaultAccount;
|
||||
try {
|
||||
let toSend, gas;
|
||||
|
||||
const balance = web3.utils.toBN(await SNT.methods.balanceOf(mainAccount).call());
|
||||
const allowance = web3.utils.toBN(await SNT.methods.allowance(mainAccount, Meritocracy.options.address).call());
|
||||
|
||||
if (balance.lt(web3.utils.toBN(sntAmount))) {
|
||||
throw new Error('Not enough SNT');
|
||||
}
|
||||
|
||||
if (allowance.gt(web3.utils.toBN('0')) && allowance.lt(web3.utils.toBN(sntAmount))) {
|
||||
alert('Reset allowance to 0');
|
||||
toSend = SNT.methods.approve(Meritocracy.options.address, '0');
|
||||
gas = await toSend.estimateGas({ from: mainAccount });
|
||||
await toSend.send({ from: mainAccount, gas: gas + 1000 });
|
||||
}
|
||||
|
||||
if (allowance.eq(web3.utils.toBN('0'))) {
|
||||
alert(`Approving ${web3.utils.fromWei(sntAmount, 'ether')} to meritocracy contract`);
|
||||
toSend = SNT.methods.approve(Meritocracy.options.address, sntAmount);
|
||||
gas = await toSend.estimateGas({ from: mainAccount });
|
||||
await toSend.send({ from: mainAccount, gas: gas + 1000 });
|
||||
}
|
||||
|
||||
alert('Allocating SNT');
|
||||
toSend = Meritocracy.methods.allocate(sntAmount);
|
||||
gas = await toSend.estimateGas({ from: mainAccount });
|
||||
await toSend.send({ from: mainAccount, gas: gas + 1000 });
|
||||
|
||||
resolve(true);
|
||||
} catch (error) {
|
||||
let message;
|
||||
|
@ -152,10 +170,8 @@ export function allocate(sntAmount) {
|
|||
if (error.message === 'Not enough SNT') {
|
||||
message = 'Not enough SNT';
|
||||
} else {
|
||||
message = 'Error forfeiting allocation';
|
||||
message = 'Error doing allocation';
|
||||
}
|
||||
|
||||
console.error(message);
|
||||
console.error(error);
|
||||
reject(message);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue