1import { useCallback, useEffect, useMemo, useState } from 'react';
2import * as wg from 'lib/walletgen';
3import * as need from 'lib/need';
4import * as azimuth from 'azimuth-js';
15} from '@urbit/roller-api';
17import { isDevelopment, isRopsten } from './flags';
18import { ROLLER_HOSTS } from './constants';
19import { useRollerStore } from 'store/roller';
20import { getTimeToNextBatch } from './utils/roller';
21import { useWallet } from 'store/wallet';
22import { usePointCursor } from 'store/pointCursor';
23import { useNetwork } from 'store/network';
24import { signTransactionHash } from './authToken';
25import { Invite } from 'types/Invite';
30} from 'store/storage/roller';
31import { usePointCache } from 'store/pointCache';
32import { getOutgoingPoints, maybeGetResult } from 'views/Points';
34const hasPoint = (point: number) => (invite: Invite) => invite.planet === point;
36const getProxyAndNonce = (
39): { proxy?: string; nonce?: number } =>
40 point.ownership?.managementProxy?.address === address
41 ? { proxy: 'manage', nonce: point.ownership?.managementProxy.nonce }
42 : point.ownership?.owner?.address === address
43 ? { proxy: 'own', nonce: point.ownership?.owner.nonce }
44 : point.ownership?.spawnProxy?.address === address
45 ? { proxy: 'spawn', nonce: point.ownership?.spawn?.owner.nonce }
46 : point.ownership?.votingProxy?.address === address
47 ? { proxy: 'vote', nonce: point.ownership?.votingProxy?.owner.nonce }
48 : point.ownership?.transferProxy?.address === address
51 nonce: point.transferProxy?.votingProxy?.owner.nonce,
53 : { proxy: undefined, nonce: undefined };
55export default function useRoller() {
56 const { wallet, authToken }: any = useWallet();
57 const { pointCursor }: any = usePointCursor();
58 const { web3, contracts }: any = useNetwork();
59 const allPoints: any = usePointCache();
60 const controlledPoints = allPoints?.controlledPoints;
61 const getDetails = allPoints?.getDetails;
67 setPendingTransactions,
71 const [config, setConfig] = useState<Config | null>(null);
73 const options: Options = useMemo(() => {
74 const type = isRopsten || !isDevelopment ? 'https' : 'http';
75 const host = isRopsten
76 ? ROLLER_HOSTS.ROPSTEN
79 : ROLLER_HOSTS.MAINNET;
80 const port = isDevelopment ? 8080 : 80;
81 const path = '/v1/roller';
93 const api = useMemo(() => {
94 return new RollerRPCAPI(options);
97 const fetchConfig = useCallback(async () => {
102 setNextBatchTime(response.nextBatch);
105 // TODO: more elegant error handling
107 '[fetchConfig:failed] is roller running on localhost?\n',
111 }, [api]); // eslint-disable-line react-hooks/exhaustive-deps
113 const generateInviteCodes = useCallback(
114 async (numInvites: number) => {
115 const _point = need.point(pointCursor);
116 const _contracts = contracts.getOrElse(null);
117 const _web3 = web3.getOrElse(null);
118 const _wallet = wallet.getOrElse(null);
119 const _authToken = authToken.getOrElse(null);
120 if (!_contracts || !_web3 || !_wallet || !_authToken) {
121 // not using need because we want a custom error
122 throw new Error('Internal Error: Missing Contracts/Web3/Wallet');
125 const planets: UnspawnedPoints = await api.getUnspawned(_point);
126 const starInfo = await api.getPoint(_point);
128 const tickets: { ticket: string; planet: number; owner: string }[] = [];
129 const requests: Promise<string>[] = [];
131 const { proxy, nonce } = getProxyAndNonce(starInfo, _wallet.address);
133 if (!(proxy === 'own' || proxy === 'spawn') || nonce === undefined)
134 throw new Error("Error: Address doesn't match proxy");
136 for (let i = 0; i < numInvites && planets[i]; i++) {
137 const planet = planets[i];
139 const { ticket, owner } = await wg.generateTemporaryDeterministicWallet(
145 ship: _point, //ship that is spawning the planet
150 address: owner.keys.address, // the new owner of the star (invite wallet)
151 ship: planet, // ship to spawn
154 const txHash = await api.hashTransaction(
161 const signature = signTransactionHash(txHash, _wallet.privateKey);
162 requests.push(api.spawn(signature, from, _wallet.address, data));
166 owner: owner.keys.address,
170 const hashes = await Promise.all(requests);
171 const pendingInvites = hashes.map(
172 (hash, i): Invite => ({
178 setPendingInvites(_point, pendingInvites);
192 const getPoints = useCallback(
193 async (proxy: Proxy, address: EthAddress) => {
194 const points: Ship[] =
196 ? await api.getOwnedPoints(address)
198 ? await api.getManagerFor(address)
200 ? await api.getVotingFor(address)
201 : proxy === 'transfer'
202 ? await api.getTransferringFor(address)
204 ? await api.getSpawningFor(address)
212 const getPendingTransactions = useCallback(async () => {
214 const curPoint = need.point(pointCursor);
215 const newPending = await api.getPendingByShip(Number(curPoint));
216 setPendingTransactions(newPending);
218 // const allTransactions = await api.getHistory()
220 console.warn('ERROR GETTING PENDING', error);
222 }, [api, setPendingTransactions, pointCursor]);
224 const getInvites = useCallback(
225 async (isL2: boolean) => {
227 const curPoint: string = need.point(pointCursor);
228 const invites = getStoredInvites(curPoint);
229 const availableInvites = invites.available;
231 const pendingTransactions = await api.getPendingByShip(curPoint);
233 console.log('PENDING', pendingTransactions);
235 setPendingTransactions(pendingTransactions);
237 const stillPending = invites.pending.filter(invite => {
238 const completed = !pendingTransactions.find(
239 p => p?.rawTx?.tx?.tx?.data?.ship === invite.planet
243 availableInvites.push({ ...invite, status: 'available' });
249 setStoredInvites(curPoint, {
250 available: availableInvites,
251 pending: stillPending,
252 claimed: invites.claimed,
254 setInvites(availableInvites);
256 const _authToken = authToken.getOrElse(null);
257 const _contracts = contracts.getOrElse(null);
259 if (_authToken && _contracts) {
260 let possibleMissingInvites: number[] = [];
262 const allSpawned = await api.getSpawned(Number(curPoint));
263 const ownedPoints = maybeGetResult(
268 possibleMissingInvites = allSpawned.filter(
270 ownedPoints.includes(p) &&
271 azimuth.azimuth.getPointSize(p) ===
272 azimuth.azimuth.PointSize.Planet
275 const outgoingPoints = getOutgoingPoints(
280 const availablePoints = await azimuth.azimuth.getUnspawnedChildren(
285 possibleMissingInvites = outgoingPoints.filter(
287 azimuth.azimuth.getPointSize(p) ===
288 azimuth.azimuth.PointSize.Planet &&
289 availablePoints.includes(p)
293 // Iterate over all spawned and controlled planets
294 // If the planet is not in available invites, generate the ticket and add it
296 console.log('POSSIBLE MISSING', possibleMissingInvites);
299 const newClaimed = availableInvites.filter(
300 ({ planet }) => !possibleMissingInvites.includes(planet)
303 for (let i = 0; i < possibleMissingInvites.length; i++) {
304 const planet = possibleMissingInvites[i];
307 !availableInvites.find(hasPoint(planet)) &&
308 !(await azimuth.azimuth.isActive(_contracts, planet))
310 console.log('MISSING IN AVAILABLE', planet);
314 } = await wg.generateTemporaryDeterministicWallet(
319 availableInvites.push({
324 owner: owner.keys.address,
329 setStoredInvites(curPoint, {
330 available: availableInvites.filter(({ planet }) =>
331 possibleMissingInvites.includes(planet)
333 pending: stillPending,
334 claimed: invites.claimed.concat(newClaimed),
336 setInvites(availableInvites);
339 console.warn('ERROR GETTING INVITES', error);
346 setPendingTransactions,
354 // On load, get initial config
361 }, [config, fetchConfig]);
364 const interval = setInterval(() => {
365 const nextRoll = getTimeToNextBatch(nextBatchTime, new Date().getTime());
366 setNextRoll(nextRoll);
368 if (nextBatchTime <= new Date().getTime()) {
369 api.getRollerConfig().then(response => {
370 setNextBatchTime(response.nextBatch);
373 getInvites(currentL2);
377 return () => clearInterval(interval);
378 }, [nextBatchTime, getPendingTransactions, currentL2]); // eslint-disable-line react-hooks/exhaustive-deps
385 getPendingTransactions,
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list