Skip to content
This repository has been archived by the owner on Dec 12, 2024. It is now read-only.

Commit

Permalink
Handle requiredPaymentDetails undefined for RFQ verification
Browse files Browse the repository at this point in the history
  • Loading branch information
Diane Huxley committed Jan 20, 2024
1 parent e1897d6 commit c6aae4c
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 6 deletions.
13 changes: 9 additions & 4 deletions packages/protocol/src/message-kinds/rfq.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,21 +112,26 @@ export class Rfq extends Message<'rfq'> {
const paymentMethodMatches = allowedPaymentMethods.filter(paymentMethod => paymentMethod.kind === rfqPaymentMethod.kind)

if (!paymentMethodMatches.length) {
const paymentMethodKinds = allowedPaymentMethods.map(paymentMethod => paymentMethod.kind).join()
const paymentMethodKinds = allowedPaymentMethods.map(paymentMethod => paymentMethod.kind).join(', ')
throw new Error(
`offering does not support rfq's ${payDirection}Method kind. (rfq) ${rfqPaymentMethod.kind} was not found in: ${paymentMethodKinds} (offering)`
`offering does not support rfq's ${payDirection}Method kind. (rfq) ${rfqPaymentMethod.kind} was not found in: [${paymentMethodKinds}] (offering)`
)
}

const ajv = new Ajv.default()
const invalidPaymentDetailsErrors = new Set()

// Only one matching paymentMethod is needed
for (const paymentMethodMatch of paymentMethodMatches) {
if (!paymentMethodMatch.requiredPaymentDetails) {
// The offering does not required any payment details for this kind of payment method
return
}

const validate = ajv.compile(paymentMethodMatch.requiredPaymentDetails)
const isValid = validate(rfqPaymentMethod.paymentDetails)
if (isValid) {
break
// Selected payment method matches one of the offering's allowed payment methods
return
}
invalidPaymentDetailsErrors.add(validate.errors)
}
Expand Down
75 changes: 74 additions & 1 deletion packages/protocol/tests/rfq.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { CreateRfqOptions, Offering } from '../src/main.js'
import { CreateRfqOptions, Offering } from '../src/main.js'

import { Rfq, DevTools } from '../src/main.js'
import { Convert } from '@web5/common'
Expand Down Expand Up @@ -281,6 +281,79 @@ describe('Rfq', () => {
expect(e.message).to.include('rfq payoutMethod paymentDetails could not be validated against offering requiredPaymentDetails')
}
})

it('accepts selected payment method if it matches one but not all of the Offerings requiredPaymentDetails of matching kind', async () => {
// scenario: An offering has two payin methods with kind 'card'. One payin method requires property 'cardNumber' and 'pin' in the RFQ's selected
// payin method. The second payin method only requires 'cardNumber'. An RFQ has selected payin method with kind 'card' and only
// payment detail 'cardNumber', so it matches the Offering's second payin method but not the first. The RFQ is valid against the offering.
const offeringData = DevTools.createOfferingData()

// Supply Offering with two payin methods of kind 'card'.
// The first requires 'cardNumber' and 'pin'. The second only requires 'cardNumber'.
offeringData.requiredClaims = undefined
offeringData.payinMethods = [
{
kind : 'card',
requiredPaymentDetails : {
$schema : 'http://json-schema.org/draft-07/schema',
type : 'object',
properties : {
cardNumber: {
type: 'string'
},
pin: {
type: 'string'
},
},
required : ['cardNumber', 'pin'],
additionalProperties : false
}
},
{
kind : 'card',
requiredPaymentDetails : {
$schema : 'http://json-schema.org/draft-07/schema',
type : 'object',
properties : {
cardNumber: {
type: 'string'
}
},
required : ['cardNumber'],
additionalProperties : false
}
}
]

const pfi = await DevTools.createDid()

const offering = Offering.create({
metadata : { from: pfi.did },
data : offeringData,
})
await offering.sign(pfi)

// Construct RFQ with a payin method that has payin detail 'cardNumber'
const alice = await DevTools.createDid()
const rfqData = await DevTools.createRfqData()
rfqData.offeringId = offering.metadata.id
rfqData.payinMethod = {
kind : 'card',
paymentDetails : {
cardNumber: '1234'
}
}
const rfq = Rfq.create({
metadata: {
from : alice.did,
to : pfi.did,
},
data: rfqData,
})
await rfq.sign(alice)

await rfq.verifyOfferingRequirements(offering)
})
})

describe('verifyClaims', () => {
Expand Down
2 changes: 1 addition & 1 deletion tbdex

0 comments on commit c6aae4c

Please sign in to comment.