@@ -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,10 @@ import { RestartButton, ForwardButton } from 'components/Buttons';
2526import WarningBox from 'components/WarningBox';
2627import LoadingBar from 'components/LoadingBar';
2728import NeedFundsNotice from 'components/NeedFundsNotice';
29+import { debugLog } from 'lib/utils/debug';
30+import { ReticketProgressCallback } from 'lib/types/L2Transaction';
2831
29−const labelForProgress = progress => {
32+const labelForProgress = (progress: number) => {
3033 if (progress <= 0) {
3134 return 'Starting...';
3235 } else if (progress <= TRANSACTION_PROGRESS.GENERATING) {
@@ -44,9 +47,19 @@ const labelForProgress = progress => {
4447 }
4548};
4649
47−export default function ResetExecute({ newWallet, setNewWallet }) {
48− const { popTo, names, reset } = useHistory();
49− const { web3, contracts, networkType } = useNetwork();
50+interface ResetExecuteProps {
51+ // a Maybe<UrbitWallet>
52+ newWallet: any;
53+ // a useState setter, accepts Maybe<UrbitWallet>
54+ setNewWallet: (args: any) => {};
55+}
56+
57+export default function ResetExecute({
58+ newWallet,
59+ setNewWallet,
60+}: ResetExecuteProps) {
61+ const { popTo, names, reset }: any = useHistory();
62+ const { web3, contracts, networkType }: any = useNetwork();
5063 const {
5164 wallet,
5265 setWalletType,
@@ -54,23 +67,25 @@ export default function ResetExecute({ newWallet, setNewWallet }) {
5467 setUrbitWallet,
5568 walletType,
5669 walletHdPath,
57− } = useWallet();
58− const { performL2Reticket } = useRoller();
70+ }: any = useWallet();
71+ const { api, performL2Reticket } = useRoller();
5972 const {
60− point: { isL2Spawn },
73+ point: { isL2 },
6174 } = useRollerStore();
62− const { pointCursor } = usePointCursor();
63− const { getDetails } = usePointCache();
75+ const { pointCursor }: any = usePointCursor();
76+ const { getDetails }: any = usePointCache();
6477 const {
6578 signTransaction: wcSign,
6679 sendTransaction: wcSend,
6780 connector,
6881 } = useWalletConnect();
82+ const { performL2SpawnReticket } = useReticketL2Spawn();
6983
70− const [generalError, setGeneralError] = useState();
84+ const [generalError, setGeneralError] = useState<Error | undefined>();
7185 const [progress, setProgress] = useState(0);
72− const [needFunds, setNeedFunds] = useState();
86+ const [needFunds, setNeedFunds] = useState<string | boolean | undefined>();
7387 const isDone = progress >= 1.0;
88+ const point = need.point(pointCursor);
7489
7590 useBlockWindowClose();
7691
@@ -79,17 +94,26 @@ export default function ResetExecute({ newWallet, setNewWallet }) {
7994 setNewWallet(Nothing());
8095 }, [reset, setNewWallet]);
8196
82− const loginAndGoHome = useCallback(() => {
97+ const loginAndGoHome = useCallback(async () => {
8398 // set wallet state
8499 resetWallet();
85100 setWalletType(WALLET_TYPES.TICKET);
86101 setUrbitWallet(Just(newWallet.value.wallet));
87102 // (implicit) pointCursor stays the same
103+ // TODO: do we need to update the point?
104+ // await getAndUpdatePoint(point);
88105 // redirect to point
89106 popTo(names.POINT);
90− }, [resetWallet, setWalletType, setUrbitWallet, newWallet, popTo, names]);
107+ }, [
108+ resetWallet,
109+ setWalletType,
110+ setUrbitWallet,
111+ newWallet.value.wallet,
112+ popTo,
113+ names.POINT,
114+ ]);
91115
92− const handleUpdate = useCallback(
116+ const handleUpdate: ReticketProgressCallback = useCallback(
93117 ({ type, state, value }) => {
94118 switch (type) {
95119 case 'progress':
@@ -106,69 +130,92 @@ export default function ResetExecute({ newWallet, setNewWallet }) {
106130 );
107131
108132 const performReticket = useCallback(async () => {
109− (async () => {
110− // due to react shenanigans we may need to wait for the connector
111− if (
112− walletType === WALLET_TYPES.WALLET_CONNECT &&
113− (!connector || !connector.connected)
114− ) {
115− setGeneralError(new Error('Awaiting WalletConnect connection...'));
116− return;
117− }
118− setGeneralError();
133+ // due to react shenanigans we may need to wait for the connector
134+ if (
135+ walletType === WALLET_TYPES.WALLET_CONNECT &&
136+ (!connector || !connector.connected)
137+ ) {
138+ setGeneralError(new Error('Awaiting WalletConnect connection...'));
139+ return;
140+ }
119141
120− const point = need.point(pointCursor);
121− const details = need.details(getDetails(point));
122− const networkRevision = convertToInt(details.keyRevisionNumber, 10);
142+ setGeneralError(undefined);
123143
124− // see also comment in useEthereumTransaction
125− const txnSigner =
126− walletType === WALLET_TYPES.WALLET_CONNECT ? wcSign : undefined;
127− const txnSender =
128− walletType === WALLET_TYPES.WALLET_CONNECT ? wcSend : undefined;
144+ const l2point = await api.getPoint(point);
145+ const details = need.details(getDetails(point));
146+ const networkRevision = convertToInt(details.keyRevisionNumber, 10);
129147
130− try {
131− if (isL2Spawn) {
132− // FIXME: the useEffect is called twice, which is fine since the duplicate
133− // L2 txs will be discarded
134− await performL2Reticket({
135− point,
136− to: newWallet.value.wallet.ownership.keys.address,
137− manager: newWallet.value.wallet.management.keys.address,
138− toWallet: newWallet.value.wallet,
139− fromWallet: need.wallet(wallet),
140− onUpdate: handleUpdate,
141− });
142− } else
143− await reticketPointBetweenWallets({
144− fromWallet: need.wallet(wallet),
145− fromWalletType: walletType,
146− fromWalletHdPath: walletHdPath,
147− toWallet: newWallet.value.wallet,
148− point: point,
149− web3: need.web3(web3),
150− contracts: need.contracts(contracts),
151− networkType,
152− onUpdate: handleUpdate,
153− nextRevision: networkRevision + 1,
154− txnSigner,
155− txnSender,
156− });
157− } catch (err) {
158− console.error(err);
159− setGeneralError(err);
160− }
161− })();
148+ // see also comment in useEthereumTransaction
149+ const txnSigner =
150+ walletType === WALLET_TYPES.WALLET_CONNECT ? wcSign : undefined;
151+ const txnSender =
152+ walletType === WALLET_TYPES.WALLET_CONNECT ? wcSend : undefined;
153+
154+ try {
155+ // if L1 point with migrated spawn proxy (dominion = 'spawn')
156+ if (l2point.dominion === POINT_DOMINIONS.SPAWN) {
157+ debugLog('reticketing L1 point with dominion spawn...');
158+ await performL2SpawnReticket({
159+ fromWallet: need.wallet(wallet),
160+ fromWalletType: walletType,
161+ fromWalletHdPath: walletHdPath,
162+ toWallet: newWallet.value.wallet,
163+ to: newWallet.value.wallet.ownership.keys.address,
164+ point: point,
165+ web3: need.web3(web3),
166+ contracts: need.contracts(contracts),
167+ networkType,
168+ onUpdate: handleUpdate,
169+ nextRevision: networkRevision + 1,
170+ txnSigner,
171+ txnSender,
172+ });
173+ debugLog('done');
174+ // If L2 point
175+ } else if (isL2) {
176+ debugLog('reticketing L2 point ...');
177+ await performL2Reticket({
178+ point,
179+ to: newWallet.value.wallet.ownership.keys.address,
180+ manager: newWallet.value.wallet.management.keys.address,
181+ toWallet: newWallet.value.wallet,
182+ fromWallet: need.wallet(wallet),
183+ onUpdate: handleUpdate,
184+ });
185+ debugLog('done');
186+ // Fallback to L1 point flow
187+ } else debugLog('reticketing L1 point ...');
188+ await reticketPointBetweenWallets({
189+ fromWallet: need.wallet(wallet),
190+ fromWalletType: walletType,
191+ fromWalletHdPath: walletHdPath,
192+ toWallet: newWallet.value.wallet,
193+ point: point,
194+ web3: need.web3(web3),
195+ contracts: need.contracts(contracts),
196+ networkType,
197+ onUpdate: handleUpdate,
198+ nextRevision: networkRevision + 1,
199+ txnSigner,
200+ txnSender,
201+ });
202+ debugLog('done');
203+ } catch (err) {
204+ console.error(err);
205+ setGeneralError(err);
206+ }
162207 }, [
208+ api,
163209 connector,
164210 contracts,
165211 getDetails,
166212 handleUpdate,
167− isL2Spawn,
213+ isL2,
168214 networkType,
169215 newWallet.value.wallet,
170216 performL2Reticket,
171− pointCursor,
217+ performL2SpawnReticket,
218+ point,
172219 wallet,
173220 walletHdPath,
174221 walletType,
@@ -177,12 +224,14 @@ export default function ResetExecute({ newWallet, setNewWallet }) {
177224 web3,
178225 ]);
179226
180− // start reticketing transactions on mount
181227 useEffect(() => {
228+ if (!connector) {
229+ return;
230+ }
231+
182232 performReticket();
183− //NOTE this was using useLifecycle previously (which is useEffect without
184− // dependencies) and worked fine, but in the wc case we might need to
185− // wait for the connector to get set due to react state shenanigans.
233+ // We want to perform the reticket only once, after the WalletConnect
234+ // connector has finished instantiating and setting up a websocket
186235 // eslint-disable-next-line react-hooks/exhaustive-deps
187236 }, [connector]);
188237
@@ -193,7 +242,9 @@ export default function ResetExecute({ newWallet, setNewWallet }) {
193242 return (
194243 <>
195244 <Grid.Item full className="mt4">
196− <ErrorText>{generalError.message.toString()}</ErrorText>
245+ <ErrorText className={''}>
246+ {generalError.message.toString()}
247+ </ErrorText>
197248 </Grid.Item>
198249 <Grid.Item
199250 full