@@ -214,19 +214,27 @@ class InviteVerify extends React.Component {
215 if (cost > balance) {
215 if (cost > balance) {
217− const fundsRemaining = await tank.remainingTransactions(point);
219+ const fundsRemaining = await tank.remainingTransactions(point);
218− if (fundsRemaining < signedTxs.length) {
220+ if (fundsRemaining < signedTxs.length) {
219− throw new Error(`TODO present user with "please fund $(address) with at least $(cost), then click to retry"`);
221+ throw new Error('request invalid');
224+ const res = await tank.fundTransactions(signedTxs);
226+ throw new Error('request rejected');
228+ await waitForTransactionConfirm(web3, res.txHash);
229+ let newBalance = await web3.eth.getBalance(address);
230+ console.log('funds have confirmed', balance >= cost, balance, newBalance);
235+ console.log('funding failed', e);
236+ await this.waitForBalance(web3, address, cost);
222− const res = await tank.fundTransactions(signedTxs);
224− //TODO show pls fund msg
225− console.log('tank request failed');
227− await waitForTransactionConfirm(web3, res.txHash);
228− let newBalance = await web3.eth.getBalance(address);
229− console.log('funds have confirmed', balance >= cost, balance, newBalance);
@@ -234,28 +242,70 @@ class InviteVerify extends React.Component {
245+ // resolves when address has at least minBalance
247+ async waitForBalance(web3, address, minBalance) {
248+ console.log('awaiting balance', address, minBalance);
249+ return new Promise((resolve, reject) => {
250+ let oldBalance = null;
251+ const checkForBalance = async () => {
252+ const balance = await web3.eth.getBalance(address);
253+ if (balance >= minBalance) {
256+ if (balance !== oldBalance) {
257+ this.askForFunding(address, minBalance, balance);
259+ setTimeout(checkForBalance, 13000);
237 async sendAndAwaitConfirm(web3, signedTxs) {
266 async sendAndAwaitConfirm(web3, signedTxs) {
238− let promises = signedTxs.map(tx => {
267+ await Promise.all(signedTxs.map(tx => {
239 console.log('sending...');
268 console.log('sending...');
240 return new Promise((resolve, reject) => {
269 return new Promise((resolve, reject) => {
241 web3.eth.sendSignedTransaction(tx).then(res => {
270 web3.eth.sendSignedTransaction(tx).then(res => {
242− //TODO figure out how to handle the doesn't-resolve-immediately case
271+ console.log('sent, now waiting for confirm!', res.transactionHash);
243− //res.transactionHash;
272+ waitForTransactionConfirm(web3, res.transactionHash)
244− resolve();
273+ .then(resolve);
245 }).catch(async err => {
274 }).catch(async err => {
246 // if there's an error, check if it's because the transaction was
275 // if there's an error, check if it's because the transaction was
247 // already confirmed prior to sending.
276 // already confirmed prior to sending.
248 // this is really only the case in local dev environments.
277 // this is really only the case in local dev environments.
249 const txHash = web3.utils.keccak256(tx);
278 const txHash = web3.utils.keccak256(tx);
279+ console.log(err.message);
280+ if (err.message.slice(0,54) ===
281+ "Returned error: the tx doesn't have the correct nonce.") {
282+ console.log('nonce error, awaiting confirm', err.message.slice(55));
283+ //TODO max wait time before assume failure?
284+ let res = await waitForTransactionConfirm(web3, txHash);
286+ else reject(new Error('Unexpected tx failure'));
250− const confirmed = await isTransactionConfirmed(web3, txHash);
288+ const confirmed = await isTransactionConfirmed(web3, txHash);
289+ console.log('error, but maybe confirmed:', confirmed);
251− if (confirmed) resolve();
290+ if (confirmed) resolve();
252− else reject(err);
291+ else reject(err);
258− //TODO waitForBalance(address, minBalance)
298+ awaitForResult(desired, retryTime, func) {
299+ return new Promise((resolve, reject) => {
300+ const retry = async () => {
301+ const result = await func();
302+ console.log('result vs desired', result, desired);
303+ if (result === desired) resolve();
304+ else setTimeout(retry, retryTime);
260 render() {
310 render() {