@rhino.fi/client-js
Version:
118 lines (103 loc) • 3.15 kB
JavaScript
const {
Joi,
toQuantizedAmountBN,
} = require('@rhino.fi/dvf-utils')
const validateWithJoi = require('../validators/validateWithJoi')
const DVFError = require('./DVFError')
const makeCreateSignedTransferTx = require('./makeCreateSignedTransferTx')
const getSafeQuantizedAmountOrThrow = require(
'./token/getSafeQuantizedAmountOrThrow',
)
const getValidTokenInfo = dvf => token => {
const tokenInfo = dvf.token.getTokenInfoOrThrow(token)
if (!tokenInfo.starkVaultId) {
throw new DVFError(
'NO_STARK_VAULT_ID_FOR_TOKEN',
{ token, context: 'createTransferPayload' },
)
}
return tokenInfo
}
const transferDataSchema = Joi.object({
amount: Joi.amount(),
// NOTE: we are not specifying allowed tokens here since these can change
// dynamically. However a call to `getTokenInfoOrThrow` will ensure that
// the token in valid.
memo: Joi.string().optional(),
partnerId: Joi.string().optional(),
token: Joi.string(),
recipientPublicKey: Joi.prefixedHexString(),
recipientVaultId: Joi.number().integer(),
})
const feeRecipientSchema = Joi.object({
starkKey: Joi.prefixedHexString(),
vaultId: Joi.number().integer(),
})
const errorProps = { context: 'transferUsingVaultIdAndStarkKey' }
const validateArg0 = validateWithJoi(transferDataSchema)(
'INVALID_METHOD_ARGUMENT',
)({
...errorProps,
argIdx: 0,
})
const validateArg1 = validateWithJoi(feeRecipientSchema)(
'INVALID_METHOD_ARGUMENT',
)({
...errorProps,
argIdx: 1,
})
module.exports = async (
dvf,
transferData,
feesRecipient,
createSignedTransferTx = makeCreateSignedTransferTx(dvf),
) => {
const {
amount,
token,
recipientPublicKey,
recipientVaultId,
memo,
partnerId,
} = validateArg0(transferData)
const tokenInfo = getValidTokenInfo(dvf)(token)
const quantisedAmount = getSafeQuantizedAmountOrThrow(amount, tokenInfo)
// tokenInfo.transferFee from conf as fee switch
if (!tokenInfo.transferFee || !feesRecipient) {
console.warn(
'No fees set for token or not recipient. Skipping fee tx',
token,
feesRecipient,
)
return createSignedTransferTx({
recipientPublicKey,
recipientVaultId,
tokenInfo,
quantisedAmount,
})
}
// Fees are handled by deducting from the requested amount
// Two distinct txs are created : tx and feeTx with amount defined in conf
// On the server side, the two txs are processed atomically and
// fee amount and recipient are checked against current configuration
const {
starkKey: feeStarkKey,
vaultId: feeVaultId,
} = validateArg1(feesRecipient)
const feeAmount = toQuantizedAmountBN(tokenInfo, tokenInfo.transferFee)
// Sign fees tx
const { tx: feeTx } = await createSignedTransferTx({
recipientPublicKey: feeStarkKey,
recipientVaultId: feeVaultId,
tokenInfo,
quantisedAmount: feeAmount,
})
// Sign main tx
const { starkPublicKey, tx } = await createSignedTransferTx({
recipientPublicKey,
recipientVaultId,
tokenInfo,
quantisedAmount: quantisedAmount.minus(feeAmount),
})
return { tx, feeTx, starkPublicKey, memo, partnerId }
}