-
Notifications
You must be signed in to change notification settings - Fork 504
/
sagas.js
executable file
·154 lines (143 loc) · 5.12 KB
/
sagas.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import * as A from './actions'
import * as eth from '../../../utils/eth'
import {
assoc,
filter,
forEach,
head,
includes,
isEmpty,
isNil,
keys,
path,
pathOr,
prop,
toLower
} from 'ramda'
import { call, put, select } from 'redux-saga/effects'
import { callTask } from '../../../utils/functional'
import { derivationMap, ETH } from '../config'
import {
getErc20CoinList,
getSupportedCoins
} from '../../walletOptions/selectors'
import { getMetadataXpriv } from '../root/selectors'
import { getMnemonic } from '../../wallet/selectors'
import { KVStoreEntry } from '../../../types'
import { Map } from 'immutable-ext'
import { set } from 'ramda-lens'
export default ({ api, networks } = {}) => {
const deriveAccount = function * (password) {
try {
const obtainMnemonic = state => getMnemonic(state, password)
const mnemonicT = yield select(obtainMnemonic)
const mnemonic = yield callTask(mnemonicT)
const defaultIndex = 0
const addr = eth.deriveAddress(mnemonic, defaultIndex)
return { defaultIndex, addr }
} catch (e) {
throw new Error(
'[NOT IMPLEMENTED] MISSING_SECOND_PASSWORD in core.createEth saga'
)
}
}
const buildErc20Entry = (token, coinModels) => ({
label: `My ${coinModels[token].displayName} Wallet`,
contract: path([token, 'contractAddress'], coinModels),
has_seen: false,
tx_notes: {}
})
const createNewErc20Entry = function * () {
const entries = {}
const erc20List = (yield select(getErc20CoinList)).getOrFail()
const coinModels = (yield select(getSupportedCoins)).getOrFail()
forEach(token => {
entries[toLower(token)] = buildErc20Entry(token, coinModels)
}, erc20List)
return entries
}
const createEth = function * ({ kv, password }) {
const { defaultIndex, addr } = yield call(deriveAccount, password)
const erc20Entry = yield call(createNewErc20Entry)
const ethereum = {
has_seen: true,
default_account_idx: defaultIndex,
accounts: [
{
label: 'My Ether Wallet',
archived: false,
correct: true,
addr: addr
}
],
erc20: erc20Entry,
tx_notes: {},
last_tx: null,
legacy_account: null,
last_tx_timestamp: null
}
const newkv = set(KVStoreEntry.value, { ethereum }, kv)
yield put(A.createMetadataEth(newkv))
}
const createErc20 = function * ({ newkv }) {
const erc20List = (yield select(getErc20CoinList)).getOrFail()
const coinModels = (yield select(getSupportedCoins)).getOrFail()
const erc20 = pathOr({}, ['value', 'ethereum', 'erc20'], newkv)
const newTokens = filter(c => !includes(toLower(c), keys(erc20)), erc20List)
forEach(token => {
erc20[toLower(token)] = buildErc20Entry(token, coinModels)
}, newTokens)
const ethereum = assoc('erc20', erc20, newkv.value.ethereum)
const newkvErc20 = set(KVStoreEntry.value, { ethereum }, newkv)
yield put(A.fetchMetadataEthSuccess(newkvErc20))
}
const transitionFromLegacy = function * ({ newkv, password }) {
const { defaultIndex, addr } = yield call(deriveAccount, password)
const erc20Entry = yield call(createNewErc20Entry)
const defaultAccount = Map(newkv.value.ethereum.accounts[defaultIndex])
newkv.value.ethereum.legacy_account = defaultAccount.toJS()
newkv.value.ethereum.accounts[defaultIndex].addr = addr
newkv.value.ethereum.accounts[defaultIndex].correct = true
newkv.value.ethereum.erc20 = erc20Entry
yield put(A.fetchMetadataEthSuccess(newkv))
}
const updatePaxLabelToUSDDigital = function * ({ newkv }) {
const coinModels = (yield select(getSupportedCoins)).getOrFail()
newkv.value.ethereum.erc20.pax.label = `My ${coinModels['PAX'].displayName} Wallet`
yield put(A.fetchMetadataEthSuccess(newkv))
}
const fetchMetadataEth = function * (secondPasswordSagaEnhancer) {
try {
const typeId = derivationMap[ETH]
const mxpriv = yield select(getMetadataXpriv)
const kv = KVStoreEntry.fromMetadataXpriv(mxpriv, typeId, networks.btc)
yield put(A.fetchMetadataEthLoading())
const newkv = yield callTask(api.fetchKVStore(kv))
const erc20List = (yield select(getErc20CoinList)).getOrFail()
if (isNil(newkv.value) || isEmpty(newkv.value)) {
yield call(secondPasswordSagaEnhancer(createEth), { kv })
} else if (
newkv.value.ethereum &&
!prop('correct', head(newkv.value.ethereum.accounts))
) {
yield call(secondPasswordSagaEnhancer(transitionFromLegacy), { newkv })
} else if (keys(newkv.value.ethereum.erc20).length !== erc20List.length) {
// missing 1 or more supported erc20 token entries, add each to kvStore
yield call(createErc20, { newkv })
} else if (newkv.value.ethereum.erc20.pax.label === 'My USD Pax Wallet') {
yield call(updatePaxLabelToUSDDigital, { newkv })
} else {
yield put(A.fetchMetadataEthSuccess(newkv))
}
} catch (e) {
yield put(A.fetchMetadataEthFailure(e.message))
}
}
return {
createEth,
createNewErc20Entry,
deriveAccount,
fetchMetadataEth,
transitionFromLegacy
}
}