@@ -1,4 +1,5 @@
1import { useCallback, useEffect, useMemo, useState } from 'react';
1import { useCallback, useEffect, useMemo, useState } from 'react';
2+import _ from 'lodash';
2import * as azimuth from 'azimuth-js';
3import * as azimuth from 'azimuth-js';
3import * as need from 'lib/need';
4import * as need from 'lib/need';
4import * as ob from 'urbit-ob';
5import * as ob from 'urbit-ob';
@@ -7,17 +8,24 @@ import { Just } from 'folktale/maybe';
7import { Invite } from 'lib/types/Invite';
8import { Invite } from 'lib/types/Invite';
8import { convertToInt } from './convertToInt';
9import { convertToInt } from './convertToInt';
9import { ensureHexPrefix } from 'form/formatters';
10import { ensureHexPrefix } from 'form/formatters';
10−import { getOutgoingPoints } from 'views/Points';
11import { isDevelopment, isRopsten } from './flags';
11import { isDevelopment, isRopsten } from './flags';
12−import { isPlanet } from './utils/point';
13import { hasPoint, generateInviteWallet } from './utils/roller';
12import { hasPoint, generateInviteWallet } from './utils/roller';
14import { ROLLER_HOSTS } from './constants';
13import { ROLLER_HOSTS } from './constants';
15import { signTransactionHash } from './authToken';
14import { signTransactionHash } from './authToken';
16import { useNetwork } from 'store/network';
16import { useNetwork } from 'store/network';
17−import { usePointCache } from 'store/pointCache';
18import { usePointCursor } from 'store/pointCursor';
17import { usePointCursor } from 'store/pointCursor';
19import { useRollerStore } from 'store/roller';
18import { useRollerStore } from 'store/roller';
20import { useWallet } from 'store/wallet';
19import { useWallet } from 'store/wallet';
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';
23 deriveNetworkKeys,
31 deriveNetworkKeys,
@@ -28,7 +36,6 @@ import {
33 RollerRPCAPI,
40 RollerRPCAPI,
@@ -36,6 +43,8 @@ import {
36 UnspawnedPoints,
43 UnspawnedPoints,
39} from '@urbit/roller-api';
48} from '@urbit/roller-api';
@@ -43,33 +52,16 @@ import {
43 getTimeToNextBatch,
52 getTimeToNextBatch,
45 transferPoint,
54 transferPoint,
46} from './utils/roller';
56} from './utils/roller';
48−import {
58+function isSpawn(tx: L2Data | undefined): tx is SpawnParams {
49− getStoredInvites,
59+ return (tx as SpawnParams) !== undefined;
50− setPendingInvites,
60+}
52−} from 'store/storage/roller';
54−const getProxyAndNonce = (
62+function isShipNumber(ship: number | string | undefined): ship is number {
55− point: L2Point,
63+ return (ship as number) !== undefined;
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
69− nonce: point.transferProxy?.votingProxy?.owner.nonce,
71− : { proxy: undefined, nonce: undefined };
74export default function useRoller() {
66export default function useRoller() {
75 const { wallet, authToken, authMnemonic, urbitWallet }: any = useWallet();
67 const { wallet, authToken, authMnemonic, urbitWallet }: any = useWallet();
@@ -86,6 +78,8 @@ export default function useRoller() {
86 setPendingTransactions,
78 setPendingTransactions,
87 setInvites,
79 setInvites,
88 currentL2,
80 currentL2,
89 } = useRollerStore();
83 } = useRollerStore();
90 const [config, setConfig] = useState<Config | null>(null);
84 const [config, setConfig] = useState<Config | null>(null);
@@ -137,6 +131,7 @@ export default function useRoller() {
137 const _wallet = wallet.getOrElse(null);
131 const _wallet = wallet.getOrElse(null);
138 const _authToken = authToken.getOrElse(null);
132 const _authToken = authToken.getOrElse(null);
139 const _details = getDetails(_point);
133 const _details = getDetails(_point);
140 if (!_contracts || !_web3 || !_wallet || !_authToken || !_details) {
135 if (!_contracts || !_web3 || !_wallet || !_authToken || !_details) {
141 // not using need because we want a custom error
136 // not using need because we want a custom error
142 throw new Error('Internal Error: Missing Contracts/Web3/Wallet');
137 throw new Error('Internal Error: Missing Contracts/Web3/Wallet');
@@ -147,9 +142,27 @@ export default function useRoller() {
147 "Auth key Error: A management mnemonic can't create invite codes"
142 "Auth key Error: A management mnemonic can't create invite codes"
150− const planets: UnspawnedPoints = await api.getUnspawned(_point);
145+ let planets: UnspawnedPoints = await api.getUnspawned(_point);
151− const starInfo = await api.getPoint(_point);
147+ const pendingTxs = await api.getPendingByShip(_point);
149+ const pendingSpawns = _.reduce(
152+ return isSpawn(pending.rawTx?.tx) &&
153+ isShipNumber(pending.rawTx?.tx.data.ship)
154+ ? acc.add(pending.rawTx?.tx.data.ship!)
160+ console.log(pendingTxs, pendingSpawns);
162+ planets = planets.filter((point: number) => !pendingSpawns.has(point));
164+ const starInfo = nonces[_point];
165+ console.log(starInfo);
153 const tickets: {
166 const tickets: {
154 ticket: string;
167 ticket: string;
155 planet: number;
168 planet: number;
@@ -157,37 +170,37 @@ export default function useRoller() {
157 }[] = [];
170 }[] = [];
158 const requests: Promise<string>[] = [];
171 const requests: Promise<string>[] = [];
160− // TODO: replace with "currentNonce" from store, that would reflect the latest nonce
173+ const operator =
161− // Bridge has used for the star _wallet.address
174+ getSpawnNonce(starInfo, _wallet.address) ||
163− const { proxy, nonce } = getProxyAndNonce(starInfo, _wallet.address);
175+ getOwnerNonce(starInfo, _wallet.address);
165− if (!(proxy === 'own' || proxy === 'spawn') || nonce === undefined)
177+ if (operator === undefined)
166 throw new Error("Error: Address doesn't match proxy");
178 throw new Error("Error: Address doesn't match proxy");
167−
179+ console.log('operator', operator);
168 for (let i = 0; i < numInvites && planets[i]; i++) {
180 for (let i = 0; i < numInvites && planets[i]; i++) {
169 const planet = planets[i];
181 const planet = planets[i];
170− const nonceInc = i + nonce;
182+ const nonceInc = i + operator.nonce!;
172− const { ticket, owner } = await generateInviteWallet(
184+ const { ticket, inviteWallet } = await generateInviteWallet(
174 _authToken
186 _authToken
176−
188+ console.log(inviteWallet);
177 const spawnRequest = await spawn(
189 const spawnRequest = await spawn(
181− proxy,
193+ operator.proxy!,
182 nonceInc,
194 nonceInc,
197+ increaseNonce(_point, operator.proxy!);
186 const configureKeysRequest = await configureKeys(
199 const configureKeysRequest = await configureKeys(
190− proxy,
203+ operator.proxy!,
192 _details,
205 _details,
193 authToken,
206 authToken,
@@ -196,20 +209,34 @@ export default function useRoller() {
196 urbitWallet
209 urbitWallet
199− const transferPointRequest = await transferPoint(
212+ const setManagementProxyRequest = await setSpawnProxy(
203− proxy,
216+ operator.proxy!,
205− owner.keys.address
218+ inviteWallet.management.keys.address
221+ const transferPointRequest = await transferPoint(
227+ inviteWallet.ownership.keys.address
208− requests.push(spawnRequest, configureKeysRequest, transferPointRequest);
232+ configureKeysRequest,
233+ setManagementProxyRequest,
234+ transferPointRequest
209 tickets.push({
236 tickets.push({
212− owner: owner.keys.address,
239+ owner: inviteWallet.ownership.keys.address,
@@ -221,6 +248,7 @@ export default function useRoller() {
221 status: 'pending',
248 status: 'pending',
251+ console.log('latest update', nonces[_point]);
224 setPendingInvites(_point, pendingInvites);
252 setPendingInvites(_point, pendingInvites);
@@ -233,6 +261,8 @@ export default function useRoller() {
233 getDetails,
261 getDetails,
234 authMnemonic,
262 authMnemonic,
235 urbitWallet,
263 urbitWallet,
@@ -343,7 +373,7 @@ export default function useRoller() {
343 const planet = possibleMissingInvites[i];
373 const planet = possibleMissingInvites[i];
344 if (!availableInvites.find(hasPoint(planet))) {
374 if (!availableInvites.find(hasPoint(planet))) {
345 console.log('MISSING IN AVAILABLE', planet);
375 console.log('MISSING IN AVAILABLE', planet);
346− const { ticket, owner } = await generateInviteWallet(
376+ const { ticket, inviteWallet } = await generateInviteWallet(
348 _authToken
378 _authToken
@@ -353,7 +383,7 @@ export default function useRoller() {
353 status: 'available',
383 status: 'available',
355 hash: '',
385 hash: '',
356− owner: owner.keys.address,
386+ owner: inviteWallet.ownership.keys.address,
@@ -371,14 +401,14 @@ export default function useRoller() {
375− pointCursor,
405+ // pointCursor,
376− setInvites,
406+ // setInvites,
377− setPendingTransactions,
407+ // setPendingTransactions,
378− authToken,
408+ // authToken,
379− contracts,
409+ // contracts,
380− controlledPoints,
410+ // controlledPoints,
381− getDetails,
411+ // getDetails,
@@ -394,6 +424,7 @@ export default function useRoller() {
394 interface AcceptInviteParams {
424 interface AcceptInviteParams {
395 point: Ship;
425 point: Ship;
396 to: EthAddress;
426 to: EthAddress;
427+ manager: EthAddress;
397 fromWallet: any; // TODO: wallet type
428 fromWallet: any; // TODO: wallet type
398 toWallet: any; // TODO: wallet type
429 toWallet: any; // TODO: wallet type
@@ -401,6 +432,7 @@ export default function useRoller() {
401 const acceptInvite = async ({
432 const acceptInvite = async ({
404 fromWallet,
436 fromWallet,
405 toWallet,
437 toWallet,
406 }: AcceptInviteParams) => {
438 }: AcceptInviteParams) => {
@@ -408,10 +440,14 @@ export default function useRoller() {
408 console.log('azimuthPoint', azimuthPoint);
440 console.log('azimuthPoint', azimuthPoint);
409 const ownerAddress = azimuthPoint?.ownership?.owner?.address!;
441 const ownerAddress = azimuthPoint?.ownership?.owner?.address!;
444+ azimuthPoint.ownership &&
411− const { nonce } = getProxyAndNonce(azimuthPoint, ownerAddress);
445+ getOwnerNonce(azimuthPoint.ownership, ownerAddress);
412− if (nonce === undefined) {
447+ if (operator === undefined)
413− throw new Error('Nonce unavailable');
448+ throw new Error("Error: Address doesn't match proxy");
450+ const nonce = operator.nonce!;
416 // 1. Update networking keys
452 // 1. Update networking keys
417 // TODO: extract this to a useRoller#configureKeys function?
453 // TODO: extract this to a useRoller#configureKeys function?
@@ -445,11 +481,30 @@ export default function useRoller() {
445 ownerAddress,
481 ownerAddress,
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!);
488+ // 2. Set Management Proxy
489+ const managementData = { address: manager };
490+ const managementHash: Hash = await api.hashTransaction(
493+ 'setManagementProxy',
497+ await api.setManagementProxy(
498+ signTransactionHash(managementHash, Buffer.from(keysSigningKey, 'hex')),
449− // 2. Transfer point
504+ // 3. Transfer point
450 const transferData = { address: to, reset: false };
505 const transferData = { address: to, reset: false };
451 const transferHash: Hash = await api.hashTransaction(
506 const transferHash: Hash = await api.hashTransaction(
452− nonce + 1,
507+ nonce + 2,
453 fromOwnerProxy,
508 fromOwnerProxy,
454 'transferPoint',
509 'transferPoint',
455 transferData
510 transferData