@@ -3,6 +3,15 @@ import * as wg from 'lib/walletgen';
33import * as need from 'lib/need';
44import * as azimuth from 'azimuth-js';
55import * as ob from 'urbit-ob';
6+import { Just } from 'folktale/maybe';
7+import { randomHex } from 'web3-utils';
8+
9+import {
10+ attemptNetworkSeedDerivation,
11+ deriveNetworkKeys,
12+ CRYPTO_SUITE_VERSION,
13+} from 'lib/keys';
14+import { addHexPrefix } from 'lib/utils/address';
615
716import {
817 Config,
@@ -33,6 +42,97 @@ import { usePointCache } from 'store/pointCache';
3342import { getOutgoingPoints, maybeGetResult } from 'views/Points';
3443import { isPlanet } from './utils/point';
3544
45+const spawn = async (
46+ api: any,
47+ _wallet: any,
48+ _point: number,
49+ proxy: string,
50+ nonce: number,
51+ planet: number
52+) => {
53+ const from = {
54+ ship: _point, //ship that is spawning the planet
55+ proxy,
56+ };
57+
58+ const data = {
59+ address: _wallet.address,
60+ ship: planet, // ship to spawn
61+ };
62+
63+ const hash = await api.hashTransaction(nonce, from, 'spawn', data);
64+ const sSig = signTransactionHash(hash, _wallet.privateKey);
65+ return api.spawn(sSig, from, _wallet.address, data);
66+};
67+
68+const configureKeys = async (
69+ api: any,
70+ _wallet: any,
71+ _point: number,
72+ proxy: string,
73+ nonce: number,
74+ details: any,
75+ authToken: string,
76+ authMnemonic: string,
77+ wallet: any,
78+ urbitWallet: any
79+) => {
80+ const from = {
81+ ship: _point, //ship that is spawning the planet
82+ proxy,
83+ };
84+
85+ const networkSeed = await attemptNetworkSeedDerivation({
86+ urbitWallet,
87+ wallet,
88+ authMnemonic,
89+ details,
90+ point: _point,
91+ authToken,
92+ revision: 1,
93+ });
94+
95+ const seed = Just.hasInstance(networkSeed)
96+ ? networkSeed.value
97+ : randomHex(32);
98+
99+ const pair = deriveNetworkKeys(seed);
100+
101+ const data = {
102+ encrypt: addHexPrefix(pair.crypt.public),
103+ auth: addHexPrefix(pair.auth.public),
104+ cryptoSuite: String(CRYPTO_SUITE_VERSION),
105+ breach: false,
106+ };
107+
108+ const hash = await api.hashTransaction(nonce, from, 'configureKeys', data);
109+ const sig = signTransactionHash(hash, _wallet.privateKey);
110+ return api.configureKeys(sig, from, _wallet.address, data);
111+};
112+
113+const transferPoint = async (
114+ api: any,
115+ _wallet: any,
116+ _point: number,
117+ proxy: string,
118+ nonce: number,
119+ address: string
120+) => {
121+ const from = {
122+ ship: _point, //ship that is spawning the planet
123+ proxy,
124+ };
125+
126+ const data = {
127+ address,
128+ reset: false,
129+ };
130+
131+ const hash = await api.hashTransaction(nonce, from, 'transferPoint', data);
132+ const sig = signTransactionHash(hash, _wallet.privateKey);
133+ return api.transferPoint(sig, from, _wallet.address, data);
134+};
135+
36136const hasPoint = (point: number) => (invite: Invite) => invite.planet === point;
37137
38138const getProxyAndNonce = (
@@ -55,7 +155,7 @@ const getProxyAndNonce = (
55155 : { proxy: undefined, nonce: undefined };
56156
57157export default function useRoller() {
58− const { wallet, authToken }: any = useWallet();
158+ const { wallet, authToken, authMnemonic, urbitWallet }: any = useWallet();
59159 const { pointCursor }: any = usePointCursor();
60160 const { web3, contracts }: any = useNetwork();
61161 const allPoints: any = usePointCache();
@@ -119,7 +219,8 @@ export default function useRoller() {
119219 const _web3 = web3.getOrElse(null);
120220 const _wallet = wallet.getOrElse(null);
121221 const _authToken = authToken.getOrElse(null);
122− if (!_contracts || !_web3 || !_wallet || !_authToken) {
222+ const _details = getDetails(_point);
223+ if (!_contracts || !_web3 || !_wallet || !_authToken || !_details) {
123224 // not using need because we want a custom error
124225 throw new Error('Internal Error: Missing Contracts/Web3/Wallet');
125226 }
@@ -137,31 +238,45 @@ export default function useRoller() {
137238
138239 for (let i = 0; i < numInvites && planets[i]; i++) {
139240 const planet = planets[i];
241+ const nonceInc = i * 3;
140242
141243 const { ticket, owner } = await wg.generateTemporaryDeterministicWallet(
142244 planet,
143245 _authToken
144246 );
145247
146− const from = {
147− ship: _point, //ship that is spawning the planet
248+ const spawnRequest = await spawn(
249+ api,
250+ _wallet,
251+ _point,
148252 proxy,
149− };
150−
151− const data = {
152− address: owner.keys.address, // the new owner of the star (invite wallet)
153− ship: planet, // ship to spawn
154− };
155−
156− const txHash = await api.hashTransaction(
157− nonce + i,
158− from,
159− 'spawn',
160− data
253+ nonceInc,
254+ planet
161255 );
162256
163− const signature = signTransactionHash(txHash, _wallet.privateKey);
164− requests.push(api.spawn(signature, from, _wallet.address, data));
257+ const configureKeysRequest = await configureKeys(
258+ api,
259+ _wallet,
260+ _point,
261+ proxy,
262+ nonceInc + 1,
263+ _details,
264+ authToken,
265+ authMnemonic,
266+ wallet,
267+ urbitWallet
268+ );
269+
270+ const transferPointRequest = await transferPoint(
271+ api,
272+ _wallet,
273+ _point,
274+ proxy,
275+ nonceInc + 2,
276+ owner.keys.address
277+ );
278+
279+ requests.push(spawnRequest, configureKeysRequest, transferPointRequest);
165280 tickets.push({
166281 ticket,
167282 planet,
@@ -170,13 +285,13 @@ export default function useRoller() {
170285 }
171286
172287 const hashes = await Promise.all(requests);
173− const pendingInvites = hashes.map(
174− (hash, i): Invite => ({
175− hash,
176− ...tickets[i],
177− status: 'pending',
178− })
179− );
288+
289+ const pendingInvites = tickets.map((ticket, ind) => ({
290+ ...ticket,
291+ hash: hashes[ind * 3 + 2],
292+ status: 'pending',
293+ }));
294+
180295 setPendingInvites(_point, pendingInvites);
181296 },
182297 [
@@ -188,6 +303,9 @@ export default function useRoller() {
188303 // walletHdPath,
189304 // walletType,
190305 web3,
306+ getDetails,
307+ authMnemonic,
308+ urbitWallet,
191309 ]
192310 );
193311
@@ -240,9 +358,14 @@ export default function useRoller() {
240358 const completed = !pendingTransactions.find(
241359 p => `~${p?.rawTx?.tx?.tx?.data?.ship}` === ob.patp(invite.planet)
242360 );
243− if (completed) {
361+
362+ if (
363+ completed &&
364+ !availableInvites.find(({ ship }) => invite.ship === ship)
365+ ) {
244366 availableInvites.push({ ...invite, status: 'available' });
245367 }
368+
246369 return !completed;
247370 });
248371