Skip to content

Commit

Permalink
Create domain models
Browse files Browse the repository at this point in the history
First step for creating a layered architecture for connector
interledger-deprecated/five-bells-ledger#112
  • Loading branch information
Alan Cohen committed Mar 11, 2016
1 parent f95b0fd commit 7fbd757
Show file tree
Hide file tree
Showing 10 changed files with 238 additions and 181 deletions.
14 changes: 2 additions & 12 deletions src/controllers/metadata.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
'use strict'
const config = require('../services/config')

const metadata = {
public_key: config.getIn(['keys', 'ed25519', 'public']),
urls: {
health: '/health',
pairs: '/pairs',
payment: '/payments/:uuid',
quote: '/quote',
notifications: '/notifications'
}
}
const model = require('../models/metadata')

/**
* @api {get} / Get the server metadata
Expand All @@ -22,4 +12,4 @@ const metadata = {
*
* @returns {void}
*/
exports.getResource = function * () { this.body = metadata }
exports.getResource = function * () { this.body = model.getMetadata() }
10 changes: 3 additions & 7 deletions src/controllers/notifications.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
'use strict'

const requestUtil = require('five-bells-shared/utils/request')
const Payments = require('../services/payments')
const log = require('../services/log')('notifications')
const model = require('../models/notifications')

/* eslint-disable */
/**
Expand Down Expand Up @@ -59,13 +59,9 @@ const log = require('../services/log')('notifications')
/* eslint-enable */

exports.post = function * postNotification () {
let notification = yield requestUtil.validateBody(this, 'Notification')

const notification = yield requestUtil.validateBody(this, 'Notification')
log.debug('Got notification: ' + JSON.stringify(notification))

if (notification.event === 'transfer.update') {
yield Payments.updateTransfer(notification.resource, notification.related_resources)
}
yield model.processNotification(notification)

this.status = 200
}
15 changes: 2 additions & 13 deletions src/controllers/pairs.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict'

const config = require('../services/config')
const model = require('../models/pairs')

/* eslint-disable */
/**
Expand Down Expand Up @@ -36,16 +36,5 @@ const config = require('../services/config')
*/
/* eslint-enable */
exports.getCollection = function * getCollection () {
let pairs = config.get('tradingPairs').map(function (pair) {
let currencies = pair.map(function (s) {
return s.split('@')
})
return {
source_asset: currencies[0][0],
source_ledger: currencies[0][1],
destination_asset: currencies[1][0],
destination_ledger: currencies[1][1]
}
})
this.body = pairs
this.body = model.getPairs()
}
21 changes: 7 additions & 14 deletions src/controllers/payments.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
const requestUtil = require('five-bells-shared/utils/request')
const InvalidBodyError = require('five-bells-shared/errors/invalid-body-error')
const config = require('../services/config')
const Payments = require('../services/payments')
const settlementQueue = require('../services/settlementQueue')
const ledgers = require('../services/ledgers')
const model = require('../models/payments')

/* eslint-disable */
/**
Expand Down Expand Up @@ -124,30 +123,24 @@ const ledgers = require('../services/ledgers')
exports.put = function * (id) {
// TODO: check that this UUID hasn't been used before
requestUtil.validateUriParameter('id', id, 'Uuid')
let payment = yield requestUtil.validateBody(this, 'Payment')
let paymentData = yield requestUtil.validateBody(this, 'Payment')

let result = ledgers.validatePayment(payment)
let result = ledgers.validatePayment(paymentData)
if (!result.valid) {
throw new InvalidBodyError('Failed to parse Payment: ' + JSON.stringify(result))
}

if (typeof payment.id !== 'undefined') {
if (typeof paymentData.id !== 'undefined') {
requestUtil.assert.strictEqual(
payment.id,
paymentData.id,
config.getIn(['server', 'base_uri']) + this.originalUrl,
'Payment ID must match the one in the URL'
)
}

payment.id = id.toLowerCase()

yield Payments.validate(payment)
const trustedPayment = settlementQueue.storePayment(payment)
if (trustedPayment) {
yield Payments.settle(trustedPayment)
payment = trustedPayment
}
const payment = yield model.create(paymentData)

payment.id = id.toLowerCase()
// Externally we want to use a full URI ID
payment.id = config.getIn(['server', 'base_uri']) + '/payments/' + payment.id

Expand Down
137 changes: 2 additions & 135 deletions src/controllers/quote.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
'use strict'

const request = require('co-request')
const BigNumber = require('bignumber.js')
const config = require('../services/config')
const log = require('../services/log')('quote')
const backend = require('../services/backend')
const ledgers = require('../services/ledgers')
const balanceCache = require('../services/balance-cache')
const UnacceptableExpiryError = require('../errors/unacceptable-expiry-error')
const UnacceptableAmountError = require('../errors/unacceptable-amount-error')
const ExternalError = require('../errors/external-error')
const model = require('../models/quote')

/* eslint-disable */
/**
Expand Down Expand Up @@ -118,130 +109,6 @@ const ExternalError = require('../errors/external-error')
/* eslint-enable */

exports.get = function * () {
const query = yield makeQuoteQuery(this.query)
const quote = yield backend.getQuote(makeQuoteArgs(query))

const sourceBalance = yield balanceCache.get(query.source_ledger)
const sourceAmount = new BigNumber(quote.source_amount)
if (sourceBalance.lessThan(sourceAmount)) {
throw new UnacceptableAmountError('Insufficient liquidity in market maker account')
}

log.debug('' +
quote.source_amount + ' ' +
query.source_ledger + ' => ' +
quote.destination_amount + ' ' +
query.destination_ledger)

this.body = makePaymentTemplate(query, quote)
this.body = yield model.getQuote(this.query)
}

