diff --git a/hosted/json-schemas/balance.schema.json b/hosted/json-schemas/balance.schema.json new file mode 100644 index 00000000..c68b37c0 --- /dev/null +++ b/hosted/json-schemas/balance.schema.json @@ -0,0 +1,34 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "https://tbdex.dev/offering.schema.json", + "definitions": { + "Balance": { + "type": "object", + "additionalProperties": false, + "properties": { + "currencyCode": { + "type": "string", + "description": "ISO 3166 currency code string" + }, + "available": { + "$ref": "definitions.json#/definitions/decimalString", + "description": "The amount available to be transacted with" + } + }, + "required": ["currencyCode", "available"] + } + }, + "type": "object", + "properties": { + "additionalProperties": false, + "balances": { + "type": "array", + "items": { + "$ref": "#/definitions/Balance" + } + } + }, + "required": [ + "balances" + ] + } \ No newline at end of file diff --git a/hosted/json-schemas/resource.schema.json b/hosted/json-schemas/resource.schema.json index 939343f6..2b56ca18 100644 --- a/hosted/json-schemas/resource.schema.json +++ b/hosted/json-schemas/resource.schema.json @@ -13,7 +13,7 @@ }, "kind": { "type": "string", - "enum": ["offering"], + "enum": ["offering", "balance"], "description": "The resource kind (e.g. Offering)" }, "id": { diff --git a/specs/http-api/README.md b/specs/http-api/README.md index 529e427a..558191b5 100644 --- a/specs/http-api/README.md +++ b/specs/http-api/README.md @@ -74,6 +74,12 @@ Version: Draft - [Protected](#protected-6) - [Response](#response-6) - [Query Params](#query-params-3) + - [List Balances](#list-balances) + - [Description](#description-4) + - [Authentication](#protected-7) + - [Endpoint](#endpoint-7) + - [Response](#response-7) + - [Example](#example-2) - [References](#references) # Discoverability @@ -139,7 +145,6 @@ If the serviceEndpoint is itself a DID, this DID should resolve to a document an } ] - } ``` @@ -476,5 +481,41 @@ True --- +## List Balances +This endpoint is *OPTIONAL*. It is only relevant for PFIs which expose a stored balance functionality either for institutional or retail customers. + +### Description +Returns an array of balance resources for each currency held by the caller. + +### Protected +True + +### Endpoint +`GET /balances` + +### Response +| Status | Body | +| ------------------ | -------------------------------------- | +| `200: OK. ` | `{ data: { Balance[] } }` | +| `400: Bad Request` | `{ errors: Error[] }` | +| `404: Not Found` | N/A | +| `403: Forbidden` | N/A | + +#### Example + +```json +{ + "data": [ + { + /** ISO 4217 currency code or widely adopted cryptocurrency code as string */ + "currencyCode": "USD", + /** same format used to represent currency values across messages */ + "available": "400.00", + } + ] +} + +``` + # References * JSON:API spec: https://jsonapi.org/format/ \ No newline at end of file diff --git a/specs/protocol/README.md b/specs/protocol/README.md index 9a38a409..0637a3d6 100644 --- a/specs/protocol/README.md +++ b/specs/protocol/README.md @@ -53,10 +53,13 @@ Version: Draft - [Signatures](#signatures) - [tbDEX conversation sequence](#tbdex-conversation-sequence) - [Jargon Decoder](#jargon-decoder) +- [Stored Balances](#stored-balances) - [Additional Resources](#additional-resources) # Resources -tbDEX Resources are published by PFIs for anyone to consume and generally used as a part of the discovery process. They are not part of the message exchange, i.e Alice cannot reply to a Resource. +tbDEX Resources are published by PFIs and generally used as a part of the discovery process. They are not part of the message exchange, i.e Alice cannot reply to a Resource. + +There exist both publicly available and protected resources. Publicly available ones can be listed by any caller without authorization. Protected resources may only be accessible to specific DIDs. ## Fields All tbdex resources are JSON objects which can include the following top-level properties: @@ -118,6 +121,13 @@ An `Offering` is used by the PFI to describe a currency pair they have to _offer | `requiredPaymentDetails` | [JSON Schema](https://json-schema.org/) | N | A JSON Schema containing the fields that need to be collected in order to use this payment method | | `fee` | [`DecimalString`](#decimalstring) | N | The fee to use of this payment method | +##### Reserved `PaymentMethod`s + +Some payment methods should be consistent across PFIs and therefore have reserved `kind` values. PFIs may provide, as a feature, stored balances, which are effectively the PFI custodying assets or funds on behalf of their customer. Customers can top up this balance and their transactions can draw against this balance. + +| kind | description | +| ------------------------ | --------------------------------------------------------------------------------- | +| `STORED_BALANCE`| Represents a customer's balance with the PFI. See [Stored Balances](#stored-balances) for information on usage | #### Example Offering ```json @@ -222,6 +232,42 @@ An `Offering` is used by the PFI to describe a currency pair they have to _offer } ``` +### `Balance` +A `Balance` is a protected resource used to communicate the amounts of each currency held by the PFI on behalf of its customer. + +| field | data type | required | description | +|----------------|-----------------------------------|----------|--------------------------------------------------------| +| `currencyCode` | string | Y | ISO 3166 currency code string | +| `available ` | [`DecimalString`](#decimalstring) | Y | The amount available to be transacted with | + +#### Example Balance +```json +{ + "metadata": { + "from": "did:ex:pfi", + "kind": "balance", + "id": "balance_01ha82y8d0fhstg95hhfjwmgxf", + "createdAt": "2023-09-13T20:15:22.528Z", + "updatedAt": "2023-09-13T20:15:22.528Z" + }, + "data": { + "balances": [ + { + /** ISO 4217 currency code or widely adopted cryptocurrency code as string */ + "currencyCode": "USD", + /** same format used to represent currency values across messages */ + "available": "400.00", + }, + { + "currencyCode": "MXN", + "available": "100.00", + } + ] + }, + "signature": "eyJhbGciOiJFZERTQSIsImtpZCI6ImRpZDprZXk6ejZNa2syc1QyZUtvQWdUUTdzWjY3YTdmRDMzR21jYzZ1UXdaYmlxeWF5Rk1hYkhHI3o2TWtrMnNUMmVLb0FnVFE3c1o2N2E3ZkQzM0dtY2M2dVF3WmJpcXlheUZNYWJIRyJ9..9EBTL3VcajsQzSNOm8GElhcwvYcFGaRp24FTwmC845RCF84Md-ZB-CxdCo7kEjzsAY8OaB55XFSH_8K9vedhAw" +} +``` + ### `Reputation` A set of Verifiable Credentials _issued_ to the PFI that can be consumed by any interested party in order to assess the reputability of the respective PFI. @@ -616,6 +662,62 @@ Quick explanation of terms used. | payout currency | currency that the PFI is paying out to Alice. Alice will _receive_ the payout currency from the PFI. | | payin currency | currency the PFI will accept in exchange for the payin currency. The PFI will _receive_ the payin currency from Alice. | +# Stored Balances +Stored balances are assets or funds custodied by a PFI on behalf of a customer. They are relevant for PFIs which provide options for institutional top ups, or which are custodial. Supporting stored balances is entirely optional. The intent is to provide the ability for PFIs who choose to do so. + +If a PFI offers `STORED_BALANCE` as a payout kind, they MUST necessarily have a respective offering with`STORED_BALANCE` as a payin kind. + +## Top up stored balance +A USD -> USDC institutional top-up offering could appear as: + +```json +{ + "payinCurrency": "USD", + "payoutCurrency": "USDC", + "payinMethods": [{ + "kind": "WIRE_TRANSFER" + }], + "payoutMethods": [{ + "kind": "STORED_BALANCE" + }], + "requiredClaims": ["KnownBusinessCredential"] +} +``` + +A USD -> USDC retail customer offering could appear as: + +```json +{ + "payinCurrency": "USD", + "payoutCurrency": "USDC", + "payinMethods": [{ + "kind": "WIRE_TRANSFER" + }], + "payoutMethods": [{ + "kind": "STORED_BALANCE" + }], + "requiredClaims": ["KnownCustomerCredential"] +} +``` + +## Off ramp using stored balance + +A USDC -> KES off ramp offering could appear as: + +```json +{ + "payinCurrency": "USDC", + "payoutCurrency": "KES", + "payinMethods": [{ + "kind": "STORED_BALANCE" + }], + "payoutMethods": [{ + "kind": "MOMO_MPESA" + }], + "requiredClaims": ["SanctionsCredential"] +} +``` + # Additional Resources | Resource Name | Description |