openethereum/js/src/modals/Verification/store.js

244 lines
7.4 KiB
JavaScript
Raw Normal View History

2016-12-11 19:30:54 +01:00
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
2016-12-06 16:09:02 +01:00
import { observable, autorun, action } from 'mobx';
import { sha3 } from '~/api/util/sha3';
import Contract from '~/api/contract';
import Contracts from '~/contracts';
2016-12-12 12:33:58 +01:00
import { checkIfVerified, checkIfRequested, awaitPuzzle } from '~/contracts/verification';
import { checkIfTxFailed, waitForConfirmations } from '~/util/tx';
export const LOADING = 'fetching-contract';
export const QUERY_DATA = 'query-data';
export const POSTING_REQUEST = 'posting-request';
export const POSTED_REQUEST = 'posted-request';
2016-12-06 16:09:02 +01:00
export const REQUESTING_CODE = 'requesting-code';
export const QUERY_CODE = 'query-code';
export const POSTING_CONFIRMATION = 'posting-confirmation';
export const POSTED_CONFIRMATION = 'posted-confirmation';
export const DONE = 'done';
export default class VerificationStore {
@observable step = null;
@observable error = null;
@observable contract = null;
@observable fee = null;
@observable isVerified = null;
@observable hasRequested = null;
@observable isServerRunning = null;
@observable consentGiven = false;
@observable requestTx = null;
@observable code = '';
@observable isCodeValid = null;
@observable confirmationTx = null;
2016-12-15 18:09:52 +01:00
constructor (api, abi, certifierId, account, isTestnet) {
this.api = api;
this.account = account;
this.isTestnet = isTestnet;
this.step = LOADING;
2016-12-15 18:09:52 +01:00
Contracts.get().badgeReg.fetchCertifier(certifierId)
.then(({ address }) => {
this.contract = new Contract(api, abi).at(address);
this.load();
})
.catch((err) => {
console.error('error', err);
this.error = 'Failed to fetch the contract: ' + err.message;
});
autorun(() => {
if (this.error) {
2016-12-06 16:09:02 +01:00
console.error('verification: ' + this.error);
}
});
}
@action load = () => {
const { contract, account } = this;
this.step = LOADING;
const isServerRunning = this.isServerRunning()
.then((isRunning) => {
this.isServerRunning = isRunning;
})
.catch((err) => {
this.error = 'Failed to check if server is running: ' + err.message;
});
const fee = contract.instance.fee.call()
.then((fee) => {
this.fee = fee;
})
.catch((err) => {
this.error = 'Failed to fetch the fee: ' + err.message;
});
const isVerified = checkIfVerified(contract, account)
.then((isVerified) => {
this.isVerified = isVerified;
})
.catch((err) => {
this.error = 'Failed to check if verified: ' + err.message;
});
const hasRequested = checkIfRequested(contract, account)
.then((txHash) => {
this.hasRequested = !!txHash;
if (txHash) {
this.requestTx = txHash;
}
})
.catch((err) => {
this.error = 'Failed to check if requested: ' + err.message;
});
Promise
.all([ isServerRunning, fee, isVerified, hasRequested ])
.then(() => {
this.step = QUERY_DATA;
});
}
@action setConsentGiven = (consentGiven) => {
this.consentGiven = consentGiven;
}
@action setCode = (code) => {
const { contract, account } = this;
if (!contract || !account || code.length === 0) {
return;
}
const confirm = contract.functions.find((fn) => fn.name === 'confirm');
const options = { from: account };
const values = [ sha3.text(code) ];
this.code = code;
this.isCodeValid = null;
confirm.estimateGas(options, values)
.then((gas) => {
options.gas = gas.mul(1.2).toFixed(0);
return confirm.call(options, values);
})
.then((result) => {
this.isCodeValid = result === true;
})
.catch((err) => {
this.error = 'Failed to check if the code is valid: ' + err.message;
});
}
requestValues = () => []
@action sendRequest = () => {
2016-12-06 16:09:02 +01:00
const { api, account, contract, fee, hasRequested } = this;
const request = contract.functions.find((fn) => fn.name === 'request');
const options = { from: account, value: fee.toString() };
const values = this.requestValues();
let chain = Promise.resolve();
if (!hasRequested) {
this.step = POSTING_REQUEST;
chain = request.estimateGas(options, values)
.then((gas) => {
options.gas = gas.mul(1.2).toFixed(0);
return request.postTransaction(options, values);
})
.then((handle) => {
// TODO: The "request rejected" error doesn't have any property to
// distinguish it from other errors, so we can't give a meaningful error here.
return api.pollMethod('parity_checkRequest', handle);
})
.then((txHash) => {
this.requestTx = txHash;
return checkIfTxFailed(api, txHash, options.gas)
.then((hasFailed) => {
if (hasFailed) {
throw new Error('Transaction failed, all gas used up.');
}
this.step = POSTED_REQUEST;
return waitForConfirmations(api, txHash, 1);
});
});
}
chain
.then(() => {
2016-12-06 16:09:02 +01:00
this.step = REQUESTING_CODE;
return this.requestCode();
})
.then(() => awaitPuzzle(api, contract, account))
.then(() => {
this.step = QUERY_CODE;
})
.catch((err) => {
2016-12-06 16:09:02 +01:00
this.error = 'Failed to request a confirmation code: ' + err.message;
});
}
2016-11-15 16:21:53 +01:00
@action queryCode = () => {
this.step = QUERY_CODE;
}
@action sendConfirmation = () => {
const { api, account, contract, code } = this;
const token = sha3.text(code);
const confirm = contract.functions.find((fn) => fn.name === 'confirm');
const options = { from: account };
const values = [ token ];
this.step = POSTING_CONFIRMATION;
confirm.estimateGas(options, values)
.then((gas) => {
options.gas = gas.mul(1.2).toFixed(0);
return confirm.postTransaction(options, values);
})
.then((handle) => {
// TODO: The "request rejected" error doesn't have any property to
// distinguish it from other errors, so we can't give a meaningful error here.
return api.pollMethod('parity_checkRequest', handle);
})
.then((txHash) => {
this.confirmationTx = txHash;
return checkIfTxFailed(api, txHash, options.gas)
.then((hasFailed) => {
if (hasFailed) {
throw new Error('Transaction failed, all gas used up.');
}
this.step = POSTED_CONFIRMATION;
return waitForConfirmations(api, txHash, 1);
});
})
.then(() => {
this.step = DONE;
})
.catch((err) => {
this.error = 'Failed to send the verification code: ' + err.message;
});
}
2016-11-15 16:21:53 +01:00
@action done = () => {
this.step = DONE;
2016-11-15 16:21:53 +01:00
}
}