generated from TBD54566975/tbd-project-template
-
Notifications
You must be signed in to change notification settings - Fork 106
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* add create offerings page * rename * add creating quotes page * add onboarding docs * remove infinite loop * add overview and process-orders page. Recreate LanguageSwitchLink * support older dependency components
- Loading branch information
1 parent
cfa6c37
commit d35656e
Showing
13 changed files
with
946 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
--- | ||
title: Creating Offerings | ||
hide_title: true | ||
sidebar_position: 6 | ||
--- | ||
|
||
import Shnip from "@site/src/components/Shnip"; | ||
|
||
# Creating Offerings | ||
|
||
Offerings describe a currency pair that can be exchanged and specify the requirements, conditions, and constraints needed to fulfill the described transaction. | ||
In other words, an Offering is a way of describing a financial product you’re offering as a PFI on a tbDEX network. | ||
|
||
Any Wallet that has your PFI's DID will be able to query your PFI for all available Offerings, as well as fetch specific Offerings. Wallets will then use that data to make an [Request for Quote (RFQ)](/docs/tbdex/wallet/send-rfq) to your PFI to begin a potential transaction process. | ||
|
||
## Create an Offering | ||
|
||
You can use the tbDEX SDK to create Offerings. | ||
An Offering must adhere to the [Offering schema](https://github.com/TBD54566975/tbdex/tree/main/specs/protocol#offering). | ||
|
||
<Shnip languages={["JavaScript", "Kotlin"]} snippetName="pfiCreateOffering" /> | ||
|
||
### Required Claims | ||
|
||
In order to comply with certain financial regulations, you may require information about the customer you are transacting with. | ||
You can obtain this information via [Verifiable Credentials](/docs/web5/verifiable-credentials/what-are-vcs). | ||
|
||
To specify the exact credentials you need, you can do so in the `requiredClaims` section of your Offering by [creating a Presentation Definition](/docs/web5/verifiable-credentials/presentation-definition/). | ||
You'll specify all required forms and details of proof, optional selection rules, and define flexibility where possible when different types of input may satisfy the requirements. | ||
|
||
For a full breakdown of all the available fields and combinations, [see the DIF website](https://identity.foundation/presentation-exchange/#presentation-definition) for details. | ||
|
||
Below is an example of how you could specify that a [KnownCustomerCredential](https://www.tbdex.io/guides/kcc) is required to order this Offering: | ||
|
||
<Shnip | ||
languages={["JavaScript", "Kotlin"]} | ||
snippetName="kccPresentationDefinition" | ||
/> | ||
|
||
Once you've created your required claims, it's important to validate them to ensure there are no errors in the design. | ||
This will throw an error if it's not valid. | ||
|
||
<Shnip languages={["JavaScript", "Kotlin"]} snippetName="kccValidatePd" /> | ||
|
||
### Sign Offering | ||
|
||
After creating your Offering, it's necessary to cryptographically sign it so that Wallet apps know that it's authentic. | ||
|
||
<Shnip languages={["JavaScript", "Kotlin"]} snippetName="pfiSignOffering" /> | ||
|
||
### Validate Offering | ||
|
||
After signing the Offering, you can validate that your Offering's structure is valid. | ||
This will throw an error if it's not valid. | ||
|
||
<Shnip languages={["JavaScript", "Kotlin"]} snippetName="pfiValidateOffering" /> | ||
|
||
Once the Offering has been generated, you can store it in your database using code as shown in the [Offerings API Provider section](/docs/tbdex/pfi/anatomy-of-a-pfi#offerings-api-provider). | ||
|
||
## Sample Offering | ||
|
||
When combining all the data above, you can end up with a full Offering object that looks something like the following: | ||
|
||
```js | ||
{ | ||
"metadata": { | ||
"from": "did:dht:d4sgiggd3dwimo4ubki7spo45q5dazxphrizbxhcgapapcnzpouy", | ||
"protocol": "1.0", | ||
"kind": "offering", | ||
"id": "offering_01htkr88ybffzbxfea01rq3ht9", | ||
"createdAt": "2024-04-04T05:10:38.796Z" | ||
}, | ||
"data": { | ||
"description": "Selling BTC for USD", | ||
"payin": { | ||
"currencyCode": "USD", | ||
"methods": [ | ||
{ | ||
"kind": "DEBIT_CARD", | ||
"requiredPaymentDetails": { | ||
"$schema": "http://json-schema.org/draft-07/schema", | ||
"type": "object", | ||
"properties": { | ||
"cardNumber": { | ||
"type": "string", | ||
"description": "The 16-digit debit card number", | ||
"minLength": 16, | ||
"maxLength": 16 | ||
}, | ||
"expiryDate": { | ||
"type": "string", | ||
"description": "The expiry date of the card in MM/YY format", | ||
"pattern": "^(0[1-9]|1[0-2])\\/([0-9]{2})$" | ||
}, | ||
"cardHolderName": { | ||
"type": "string", | ||
"description": "Name of the cardholder as it appears on the card" | ||
}, | ||
"cvv": { | ||
"type": "string", | ||
"description": "The 3-digit CVV code", | ||
"minLength": 3, | ||
"maxLength": 3 | ||
} | ||
} | ||
} | ||
} | ||
] | ||
}, | ||
"payout": { | ||
"currencyCode": "BTC", | ||
"methods": [ | ||
{ | ||
"kind": "BITCOIN_ADDRESS", | ||
"estimatedSettlementTime": 60, | ||
"fee": "0.25" | ||
} | ||
] | ||
}, | ||
"payoutUnitsPerPayinUnit": "0.00003826", | ||
"requiredClaims": { | ||
"id": "presentation-definition-kcc", | ||
"name": "Customer Verification", | ||
"purpose": "We need to verify your customer status and conduct necessary checks.", | ||
"format": { | ||
"jwt_vc": { | ||
"alg": [ | ||
"ES256K", | ||
"EdDSA" | ||
] | ||
} | ||
}, | ||
"input_descriptors": [ | ||
{ | ||
"id": "known-customer-credential", | ||
"name": "Known Customer Credential", | ||
"purpose": "Please present your Known Customer Credential for verification.", | ||
"constraints": { | ||
"fields": [ | ||
{ | ||
"path": [ | ||
"$.credentialSchema[*].id" | ||
], | ||
"filter": { | ||
"type": "string", | ||
"const": "https://vc.schemas.host/kcc.schema.json" | ||
} | ||
}, | ||
{ | ||
"path": [ | ||
"$.evidence[*].kind" | ||
], | ||
"filter": { | ||
"type": "string", | ||
"pattern": "sanction_screening" | ||
} | ||
}, | ||
{ | ||
"path": [ | ||
"$.credentialSubject.countryOfResidence" | ||
], | ||
"filter": { | ||
"type": "string", | ||
"const": "US" | ||
} | ||
}, | ||
{ | ||
"path": [ | ||
"$.issuer" | ||
], | ||
"filter": { | ||
"type": "string", | ||
"const": "did:dht:d4sgiggd3dwimo4ubki7spo45q5dazxphrizbxhcgapapcnzpouy" | ||
} | ||
} | ||
] | ||
} | ||
} | ||
] | ||
} | ||
}, | ||
"signature": "eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDpkaHQ6ZDRzZ2lnZ2QzZHdpbW80dWJraTdzcG80NXE1ZGF6eHBocml6YnhoY2dhcGFwY256cG91eSMwIn0..CcC0pWCpZXzqvPF-2z-axvJQyHhT6-Of4lavPIrrIrJ4WM5eyKRaR7YgEORh7xMwR_pXZ_KUHnPksmSQZsm2Ag" | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
--- | ||
title: Creating Quotes | ||
hide_title: true | ||
sidebar_position: 7 | ||
--- | ||
|
||
import Shnip from "@site/src/components/Shnip"; | ||
|
||
# Creating Quotes | ||
|
||
When you receive an `RFQ` message, you’ll want to do the following: | ||
|
||
1. Store the `RFQ` message in your database | ||
2. Get the `Offering` specified by `offeringId` in the `RFQ` | ||
3. Create a `Quote` and store it in your database | ||
|
||
## Store RFQ message | ||
|
||
An `RFQ` is the first message of an exchange. | ||
When a Wallet application sends your PFI an `RFQ` message, your server's `onCreateExchange()` callback parameter will be invoked. | ||
This is where you should implement your business logic for determining the customer's exact Quote. | ||
|
||
As a best practice, store the `RFQ` message in your [Exchanges database](/docs/tbdex/pfi/anatomy-of-a-pfi#main-server-entrypoint) so that both you and the Wallet app can access it. | ||
|
||
## Get the Offering | ||
|
||
After inserting the `RFQ` into your database, you can search your database for the `Offering` the `RFQ` is requesting. | ||
|
||
RFQs contain a required `offeringId` field that you pass to your Offerings API provider’s `getOffering()` method to obtain the exact Offering. | ||
|
||
Building on the example from the [Exchange API Provider section](/docs/tbdex/pfi/anatomy-of-a-pfi#exchange-api-provider), your code might look like this: | ||
|
||
<Shnip languages={["JavaScript", "Kotlin"]} snippetName="pfiWriteOffering" /> | ||
|
||
## Verify Credentials | ||
|
||
Upon receiving an `RFQ`, the tbDEX SDK will automatically [verify the submitted credentials](/docs/web5/verifiable-credentials/verify-vc#verify-verifiable-credentials) to guarantee their integrity and authenticity as well as ensure that they meet the `requiredClaims` specified in the `Offering`. | ||
|
||
## Create a Quote | ||
|
||
Before creating a `Quote` in response to the received `RFQ`, you can review the [protocol definition for Quotes](https://github.com/TBD54566975/tbdex/tree/main/specs/protocol#quote). | ||
With that in mind, you can then create your quote using the `Quote.create()` method as shown below: | ||
|
||
<Shnip languages={["JavaScript", "Kotlin"]} snippetName="pfiCreateQuote" /> | ||
|
||
With the `Quote` created, you’ll then sign it for authorization purposes and write it to your own database: | ||
|
||
<Shnip languages={["JavaScript", "Kotlin"]} snippetName="pfiSignQuote" /> | ||
|
||
:::tip Note | ||
If the Wallet Application supplied a `replyTo` address with their RFQ, the tbDEX SDK will send the Quote to that address. | ||
|
||
If not, the Wallet Application will poll your PFI awaiting the Quote message to appear within the exchange. | ||
::: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
--- | ||
sidebar_position: 3 | ||
title: Onboarding | ||
hide_title: true | ||
--- | ||
|
||
import Shnip from "@site/src/components/Shnip"; | ||
|
||
# Onboarding | ||
|
||
Before beginning development of your PFI’s code, you’ll need to create an identity to use on the network. A tbDEX network is built to be decentralized, which is why you’ll need to create your own [Decentralized Identifier](/docs/web5/decentralized-identifiers/what-are-dids) (DID) to assign to the PFI. That DID will represent the PFI, as well as serve as the signer for tbDEX messages and resources that are sent to other parties. | ||
|
||
DIDs are associated with [DID Documents](/docs/web5/decentralized-identifiers/did_documents) which describe how to engage with your PFI. | ||
|
||
To create a DID and identify yourself as a PFI, use the `web5/dids` package: | ||
|
||
### Import Classes | ||
|
||
<Shnip | ||
languages={["JavaScript", "Kotlin"]} | ||
snippetName="pfiOnboardingImports" | ||
/> | ||
|
||
### Create DID with Service Endpoint | ||
|
||
For a DID to be recognized as a PFI, it is important to include a service endpoint in the DID document. The value for `serviceEndpoint` should be the URL to your PFI's service entry. | ||
|
||
If you also have an existing key management system to secure your secrets, e.g., [AWS KMS](https://aws.amazon.com/kms/), [Google Cloud KMS](https://cloud.google.com/security/products/security-key-management), etc., creating a DID provides a `keyManager` interface that you can pass it through. | ||
|
||
<Shnip | ||
languages={["JavaScript", "Kotlin"]} | ||
snippetName="pfiOnboardingCreateDid" | ||
/> | ||
|
||
:::note Notes | ||
|
||
- `LocalKeyManager` or `InMemoryKeyManager` should only be used in non-production environments. See [Key Management Service](/docs/web5/decentralized-identifiers/key-management) for more details. | ||
::: |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
--- | ||
sidebar_position: 1 | ||
--- | ||
|
||
# PFI Overview | ||
|
||
PFIs are **Participating Financial Institutions** that offer liquidity on a tbDEX network. | ||
|
||
PFIs make themselves known to [Wallet applications](/docs/tbdex/wallet/overview) and engage in verifying necessary information for transaction completion with [Verifiable Credential](/docs/web5/verifiable-credentials/what-are-vcs) Issuers. | ||
|
||
For more on how PFIs fit into the overall structure of tbDEX, please [refer to the tbDEX overview](/docs/tbdex/#example-scenario). | ||
|
||
The PFI guides are intended to provide you with what you need to begin participating on a tbDEX network. | ||
|
||
## Recommended Path | ||
|
||
1. [tbDEX Overview](/docs/tbdex/) | ||
2. [Review Message Types](/docs/tbdex/message-types) | ||
3. [Install Required SDKs](/docs/tbdex/pfi/required-sdks) | ||
4. [Onboard as a PFI](/docs/tbdex/pfi/onboarding) | ||
5. [Review Anatomy of a PFI](/docs/tbdex/pfi/anatomy-of-a-pfi) | ||
6. [Create Offerings](/docs/tbdex/pfi/creating-offerings) | ||
7. [Create Quotes](/docs/tbdex/pfi/creating-quotes) | ||
8. [Process Orders](/docs/tbdex/pfi/processing-orders) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
--- | ||
title: Processing Orders | ||
sidebar_position: 9 | ||
hide_title: true | ||
--- | ||
|
||
import Shnip from "@site/src/components/Shnip"; | ||
import LanguageSwitchLink from "@site/src/components/LanguageSwitchLink"; | ||
|
||
# Processing Orders | ||
|
||
After the Wallet app receives a [Quote](/docs/tbdex/pfi/creating-quotes) from your PFI, they are able to submit an Order. | ||
This guide covers how to use tbDEX to communicate progress on Orders you receive. | ||
|
||
## Receiving an Order | ||
|
||
When a Wallet application places an order, your server's `onSubmitOrder()` callback parameter will be invoked. | ||
This is where you should implement your business logic for handling these incoming orders. | ||
|
||
As a best practice, store the `Order` message in your [Exchanges database](/docs/tbdex/pfi/anatomy-of-a-pfi#main-server-entrypoint). | ||
|
||
## Accessing Hashed Data | ||
|
||
The payment details for the Order were specified in the <LanguageSwitchLink text="RFQ message" links='{"JavaScript": "https://tbd54566975.github.io/tbdex-js/classes/_tbdex_protocol.Rfq.html", | ||
"Kotlin": "https://tbd54566975.github.io/tbdex-kt/docs/tb-d-e-x%20-s-d-k%20-documentation/tbdex.sdk.protocol.models/-rfq/index.html"}'/> that was sent by the Wallet application. | ||
|
||
Sensitive information such as payment details and claims are hashed and are accessible from the [privateData](https://github.com/TBD54566975/tbdex/tree/main/specs/protocol#privatedata-1) section of the RFQ: | ||
|
||
<Shnip | ||
languages={["JavaScript", "Kotlin"]} | ||
snippetName="pfiAccessPrivateData" | ||
/> | ||
|
||
Using this information, you are free to use the logic of choice to fulfill the Order. | ||
|
||
:::note | ||
tbDEX is a messaging protocol that facilitates communication to enable transactions but does not actually provide the APIs to fulfill them. | ||
That responsibility lies with the transacting parties. | ||
::: | ||
|
||
## Provide Order Status | ||
|
||
As you deem appropriate for your customers, you can provide them with <LanguageSwitchLink text="OrderStatus messages" links='{"JavaScript": "https://tbd54566975.github.io/tbdex-js/classes/_tbdex_http_client.OrderStatus.html", "Kotlin": "https://tbd54566975.github.io/tbdex-kt/docs/tb-d-e-x%20-s-d-k%20-documentation/tbdex.sdk.protocol.models/-order-status/index.html"}'/> to keep them updated on the status of their `Order`: | ||
|
||
<Shnip languages={["JavaScript", "Kotlin"]} snippetName="pfiOrderStatus" /> | ||
|
||
If the Wallet application supplied a `replyTo` address, the tbDEX SDK will send the `OrderStatus` message there. | ||
|
||
You should also write the `OrderStatus` to your database and the Wallet will poll for these updates. | ||
|
||
## Close the Order | ||
|
||
When the `Order` has reached a terminal state (e.g. order fulfilled, order rejected, etc), you can create a `Close` message, which will be the final message of the thread: | ||
|
||
<Shnip languages={["JavaScript", "Kotlin"]} snippetName="pfiCloseOrder" /> | ||
|
||
After writing the `Close` message to your database, the Wallet will be able to know that their transaction has closed via polling or callback. |
Oops, something went wrong.