Skip to content

Commit

Permalink
feat(Blockstack): register user for blockstack airdrop
Browse files Browse the repository at this point in the history
  • Loading branch information
Philip London committed Oct 29, 2019
1 parent 3e306b4 commit f9d0da6
Show file tree
Hide file tree
Showing 16 changed files with 147 additions and 2 deletions.
15 changes: 15 additions & 0 deletions config/mocks/wallet-options-v4.json
Expand Up @@ -139,6 +139,21 @@
"txExplorerBaseUrl": "https://www.blockchain.com/eth/tx",
"txListAppRoute": "/pax/transactions"
},
"STX": {
"campaign": "BLOCKSTACK",
"coinCode": "STX",
"coinTicker": "STX",
"displayName": "Stacks",
"availability": {
"send": false,
"request": false,
"lockbox": false,
"exchangeTo": false,
"exchangeFrom": false,
"syncToPit": false
},
"hasLockboxSupport": false
},
"XLM": {
"airdrop": {
"link": "https://support.blockchain.com/hc/en-us/categories/360001126692-Crypto-Giveaway",
Expand Down
Expand Up @@ -83,6 +83,7 @@ export default ({ api, coreSagas }) => {

const saveGoals = function * (firstLogin) {
yield put(actions.goals.saveGoal('walletTour', { firstLogin }))
yield put(actions.goals.saveGoal('registerForBlockstackAirdrop'))
yield put(actions.goals.saveGoal('coinifyUpgrade'))
yield put(actions.goals.saveGoal('coinifyBuyViaCard'))
yield put(actions.goals.saveGoal('upgradeForAirdrop'))
Expand Down
26 changes: 26 additions & 0 deletions packages/blockchain-wallet-v4-frontend/src/data/goals/sagas.js
Expand Up @@ -424,6 +424,28 @@ export default ({ api }) => {
}
}

const runRegisterForBlockstackAirdropGoal = function * (goal) {
const { id } = goal
yield put(actions.goals.deleteGoal(id))
yield call(waitForUserData)
// const { current } = (yield select(
// selectors.modules.profile.getUserTiers
// )).getOrElse({ current: 0 }) || { current: 0 }
const blockstackTag = (yield select(
selectors.modules.profile.getBlockstackTag
)).getOrElse(false)
// TODO: check current === TIERS[2]
if (!blockstackTag) {
const password = null
yield put(actions.core.data.stx.generateAddress(password))
const { payload } = yield take(actions.core.data.stx.setAddress)
const { address } = payload
yield call(api.registerUserCampaign, 'BLOCKSTACK', {
'x-campaign-address': address
})
}
}

const runWalletTour = function * (goal) {
const { id, data } = goal
yield put(actions.goals.deleteGoal(id))
Expand Down Expand Up @@ -475,6 +497,7 @@ export default ({ api }) => {
upgradeForAirdrop,
walletTour
} = initialModals
// Order matters here
if (linkAccount) {
return yield put(
actions.modals.showModal(linkAccount.name, linkAccount.data)
Expand Down Expand Up @@ -527,6 +550,7 @@ export default ({ api }) => {

const runGoal = function * (goal) {
try {
// Ordering doesn't matter here
switch (goal.name) {
case 'linkAccount':
yield call(runLinkAccountGoal, goal)
Expand Down Expand Up @@ -567,6 +591,8 @@ export default ({ api }) => {
case 'walletTour':
yield call(runWalletTour, goal)
break
case 'registerForBlockstackAirdrop':
yield call(runRegisterForBlockstackAirdropGoal, goal)
}
} catch (error) {
yield put(actions.logs.logErrorMessage(logLocation, 'runGoal', error))
Expand Down
Expand Up @@ -44,6 +44,10 @@ export const getPowerPaxTag = compose(
lift(hasPath(['tags', 'POWER_PAX'])),
getUserData
)
export const getBlockstackTag = compose(
lift(path(['tags', 'BLOCKSTACK'])),
getUserData
)
export const isUserCreated = compose(
lift(equals(USER_ACTIVATION_STATES.CREATED)),
getUserActivationState
Expand Down
3 changes: 2 additions & 1 deletion packages/blockchain-wallet-v4/src/redux/data/actionTypes.js
Expand Up @@ -4,6 +4,7 @@ import * as coinify from './coinify/actionTypes'
import * as eth from './eth/actionTypes'
import * as misc from './misc/actionTypes'
import * as sfox from './sfox/actionTypes'
import * as stx from './stx/actionTypes'
import * as xlm from './xlm/actionTypes'

export { bch, btc, coinify, eth, misc, sfox, xlm }
export { bch, btc, coinify, eth, misc, sfox, stx, xlm }
3 changes: 2 additions & 1 deletion packages/blockchain-wallet-v4/src/redux/data/actions.js
Expand Up @@ -4,6 +4,7 @@ import * as coinify from './coinify/actions'
import * as eth from './eth/actions'
import * as misc from './misc/actions'
import * as sfox from './sfox/actions'
import * as stx from './stx/actions'
import * as xlm from './xlm/actions'

export { bch, btc, coinify, eth, misc, sfox, xlm }
export { bch, btc, coinify, eth, misc, sfox, stx, xlm }
2 changes: 2 additions & 0 deletions packages/blockchain-wallet-v4/src/redux/data/sagaRegister.js
Expand Up @@ -6,6 +6,7 @@ import coinify from './coinify/sagaRegister'
import eth from './eth/sagaRegister'
import misc from './misc/sagaRegister'
import sfox from './sfox/sagaRegister'
import stx from './stx/sagaRegister'
import xlm from './xlm/sagaRegister'

export default ({ api, options, networks }) =>
Expand All @@ -16,5 +17,6 @@ export default ({ api, options, networks }) =>
yield fork(eth({ api }))
yield fork(misc({ api }))
yield fork(sfox({ api, options }))
yield fork(stx())
yield fork(xlm({ api, networks }))
}
2 changes: 2 additions & 0 deletions packages/blockchain-wallet-v4/src/redux/data/sagas.js
Expand Up @@ -3,6 +3,7 @@ import btc from './btc/sagas'
import coinify from './coinify/sagas'
import eth from './eth/sagas'
import sfox from './sfox/sagas'
import stx from './stx/sagas'
import xlm from './xlm/sagas'

export default ({ api, options, networks }) => ({
Expand All @@ -11,5 +12,6 @@ export default ({ api, options, networks }) => ({
coinify: coinify({ api, options }),
eth: eth({ api }),
sfox: sfox({ api, options }),
stx: stx(),
xlm: xlm({ api, networks })
})
@@ -0,0 +1,2 @@
export const GENERATE_ADDRESS = '@CORE.DATA.GENERATE_STX_ADDRESS'
export const SET_ADDRESS = '@CORE.DATA.SET_STX_ADDRESS'
11 changes: 11 additions & 0 deletions packages/blockchain-wallet-v4/src/redux/data/stx/actions.js
@@ -0,0 +1,11 @@
import * as AT from './actionTypes'

export const generateAddress = password => ({
type: AT.GENERATE_ADDRESS,
payload: { password }
})

export const setAddress = address => ({
type: AT.SET_ADDRESS,
payload: { address }
})
15 changes: 15 additions & 0 deletions packages/blockchain-wallet-v4/src/redux/data/stx/reducers.js
@@ -0,0 +1,15 @@
import { assoc } from 'ramda'
import * as AT from './actionTypes'

const INITIAL_STATE = {
address: null
}

export default (state = INITIAL_STATE, action) => {
const { type, payload } = action
switch (type) {
case AT.SET_ADDRESS: {
return assoc('address', payload.address, state)
}
}
}
11 changes: 11 additions & 0 deletions packages/blockchain-wallet-v4/src/redux/data/stx/sagaRegister.js
@@ -0,0 +1,11 @@
import { takeLatest } from 'redux-saga/effects'
import * as AT from './actionTypes'
import sagas from './sagas'

export default () => {
const dataStxSagas = sagas()

return function * coreDataXlmSaga () {
yield takeLatest(AT.GENERATE_ADDRESS, dataStxSagas.generateAddress)
}
}
20 changes: 20 additions & 0 deletions packages/blockchain-wallet-v4/src/redux/data/stx/sagas.js
@@ -0,0 +1,20 @@
import { put, select } from 'redux-saga/effects'
import { getMnemonic } from '../../wallet/selectors'
import { callTask } from '../../../utils/functional'
import { deriveAddress } from '../../../utils/stx'
import * as A from './actions'

export default () => {
const generateAddress = function * (action) {
const { payload } = action
const { password } = payload
const mnemonicT = yield select(getMnemonic, password)
const mnemonic = yield callTask(mnemonicT)
const address = deriveAddress(mnemonic)
yield put(A.setAddress(address))
}

return {
generateAddress
}
}
Expand Up @@ -56,6 +56,8 @@ export const getXlmSendTimeOutSeconds = state =>
getSupportedCoins(state).map(path(['XLM', 'config', 'sendTimeOutSeconds']))
export const getXlmExchangeAddresses = state =>
getSupportedCoins(state).map(path(['XLM', 'exchangeAddresses']))
export const getStxCampaign = state =>
getWebOptions(state).map(path(['coins', 'STX', 'campaign']))
export const getCoinAvailability = curry((state, coin) =>
getSupportedCoins(state).map(path([toUpper(coin), 'availability']))
)
Expand Down
15 changes: 15 additions & 0 deletions packages/blockchain-wallet-v4/src/utils/stx.js
@@ -0,0 +1,15 @@
import BIP39 from 'bip39'
import Bitcoin from 'bitcoinjs-lib'

export const deriveAddress = mnemonic => {
const seed = BIP39.mnemonicToSeed(mnemonic)
const address = Bitcoin.HDNode.fromSeedBuffer(seed)
.deriveHardened(44)
.deriveHardened(5757)
.deriveHardened(0)
.derive(0)
.derive(0)
.getAddress()

return address
}
17 changes: 17 additions & 0 deletions packages/blockchain-wallet-v4/src/utils/stx.spec.js
@@ -0,0 +1,17 @@
import { deriveAddress } from './stx'

describe('deriveAddress', () => {
it('should derive correct address', () => {
expect(
deriveAddress(
'rubber recipe vote copper obtain negative erosion strong kingdom thank tomato void'
)
).toBe('1EaiavwwQY2eE2vff5JJGo89dRC13xRM7f')

expect(
deriveAddress(
'one remember hint unlock finger reform utility acid speed cushion split client bitter myself protect actor frame forward rather better mercy clay card awesome'
)
).toBe('1LJepqGsKKLPxFumnzFndsWTWsaCfkSDTp')
})
})

0 comments on commit f9d0da6

Please sign in to comment.