on master help sign in
Merge pull request #193 from urbit/mino-txn-refactor
4af7360Fang
package-lock.json+13
@@ -2573,6 +2573,14 @@
2573 "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
2573 "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
2574 "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
2574 "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg=="
2575 },
2575 },
2576+ "async-retry": {
2577+ "version": "1.2.3",
2578+ "resolved": "https://registry.npmjs.org/async-retry/-/async-retry-1.2.3.tgz",
2579+ "integrity": "sha512-tfDb02Th6CE6pJUF2gjW5ZVjsgwlucVXOEQMvEX9JgSJMs9gAX+Nz3xRuJBKuUYjTSYORqvDBORdAQ3LU59g7Q==",
2580+ "requires": {
2581+ "retry": "0.12.0"
2582+ }
2583+ },
2576 "asynckit": {
2584 "asynckit": {
2577 "version": "0.4.0",
2585 "version": "0.4.0",
2578 "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
2586 "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
@@ -14927,6 +14935,11 @@
14927 "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
14935 "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
14928 "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="
14936 "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="
14929 },
14937 },
14938+ "retry": {
14939+ "version": "0.12.0",
14940+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz",
14941+ "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs="
14942+ },
14930 "rgb-regex": {
14943 "rgb-regex": {
14931 "version": "1.0.1",
14944 "version": "1.0.1",
14932 "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz",
14945 "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz",
package.json+1
@@ -18,6 +18,7 @@
18 "@ledgerhq/hw-app-eth": "^4.61.0",
18 "@ledgerhq/hw-app-eth": "^4.61.0",
19 "@ledgerhq/hw-transport-u2f": "^4.61.0",
19 "@ledgerhq/hw-transport-u2f": "^4.61.0",
20 "PaperCollateralRenderer": "github:urbit/PaperCollateralRenderer",
20 "PaperCollateralRenderer": "github:urbit/PaperCollateralRenderer",
21+ "async-retry": "^1.2.3",
21 "azimuth-js": "^0.15.0",
22 "azimuth-js": "^0.15.0",
22 "azimuth-solidity": "^1.2.0",
23 "azimuth-solidity": "^1.2.0",
23 "bip32": "^1.0.2",
24 "bip32": "^1.0.2",
src/components/old/StatelessTransaction.js+9−8
@@ -185,7 +185,7 @@ class StatelessTransaction extends React.Component {
185 const stx = state.stx.matchWith({
185 const stx = state.stx.matchWith({
186 Just: tx => tx.value,
186 Just: tx => tx.value,
187 Nothing: () => {
187 Nothing: () => {
188− throw BRIDGE_ERROR.MISSING_TXN;
188+ throw new Error(BRIDGE_ERROR.MISSING_TXN);
189 },
189 },
190 });
190 });
191
191
@@ -233,12 +233,7 @@ class StatelessTransaction extends React.Component {
233 } else {
233 } else {
234 this.setState({ txStatus: SUBMISSION_STATES.SENDING });
234 this.setState({ txStatus: SUBMISSION_STATES.SENDING });
235
235
236− sendSignedTransaction(
237− web3,
238− state.stx,
239− usedTank,
240− props.setTxnConfirmations
236+ sendSignedTransaction(web3, stx, usedTank, props.setTxnConfirmations)
241− )
242 .then(txHash => {
237 .then(txHash => {
243 props.setTxnCursor(Just(Ok(txHash)));
238 props.setTxnCursor(Just(Ok(txHash)));
244
239
@@ -499,7 +494,13 @@ class StatelessTransaction extends React.Component {
499 prop-size={'lg wide'}
494 prop-size={'lg wide'}
500 prop-color={signerButtonColor}
495 prop-color={signerButtonColor}
501 onClick={() =>
496 onClick={() =>
497+ signTransaction({
498+ ...this.props,
499+ ...this.state,
502− signTransaction({ ...this.props, ...this.state, setStx: this.setStx })
500+ setStx: this.setStx,
501+ wallet: this.props.wallet.value,
502+ txn: txn.value,
503+ })
503 }>
504 }>
504 {'Sign Transaction'}
505 {'Sign Transaction'}
505 </Button>
506 </Button>
src/lib/constants.js+2−2
@@ -16,7 +16,7 @@ const SEED_ENTROPY_BITS = 128;
16//TODO move into azimuth-js
16//TODO move into azimuth-js
17const GAS_LIMITS = {
17const GAS_LIMITS = {
18 SPAWN: 250000,
18 SPAWN: 250000,
19− TRANSFER: 490000,
19+ TRANSFER: 550000,
20 CONFIGURE_KEYS: 100000,
20 CONFIGURE_KEYS: 100000,
21 SET_PROXY: 120000,
21 SET_PROXY: 120000,
22 //
22 //
@@ -28,7 +28,7 @@ const GAS_LIMITS = {
28 //
28 //
29 GIFT_PLANET: 400000, //NOTE low sample size
29 GIFT_PLANET: 400000, //NOTE low sample size
30 //
30 //
31− DEFAULT: 500000,
31+ DEFAULT: 550000,
32};
32};
33
33
34// TODO: this is walletgen-ui specific, move into a wallet router later
34// TODO: this is walletgen-ui specific, move into a wallet router later
src/lib/error.js+11−11
@@ -1,15 +1,15 @@
1const BRIDGE_ERROR = {
1const BRIDGE_ERROR = {
2− MISSING_WEB3: new Error('no web3 object found'),
2+ MISSING_WEB3: 'no web3 object found',
3− MISSING_WALLET: new Error('no wallet found'),
3+ MISSING_WALLET: 'no wallet found',
4− MISSING_TXN: new Error('no transaction found'),
4+ MISSING_TXN: 'no transaction found',
5− MISSING_CONTRACTS: new Error('no contracts found'),
5+ MISSING_CONTRACTS: 'no contracts found',
6− MISSING_KEYSTORE: new Error('no keystore text found'),
6+ MISSING_KEYSTORE: 'no keystore text found',
7− MISSING_MNEMONIC: new Error('no authentication mnemonic found'),
7+ MISSING_MNEMONIC: 'no authentication mnemonic found',
8− MISSING_URBIT_WALLET: new Error('no urbit wallet found'),
8+ MISSING_URBIT_WALLET: 'no urbit wallet found',
9− MISSING_POINT: new Error('no point found'),
9+ MISSING_POINT: 'no point found',
10− INVALID_ROUTE: new Error('invalid route'),
10+ INVALID_ROUTE: 'invalid route',
11− INVALID_NETWORK_TYPE: new Error('invalid network type'),
11+ INVALID_NETWORK_TYPE: 'invalid network type',
12− INVALID_WALLET_TYPE: new Error('invalid wallet type'),
12+ INVALID_WALLET_TYPE: 'invalid wallet type',
13};
13};
14
14
15const renderTxnError = (web3, msg) => {
15const renderTxnError = (web3, msg) => {
src/lib/invite.js+2−12
@@ -9,7 +9,7 @@ import * as tank from './tank';
9import JSZip from 'jszip';
9import JSZip from 'jszip';
10import saveAs from 'file-saver';
10import saveAs from 'file-saver';
11
11
12−import { sendSignedTransaction, hexify } from './txn';
12+import { sendAndAwaitAll, hexify } from './txn';
13import { attemptNetworkSeedDerivation } from './keys';
13import { attemptNetworkSeedDerivation } from './keys';
14import { addHexPrefix, WALLET_TYPES } from './wallet';
14import { addHexPrefix, WALLET_TYPES } from './wallet';
15import { GAS_LIMITS } from './constants';
15import { GAS_LIMITS } from './constants';
@@ -258,7 +258,7 @@ async function claimPointFromInvite({
258
258
259 progress(TRANSACTION_STATES.CLAIMING);
259 progress(TRANSACTION_STATES.CLAIMING);
260
260
261− await sendAndAwaitConfirm(web3, txPairs.map(p => Just(p.signed)), usedTank);
261+ await sendAndAwaitAll(web3, txPairs.map(p => p.signed), usedTank);
262
262
263 //
263 //
264 // move leftover eth
264 // move leftover eth
@@ -291,16 +291,6 @@ async function claimPointFromInvite({
291 progress(TRANSACTION_STATES.DONE);
291 progress(TRANSACTION_STATES.DONE);
292}
292}
293
293
294−async function sendAndAwaitConfirm(web3, signedTxs, usedTank) {
295− await Promise.all(
296− signedTxs.map(tx => {
297− return new Promise((resolve, reject) => {
298− sendSignedTransaction(web3, tx, usedTank, resolve);
299− });
300− })
301− );
302−}
303−
304export {
294export {
305 generateWallet,
295 generateWallet,
306 downloadWallet,
296 downloadWallet,
src/lib/keys.js+2−2
@@ -89,7 +89,7 @@ const attemptNetworkSeedDerivation = async (next, args) => {
89 const uwal = urbitWallet.matchWith({
89 const uwal = urbitWallet.matchWith({
90 Just: uw => uw.value,
90 Just: uw => uw.value,
91 Nothing: _ => {
91 Nothing: _ => {
92− throw BRIDGE_ERROR.MISSING_URBIT_WALLET;
92+ throw new Error(BRIDGE_ERROR.MISSING_URBIT_WALLET);
93 },
93 },
94 });
94 });
95
95
@@ -100,7 +100,7 @@ const attemptNetworkSeedDerivation = async (next, args) => {
100 const mnemonic = authMnemonic.matchWith({
100 const mnemonic = authMnemonic.matchWith({
101 Just: mnem => mnem.value,
101 Just: mnem => mnem.value,
102 Nothing: _ => {
102 Nothing: _ => {
103− throw BRIDGE_ERROR.MISSING_MNEMONIC;
103+ throw new Error(BRIDGE_ERROR.MISSING_MNEMONIC);
104 },
104 },
105 });
105 });
106
106
src/lib/need.js+6−6
@@ -19,26 +19,26 @@ export const web3 = needBuilder(() => {
19});
19});
20
20
21export const contracts = needBuilder(() => {
21export const contracts = needBuilder(() => {
22− throw new Error(BRIDGE_ERROR.MISSING_CONTRACTS.message);
22+ throw new Error(BRIDGE_ERROR.MISSING_CONTRACTS);
23});
23});
24
24
25export const wallet = needBuilder(() => {
25export const wallet = needBuilder(() => {
26− throw new Error(BRIDGE_ERROR.MISSING_WALLET.message);
26+ throw new Error(BRIDGE_ERROR.MISSING_WALLET);
27});
27});
28
28
29export const addressFromWallet = obj => wallet(obj).address;
29export const addressFromWallet = obj => wallet(obj).address;
30
30
31export const point = needBuilder(() => {
31export const point = needBuilder(() => {
32− throw new Error(BRIDGE_ERROR.MISSING_POINT.message);
32+ throw new Error(BRIDGE_ERROR.MISSING_POINT);
33});
33});
34
34
35export const pointCache = needBuilder(() => {
35export const pointCache = needBuilder(() => {
36− throw new Error(BRIDGE_ERROR.MISSING_POINT.message);
36+ throw new Error(BRIDGE_ERROR.MISSING_POINT);
37});
37});
38
38
39export const fromPointCache = (cache, point) => {
39export const fromPointCache = (cache, point) => {
40 if (!(point in cache)) {
40 if (!(point in cache)) {
41− throw new Error(BRIDGE_ERROR.MISSING_POINT.message);
41+ throw new Error(BRIDGE_ERROR.MISSING_POINT);
42 }
42 }
43
43
44 return cache[point];
44 return cache[point];
@@ -49,7 +49,7 @@ export const keystore = obj => {
49 return ks.value.matchWith({
49 return ks.value.matchWith({
50 Ok: result => result.value,
50 Ok: result => result.value,
51 Error: _ => {
51 Error: _ => {
52− throw BRIDGE_ERROR.MISSING_KEYSTORE;
52+ throw new Error(BRIDGE_ERROR.MISSING_KEYSTORE);
53 },
53 },
54 });
54 });
55};
55};
src/lib/tank.js+24−35
@@ -1,6 +1,7 @@
1// /lib/tank: functions for funding transactions
1// /lib/tank: functions for funding transactions
2
2
3+import * as retry from 'async-retry';
3−import { waitForTransactionConfirm } from './txn';
4+import { RETRY_OPTIONS, waitForTransactionConfirm } from './txn';
4
5
5//NOTE if accessing this in a localhost configuration fails with "CORS request
6//NOTE if accessing this in a localhost configuration fails with "CORS request
6// did not succeed", you might need to visit localhost:3001 or whatever
7// did not succeed", you might need to visit localhost:3001 or whatever
@@ -92,41 +93,29 @@ const ensureFundsFor = async (
92 return false;
93 return false;
93};
94};
94
95
95−// resolves when address has at least minBalance
96+// returns a promise that resolves when address has at least minBalance
96−//
97−//TODO should maybe do a "we got it" callback also, so clients can hide msg?
98−async function waitForBalance(
97+function waitForBalance(web3, address, minBalance, askForFunding, gotFunding) {
99− web3,
98+ let oldBalance = null;
100− address,
99+ return retry(async (bail, n) => {
101− minBalance,
102− askForFunding,
103− gotFunding
104−) {
105− console.log('tank: awaiting balance', address, minBalance);
106− return new Promise((resolve, reject) => {
107− let oldBalance = null;
108− const checkForBalance = async () => {
109− const balance = await web3.eth.getBalance(address);
100+ const balance = await web3.eth.getBalance(address);
110− if (balance >= minBalance) {
101+ if (balance >= minBalance) {
111− // if we ever asked for funding, retract that request now
102+ // if we ever asked for funding, retract that request now
112− if (gotFunding && oldBalance !== null) {
103+ if (gotFunding && oldBalance !== null) {
113− gotFunding();
104+ gotFunding();
114− }
115− resolve();
116− } else {
117− if (balance !== oldBalance) {
118− // TODO: minBalance is a `number` type
119− // but we want to display ETH, which will never accept a number
120− // but instead wants string or BN/BigNumber.
121− // this will be heavily refactored to correctly do BN math, but until
122− // then we'll manually convert this number to an integer string
123− askForFunding(address, minBalance.toFixed(), balance);
124− }
125− setTimeout(checkForBalance, 13000);
126 }
105 }
127− };
106+ return;
128− checkForBalance();
107+ } else {
129− });
108+ if (balance !== oldBalance) {
109+ // TODO: minBalance is a `number` type
110+ // but we want to display ETH, which will never accept a number
111+ // but instead wants string or BN/BigNumber.
112+ // this will be heavily refactored to correctly do BN math, but until
113+ // then we'll manually convert this number to an integer string
114+ askForFunding(address, minBalance.toFixed(), balance);
115+ }
116+ throw new Error('retrying');
117+ }
118+ }, RETRY_OPTIONS);
130}
119}
131
120
132export { remainingTransactions, fundTransactions, ensureFundsFor };
121export { remainingTransactions, fundTransactions, ensureFundsFor };
src/lib/txn.js+33−60
@@ -2,8 +2,8 @@ import * as ob from 'urbit-ob';
2import { Just } from 'folktale/maybe';
2import { Just } from 'folktale/maybe';
3import Tx from 'ethereumjs-tx';
3import Tx from 'ethereumjs-tx';
4import { toWei, fromWei, toHex } from 'web3-utils';
4import { toWei, fromWei, toHex } from 'web3-utils';
5+import * as retry from 'async-retry';
5
6
6−import { BRIDGE_ERROR } from './error';
7import { NETWORK_TYPES } from './network';
7import { NETWORK_TYPES } from './network';
8import { ledgerSignTransaction } from './ledger';
8import { ledgerSignTransaction } from './ledger';
9import { trezorSignTransaction } from './trezor';
9import { trezorSignTransaction } from './trezor';
@@ -12,6 +12,13 @@ import { WALLET_TYPES, addHexPrefix } from './wallet';
12const CHECK_BLOCK_EVERY_MS =
12const CHECK_BLOCK_EVERY_MS =
13 process.env.NODE_ENV === 'development' ? 1000 : 5000;
13 process.env.NODE_ENV === 'development' ? 1000 : 5000;
14
14
15+const RETRY_OPTIONS = {
16+ retries: 99999,
17+ factor: 1,
18+ minTimeout: CHECK_BLOCK_EVERY_MS,
19+ randomize: false,
20+};
21+
15const TXN_PURPOSE = {
22const TXN_PURPOSE = {
16 SET_MANAGEMENT_PROXY: Symbol('SET_MANAGEMENT_PROXY'),
23 SET_MANAGEMENT_PROXY: Symbol('SET_MANAGEMENT_PROXY'),
17 SET_TRANSFER_PROXY: Symbol('SET_TRANSFER_PROXY'),
24 SET_TRANSFER_PROXY: Symbol('SET_TRANSFER_PROXY'),
@@ -56,6 +63,7 @@ const signTransaction = async config => {
56 gasLimit,
63 gasLimit,
57 } = config;
64 } = config;
58
65
66+ //TODO require these in txn object
59 nonce = toHex(nonce);
67 nonce = toHex(nonce);
60 chainId = toHex(chainId);
68 chainId = toHex(chainId);
61 gasPrice = toHex(toWei(gasPrice, 'gwei'));
69 gasPrice = toHex(toWei(gasPrice, 'gwei'));
@@ -106,45 +114,27 @@ const signTransaction = async config => {
106 ? Object.assign(txParams, eip155Params)
114 ? Object.assign(txParams, eip155Params)
107 : txParams;
115 : txParams;
108
116
109− const wal = wallet.matchWith({
110− Just: w => w.value,
111− Nothing: () => {
112− throw BRIDGE_ERROR.MISSING_WALLET;
113− },
114− });
115−
116− const sec = wal.privateKey;
117−
118− const utx = txn.matchWith({
119− Just: tx => Object.assign(tx.value, signingParams),
117+ const utx = Object.assign(txn, signingParams);
120− Nothing: () => {
121− throw BRIDGE_ERROR.MISSING_TXN;
122− },
123− });
124
118
125 const stx = new Tx(utx);
119 const stx = new Tx(utx);
126
120
121+ //TODO should try-catch and display error message to user,
122+ // ie ledger's "pls enable contract data"
123+ // needs to maybe happen at call-site though
127 if (walletType === WALLET_TYPES.LEDGER) {
124 if (walletType === WALLET_TYPES.LEDGER) {
128 await ledgerSignTransaction(stx, walletHdPath);
125 await ledgerSignTransaction(stx, walletHdPath);
129 } else if (walletType === WALLET_TYPES.TREZOR) {
126 } else if (walletType === WALLET_TYPES.TREZOR) {
130 await trezorSignTransaction(stx, walletHdPath);
127 await trezorSignTransaction(stx, walletHdPath);
131 } else {
128 } else {
132− stx.sign(sec);
129+ stx.sign(wallet.privateKey);
133 }
130 }
134
131
135 setStx(Just(stx));
132 setStx(Just(stx));
136 return stx;
133 return stx;
137};
134};
138
135
139−const sendSignedTransaction = (web3, stx, doubtNonceError, confirmationCb) => {
136+const sendSignedTransaction = (web3, stx, doubtNonceError) => {
140− const txn = stx.matchWith({
141− Just: tx => tx.value,
142− Nothing: () => {
143− throw BRIDGE_ERROR.MISSING_TXN;
144− },
145− });
146−
147− const rawTx = hexify(txn.serialize());
137+ const rawTx = hexify(stx.serialize());
148
138
149 return new Promise(async (resolve, reject) => {
139 return new Promise(async (resolve, reject) => {
150 web3.eth
140 web3.eth
@@ -152,14 +142,6 @@ const sendSignedTransaction = (web3, stx, doubtNonceError, confirmationCb) => {
152 .on('transactionHash', hash => {
142 .on('transactionHash', hash => {
153 resolve(hash);
143 resolve(hash);
154 })
144 })
155− //TODO do we also reach this if network is slow? web3 only tries a set
156− // amount of times... should we instead do waitForTransactionConfirm
157− // in on-transactionHash? we don't care (much) about additional
158− // confirms anyway.
159− .on('confirmation', (confirmationNum, txn) => {
160− confirmationCb(txn.transactionHash, confirmationNum + 1);
161− resolve(txn.transactionHash);
162− })
163 .on('error', err => {
145 .on('error', err => {
164 // if there's a nonce error, but we used the gas tank, it's likely
146 // if there's a nonce error, but we used the gas tank, it's likely
165 // that it's because the tank already submitted our transaction.
147 // that it's because the tank already submitted our transaction.
@@ -176,16 +158,7 @@ const sendSignedTransaction = (web3, stx, doubtNonceError, confirmationCb) => {
176 'tx send error likely from gas tank submission, ignoring'
158 'tx send error likely from gas tank submission, ignoring'
177 );
159 );
178 const txHash = web3.utils.keccak256(rawTx);
160 const txHash = web3.utils.keccak256(rawTx);
179− //TODO can we do does-exists check first?
180− //TODO max wait time before assume fail?
181− waitForTransactionConfirm(web3, txHash).then(res => {
182− if (res) {
183− resolve(txHash);
161+ resolve(txHash);
184− confirmationCb(txHash, 1);
185− } else {
186− reject('Unexpected tx failure');
187− }
188− });
189 } else {
162 } else {
190 reject(err.message || 'Transaction sending failed!');
163 reject(err.message || 'Transaction sending failed!');
191 }
164 }
@@ -195,23 +168,22 @@ const sendSignedTransaction = (web3, stx, doubtNonceError, confirmationCb) => {
195
168
196// returns a Promise<bool>, where the bool indicates tx success/failure
169// returns a Promise<bool>, where the bool indicates tx success/failure
197const waitForTransactionConfirm = (web3, txHash) => {
170const waitForTransactionConfirm = (web3, txHash) => {
198− return new Promise((resolve, reject) => {
171+ return retry(async (bail, n) => {
199− const checkForConfirm = async () => {
200− console.log('checking for confirm', txHash);
201− const receipt = await web3.eth.getTransactionReceipt(txHash);
172+ const receipt = await web3.eth.getTransactionReceipt(txHash);
202− console.log('tried, got', receipt);
203− let confirmed = receipt !== null;
173+ const confirmed = receipt !== null;
204− if (confirmed) resolve(receipt.status === true);
174+ if (confirmed) return receipt.status === true;
205− else setTimeout(checkForConfirm, CHECK_BLOCK_EVERY_MS);
175+ else throw new Error('retrying');
206− };
176+ }, RETRY_OPTIONS);
207− checkForConfirm();
208− });
209};
177};
210
178
211−const isTransactionConfirmed = async (web3, txHash) => {
179+// returns a Promise that resolves when all stxs have been sent & confirmed
212− const receipt = await web3.eth.getTransactionReceipt(txHash);
180+const sendAndAwaitAll = (web3, stxs, doubtNonceError) => {
213− console.log('got confirm state', receipt !== null, receipt.confirmations);
181+ return Promise.all(
214− return receipt !== null;
182+ stxs.map(async tx => {
183+ const txHash = await sendSignedTransaction(web3, tx, doubtNonceError);
184+ await waitForTransactionConfirm(web3, txHash);
185+ })
186+ );
215};
187};
216
188
217const hexify = val => addHexPrefix(val.toString('hex'));
189const hexify = val => addHexPrefix(val.toString('hex'));
@@ -245,10 +217,11 @@ const canDecodePatp = p => {
245};
217};
246
218
247export {
219export {
220+ RETRY_OPTIONS,
248 signTransaction,
221 signTransaction,
249 sendSignedTransaction,
222 sendSignedTransaction,
250 waitForTransactionConfirm,
223 waitForTransactionConfirm,
251− isTransactionConfirmed,
224+ sendAndAwaitAll,
252 TXN_PURPOSE,
225 TXN_PURPOSE,
253 getTxnInfo,
226 getTxnInfo,
254 renderTxnPurpose,
227 renderTxnPurpose,
src/store/network.js+1−1
@@ -20,7 +20,7 @@ function _useNetwork(initialNetworkType = null) {
20
20
21 const setNetworkType = networkType => {
21 const setNetworkType = networkType => {
22 if (!includes(NETWORK_TYPES, networkType)) {
22 if (!includes(NETWORK_TYPES, networkType)) {
23− throw BRIDGE_ERROR.INVALID_NETWORK_TYPE;
23+ throw new Error(BRIDGE_ERROR.INVALID_NETWORK_TYPE);
24 }
24 }
25 _setNetworkType(networkType);
25 _setNetworkType(networkType);
26 };
26 };
src/store/wallet.js+1−1
@@ -44,7 +44,7 @@ function _useWallet(initialWallet = Nothing(), initialMnemonic = Nothing()) {
44 const setWalletType = useCallback(
44 const setWalletType = useCallback(
45 walletType => {
45 walletType => {
46 if (!includes(WALLET_TYPES, walletType)) {
46 if (!includes(WALLET_TYPES, walletType)) {
47− throw BRIDGE_ERROR.INVALID_WALLET_TYPE;
47+ throw new Error(BRIDGE_ERROR.INVALID_WALLET_TYPE);
48 }
48 }
49
49
50 _setWalletType(walletType);
50 _setWalletType(walletType);
src/views/Invite/InviteEmail.js+3−4
@@ -1,6 +1,5 @@
1import React, { useCallback, useEffect, useMemo, useState } from 'react';
1import React, { useCallback, useEffect, useMemo, useState } from 'react';
2import cn from 'classnames';
2import cn from 'classnames';
3−import { Just } from 'folktale/maybe';
4import * as azimuth from 'azimuth-js';
3import * as azimuth from 'azimuth-js';
5import {
4import {
6 Grid,
5 Grid,
@@ -247,12 +246,12 @@ export default function InviteEmail() {
247 owner.keys.address
246 owner.keys.address
248 );
247 );
249 const signedTx = await signTransaction({
248 const signedTx = await signTransaction({
250− wallet,
249+ wallet: _wallet,
251 walletType,
250 walletType,
252 walletHdPath,
251 walletHdPath,
253 networkType,
252 networkType,
254 // TODO: ^ make a useTransactionSigner to encapsulate this logic
253 // TODO: ^ make a useTransactionSigner to encapsulate this logic
255− txn: Just(inviteTx),
254+ txn: inviteTx,
256 gasPrice: GAS_PRICE_GWEI.toString(),
255 gasPrice: GAS_PRICE_GWEI.toString(),
257 gasLimit: GAS_LIMIT.toString(),
256 gasLimit: GAS_LIMIT.toString(),
258 nonce: nonce + i,
257 nonce: nonce + i,
@@ -320,7 +319,7 @@ export default function InviteEmail() {
320 try {
319 try {
321 const txHash = await sendSignedTransaction(
320 const txHash = await sendSignedTransaction(
322 _web3,
321 _web3,
323− Just(invite.signedTx),
322+ invite.signedTx,
324 tankWasUsed,
323 tankWasUsed,
325 () => {}
324 () => {}
326 );
325 );
src/views/SentTransaction.js+1−1
@@ -125,7 +125,7 @@ function SentTransaction(props) {
125
125
126 const result = txnCursor.matchWith({
126 const result = txnCursor.matchWith({
127 Nothing: _ => {
127 Nothing: _ => {
128− throw BRIDGE_ERROR.MISSING_TXN;
128+ throw new Error(BRIDGE_ERROR.MISSING_TXN);
129 },
129 },
130 Just: res => res.value,
130 Just: res => res.value,
131 });
131 });