@@ -7,9 +7,10 @@ import {
77 TRANSACTION_PROGRESS,
88} from 'lib/reticket';
99import * as need from 'lib/need';
10−import { WALLET_TYPES } from 'lib/constants';
10+import { POINT_DOMINIONS, WALLET_TYPES } from 'lib/constants';
1111import { convertToInt } from 'lib/convertToInt';
1212import useBlockWindowClose from 'lib/useBlockWindowClose';
13+import { useReticketL2Spawn } from 'lib/useReticketL2Spawn';
1314
1415import { useNetwork } from 'store/network';
1516import { useWallet } from 'store/wallet';
@@ -25,8 +26,9 @@ import { RestartButton, ForwardButton } from 'components/Buttons';
2526import WarningBox from 'components/WarningBox';
2627import LoadingBar from 'components/LoadingBar';
2728import NeedFundsNotice from 'components/NeedFundsNotice';
29+import { ReticketProgressCallback } from 'lib/types/L2Transaction';
2830
29−const labelForProgress = progress => {
31+const labelForProgress = (progress: number) => {
3032 if (progress <= 0) {
3133 return 'Starting...';
3234 } else if (progress <= TRANSACTION_PROGRESS.GENERATING) {
@@ -44,9 +46,19 @@ const labelForProgress = progress => {
4446 }
4547};
4648
47−export default function ResetExecute({ newWallet, setNewWallet }) {
48− const { popTo, names, reset } = useHistory();
49− const { web3, contracts, networkType } = useNetwork();
49+interface ResetExecuteProps {
50+ // a Maybe<UrbitWallet>
51+ newWallet: any;
52+ // a useState setter, accepts Maybe<UrbitWallet>
53+ setNewWallet: (args: any) => {};
54+}
55+
56+export default function ResetExecute({
57+ newWallet,
58+ setNewWallet,
59+}: ResetExecuteProps) {
60+ const { popTo, names, reset }: any = useHistory();
61+ const { web3, contracts, networkType }: any = useNetwork();
5062 const {
5163 wallet,
5264 setWalletType,
@@ -54,94 +66,34 @@ export default function ResetExecute({ newWallet, setNewWallet }) {
5466 setUrbitWallet,
5567 walletType,
5668 walletHdPath,
57− } = useWallet();
58− const { performL2Reticket } = useRoller();
69+ }: any = useWallet();
70+ const { api, performL2Reticket } = useRoller();
5971 const {
6072 point: { isL2 },
6173 } = useRollerStore();
62− const { pointCursor } = usePointCursor();
63− const { getDetails } = usePointCache();
74+ const { pointCursor }: any = usePointCursor();
75+ const { getDetails }: any = usePointCache();
6476 const {
6577 signTransaction: wcSign,
6678 sendTransaction: wcSend,
6779 connector,
6880 } = useWalletConnect();
81+ const { performL2SpawnReticket } = useReticketL2Spawn();
6982
70− const [generalError, setGeneralError] = useState();
83+ const [generalError, setGeneralError] = useState<Error | undefined>();
7184 const [progress, setProgress] = useState(0);
72− const [needFunds, setNeedFunds] = useState();
85+ const [needFunds, setNeedFunds] = useState<string | boolean | undefined>();
7386 const isDone = progress >= 1.0;
87+ const point = need.point(pointCursor);
7488
7589 useBlockWindowClose();
7690
77− // start reticketing transactions on mount
78− useEffect(() => {
79− (async () => {
80− // due to react shenanigans we may need to wait for the connector
81− if (
82− walletType === WALLET_TYPES.WALLET_CONNECT &&
83− (!connector || !connector.connected)
84− ) {
85− setGeneralError(new Error('Awaiting WalletConnect connection...'));
86− return;
87− }
88− setGeneralError();
89−
90− const point = need.point(pointCursor);
91− const details = need.details(getDetails(point));
92− const networkRevision = convertToInt(details.keyRevisionNumber, 10);
93−
94− // see also comment in useEthereumTransaction
95− const txnSigner =
96− walletType === WALLET_TYPES.WALLET_CONNECT ? wcSign : undefined;
97− const txnSender =
98− walletType === WALLET_TYPES.WALLET_CONNECT ? wcSend : undefined;
99−
100− try {
101− if (isL2) {
102− console.log(newWallet.value);
103− // FIXME: the useEffect is called twice, which is fine since the duplicate
104− // L2 txs will be discarded
105− //
106− await performL2Reticket({
107− point,
108− to: newWallet.value.wallet.ownership.keys.address,
109− manager: newWallet.value.wallet.management.keys.address,
110− toWallet: newWallet.value.wallet,
111− fromWallet: need.wallet(wallet),
112− });
113− } else
114− await reticketPointBetweenWallets({
115− fromWallet: need.wallet(wallet),
116− fromWalletType: walletType,
117− fromWalletHdPath: walletHdPath,
118− toWallet: newWallet.value.wallet,
119− point: point,
120− web3: need.web3(web3),
121− contracts: need.contracts(contracts),
122− networkType,
123− onUpdate: handleUpdate,
124− nextRevision: networkRevision + 1,
125− txnSigner,
126− txnSender,
127− });
128− } catch (err) {
129− console.error(err);
130− setGeneralError(err);
131− }
132− })();
133− //NOTE this was using useLifecycle previously (which is useEffect without
134− // dependencies) and worked fine, but in the wc case we might need to
135− // wait for the connector to get set due to react state shenanigans.
136− // eslint-disable-next-line react-hooks/exhaustive-deps
137− }, [connector]);
138−
13991 const goToRestart = useCallback(() => {
14092 reset();
14193 setNewWallet(Nothing());
14294 }, [reset, setNewWallet]);
14395
144− const loginAndGoHome = useCallback(() => {
96+ const loginAndGoHome = useCallback(async () => {
14597 // set wallet state
14698 resetWallet();
14799 setWalletType(WALLET_TYPES.TICKET);
@@ -149,9 +101,16 @@ export default function ResetExecute({ newWallet, setNewWallet }) {
149101 // (implicit) pointCursor stays the same
150102 // redirect to point
151103 popTo(names.POINT);
152− }, [resetWallet, setWalletType, setUrbitWallet, newWallet, popTo, names]);
104+ }, [
105+ resetWallet,
106+ setWalletType,
107+ setUrbitWallet,
108+ newWallet.value.wallet,
109+ popTo,
110+ names.POINT,
111+ ]);
153112
154− const handleUpdate = useCallback(
113+ const handleUpdate: ReticketProgressCallback = useCallback(
155114 ({ type, state, value }) => {
156115 switch (type) {
157116 case 'progress':
@@ -167,6 +126,108 @@ export default function ResetExecute({ newWallet, setNewWallet }) {
167126 [setProgress, setNeedFunds]
168127 );
169128
129+ const performReticket = useCallback(async () => {
130+ // due to react shenanigans we may need to wait for the connector
131+ if (
132+ walletType === WALLET_TYPES.WALLET_CONNECT &&
133+ (!connector || !connector.connected)
134+ ) {
135+ setGeneralError(new Error('Awaiting WalletConnect connection...'));
136+ return;
137+ }
138+
139+ setGeneralError(undefined);
140+
141+ const l2point = await api.getPoint(point);
142+ const details = need.details(getDetails(point));
143+ const networkRevision = convertToInt(details.keyRevisionNumber, 10);
144+
145+ // see also comment in useEthereumTransaction
146+ const txnSigner =
147+ walletType === WALLET_TYPES.WALLET_CONNECT ? wcSign : undefined;
148+ const txnSender =
149+ walletType === WALLET_TYPES.WALLET_CONNECT ? wcSend : undefined;
150+
151+ try {
152+ // if L1 point with migrated spawn proxy (dominion = 'spawn')
153+ if (l2point.dominion === POINT_DOMINIONS.SPAWN) {
154+ await performL2SpawnReticket({
155+ fromWallet: need.wallet(wallet),
156+ fromWalletType: walletType,
157+ fromWalletHdPath: walletHdPath,
158+ toWallet: newWallet.value.wallet,
159+ to: newWallet.value.wallet.ownership.keys.address,
160+ point: point,
161+ web3: need.web3(web3),
162+ contracts: need.contracts(contracts),
163+ networkType,
164+ onUpdate: handleUpdate,
165+ nextRevision: networkRevision + 1,
166+ txnSigner,
167+ txnSender,
168+ });
169+ // If L2 point
170+ } else if (isL2) {
171+ await performL2Reticket({
172+ point,
173+ to: newWallet.value.wallet.ownership.keys.address,
174+ manager: newWallet.value.wallet.management.keys.address,
175+ toWallet: newWallet.value.wallet,
176+ fromWallet: need.wallet(wallet),
177+ onUpdate: handleUpdate,
178+ });
179+ // Fallback to L1 point flow
180+ } else {
181+ await reticketPointBetweenWallets({
182+ fromWallet: need.wallet(wallet),
183+ fromWalletType: walletType,
184+ fromWalletHdPath: walletHdPath,
185+ toWallet: newWallet.value.wallet,
186+ point: point,
187+ web3: need.web3(web3),
188+ contracts: need.contracts(contracts),
189+ networkType,
190+ onUpdate: handleUpdate,
191+ nextRevision: networkRevision + 1,
192+ txnSigner,
193+ txnSender,
194+ });
195+ }
196+ } catch (err) {
197+ console.error(err);
198+ setGeneralError(err);
199+ }
200+ }, [
201+ api,
202+ connector,
203+ contracts,
204+ getDetails,
205+ handleUpdate,
206+ isL2,
207+ networkType,
208+ newWallet.value.wallet,
209+ performL2Reticket,
210+ performL2SpawnReticket,
211+ point,
212+ wallet,
213+ walletHdPath,
214+ walletType,
215+ wcSend,
216+ wcSign,
217+ web3,
218+ ]);
219+
220+ useEffect(() => {
221+ if (!connector) {
222+ return;
223+ }
224+
225+ performReticket();
226+ // We want to perform the reticket only once, after the WalletConnect
227+ // connector has finished instantiating and setting up a websocket
228+ // eslint-disable-next-line react-hooks/exhaustive-deps
229+ }, [connector]);
230+
170231 const renderAdditionalInfo = () => {
171232 if (generalError) {
172233 console.log(generalError);
@@ -174,7 +235,9 @@ export default function ResetExecute({ newWallet, setNewWallet }) {
174235 return (
175236 <>
176237 <Grid.Item full className="mt4">
177− <ErrorText>{generalError.message.toString()}</ErrorText>
238+ <ErrorText className={''}>
239+ {generalError.message.toString()}
240+ </ErrorText>
178241 </Grid.Item>
179242 <Grid.Item
180243 full