Skip to content

Commit

Permalink
feat(custodial): allow custodial to custodial transfers
Browse files Browse the repository at this point in the history
  • Loading branch information
schnogz committed Nov 16, 2020
1 parent 7e165a4 commit cbe704a
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import sendSagas from '../send/sagas'
import utils from './sagas.utils'

const { INTEREST_EVENTS } = model.analytics
const DEPOSIT_FORM = 'interestDepositForm'

export default ({
api,
Expand Down Expand Up @@ -177,11 +178,11 @@ export default ({

const formChanged = function * (action: FormAction) {
const form = action.meta.form
const values: InterestDepositFormType = yield select(
selectors.form.getFormValues('interestDepositForm')
)
if (form !== 'interestDepositForm') return
if (form !== DEPOSIT_FORM) return

const formValues: InterestDepositFormType = yield select(
selectors.form.getFormValues(DEPOSIT_FORM)
)
const coin = S.getCoinType(yield select())
const ratesR = S.getRates(yield select())
const userCurrency = (yield select(
Expand Down Expand Up @@ -223,27 +224,27 @@ export default ({

break
case 'interestDepositAccount':
let newPayment: PaymentValue | undefined
let custodialBalances: SBBalancesType | undefined
let depositPayment: PaymentValue
const isCustodialDeposit =
prop('type', formValues.interestDepositAccount) === 'CUSTODIAL'

yield put(A.setPaymentLoading())
// custodial deposit
if (prop('type', values.interestDepositAccount) === 'CUSTODIAL') {
const custodialBalances: SBBalancesType = (yield select(
if (isCustodialDeposit) {
custodialBalances = (yield select(
selectors.components.simpleBuy.getSBBalances
)).getOrFail('Failed to get balance')
yield call(createLimits, undefined, custodialBalances)
} else {
// non-custodial deposit
yield put(A.setPaymentLoading())
newPayment = yield call(createPayment, {
...values.interestDepositAccount,
address: getAccountIndexOrAccount(
coin,
values.interestDepositAccount
)
})

yield call(createLimits, newPayment)
yield put(A.setPaymentSuccess(newPayment))
}
depositPayment = yield call(createPayment, {
...formValues.interestDepositAccount,
address: getAccountIndexOrAccount(
coin,
formValues.interestDepositAccount
)
})
yield call(createLimits, depositPayment, custodialBalances)
yield put(A.setPaymentSuccess(depositPayment))
}
}

Expand Down Expand Up @@ -309,7 +310,7 @@ export default ({
yield call(createLimits, payment)
yield put(A.setPaymentSuccess(payment))
yield put(
initialize('interestDepositForm', {
initialize(DEPOSIT_FORM, {
interestDepositAccount: defaultAccountR.getOrElse(),
coin,
currency
Expand Down Expand Up @@ -350,44 +351,63 @@ export default ({
}

const sendDeposit = function * () {
const FORM = 'interestDepositForm'

try {
yield put(actions.form.startSubmit(FORM))
yield put(actions.form.startSubmit(DEPOSIT_FORM))
const formValues: InterestDepositFormType = yield select(
selectors.form.getFormValues(DEPOSIT_FORM)
)
const isCustodialDeposit =
prop('type', formValues.interestDepositAccount) === 'CUSTODIAL'
const coin = S.getCoinType(yield select())
yield call(fetchInterestAccount, coin)
const depositAddress = yield select(S.getDepositAddress)
const paymentR = S.getPayment(yield select())
let payment = paymentGetOrElse(
const payment = paymentGetOrElse(
coin,
paymentR as RemoteDataType<string, any>
)
// build and publish payment to network
const depositTx = yield call(
buildAndPublishPayment,
coin,
payment,
depositAddress
)
// notify backend of incoming non-custodial deposit
yield put(
actions.components.send.notifyNonCustodialToCustodialTransfer(
depositTx,
'SAVINGS'
if (isCustodialDeposit) {
const { amount } = payment.value()
// custodial deposit
yield call(
// @ts-ignore
api.initiateCustodialTransfer,
amount && amount[0].toString(),
coin,
'SAVINGS',
'SIMPLEBUY'
)
)
} else {
// non-custodial deposit
yield call(fetchInterestAccount, coin)
const depositAddress = yield select(S.getDepositAddress)

// build and publish payment to network
const depositTx = yield call(
buildAndPublishPayment,
coin,
payment,
depositAddress
)
// notify backend of incoming non-custodial deposit
yield put(
actions.components.send.notifyNonCustodialToCustodialTransfer(
depositTx,
'SAVINGS'
)
)
}

// notify UI of success
yield put(actions.form.stopSubmit(FORM))
yield put(actions.form.stopSubmit(DEPOSIT_FORM))
yield put(A.setInterestStep('ACCOUNT_SUMMARY', { depositSuccess: true }))
yield put(
actions.analytics.logEvent(INTEREST_EVENTS.DEPOSIT.SEND_SUCCESS)
)
yield delay(1500)
yield delay(2500)
yield put(A.fetchInterestBalance())
yield put(actions.router.push('/interest/history'))
} catch (e) {
const error = errorHandler(e)
yield put(actions.form.stopSubmit(FORM, { _error: error }))
yield put(actions.form.stopSubmit(DEPOSIT_FORM, { _error: error }))
yield put(
A.setInterestStep('ACCOUNT_SUMMARY', { depositSuccess: false, error })
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,16 @@ export default ({ coreSagas, networks }: { coreSagas: any; networks: any }) => {
})

const createLimits = function * (
payment?: PaymentValue,
balances?: SBBalancesType
payment: PaymentValue,
custodialBalances?: SBBalancesType
) {
try {
const coin = S.getCoinType(yield select())
const limitsR = S.getInterestLimits(yield select())
const limits = limitsR.getOrFail('NO_LIMITS_AVAILABLE')
const balance = payment && payment.effectiveBalance
const custodialBalance = balances && balances[coin]?.available
const custodialBalance =
custodialBalances && custodialBalances[coin]?.available
const ratesR = S.getRates(yield select())
const rates = ratesR.getOrElse({} as RatesType)
const userCurrency = (yield select(
Expand All @@ -43,47 +44,47 @@ export default ({ coreSagas, networks }: { coreSagas: any; networks: any }) => {
switch (coin) {
case 'BCH':
maxFiat = Exchange.convertBchToFiat({
value: balance || custodialBalance || 0,
value: custodialBalance || balance || 0,
fromUnit: 'SAT',
toCurrency: userCurrency,
rates
}).value
break
case 'BTC':
maxFiat = Exchange.convertBtcToFiat({
value: balance || custodialBalance || 0,
value: custodialBalance || balance || 0,
fromUnit: 'SAT',
toCurrency: userCurrency,
rates
}).value
break
case 'ETH':
maxFiat = Exchange.convertEthToFiat({
value: balance || custodialBalance || 0,
value: custodialBalance || balance || 0,
fromUnit: 'WEI',
toCurrency: userCurrency,
rates
}).value
break
case 'PAX':
maxFiat = Exchange.convertPaxToFiat({
value: balance || custodialBalance || 0,
value: custodialBalance || balance || 0,
fromUnit: 'WEI',
toCurrency: userCurrency,
rates
}).value
break
case 'USDT':
maxFiat = Exchange.convertUsdtToFiat({
value: balance || custodialBalance || 0,
value: custodialBalance || balance || 0,
fromUnit: 'WEI',
toCurrency: userCurrency,
rates
}).value
break
case 'XLM':
maxFiat = Exchange.convertXlmToFiat({
value: balance || custodialBalance || 0,
value: custodialBalance || balance || 0,
fromUnit: 'STROOP',
toCurrency: userCurrency,
rates
Expand Down
21 changes: 20 additions & 1 deletion packages/blockchain-wallet-v4/src/network/api/custodial/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,31 @@ export default ({ authorizedGet, authorizedPost, nabuUrl }) => {
}
})

const initiateCustodialTransfer = (
amount: string,
currency: CoinType,
destination: NabuCustodialProductType,
origin: NabuCustodialProductType
) =>
authorizedPost({
url: nabuUrl,
endPoint: '/custodial/transfer',
contentType: 'application/json',
data: {
amount,
currency,
destination,
origin
}
})

return {
checkWithdrawalLocks,
getBeneficiaries,
getWithdrawalLocks,
getWithdrawalFees,
initiateCustodialTransfer,
notifyNonCustodialToCustodialTransfer,
checkWithdrawalLocks,
withdrawFunds
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ type WithdrawalLockCheckRule = {
insertedAt: string
isActive: boolean
lockTime: number
paymenthMethod: 'CARD'
paymentMethod: 'CARD'
updatedAt: string
}

Expand Down

0 comments on commit cbe704a

Please sign in to comment.