on master help sign in
wip nonce store
commit5a2bc241a3e8ab12ac2c109d8fd9b854fbac43ef authoryosoyubik <yosoyubik@gmail.com> dateSun 26 Sep 2021, 06:31 (5 years ago) parentf3545aa
11 files changed+459−127
package.json+1−1 src/components/L2/Dropdowns/AccountsDropdown.tsx+6−6 src/lib/useRoller.ts+117−62 src/lib/utils/nonce.ts+157 src/lib/utils/roller.ts+31−6 src/store/lib/useDetailsStore.js+29−2 src/store/roller.ts+31−1 src/views/Activate/MasterKeyTransfer.tsx+2−6 src/views/Login/Ticket.js+21−14 src/views/Point/Point.js+60−27 src/views/Points.js+4−2
package.json+1−1
@@ -119,7 +119,7 @@
119119 "pilot-release": "WITH_TEST_STATE=STAR_RELEASE npm run pilot",
120120 "pilot-residents": "WITH_TEST_STATE=RESIDENTS npm run pilot",
121121 "pilot-l2": "BROWSER=NONE WITH_TEST_STATE=L2 HTTPS=false NODE_ENV=development npm-run-all pilot:setup start pilot:cleanup --continue-on-error",
122− "pilot-l2-local": "REACT_APP_STUB_LOCAL=true BROWSER=NONE REACT_APP_L2=true HTTPS=false NODE_ENV=development npm run start --continue-on-error",
122+ "pilot-l2-local": "BROWSER=NONE REACT_APP_L2=true HTTPS=false NODE_ENV=development npm run start --continue-on-error",
123123 "pilot-ropsten": "REACT_APP_ROPSTEN=true HTTPS=true npm-run-all start --continue-on-error",
124124 "pilot:cleanup": "pkill -f ganache-cli",
125125 "lint:check": "eslint 'src/**/*.{js,jsx,ts,tsx}'",
src/components/L2/Dropdowns/AccountsDropdown.tsx+6−6
@@ -42,12 +42,12 @@ const AccountsDropdown = ({ showMigrate = false }: AccountsDropdownProps) => {
4242
4343 let networkKeysNotSet = true;
4444
45− if (point) {
46− const details = need.details(getDetails(point));
47− const isStarOrGalaxy = !isPlanet(point);
48− const networkRevision = convertToInt(details.keyRevisionNumber, 10);
49− networkKeysNotSet = !currentL2 && isStarOrGalaxy && networkRevision === 0;
50− }
45+ // if (point) {
46+ // const details = need.details(getDetails(point));
47+ // const isStarOrGalaxy = !isPlanet(point);
48+ // const networkRevision = convertToInt(details.keyRevisionNumber, 10);
49+ // networkKeysNotSet = !currentL2 && isStarOrGalaxy && networkRevision === 0;
50+ // }
5151
5252 const [showModal, setShowModal] = useState(false);
5353
src/lib/useRoller.ts+117−62
@@ -1,4 +1,5 @@
11import { useCallback, useEffect, useMemo, useState } from 'react';
2+import _ from 'lodash';
23import * as azimuth from 'azimuth-js';
34import * as need from 'lib/need';
45import * as ob from 'urbit-ob';
@@ -7,17 +8,24 @@ import { Just } from 'folktale/maybe';
78import { Invite } from 'lib/types/Invite';
89import { convertToInt } from './convertToInt';
910import { ensureHexPrefix } from 'form/formatters';
10−import { getOutgoingPoints } from 'views/Points';
1111import { isDevelopment, isRopsten } from './flags';
12−import { isPlanet } from './utils/point';
1312import { hasPoint, generateInviteWallet } from './utils/roller';
1413import { ROLLER_HOSTS } from './constants';
1514import { signTransactionHash } from './authToken';
15+
1616import { useNetwork } from 'store/network';
17−import { usePointCache } from 'store/pointCache';
1817import { usePointCursor } from 'store/pointCursor';
1918import { useRollerStore } from 'store/roller';
2019import { useWallet } from 'store/wallet';
20+import {
21+ getStoredInvites,
22+ setPendingInvites,
23+ setStoredInvites,
24+} from 'store/storage/roller';
25+import { usePointCache } from 'store/pointCache';
26+import { getOutgoingPoints } from 'views/Points';
27+import { getSpawnNonce, getOwnerNonce } from './utils/nonce';
28+import { isPlanet } from './utils/point';
2129
2230import {
2331 deriveNetworkKeys,
@@ -28,7 +36,6 @@ import {
2836import {
2937 Config,
3038 Ship,
31− L2Point,
3239 Proxy,
3340 RollerRPCAPI,
3441 Options,
@@ -36,6 +43,8 @@ import {
3643 UnspawnedPoints,
3744 From,
3845 Hash,
46+ SpawnParams,
47+ L2Data,
3948} from '@urbit/roller-api';
4049
4150import {
@@ -43,33 +52,16 @@ import {
4352 getTimeToNextBatch,
4453 spawn,
4554 transferPoint,
55+ setSpawnProxy,
4656} from './utils/roller';
4757
48−import {
49− getStoredInvites,
50− setPendingInvites,
51− setStoredInvites,
52−} from 'store/storage/roller';
58+function isSpawn(tx: L2Data | undefined): tx is SpawnParams {
59+ return (tx as SpawnParams) !== undefined;
60+}
5361
54−const getProxyAndNonce = (
55− point: L2Point,
56− address: string
57−): { proxy?: string; nonce?: number } => {
58− return point.ownership?.managementProxy?.address === address
59− ? { proxy: 'manage', nonce: point.ownership?.managementProxy.nonce }
60− : point.ownership?.owner?.address === address
61− ? { proxy: 'own', nonce: point.ownership?.owner.nonce }
62− : point.ownership?.spawnProxy?.address === address
63− ? { proxy: 'spawn', nonce: point.ownership?.spawn?.owner.nonce }
64− : point.ownership?.votingProxy?.address === address
65− ? { proxy: 'vote', nonce: point.ownership?.votingProxy?.owner.nonce }
66− : point.ownership?.transferProxy?.address === address
67− ? {
68− proxy: 'transfer',
69− nonce: point.transferProxy?.votingProxy?.owner.nonce,
70− }
71− : { proxy: undefined, nonce: undefined };
72−};
62+function isShipNumber(ship: number | string | undefined): ship is number {
63+ return (ship as number) !== undefined;
64+}
7365
7466export default function useRoller() {
7567 const { wallet, authToken, authMnemonic, urbitWallet }: any = useWallet();
@@ -86,6 +78,8 @@ export default function useRoller() {
8678 setPendingTransactions,
8779 setInvites,
8880 currentL2,
81+ nonces,
82+ increaseNonce,
8983 } = useRollerStore();
9084 const [config, setConfig] = useState<Config | null>(null);
9185
@@ -137,6 +131,7 @@ export default function useRoller() {
137131 const _wallet = wallet.getOrElse(null);
138132 const _authToken = authToken.getOrElse(null);
139133 const _details = getDetails(_point);
134+
140135 if (!_contracts || !_web3 || !_wallet || !_authToken || !_details) {
141136 // not using need because we want a custom error
142137 throw new Error('Internal Error: Missing Contracts/Web3/Wallet');
@@ -147,9 +142,27 @@ export default function useRoller() {
147142 "Auth key Error: A management mnemonic can't create invite codes"
148143 );
149144 }
150− const planets: UnspawnedPoints = await api.getUnspawned(_point);
151− const starInfo = await api.getPoint(_point);
145+ let planets: UnspawnedPoints = await api.getUnspawned(_point);
146+
147+ const pendingTxs = await api.getPendingByShip(_point);
148+
149+ const pendingSpawns = _.reduce(
150+ pendingTxs,
151+ (acc, pending) => {
152+ return isSpawn(pending.rawTx?.tx) &&
153+ isShipNumber(pending.rawTx?.tx.data.ship)
154+ ? acc.add(pending.rawTx?.tx.data.ship!)
155+ : acc;
156+ },
157+ new Set<number>()
158+ );
152159
160+ console.log(pendingTxs, pendingSpawns);
161+
162+ planets = planets.filter((point: number) => !pendingSpawns.has(point));
163+
164+ const starInfo = nonces[_point];
165+ console.log(starInfo);
153166 const tickets: {
154167 ticket: string;
155168 planet: number;
@@ -157,37 +170,37 @@ export default function useRoller() {
157170 }[] = [];
158171 const requests: Promise<string>[] = [];
159172
160− // TODO: replace with "currentNonce" from store, that would reflect the latest nonce
161− // Bridge has used for the star _wallet.address
162− //
163− const { proxy, nonce } = getProxyAndNonce(starInfo, _wallet.address);
173+ const operator =
174+ getSpawnNonce(starInfo, _wallet.address) ||
175+ getOwnerNonce(starInfo, _wallet.address);
164176
165− if (!(proxy === 'own' || proxy === 'spawn') || nonce === undefined)
177+ if (operator === undefined)
166178 throw new Error("Error: Address doesn't match proxy");
167−
179+ console.log('operator', operator);
168180 for (let i = 0; i < numInvites && planets[i]; i++) {
169181 const planet = planets[i];
170− const nonceInc = i + nonce;
182+ const nonceInc = i + operator.nonce!;
171183
172− const { ticket, owner } = await generateInviteWallet(
184+ const { ticket, inviteWallet } = await generateInviteWallet(
173185 planet,
174186 _authToken
175187 );
176−
188+ console.log(inviteWallet);
177189 const spawnRequest = await spawn(
178190 api,
179191 _wallet,
180192 _point,
181− proxy,
193+ operator.proxy!,
182194 nonceInc,
183195 planet
184196 );
197+ increaseNonce(_point, operator.proxy!);
185198
186199 const configureKeysRequest = await configureKeys(
187200 api,
188201 _wallet,
189202 planet,
190− proxy,
203+ operator.proxy!,
191204 0,
192205 _details,
193206 authToken,
@@ -196,20 +209,34 @@ export default function useRoller() {
196209 urbitWallet
197210 );
198211
199− const transferPointRequest = await transferPoint(
212+ const setManagementProxyRequest = await setSpawnProxy(
200213 api,
201214 _wallet,
202215 planet,
203− proxy,
216+ operator.proxy!,
204217 1,
205− owner.keys.address
218+ inviteWallet.management.keys.address
206219 );
207220
208− requests.push(spawnRequest, configureKeysRequest, transferPointRequest);
221+ const transferPointRequest = await transferPoint(
222+ api,
223+ _wallet,
224+ planet,
225+ operator.proxy!,
226+ 2,
227+ inviteWallet.ownership.keys.address
228+ );
229+
230+ requests.push(
231+ spawnRequest,
232+ configureKeysRequest,
233+ setManagementProxyRequest,
234+ transferPointRequest
235+ );
209236 tickets.push({
210237 ticket,
211238 planet,
212− owner: owner.keys.address,
239+ owner: inviteWallet.ownership.keys.address,
213240 });
214241 }
215242
@@ -221,6 +248,7 @@ export default function useRoller() {
221248 status: 'pending',
222249 }));
223250
251+ console.log('latest update', nonces[_point]);
224252 setPendingInvites(_point, pendingInvites);
225253 },
226254 [
@@ -233,6 +261,8 @@ export default function useRoller() {
233261 getDetails,
234262 authMnemonic,
235263 urbitWallet,
264+ nonces,
265+ increaseNonce,
236266 ]
237267 );
238268
@@ -343,7 +373,7 @@ export default function useRoller() {
343373 const planet = possibleMissingInvites[i];
344374 if (!availableInvites.find(hasPoint(planet))) {
345375 console.log('MISSING IN AVAILABLE', planet);
346− const { ticket, owner } = await generateInviteWallet(
376+ const { ticket, inviteWallet } = await generateInviteWallet(
347377 planet,
348378 _authToken
349379 );
@@ -353,7 +383,7 @@ export default function useRoller() {
353383 status: 'available',
354384 planet,
355385 hash: '',
356− owner: owner.keys.address,
386+ owner: inviteWallet.ownership.keys.address,
357387 });
358388 }
359389 }
@@ -371,14 +401,14 @@ export default function useRoller() {
371401 }
372402 },
373403 [
374− api,
375− pointCursor,
376− setInvites,
377− setPendingTransactions,
378− authToken,
379− contracts,
380− controlledPoints,
381− getDetails,
404+ // api,
405+ // pointCursor,
406+ // setInvites,
407+ // setPendingTransactions,
408+ // authToken,
409+ // contracts,
410+ // controlledPoints,
411+ // getDetails,
382412 ]
383413 );
384414
@@ -394,6 +424,7 @@ export default function useRoller() {
394424 interface AcceptInviteParams {
395425 point: Ship;
396426 to: EthAddress;
427+ manager: EthAddress;
397428 fromWallet: any; // TODO: wallet type
398429 toWallet: any; // TODO: wallet type
399430 }
@@ -401,6 +432,7 @@ export default function useRoller() {
401432 const acceptInvite = async ({
402433 point,
403434 to,
435+ manager,
404436 fromWallet,
405437 toWallet,
406438 }: AcceptInviteParams) => {
@@ -408,10 +440,14 @@ export default function useRoller() {
408440 console.log('azimuthPoint', azimuthPoint);
409441 const ownerAddress = azimuthPoint?.ownership?.owner?.address!;
410442
411− const { nonce } = getProxyAndNonce(azimuthPoint, ownerAddress);
412− if (nonce === undefined) {
413− throw new Error('Nonce unavailable');
414− }
443+ const operator =
444+ azimuthPoint.ownership &&
445+ getOwnerNonce(azimuthPoint.ownership, ownerAddress);
446+
447+ if (operator === undefined)
448+ throw new Error("Error: Address doesn't match proxy");
449+
450+ const nonce = operator.nonce!;
415451
416452 // 1. Update networking keys
417453 // TODO: extract this to a useRoller#configureKeys function?
@@ -445,11 +481,30 @@ export default function useRoller() {
445481 ownerAddress,
446482 keysData
447483 );
484+ // TODO: not needed? next time we operate with this point we will login, and get
485+ // the latest nonce (updated with any nonce increase from possible pending txs)
486+ // increaseNonce(point, operator.proxy!);
448487
449− // 2. Transfer point
488+ // 2. Set Management Proxy
489+ const managementData = { address: manager };
490+ const managementHash: Hash = await api.hashTransaction(
491+ nonce + 1,
492+ fromOwnerProxy,
493+ 'setManagementProxy',
494+ managementData
495+ );
496+
497+ await api.setManagementProxy(
498+ signTransactionHash(managementHash, Buffer.from(keysSigningKey, 'hex')),
499+ fromOwnerProxy,
500+ ownerAddress,
501+ managementData
502+ );
503+
504+ // 3. Transfer point
450505 const transferData = { address: to, reset: false };
451506 const transferHash: Hash = await api.hashTransaction(
452− nonce + 1,
507+ nonce + 2,
453508 fromOwnerProxy,
454509 'transferPoint',
455510 transferData
src/lib/utils/nonce.tsnew file+157
@@ -0,0 +1,157 @@
1+import { Ownership } from '@urbit/roller-api';
2+
3+export const getProxyAndNonce = (
4+ owner: Ownership,
5+ address: string
6+): { proxy?: string; nonce?: number } =>
7+ owner.managementProxy?.address === address
8+ ? { proxy: 'manage', nonce: owner.managementProxy.nonce }
9+ : owner.owner?.address === address
10+ ? { proxy: 'own', nonce: owner.owner.nonce }
11+ : owner.spawnProxy?.address === address
12+ ? { proxy: 'spawn', nonce: owner.spawn?.owner.nonce }
13+ : owner.votingProxy?.address === address
14+ ? { proxy: 'vote', nonce: owner.votingProxy?.owner.nonce }
15+ : owner.transferProxy?.address === address
16+ ? {
17+ proxy: 'transfer',
18+ nonce: owner.votingProxy?.nonce,
19+ }
20+ : { proxy: undefined, nonce: undefined };
21+
22+export const getManagementNonce = (
23+ owner: Ownership,
24+ address: string
25+): { nonce?: number; proxy?: string } | undefined =>
26+ owner.managementProxy?.address === address
27+ ? { nonce: owner.managementProxy.nonce, proxy: 'manage' }
28+ : undefined;
29+
30+export const getTransferNonce = (
31+ owner: Ownership,
32+ address: string
33+): { nonce?: number; proxy?: string } | undefined =>
34+ owner.transferProxy?.address === address
35+ ? { nonce: owner.transferProxy.nonce, proxy: 'transfer' }
36+ : undefined;
37+
38+export const getOwnerNonce = (
39+ owner: Ownership,
40+ address: string
41+): { nonce?: number; proxy?: string } | undefined =>
42+ owner.owner?.address === address
43+ ? { nonce: owner.owner.nonce, proxy: 'own' }
44+ : undefined;
45+
46+export const getSpawnNonce = (
47+ owner: Ownership,
48+ address: string
49+): { nonce?: number; proxy?: string } | undefined =>
50+ owner.spawnProxy?.address === address
51+ ? { nonce: owner.spawnProxy.nonce, proxy: 'spawn' }
52+ : undefined;
53+
54+export const getVotingNonce = (
55+ owner: Ownership,
56+ address: string
57+): { nonce?: number; proxy?: string } | undefined =>
58+ owner.votingProxy?.address === address
59+ ? { nonce: owner.votingProxy.nonce, proxy: 'vote' }
60+ : undefined;
61+
62+export const increaseProxyNonce = (
63+ owner: Ownership,
64+ proxy: string
65+): Ownership | undefined =>
66+ 'manage' === proxy
67+ ? {
68+ ...owner,
69+ managementProxy: {
70+ ...owner.managementProxy,
71+ nonce: owner.managementProxy?.nonce
72+ ? owner.managementProxy?.nonce + 1
73+ : 1,
74+ },
75+ }
76+ : 'own' === proxy
77+ ? {
78+ ...owner,
79+ owner: {
80+ ...owner.owner,
81+ nonce: owner.owner?.nonce ? owner.owner?.nonce + 1 : 1,
82+ },
83+ }
84+ : 'spawn' === proxy
85+ ? {
86+ ...owner,
87+ spawnProxy: {
88+ ...owner.spawnProxy,
89+ nonce: owner.spawnProxy?.nonce ? owner.spawnProxy?.nonce + 1 : 1,
90+ },
91+ }
92+ : 'vote' === proxy
93+ ? {
94+ ...owner,
95+ votingProxy: {
96+ ...owner.votingProxy,
97+ nonce: owner.votingProxy?.nonce ? owner.votingProxy?.nonce + 1 : 1,
98+ },
99+ }
100+ : 'transfer' === proxy
101+ ? {
102+ ...owner,
103+ transferProxy: {
104+ ...owner.transferProxy,
105+ nonce: owner.transferProxy?.nonce
106+ ? owner.transferProxy?.nonce + 1
107+ : 1,
108+ },
109+ }
110+ : undefined;
111+
112+export const setProxyNonce = (
113+ owner: Ownership,
114+ proxy: string,
115+ nonce: number
116+): Ownership | undefined =>
117+ 'manage' === proxy
118+ ? {
119+ ...owner,
120+ managementProxy: {
121+ ...owner.managementProxy,
122+ nonce,
123+ },
124+ }
125+ : 'own' === proxy
126+ ? {
127+ ...owner,
128+ owner: {
129+ ...owner.owner,
130+ nonce,
131+ },
132+ }
133+ : 'spawn' === proxy
134+ ? {
135+ ...owner,
136+ spawnProxy: {
137+ ...owner.spawnProxy,
138+ nonce,
139+ },
140+ }
141+ : 'vote' === proxy
142+ ? {
143+ ...owner,
144+ votingProxy: {
145+ ...owner.voteProxy,
146+ nonce,
147+ },
148+ }
149+ : 'transfer' === proxy
150+ ? {
151+ ...owner,
152+ transferProxy: {
153+ ...owner.transferProxy,
154+ nonce,
155+ },
156+ }
157+ : undefined;
src/lib/utils/roller.ts+31−6
@@ -8,10 +8,7 @@ import {
88 CRYPTO_SUITE_VERSION,
99} from 'lib/keys';
1010import { addHexPrefix } from 'lib/utils/address';
11−import {
12− makeDeterministicTicket,
13− generateOwnershipWallet,
14−} from 'lib/walletgen';
11+import { makeDeterministicTicket, generateWallet } from 'lib/walletgen';
1512
1613export const SECOND = 1000;
1714export const MINUTE = SECOND * 60;
@@ -35,9 +32,9 @@ export const isL2 = (dom?: string) => dom === 'l2' || dom === 'spawn';
3532
3633export const generateInviteWallet = async (point: number, seed: string) => {
3734 const ticket = makeDeterministicTicket(point, seed);
38− const owner = await generateOwnershipWallet(point, ticket);
35+ const inviteWallet = await generateWallet(point, ticket, true);
3936
40− return { ticket, owner };
37+ return { ticket, inviteWallet };
4138};
4239
4340export const spawn = async (
@@ -136,5 +133,33 @@ export const transferPoint = async (
136133 return api.transferPoint(sig, from, _wallet.address, data);
137134};
138135
136+export const setSpawnProxy = async (
137+ api: any,
138+ _wallet: any,
139+ _point: number,
140+ proxy: string,
141+ nonce: number,
142+ address: string
143+) => {
144+ const from = {
145+ ship: _point,
146+ proxy,
147+ };
148+ const managementData = { address };
149+ const managementHash = await api.hashTransaction(
150+ nonce,
151+ from,
152+ 'setManagementProxy',
153+ managementData
154+ );
155+
156+ return api.setManagementProxy(
157+ signTransactionHash(managementHash, _wallet.privateKey),
158+ from,
159+ _wallet.address,
160+ managementData
161+ );
162+};
163+
139164export const hasPoint = (point: number) => (invite: Invite) =>
140165 invite.planet === point;
src/store/lib/useDetailsStore.js+29−2
@@ -2,10 +2,33 @@ import { useState, useCallback } from 'react';
22import { Just, Nothing } from 'folktale/maybe';
33import * as azimuth from 'azimuth-js';
44
5+import useRoller from '../../lib/useRoller';
56import { useNetwork } from '../network';
67
8+const toL1Details = point => {
9+ return {
10+ dominion: 'l2',
11+ active: true,
12+ authenticationKey: point.network.keys.auth,
13+ continuityNumber: point.network.keys.rift,
14+ cryptoSuiteVersion: point.network.keys.suite,
15+ encryptionKey: point.network.keys.crypt,
16+ escapeRequested: point.network.escape ? true : false,
17+ escapeRequestedTo: point.network.escape,
18+ hasSponsor: point.network.sponsor.has,
19+ keyRevisionNumber: point.network.keys.life,
20+ managementProxy: point.ownership.managementProxy.address,
21+ owner: point.ownership.owner.address,
22+ spawnProxy: point.ownership.spawnProxy.address,
23+ sponsor: point.network.sponsor.who,
24+ transferProxy: point.ownership.transferProxy.address,
25+ votingProxy: point.ownership.votingProxy.address,
26+ };
27+};
28+
729export default function useDetailsStore() {
830 const { contracts } = useNetwork();
31+ const { api } = useRoller();
932 const [detailsCache, _setDetailsCache] = useState({});
1033
1134 const addToDetails = useCallback(
@@ -32,12 +55,16 @@ export default function useDetailsStore() {
3255 }
3356
3457 // fetch point details
35− const details = await azimuth.azimuth.getPoint(_contracts, point);
58+ const l2Point = await api.getPoint(point);
59+ const details =
60+ l2Point && l2Point.dominion === 'l2'
61+ ? toL1Details(l2Point)
62+ : await azimuth.azimuth.getPoint(_contracts, point);
3663 addToDetails({
3764 [point]: details,
3865 });
3966 },
40− [contracts, addToDetails]
67+ [api, contracts, addToDetails]
4168 );
4269
4370 return {
src/store/roller.ts+31−1
@@ -1,7 +1,8 @@
11import create from 'zustand';
2−import { L2Point, PendingTransaction } from '@urbit/roller-api/build';
2+import { L2Point, PendingTransaction, Ownership } from '@urbit/roller-api';
33
44import { HOUR, isL2 } from 'lib/utils/roller';
5+import { increaseProxyNonce, setProxyNonce } from 'lib/utils/nonce';
56import { Invite } from 'lib/types/Invite';
67
78export interface RollerStore {
@@ -10,6 +11,17 @@ export interface RollerStore {
1011 pendingTransactions: PendingTransaction[];
1112 currentPoint: L2Point | null;
1213 currentL2: boolean;
14+ nonces: {
15+ [point: number]: Ownership;
16+ };
17+ increaseNonce: (point: number, proxy: string) => void;
18+ setNonce: (
19+ point: number,
20+ owner: Ownership,
21+ proxy: string,
22+ nonce: number
23+ ) => void;
24+ setNonces: (point: number, owner: Ownership) => void;
1325 invites: Invite[];
1426 recentlyCompleted: number;
1527 setNextBatchTime: (nextBatchTime: number) => void;
@@ -27,6 +39,24 @@ export const useRollerStore = create<RollerStore>(set => ({
2739 currentL2: false,
2840 invites: [],
2941 recentlyCompleted: 0,
42+ nonces: {},
43+ increaseNonce: (point: number, proxy: string) =>
44+ set(state => {
45+ const owner = increaseProxyNonce(state.nonces[point], proxy);
46+ console.log(point, proxy, owner);
47+ if (!owner) throw new Error("Can't increase nonce for this proxy");
48+ return { ...state, nonces: { ...state.nonces, [point]: owner } };
49+ }),
50+ setNonce: (point: number, owner: Ownership, proxy: string, nonce: number) =>
51+ set(state => {
52+ const updatedOwner = setProxyNonce(owner, proxy, nonce);
53+ if (!updatedOwner) throw new Error("Can't set nonce for this proxy");
54+ return { ...state, nonces: { ...state.nonces, [point]: updatedOwner } };
55+ }),
56+ setNonces: (point: number, owner: Ownership) =>
57+ set(state => {
58+ return { ...state, nonces: { ...state.nonces, [point]: owner } };
59+ }),
3060 setNextBatchTime: (nextBatchTime: number) => set(() => ({ nextBatchTime })),
3161 setNextRoll: (nextRoll: string) => set(() => ({ nextRoll })),
3262 setPendingTransactions: (pendingTransactions: PendingTransaction[]) =>
src/views/Activate/MasterKeyTransfer.tsx+2−6
@@ -30,6 +30,7 @@ const MasterKeyTransfer = () => {
3030 await acceptInvite({
3131 point: derivedPoint.value,
3232 to: derivedWallet.value.ownership.keys.address,
33+ manager: derivedWallet.value.management.keys.address,
3334 toWallet: derivedWallet.value,
3435 fromWallet: inviteWallet.value,
3536 });
@@ -37,12 +38,7 @@ const MasterKeyTransfer = () => {
3738 console.error(error);
3839 setError(error);
3940 }
40− }, [
41− derivedPoint.value,
42− derivedWallet.value,
43− inviteWallet.value,
44− acceptInvite,
45− ]);
41+ }, [derivedWallet, acceptInvite, derivedPoint.value, inviteWallet.value]);
4642
4743 useFadeIn();
4844
src/views/Login/Ticket.js+21−14
@@ -22,6 +22,7 @@ import useImpliedPoint from 'lib/useImpliedPoint';
2222import useLoginView from 'lib/useLoginView';
2323import { patp2dec } from 'lib/patp2dec';
2424import { timeout } from 'lib/timeout';
25+import useRoller from 'lib/useRoller';
2526
2627import BridgeForm from 'form/BridgeForm';
2728import Condition from 'form/Condition';
@@ -96,6 +97,7 @@ export default function Ticket({ className, goHome }) {
9697 const { setPointCursor } = usePointCursor();
9798 const impliedPoint = useImpliedPoint();
9899 const didWarn = useRef(false);
100+ const { api, getPoints } = useRoller();
99101
100102 const validateForm = useCallback((values, errors) => {
101103 didWarn.current = false;
@@ -134,7 +136,7 @@ export default function Ticket({ className, goHome }) {
134136 : values.ticket;
135137
136138 try {
137− const _contracts = need.contracts(contracts);
139+ // const _contracts = need.contracts(contracts);
138140 const point = patp2dec(values.point);
139141
140142 await timeout(16); // allow ui events to flush
@@ -143,19 +145,24 @@ export default function Ticket({ className, goHome }) {
143145 point,
144146 values.passphrase
145147 );
146−
147− const [isOwner, isTransferProxy] = await Promise.all([
148− azimuth.azimuth.isOwner(
149− _contracts,
150− point,
151− urbitWallet.ownership.keys.address
152− ),
153− azimuth.azimuth.isTransferProxy(
154− _contracts,
155− point,
156− urbitWallet.ownership.keys.address
157− ),
148+ const [ownedPoints, incomingPoints] = await Promise.all([
149+ getPoints('own', urbitWallet.ownership.keys.address),
150+ getPoints('transfer', urbitWallet.ownership.keys.address),
158151 ]);
152+ const isOwner = ownedPoints.length !== 0;
153+ const isTransferProxy = incomingPoints.length !== 0;
154+ // const [isOwner, isTransferProxy] = await Promise.all([
155+ // azimuth.azimuth.isOwner(
156+ // _contracts,
157+ // point,
158+ // urbitWallet.ownership.keys.address
159+ // ),
160+ // azimuth.azimuth.isTransferProxy(
161+ // _contracts,
162+ // point,
163+ // urbitWallet.ownership.keys.address
164+ // ),
165+ // ]);
159166
160167 const noPermissions = !isOwner && !isTransferProxy;
161168 // warn the user
@@ -178,7 +185,7 @@ export default function Ticket({ className, goHome }) {
178185 };
179186 }
180187 },
181− [contracts, setPointCursor, setUrbitWallet]
188+ [setPointCursor, setUrbitWallet, getPoints]
182189 );
183190
184191 const validate = useMemo(
src/views/Point/Point.js+60−27
@@ -128,6 +128,8 @@ export default function Point() {
128128 const { pointCursor } = usePointCursor();
129129 const point = need.point(pointCursor);
130130 const { getDetails } = usePointCache();
131+ // sync the current cursor
132+ useSyncExtras([point]);
131133
132134 const { api, getInvites } = useRoller();
133135 const {
@@ -137,39 +139,69 @@ export default function Point() {
137139 setCurrentPoint,
138140 setPendingTransactions,
139141 currentL2,
142+ setNonces,
143+ increaseNonce,
144+ nonces,
140145 } = useRollerStore();
141146
142− const pointSize = azimuth.getPointSize(point);
143− const details = need.details(getDetails(point));
144− const isStarOrGalaxy = pointSize !== azimuth.PointSize.Planet;
145− const networkRevision = convertToInt(details.keyRevisionNumber, 10);
146− const networkKeysNotSet =
147− !currentL2 && isStarOrGalaxy && networkRevision === 0;
147+ // const pointSize = azimuth.getPointSize(point);
148+ // const details = need.details(getDetails(point));
149+ // const details = getDetails(point);
150+ // console.log(details);
151+ // const isStarOrGalaxy = pointSize !== azimuth.PointSize.Planet;
152+ // const networkRevision =
153+ // Just.hasInstance(details) &&
154+ // convertToInt(need.details(details).keyRevisionNumber, 10);
155+ // console.log(networkRevision);
156+ const networkKeysNotSet = false;
157+ // networkRevision && !currentL2 && isStarOrGalaxy && networkRevision === 0;
148158
149159 const [showModal, setShowModal] = useState(networkKeysNotSet);
150160
151− useEffect(() => {
152− if (networkKeysNotSet) {
153− setShowModal(true);
154− }
155− }, [networkKeysNotSet]);
156−
157− useEffect(() => {
158− const loadL2Info = async () => {
159− const getTransactions = async () => {
160− const pointInfo = await api.getPoint(Number(point));
161− if (isDevelopment) {
162− console.log('POINT INFO', pointInfo);
163− }
164− setCurrentPoint(pointInfo);
165− getInvites(isL2(pointInfo.dominion));
161+ // useEffect(() => {
162+ // if (networkKeysNotSet) {
163+ // setShowModal(true);
164+ // }
165+ // }, [networkKeysNotSet]);
166+
167+ useEffect(
168+ () => {
169+ const loadL2Info = async () => {
170+ const getTransactions = async () => {
171+ const pointInfo = await api.getPoint(Number(point));
172+ const pendingTxs = await api.getPendingByShip(Number(point));
173+ if (isDevelopment) {
174+ console.log('POINT INFO', pointInfo);
175+ }
176+ setNonces(point, pointInfo.ownership);
177+
178+ for (let index = 0; index < pendingTxs.length; index++) {
179+ const proxy = pendingTxs[index].rawTx?.from?.proxy;
180+ console.log(pointInfo.ownership, proxy);
181+ increaseNonce(point, proxy);
182+ }
183+ setCurrentPoint(pointInfo);
184+ getInvites(isL2(pointInfo.dominion));
185+ };
186+
187+ getTransactions();
166188 };
167189
168− getTransactions();
169− };
170−
171− loadL2Info();
172− }, [api, point, authToken, setPendingTransactions]); // eslint-disable-line
190+ loadL2Info();
191+ },
192+ [
193+ // TODO: adding this causes the effect to be called constantly...
194+ // api,
195+ // point,
196+ // authToken,
197+ // setPendingTransactions,
198+ // nonces,
199+ // setCurrentPoint,
200+ // increaseNonce,
201+ // getInvites,
202+ // setNonces,
203+ ]
204+ );
173205
174206 const { isParent, canManage, canSpawn, canVote } = useCurrentPermissions();
175207
@@ -256,7 +288,8 @@ export default function Point() {
256288 <div className="transaction">
257289 <Row className="title-row">
258290 <div className="title">
259− {numPending} Planet{numPending > 1 ? 's' : ''} Spawned
291+ {numPending} Planet
292+ {numPending > 1 ? 's' : ''} Spawned
260293 </div>
261294 <div className="rollup-timer">
262295 <Icon icon="Clock" />
src/views/Points.js+4−2
@@ -172,13 +172,15 @@ export default function Points() {
172172 ),
173173 [getDetails, controlledPoints, _contracts]
174174 );
175−
176175 // if we can only interact with a single point, forget about the existence
177176 // of this page and jump to the point page.
178177 // if there are any pending transfers, incoming or outgoing, stay on this
179178 // page, because those can only be completed/cancelled here.
180179 useEffect(() => {
181− if (outgoingPoints.length < 1 || Nothing.hasInstance(starReleaseDetails)) {
180+ if (
181+ Nothing.hasInstance(outgoingPoints) ||
182+ Nothing.hasInstance(starReleaseDetails)
183+ ) {
182184 return;
183185 }
184186 controlledPoints.matchWith({