on f181773 help sign in
bridge/src/lib/utils/roller.ts
274 lines 6.3 kB history raw
1import { Just, Nothing } from 'folktale/maybe';
2import { Invite } from 'lib/types/Invite';
3import { signTransactionHash } from 'lib/authToken';
4import { randomHex } from 'web3-utils';
6import RollerRPCAPI, {
7 Proxy,
8 Signature,
9 From,
10 EthAddress,
11 AddressParams,
12 Ship,
13 SpawnParams,
14 L2Data,
15 PendingTransaction,
16} from '@urbit/roller-api';
18import { deriveNetworkKeys, CRYPTO_SUITE_VERSION } from 'lib/keys';
19import { addHexPrefix } from 'lib/utils/address';
20import { makeDeterministicTicket, generateWallet } from 'lib/walletgen';
21import { WALLET_TYPES } from 'lib/constants';
23export const SECOND = 1000;
24export const MINUTE = SECOND * 60;
25export const HOUR = MINUTE * 60;
27export const padZero = (amount: number) =>
28 `${amount < 10 && amount >= 0 ? '0' : ''}${amount}`;
30export const hasPoint = (point: number) => (invite: Invite) =>
31 invite.planet === point;
33export const getTimeToNextBatch = (nextBatch: number, now: number) => {
34 const toNext = Math.max(nextBatch - now, 0);
35 const hours = Math.floor(toNext / HOUR);
36 const minutes = Math.floor((toNext - hours * HOUR) / MINUTE);
37 const seconds = Math.floor(
38 (toNext - hours * HOUR - minutes * MINUTE) / SECOND
39 );
41 return `${padZero(hours)}h ${padZero(minutes)}m ${padZero(seconds)}s`;
42};
44export const isL2 = (dom?: string) => dom === 'l2' || dom === 'spawn';
46export const isL2Spawn = (dom?: string) => dom === 'spawn';
48export const generateInviteWallet = async (point: number, seed: string) => {
49 const ticket = makeDeterministicTicket(point, seed);
50 const inviteWallet = await generateWallet(point, ticket, true);
52 return { ticket, inviteWallet };
53};
55export const generateHashAndSign = async (
56 api: RollerRPCAPI,
57 wallet: any,
58 nonce: number,
59 from: From,
60 type: string,
61 data: any,
62 walletType: symbol,
63 web3: any
64) => {
65 if (walletType === WALLET_TYPES.METAMASK) {
66 const hash = await api.getUnsignedTx(nonce, from, type, data);
67 const sig = await web3.eth.personal.sign(hash, wallet.address, '');
68 return sig;
69 } else {
70 const hash = await api.hashTransaction(nonce, from, type, data);
71 return signTransactionHash(hash, wallet.privateKey);
72 }
73};
75export const spawn = async (
76 api: RollerRPCAPI,
77 wallet: any,
78 _point: number,
79 proxy: string,
80 nonce: number,
81 planet: number,
82 walletType: symbol,
83 web3: any
84) => {
85 const from = {
86 ship: _point, //ship that is spawning the planet
87 proxy,
88 };
90 const data = {
91 address: wallet.address,
92 ship: planet, // ship to spawn
93 };
95 const sig = await generateHashAndSign(
96 api,
97 wallet,
98 nonce,
99 from,
100 'spawn',
101 data,
102 walletType,
103 web3
104 );
105 return api.spawn(sig, from, wallet.address, data);
106};
108export const configureKeys = async (
109 api: RollerRPCAPI,
110 wallet: any,
111 point: Ship,
112 proxy: string,
113 nonce: number,
114 networkSeed: any,
115 walletType: symbol,
116 web3: any,
117 breach?: boolean
118) => {
119 const from = {
120 ship: point, //ship to configure keys
121 proxy,
122 };
124 // TODO: do something here?
125 if (Nothing.hasInstance(networkSeed)) {
126 console.log("Network key Error: couldn't derive network keys");
127 // throw new Error("Network key Error: couldn't derive network keys");
128 }
130 const seed = Just.hasInstance(networkSeed)
131 ? networkSeed.value
132 : randomHex(32);
134 const pair = deriveNetworkKeys(seed);
136 const data = {
137 encrypt: addHexPrefix(pair.crypt.public),
138 auth: addHexPrefix(pair.auth.public),
139 cryptoSuite: String(CRYPTO_SUITE_VERSION),
140 breach: breach || false,
141 };
143 const sig = await generateHashAndSign(
144 api,
145 wallet,
146 nonce,
147 from,
148 'configureKeys',
149 data,
150 walletType,
151 web3
152 );
153 return api.configureKeys(sig, from, wallet.address, data);
154};
156export const transferPointRequest = async (
157 api: RollerRPCAPI,
158 wallet: any,
159 pointToTransfer: Ship,
160 proxy: string,
161 nonce: number,
162 address: string,
163 walletType: symbol,
164 web3: any,
165 reset?: boolean
166) => {
167 const from = {
168 ship: pointToTransfer,
169 proxy,
170 };
172 const data = {
173 address,
174 reset: reset || false,
175 };
177 const sig = await generateHashAndSign(
178 api,
179 wallet,
180 nonce,
181 from,
182 'transferPoint',
183 data,
184 walletType,
185 web3
186 );
188 return api.transferPoint(sig, from, wallet.address, data);
189};
191const proxyType = (proxy: Proxy) => {
192 switch (proxy) {
193 case 'manage':
194 return 'setManagementProxy';
195 case 'spawn':
196 return 'setSpawnProxy';
197 case 'transfer':
198 return 'setTransferProxy';
199 default:
200 throw new Error(`Unknown proxyType ${proxy}`);
201 }
202};
204const setProxy = async (
205 api: RollerRPCAPI,
206 proxyAddressType: string,
207 sig: Signature,
208 from: From,
209 address: EthAddress,
210 data: AddressParams
211) => {
212 switch (proxyAddressType) {
213 case 'manage':
214 return await api.setManagementProxy(sig, from, address, data);
215 case 'spawn':
216 return await api.setSpawnProxy(sig, from, address, data);
217 case 'transfer':
218 return await api.setTransferProxy(sig, from, address, data);
219 default:
220 throw new Error(`Unknown proxyType ${proxyAddressType}`);
221 }
222};
224export const registerProxyAddress = async (
225 api: RollerRPCAPI,
226 wallet: any,
227 _point: Ship,
228 proxy: string,
229 proxyAddressType: string,
230 nonce: number,
231 address: string,
232 walletType: symbol,
233 web3: any
234) => {
235 const from = {
236 ship: _point,
237 proxy,
238 };
239 const data = { address };
241 const sig = await generateHashAndSign(
242 api,
243 wallet,
244 nonce,
245 from,
246 proxyType(proxyAddressType),
247 data,
248 walletType,
249 web3
250 );
252 return setProxy(api, proxyAddressType, sig, from, wallet.address, data);
253};
255export const reticketL2Point = async () => {};
257export const hasInvite = (point: number) => (invite: Invite) =>
258 invite.planet === point && invite.ticket.length > 0;
260function isSpawn(tx: L2Data | undefined): tx is SpawnParams {
261 return (tx as SpawnParams) !== undefined;
264function isShipNumber(ship: number | string | undefined): ship is number {
265 return (ship as number) !== undefined;
268export const getPendingSpawns = (pendingTxs: PendingTransaction[]) =>
269 pendingTxs.reduce((acc, pending) => {
270 return isSpawn(pending.rawTx?.tx) &&
271 isShipNumber(pending.rawTx?.tx.data.ship)
272 ? acc.add(pending.rawTx?.tx.data.ship!)
273 : acc;
274 }, new Set<number>());