function * makeQuoteQuery (params) {
// TODO: include the expiry duration in the quote logic
let destinationExpiryDuration = parseFloat(params.destination_expiry_duration)
let sourceExpiryDuration = parseFloat(params.source_expiry_duration)

// Check destination_expiry_duration
if (destinationExpiryDuration) {
if (destinationExpiryDuration > config.getIn(['expiry', 'maxHoldTime'])) {
throw new UnacceptableExpiryError('Destination expiry duration ' +
'is too long, destinationExpiryDuration: ' + destinationExpiryDuration +
', maxHoldTime: ' + config.getIn(['expiry', 'maxHoldTime']))
}
} else if (sourceExpiryDuration) {
destinationExpiryDuration = sourceExpiryDuration - config.getIn(['expiry', 'minMessageWindow'])
} else {
destinationExpiryDuration = config.getIn(['expiry', 'maxHoldTime'])
}

// Check difference between destination_expiry_duration
// and source_expiry_duration
if (sourceExpiryDuration) {
if (sourceExpiryDuration - destinationExpiryDuration <
config.getIn(['expiry', 'minMessageWindow'])) {
throw new UnacceptableExpiryError('The difference between the ' +
'destination expiry duration and the source expiry duration ' +
'is insufficient to ensure that we can execute the ' +
'source transfers')
}
} else {
sourceExpiryDuration = destinationExpiryDuration + config.getIn(['expiry', 'minMessageWindow'])
}

let source_ledger = params.source_ledger
if (!source_ledger) {
if (params.source_account) source_ledger = yield getAccountLedger(params.source_account)
else throw new Error('Missing required parameter: source_ledger or source_account')
}

let destination_ledger = params.destination_ledger
if (!destination_ledger) {
if (params.destination_account) destination_ledger = yield getAccountLedger(params.destination_account)
else throw new Error('Missing required parameter: destination_ledger or destination_account')
}

return {
destinationExpiryDuration: destinationExpiryDuration,
sourceExpiryDuration: sourceExpiryDuration,
source_amount: params.source_amount,
destination_amount: params.destination_amount,
source_ledger: source_ledger,
destination_ledger: destination_ledger,
source_account: params.source_account || null,
destination_account: params.destination_account || null
}
}

function makeQuoteArgs (query) {
return {
source_ledger: query.source_ledger,
destination_ledger: query.destination_ledger,
source_amount: query.source_amount,
destination_amount: query.destination_amount
}
}

function makePaymentTemplate (query, quote) {
const source_amount = quote.source_amount
const destination_amount = quote.destination_amount
const payment = {
source_transfers: [{
type: ledgers.getType(query.source_ledger),
ledger: query.source_ledger,
debits: [{
account: query.source_account,
amount: source_amount
}],
credits: [
ledgers.makeFundTemplate(query.source_ledger, {amount: source_amount})
],
expiry_duration: String(query.sourceExpiryDuration)
}],
destination_transfers: [{
type: ledgers.getType(query.destination_ledger),
ledger: query.destination_ledger,
debits: [
ledgers.makeFundTemplate(query.destination_ledger, {amount: destination_amount})
],
credits: [{
account: query.destination_account,
amount: destination_amount
}],
expiry_duration: String(query.destinationExpiryDuration)
}]
}
return payment
}

function * getAccountLedger (account) {
const res = yield request({
method: 'get',
uri: account,
json: true
})
const ledger = res.body && res.body.ledger
if (res.statusCode !== 200 || !ledger) {
throw new ExternalError('Unable to identify ledger from account: ' + account)
}
return ledger
}
20 changes: 20 additions & 0 deletions src/models/metadata.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use strict'

const config = require('../services/config')

function getMetadata () {
return {
public_key: config.getIn(['keys', 'ed25519', 'public']),
urls: {
health: '/health',
pairs: '/pairs',
payment: '/payments/:uuid',
quote: '/quote',
notifications: '/notifications'
}
}
}

module.exports = {
getMetadata: getMetadata
}
13 changes: 13 additions & 0 deletions src/models/notifications.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
'use strict'

const Payments = require('../services/payments')

function * processNotification (notification) {
if (notification.event === 'transfer.update') {
yield Payments.updateTransfer(notification.resource, notification.related_resources)
}
}

module.exports = {
processNotification: processNotification
}
22 changes: 22 additions & 0 deletions src/models/pairs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use strict'

const config = require('../services/config')

function getPairs () {
const tradingPairs = config.get('tradingPairs')
return tradingPairs.map((pair) => {
const currencies = pair.map(function (currencyLedgerString) {
return currencyLedgerString.split('@')
})
return {
source_asset: currencies[0][0],
source_ledger: currencies[0][1],
destination_asset: currencies[1][0],
destination_ledger: currencies[1][1]
}
})
}

module.exports = {
getPairs: getPairs
}
22 changes: 22 additions & 0 deletions src/models/payments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use strict'

const _ = require('lodash')
const paymentsService = require('../services/payments')
const settlementQueue = require('../services/settlementQueue')

function * create (paymentData) {
const payment = _.cloneDeep(paymentData)

yield paymentsService.validate(payment)
const trustedPayment = settlementQueue.storePayment(payment)
if (trustedPayment) {
yield paymentsService.settle(trustedPayment)
return trustedPayment
}

return payment
}

module.exports = {
create: create
}
Loading

0 comments on commit 7fbd757

Please sign in to comment.