@@ -12,6 +12,7 @@ import saveAs from 'file-saver';
12import { sendSignedTransaction, hexify } from './txn';
12import { sendSignedTransaction, hexify } from './txn';
13import { attemptNetworkSeedDerivation } from './keys';
13import { attemptNetworkSeedDerivation } from './keys';
14import { addHexPrefix, WALLET_TYPES } from './wallet';
14import { addHexPrefix, WALLET_TYPES } from './wallet';
15+import { GAS_LIMITS } from './constants';
16const INVITE_STAGES = {
17const INVITE_STAGES = {
17 INVITE_LOGIN: 'invite login',
18 INVITE_LOGIN: 'invite login',
@@ -38,22 +39,14 @@ const TRANSACTION_STATES = {
38 label: 'Signing Transactions...',
39 label: 'Signing Transactions...',
39 progress: 0.15,
40 progress: 0.15,
41− FUNDING_INVITE: {
42+ FUNDING: {
42− label: 'Funding Invite Wallet...',
43+ label: 'Funding Transactions...',
43 progress: 0.3,
44 progress: 0.3,
45 CLAIMING: {
46 CLAIMING: {
46 label: 'Claiming Invite...',
47 label: 'Claiming Invite...',
47 progress: 0.55,
48 progress: 0.55,
50− label: 'Funding Recipient Wallet...',
54− label: 'Configuring Point...',
57 CLEANING: {
50 CLEANING: {
58 label: 'Cleaning Up...',
51 label: 'Cleaning Up...',
59 progress: 0.95,
52 progress: 0.95,
@@ -108,6 +101,7 @@ async function claimPointFromInvite({
109 contracts,
102 contracts,
110 onUpdate,
103 onUpdate,
104+ transferEth = false,
112 const askForFunding = (address, minBalance, balance) =>
106 const askForFunding = (address, minBalance, balance) =>
113 onUpdate({
107 onUpdate({
@@ -120,62 +114,29 @@ async function claimPointFromInvite({
121 const inviteAddress = inviteWallet.address;
115 const inviteAddress = inviteWallet.address;
123− progress(TRANSACTION_STATES.GENERATING);
125− // transfer from invite wallet to new wallet
126− const transferTx = azimuth.ecliptic.transferPoint(
129− wallet.ownership.keys.address
131− transferTx.gas = 500000; //TODO can maybe be lower?
133− // ping gas tank with txs if needed
134− let inviteNonce = await web3.eth.getTransactionCount(inviteAddress);
135− transferTx.nonce = inviteNonce++;
136− transferTx.gasPrice = 20000000000; //NOTE we pay the premium for faster ux
137− transferTx.from = inviteAddress;
139− progress(TRANSACTION_STATES.SIGNING);
140− // NOTE: using web3.eth.accounts.signTransaction is broken (1.0.0-beta51)
141− const transferStx = new Tx(transferTx);
142− transferStx.sign(inviteWallet.privateKey);
143− const rawTransferStx = hexify(transferStx.serialize());
144− const transferCost = transferTx.gas * transferTx.gasPrice;
146− progress(TRANSACTION_STATES.FUNDING_INVITE);
148− let usedTank = await tank.ensureFundsFor(
158− progress(TRANSACTION_STATES.CLAIMING);
161− await sendAndAwaitConfirm(web3, [Just(transferStx)], usedTank);
164− // we're gonna be operating as the new wallet from here on out, so change
118+ // generate transactions
165− // the relevant values
167− const newAddress = wallet.ownership.keys.address;
169− // configure management proxy
121+ progress(TRANSACTION_STATES.GENERATING);
123+ // transfer to invite wallet, so it can configure
124+ //NOTE doing this in the invite wallet instead of the final wallet makes
125+ // failure cases "solvable" by just telling the user to fully retry.
126+ // in other words, the invite flow is effectively idempotent.
128+ //TODO no harm done if we already owned it, but should still get a bool arg
129+ // for skipping this, if it isn't too big a burden for callers
170− const managementTx = azimuth.ecliptic.setManagementProxy(
130+ const transferTmpTx = azimuth.ecliptic.transferPoint(
171 contracts,
131 contracts,
173− wallet.management.keys.address
133+ inviteAddress,
175− managementTx.gas = 200000;
136+ transferTmpTx.gas = GAS_LIMITS.TRANSFER;
176− managementTx.nonce = 0;
178 // configure networking public keys
138 // configure networking public keys
179 //TODO feels like more of this logic should live in a lib?
140 //TODO feels like more of this logic should live in a lib?
180 const seed = await attemptNetworkSeedDerivation(true, {
141 const seed = await attemptNetworkSeedDerivation(true, {
181 walletType: WALLET_TYPES.TICKET,
142 walletType: WALLET_TYPES.TICKET,
@@ -193,7 +154,7 @@ async function claimPointFromInvite({
194 const networkKeys = kg.deriveNetworkKeys(networkSeed);
155 const networkKeys = kg.deriveNetworkKeys(networkSeed);
196− let keysTx = azimuth.ecliptic.configureKeys(
157+ const keysTx = azimuth.ecliptic.configureKeys(
197 contracts,
158 contracts,
199 addHexPrefix(networkKeys.crypt.public),
160 addHexPrefix(networkKeys.crypt.public),
@@ -201,43 +162,108 @@ async function claimPointFromInvite({
204− keysTx.gas = 150000;
165+ keysTx.gas = GAS_LIMITS.CONFIGURE_KEYS;
205− keysTx.nonce = 1;
166+
167+ // configure management proxy
169+ const managementTx = azimuth.ecliptic.setManagementProxy(
172+ wallet.management.keys.address
174+ managementTx.gas = GAS_LIMITS.SET_PROXY;
176+ // set spawn & voting proxies situationally
178+ let txs = [transferTmpTx, keysTx, managementTx];
180+ azimuth.azimuth.getPointSize(point) !== azimuth.azimuth.PointSize.Planet
182+ const spawnTx = azimuth.ecliptic.setSpawnProxy(
185+ wallet.spawn.keys.address
187+ spawnTx.gas = GAS_LIMITS.SET_PROXY;
191+ azimuth.azimuth.getPointSize(point) === azimuth.azimuth.PointSize.Galaxy
193+ const votingTx = azimuth.ecliptic.setVotingProxy(
196+ wallet.voting.keys.address
198+ votingTx.gas = GAS_LIMITS.SET_PROXY;
203+ // transfer configured point to user's new wallet
205+ const transferFinalTx = azimuth.ecliptic.transferPoint(
208+ wallet.ownership.keys.address,
211+ transferFinalTx.gas = GAS_LIMITS.TRANSFER;
212+ txs.push(transferFinalTx);
215+ // finalizing & signing transactions
218+ progress(TRANSACTION_STATES.SIGNING);
207− //TODO refactor this process into function
208 let totalCost = 0;
220 let totalCost = 0;
209− let txs = [managementTx, keysTx];
221+ let inviteNonce = await web3.eth.getTransactionCount(inviteAddress);
210 txs = txs.map(tx => {
222 txs = txs.map(tx => {
223+ tx.from = inviteAddress;
224+ tx.nonce = inviteNonce++;
211− tx.gasPrice = 20000000000;
225+ tx.gasPrice = 20000000000; //NOTE we pay the premium for faster ux
212− tx.from = newAddress;
213 totalCost = totalCost + tx.gasPrice * tx.gas;
226 totalCost = totalCost + tx.gasPrice * tx.gas;
214 return tx;
227 return tx;
217 let txPairs = txs.map(tx => {
230 let txPairs = txs.map(tx => {
218 let stx = new Tx(tx);
231 let stx = new Tx(tx);
219− stx.sign(Buffer.from(wallet.ownership.keys.private, 'hex'));
232+ stx.sign(Buffer.from(inviteWallet.privateKey, 'hex'));
221− raw: '0x' + stx.serialize().toString('hex'),
234+ raw: hexify(stx.serialize()),
222 signed: stx,
235 signed: stx,
240+ // ensuring funding for transactions
226− progress(TRANSACTION_STATES.FUNDING_RECIPIENT);
243+ progress(TRANSACTION_STATES.FUNDING);
228− usedTank = await tank.ensureFundsFor(
245+ const usedTank = await tank.ensureFundsFor(
231− newAddress,
248+ inviteAddress,
232 totalCost,
249 totalCost,
233 txPairs.map(p => p.raw),
250 txPairs.map(p => p.raw),
234− askForFunding
251+ askForFunding,
256+ // sending and awaiting transactions
237− progress(TRANSACTION_STATES.CONFIGURING);
259+ progress(TRANSACTION_STATES.CLAIMING);
239 await sendAndAwaitConfirm(web3, txPairs.map(p => Just(p.signed)), usedTank);
261 await sendAndAwaitConfirm(web3, txPairs.map(p => Just(p.signed)), usedTank);
264+ // move leftover eth
241 progress(TRANSACTION_STATES.CLEANING);
267 progress(TRANSACTION_STATES.CLEANING);
243 // if non-trivial eth left in invite wallet, transfer to new ownership
269 // if non-trivial eth left in invite wallet, transfer to new ownership
@@ -245,11 +271,10 @@ async function claimPointFromInvite({
245 const gasPrice = 20000000000;
271 const gasPrice = 20000000000;
246 const gasLimit = 21000;
272 const gasLimit = 21000;
247 const sendEthCost = gasPrice * gasLimit;
273 const sendEthCost = gasPrice * gasLimit;
248− if (balance > sendEthCost) {
274+ if (transferEth && balance > sendEthCost) {
249 const value = balance - sendEthCost;
275 const value = balance - sendEthCost;
250− console.log('sending', value);
251 const tx = {
276 const tx = {
252− to: newAddress,
277+ to: wallet.ownership.keys.address,
253 value: value,
278 value: value,
254 gasPrice: gasPrice,
279 gasPrice: gasPrice,
255 gas: gasLimit,
280 gas: gasLimit,
@@ -261,7 +286,6 @@ async function claimPointFromInvite({
261 web3.eth.sendSignedTransaction(rawTx).catch(err => {
286 web3.eth.sendSignedTransaction(rawTx).catch(err => {
262 console.log('error sending value tx, who cares', err);
287 console.log('error sending value tx, who cares', err);
264− console.log('sent old balance');
267 progress(TRANSACTION_STATES.DONE);
291 progress(TRANSACTION_STATES.DONE);