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

Commit a0ec665

Browse files
authored
Implement verifyClaims (#154)
* bump typescript version * change `offering.vcRequirements` to `offering.requiredClaims` and `rfq.vcs` to `rfq.claims` * version bump
1 parent 94fc7b8 commit a0ec665

File tree

17 files changed

+167
-76
lines changed

17 files changed

+167
-76
lines changed

README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ An `Offering` is used by the PFI to describe a currency pair they have to _offer
100100
| `quoteUnitsPerBaseUnit` | string | Y | Number of quote units on offer for one base currency unit (i.e 290000 USD for 1 BTC |
101101
| `baseCurrency` | [`CurrencyDetails`](#currencydetails) | Y | Details about the currency that the PFI is selling. |
102102
| `quoteCurrency` | [`CurrencyDetails`](#currencydetails) | Y | Details about the currency that the PFI is accepting as payment for `baseCurrency`. |
103-
| `vcRequirements` | [`PresentationDefinitionV2`](https://identity.foundation/presentation-exchange/#presentation-definition) | Y | Articulates the credential(s) required when submitting an RFQ for this offering. |
103+
| `requiredClaims` | [`PresentationDefinitionV2`](https://identity.foundation/presentation-exchange/#presentation-definition) | Y | Articulates the claim(s) required when submitting an RFQ for this offering. |
104104
| `payinMethods` | [`PaymentMethod[]`](#paymentmethod) | Y | A list of payment methods the counterparty (Alice) can choose to send payment to the PFI from in order to qualify for this offering. |
105105
| `payoutMethods` | [`PaymentMethod[]`](#paymentmethod) | Y | A list of payment methods the counterparty (Alice) can choose to receive payment from the PFI in order to qualify for this offering. |
106106
| `createdAt` | datetime | Y | The creation time of the resource. Expressed as ISO8601 |
@@ -385,13 +385,13 @@ Base64-encoded data is safe for transmission over most protocols and systems sin
385385
### `RFQ (Request For Quote)`
386386
> Alice -> PFI: "OK, that offering looks good. Give me a Quote against that Offering, and here is how much USD (quote currency) I want to trade for BTC (base currency). Here are the credentials you're asking for, the payment method I intend to pay you USD with, and the payment method I expect you to pay me BTC in."
387387
388-
| field | data type | required | description |
389-
| --------------------- | ------------------------------------------------- | -------- | ------------------------------------------------------------------------------------------------------------------- |
390-
| `offeringId` | string | Y | Offering which Alice would like to get a quote for |
391-
| `quoteAmountSubunits` | string | Y | Amount of quote currency you want to spend in order to receive base currency |
392-
| `vcs` | string | Y | VerifiablePresentation in JWT string format that meets the specification per PresentationDefinition in the Offering |
393-
| `payinMethod` | [`SelectedPaymentMethod`](#selectedpaymentmethod) | Y | Specify which payment method to send quote currency. |
394-
| `payoutMethod` | [`SelectedPaymentMethod`](#selectedpaymentmethod) | Y | Specify which payment method to receive base currency. |
388+
| field | data type | required | description |
389+
| --------------------- | ------------------------------------------------- | -------- | ------------------------------------------------------------------------------------- |
390+
| `offeringId` | string | Y | Offering which Alice would like to get a quote for |
391+
| `quoteAmountSubunits` | string | Y | Amount of quote currency you want in exchange for base currency |
392+
| `claims` | string[] | Y | an array of claims that fulfill the requirements declared in an [Offering](#offering) |
393+
| `payinMethod` | [`SelectedPaymentMethod`](#selectedpaymentmethod) | Y | Specify which payment method to send quote currency. |
394+
| `payoutMethod` | [`SelectedPaymentMethod`](#selectedpaymentmethod) | Y | Specify which payment method to receive base currency. |
395395

396396
#### `SelectedPaymentMethod`
397397
| field | data type | required | description |

js/package-lock.json

Lines changed: 7 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@tbd54566975/tbdex",
3-
"version": "0.3.0",
3+
"version": "0.4.0",
44
"type": "module",
55
"description": "Library that includes type definitions for tbdex messages",
66
"license": "Apache-2.0",
@@ -85,12 +85,12 @@
8585
"sinon": "15.0.2",
8686
"typedoc": "0.25.0",
8787
"typedoc-plugin-markdown": "3.16.0",
88-
"typescript": "5.0.4"
88+
"typescript": "5.2.2"
8989
},
9090
"scripts": {
9191
"clean": "rimraf generated dist tests/compiled",
9292
"compile-validators": "rimraf generated && node build/compile-validators.js",
93-
"build:esm": "rimraf dist/esm dist/types && npx tsc -p tsconfig.json",
93+
"build:esm": "rimraf dist/esm dist/types && tsc",
9494
"build:cjs": "rimraf dist/cjs && npx tsc -p tsconfig.cjs.json && echo '{\"type\": \"commonjs\"}' > ./dist/cjs/package.json",
9595
"build:browser": "rimraf dist/browser.mjs dist/browser.js && node build/bundles.js",
9696
"test:node": "rimraf tests/compiled && npm run compile-validators && tsc -p tests/tsconfig.json && mocha",

js/src/dev-tools.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { Convert } from '@web5/common'
88
import { Rfq } from './message-kinds/index.js'
99
import { Offering } from './resource-kinds/index.js'
1010
import { Crypto } from './crypto.js'
11-
import { OfferingModel, RfqModel } from './types.js'
11+
import { OfferingData, RfqData } from './types.js'
1212

1313
export type DidMethodOptions = 'key' | 'ion'
1414

@@ -61,7 +61,7 @@ export class DevTools {
6161
* creates and returns an example offering. Useful for testing purposes
6262
*/
6363
static createOffering() {
64-
const offeringData: OfferingModel = {
64+
const offeringData: OfferingData = {
6565
description : 'Selling BTC for USD',
6666
baseCurrency : {
6767
currencyCode : 'BTC',
@@ -118,7 +118,7 @@ export class DevTools {
118118
additionalProperties : false
119119
}
120120
}],
121-
vcRequirements: {
121+
requiredClaims: {
122122
id : '7ce4004c-3c38-4853-968b-e411bafcd945',
123123
input_descriptors : [{
124124
id : 'bbdb9b7c-5754-4f46-b63b-590bada959e0',
@@ -146,11 +146,11 @@ export class DevTools {
146146
* creates and returns an example rfq for the offering returned by {@link DevTools.createOffering}.
147147
* Useful for testing purposes.
148148
*
149-
* **NOTE**: generates a random credential that fulfills the vcRequirements of the offering
149+
* **NOTE**: generates a random credential that fulfills the offering's required claims
150150
*/
151151
static async createRfq(opts: RfqOptions) {
152152
const { sender } = opts
153-
const { signedCredential: _signedCredential } = await DevTools.createCredential({
153+
const { signedCredential } = await DevTools.createCredential({
154154
type : 'YoloCredential',
155155
issuer : sender,
156156
subject : sender.did,
@@ -159,7 +159,7 @@ export class DevTools {
159159
}
160160
})
161161

162-
const rfqData: RfqModel = {
162+
const rfqData: RfqData = {
163163
offeringId : 'abcd123',
164164
payinMethod : {
165165
kind : 'DEBIT_CARD',
@@ -177,7 +177,7 @@ export class DevTools {
177177
}
178178
},
179179
quoteAmountSubunits : '20000',
180-
vcs : ''
180+
claims : [signedCredential]
181181
}
182182

183183
return Rfq.create({

js/src/did-resolver.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ export async function deferenceDidUrl(didUrl: string): Promise<DidResource> {
5555
// create a set of possible id matches. the DID spec allows for an id to be the entire did#fragment or just #fragment.
5656
// See: https://www.w3.org/TR/did-core/#relative-did-urls
5757
// using a set for fast string comparison. DIDs can be lonnng.
58-
// TODO: check to see if parsedDid.fragment includes a '#'
5958
const idSet = new Set([didUrl, parsedDid.fragment, `#${parsedDid.fragment}`])
6059

6160
for (let vm of verificationMethod) {

js/src/message-kinds/close.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,7 @@ export type CreateCloseOptions = {
77
metadata: Omit<MessageMetadata<'close'>, 'id' |'kind' | 'createdAt'>
88
}
99

10-
/**
11-
* a Close can be sent by Alice or the PFI as a reply to an RFQ or a Quote
12-
*/
10+
/** a Close can be sent by Alice or the PFI as a reply to an RFQ or a Quote */
1311
export class Close extends Message<'close'> {
1412
/** a set of valid Message kinds that can come after a close */
1513
readonly validNext = new Set<MessageKind>([])

js/src/message-kinds/order.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export type CreateOrderOptions = {
77
private?: Record<string, any>
88
}
99

10+
/** Message sent by Alice to the PFI to accept a Quote. */
1011
export class Order extends Message<'order'> {
1112
readonly validNext = new Set<MessageKind>(['orderstatus'])
1213

js/src/message-kinds/rfq.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,16 @@ export class Rfq extends Message<'rfq'> {
5252
// TODO: validate rfq's payoutMethod.kind against offering's payoutMethods
5353
// TODO: validate rfq's payoutMethod.paymentDetails against offering's respective requiredPaymentDetails json schema
5454

55-
this.verifyCredentialRequirements(offering)
55+
this.verifyClaims(offering)
5656
}
5757

5858
/**
59-
* checks the claims provided in this rfq against the provided offering's requirements
59+
* checks the claims provided in this rfq against an offering's requirements
6060
* @param offering - the offering to check against
61-
* @throws
61+
* @throws if rfq's claims do not fulfill the offering's requirements
6262
*/
63-
verifyCredentialRequirements(offering: Offering | ResourceModel<'offering'>) {
64-
const { areRequiredCredentialsPresent } = pex.evaluatePresentation(offering.data.vcRequirements, this.vcs)
63+
verifyClaims(offering: Offering | ResourceModel<'offering'>) {
64+
const { areRequiredCredentialsPresent } = pex.evaluateCredentials(offering.data.requiredClaims, this.claims)
6565

6666
if (areRequiredCredentialsPresent === 'error') {
6767
throw new Error(`claims do not fulfill the offering's requirements`)
@@ -81,8 +81,8 @@ export class Rfq extends Message<'rfq'> {
8181
}
8282

8383
/** Presentation Submission VP that fulfills the requirements included in the respective Offering */
84-
get vcs() {
85-
return this.data.vcs
84+
get claims() {
85+
return this.data.claims
8686
}
8787

8888
/** Selected payment method that Alice will use to send the listed quote currency to the PFI. */

js/src/message.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,8 @@ export class Message<T extends MessageKind> {
8888
/**
8989
* signs the message as a jws with detached content and sets the signature property
9090
* @param privateKeyJwk - the key to sign with
91-
* @param kid - the kid to include in the jws header. used by the verifier to select the appropriate verificationMethod
92-
* when dereferencing the signer's DID
91+
* @param kid - the verification method id to include in the jws header. used by the verifier to
92+
* select the appropriate verificationMethod when dereferencing the signer's DID
9393
*/
9494
async sign(privateKeyJwk: Web5PrivateKeyJwk, kid: string): Promise<void> {
9595
const toSign = { metadata: this.metadata, data: this.data }

js/src/pfi-rest-api/client.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { ResourceMetadata, MessageModel, OfferingModel, ResourceModel, MessageKind } from '../types.js'
1+
import type { ResourceMetadata, MessageModel, OfferingData, ResourceModel, MessageKind } from '../types.js'
22
import type { DataResponse, ErrorDetail, ErrorResponse, HttpResponse } from './types.js'
33
import type { PrivateKeyJwk as Web5PrivateKeyJwk } from '@web5/crypto'
44

@@ -27,9 +27,9 @@ export type GetOfferingsOptions = {
2727
pfiDid: string
2828
params?: {
2929
/** ISO 3166 currency code string */
30-
baseCurrency: OfferingModel['baseCurrency']['currencyCode']
30+
baseCurrency: OfferingData['baseCurrency']['currencyCode']
3131
/** ISO 3166 currency code string */
32-
quoteCurrency: OfferingModel['baseCurrency']['currencyCode']
32+
quoteCurrency: OfferingData['baseCurrency']['currencyCode']
3333
id: ResourceMetadata<any>['id']
3434
}
3535
}
@@ -77,8 +77,9 @@ export class PfiRestClient {
7777
let response: Response
7878
try {
7979
response = await fetch(apiRoute, {
80-
method : 'POST',
81-
body : JSON.stringify(jsonMessage)
80+
method : 'POST',
81+
headers : { 'content-type': 'application/json' },
82+
body : JSON.stringify(jsonMessage)
8283
})
8384
} catch(e) {
8485
throw new Error(`Failed to send message to ${pfiDid}. Error: ${e.message}`)
@@ -220,6 +221,10 @@ export class PfiRestClient {
220221
* when dereferencing the signer's DID
221222
*/
222223
static async generateRequestToken(privateKeyJwk: Web5PrivateKeyJwk, kid: string): Promise<string> {
224+
// TODO: include exp property. expires 1 minute from generation time
225+
// TODO: include aud property. should be DID of receipient
226+
// TODO: include nbf property. not before current time
227+
// TODO: include iss property. should be requester's did
223228
const tokenPayload = { timestamp: new Date().toISOString() }
224229
return Crypto.sign({ privateKeyJwk, kid, payload: tokenPayload })
225230
}

0 commit comments

Comments
 (0)