Use Case 2: Sell-Side - Distributing Assets

Overview

The following is a sell-side walkthrough for integrating into your Ownera router via the FinP2P API for the purpose of issuing assets to distribute to your partnered financial organizations. The steps involved are as follows:

  1. Onboarding the asset on the Router - registering the asset so it can be distributed to other buy side routers, including:
  • Defining the asset and its issuing entity
  • Attaching certifications and other trade and marketing supporting documentation
  • Defining a primary sale intent in order to launch the asset
  • Sharing it with other buy side routers
  1. Asset tokenization request and trade processing requests - receive and process primary and secondary intent trade requests orchestrated by a comprehensive execution plan.
  2. Facilitate other operational requests - implement various operational functionality including:
  • the ability to send fund withdrawal requests from payment providers on behalf of the issuer, accrued via investment proceeds.
  • The ability to send fund withdrawal requests from payment providers on behalf of the issuer, accrued via investment proceeds.

An adapter needs to be developed in order to connect between the Router and your tokenization platform which needs to include the asset tokenization tokenization request and trade processing requests. It can also include other flows, including asset onboarding on the router for automation purposes, and other operational functionalities.

Onboarding the asset

The following outlines the walkthrough of the integration requires in order to onboard an asset on the Router. There are two different asset onboarding approaches that can be implemented:

  1. The Asset will be tokenized firstly on the tokenization platform (or has already been tokenized) and then be onboarded on to the Router. In this case an association will need to be defined to link between the Asset ID on the Router and on the Tokenization Platform (for example, add to the asset data on the Router the token ID or address).
  2. The Asset is on-boarded on the to the Ownera platform which in turn will request the tokenization platform to tokenize it. Linking is done as part of the same transaction of defining the asset on the Router and then creating the underlying associated record on the Tokenization Platform.

Asset onboarding is available either by using the Ownera Admin App, or via the Router’s own API. If you chose to utilize the Owenra Admin app, there is no need to integrate this section.

The diagram below illustrates the steps involved in this integration flow for onboarding the asset. This includes other Routers involved to illustrate the overall flow integration with other organizations:

Below it the walkthrough of using the API to onboard the asset, which you can use to integrate to in order to automate this process from your tokenization or asset management platform.

# API ReferenceDescription

Onboard the Issuer
1Create Issuer Registers the issuer on your router.
2Bind Investor to a Custodian Send a request to the associated custodian to onboard the investor on the custody system, which in turn will provide the public key (finID) that is associated with the investor.
3Attach Certificates[Optional] Attach certificates to the investor, such as KYA.

For FinP2P recommended certificate specifications refer to https://github.com/owneraio/finp2p-certificates-spec
4Attach Documentation [Optional] Add additional documentation to provide additional information about the issuer.
5Share Issuer with Payments Service Link the issuer to the applicable payments organization responsible for handling the payments leg for the issuer.

Note: If the your router provides also payment services to the issuer, this step can be omitted

Setup the Account
6n/aNote settlement account will be auto-created (if does not exist already) on-behalf of the issuer during trade execution, therefore no initial setup required.

Onboarding an Asset
7Create the Asset Define the asset you are onboarding, including values such as asset denomination, basic name, etc. If the asset has been tokenized already, you can provide a link id here (such as token id or address) that will allow
8Attach Certificates Attach certificates, such as “KYA” to the given asset.
9Attach Documentation Add additional documentation to support and facilitate asset trading.

This is done by attaching documents to the given asset certificate, such as PDFs or images of the asset.
10Select Organizations to Distribute To Share an asset with the given organization(s) that you allow to have access to the asset to invest in.
11Create a Primary Sale Allow for investors in which you shared the asset with to investment in the primary sale (issuance).

This is an intent of type “Primary Sales”.

Asset Tokenization and Trade Request Processing

The following is a walkthrough on what needs to be developed inside the adapter which will be used to connect between the Router and the Tokenization (asset management) platform, which includes all end points required to handle incoming Router requests.

Asset Onboarding Request

This request is sent to the adapter once the asset is onboarded on the given Router, in which you will handle the request based on the asset onboarding approach you elected to implement. You do need to integrate the following even if you chose to use the Ownera Admin tool since onboarding the asset there will also require interaction with the blockchain (e.g., tokenize the asset upon this call, or bind the asset setup on Ownera to the Tokenization side).

# API ReferenceDescription
12Handle Asset Creation Notification When an asset is onboarded, you will receive this notification on your ledger adapter. Based on your implementation approach:.

1. If tokenization of the asset on the blockchain is done prior to onboarding, just respond back with success,

2. Or invoke your process to tokenize the asset on the adapter.

Process Primary Sale Request

The diagram below illustrates the steps involved in this integration flow around the trade initiation from the buy side and its flow to execution plan approval. This includes other Routers involved to illustrate the overall flow integration with other organizations:

In addition the diagram below illustrates the issuance step in the overall trade processing that is orchestrated between the Routers by the execution plan, in this case including the trading platform request and the payment leg processing by the payment service.

The following outlines how to handle primary sale request, including the endpoint you will need to develop in the adapter to handle the flow:

# API ReferenceDescription
13Receive Notification and Approve New Execution Plan You will receive an execution plan notification which will be an indication that a new request for primary sale investment (issuance) in the given asset by an investor was submitted.

You can chose to immediately approve the execution plan, or response with acknowledgement and approve it in a subsequent asynchronous manner after you review the plan.
14Review Execution Plan(Optional) Poll the plan to review and asset your participation in the execution plan, and in turn will allow you to process your approval.

This step can include onboarding the investor, qualifying and approving their KYC, performing compliance and accreditation checks, etc.

Refer to the execution plan explanation.
Execution Plan

You can also elect to verify the signatures provided in the execution plan details, in this case signature for the investor requesting the issuance. Refer to the section titled "Cryptographic Keys and Signature Verifications" below.

The template for the signature is outlined in the custody section of the API specification Signature Templates .
15Query Investor (Optional) Query for the investor details, such as their certificates, if you wish to qualify the investor(s) involved in the trade.
16Process Status Polling for Execution Plan Approval(Optional) If you chose to process approval in asynchronous manner, the router will polling your side for status on approval.
17Process Issuance RequestDevelop the logic to process the primary sale intent execution request which is sent to your adapter, including:

1. Receiving the issuance request from the Router and processing it against the tokenization platform.
2. Could include logic for handling regulations and other order execution acceptance parameters.
3. Note by default the Router performs these validations on your behalf. However, additional signature verification can be performed to validate the transaction. Refer to the section titled "Cryptographic Keys and Signature Verifications" below for additional information. The template for the signature is outlined in the custody section of the API specification Signature Templates. Note based on the blockchain, signature hash can be generated using different algorithms, such as SHA-256 or Keccak-256. Note Router should be configured accordingly to the algorithm being used.The request can either be processed synchronously or asynchronously (isCompleted set to True or false accordingly)Respond with a CID which will be used as a method to poll your side for completion.
18Process Request AsynchronouslyImplement the get operation ability in order to allow to query for the status of the execution request sent to you, for the case you chose the process the issuance request asynchronously.

Process Secondary Trade Request

The diagram below illustrates the steps involved in this integration flow around the trade initiation from the buy side of the buyer and seller for secondary intent, and the flow for the execution plan approval. Diagram includes other Routers involved to illustrate the overall flow integration with other organizations:

And below is the illustration of the trade execution, which includes the illustration of the payment leg processing in this trade.

The following outlines how to handle secondary trade request, including the endpoint you will need to develop in the adapter to handle the flow:

# API ReferenceDescription
20Receive Notification and Approve New Execution PlanYou will receive an execution plan notification which will be an indication that a new request for a trade in which the given asset is requested to be transferred from one investor to another.

You can chose to immediately approve the execution plan, or response with acknowledgement and approve it in a subsequent asynchronous manner after you review the plan.
21Review Execution Plan(Optional) Poll the plan to review and asset your participation in the execution plan, and in turn will allow you to process your approval.

This step can include onboarding the investor, qualifying and approving their KYC, performing compliance and accreditation checks, etc.

Refer to the execution plan explanation.
Execution Plan

You can also elect to verify the signatures provided in the execution plan details, in this case signature for both the buying and selling investors involved in this secondary trade execution request. Refer to the section titled "Cryptographic Keys and Signature Verifications" below.

The template for the signature is outlined in the custody section of the API specification Signature Templates.
22Query Investor (Optional) Query for the investor details, such as their certificates, if you wish to qualify the investor(s) involved in the trade, in this case including the buyer and seller.
23Process Status Polling for Execution Plan Approval(Optional) If you chose to process approval in asynchronous manner, the router will polling your side for status on approval.
23Process Secondary Trade RequestDevelop the logic to process the secondary intent execution request which is sent to your adapter, including:

1. Receiving the transfer request from the Router and processing it against the tokenization platform.
2. Could include logic for handling regulations and other order execution acceptance parameters.
3. Note by default the Router performs these validations on your behalf. However, additional signature verification can be performed to validate the transaction. Refer to the section titled "Cryptographic Keys and Signature Verifications" below for additional information. The template for the signature is outlined in the custody section of the API specification Signature Templates . Note based on the blockchain, signature hash can be generated using different algorithms, such as SHA-256 or Keccak-256. Note Router should be configured accordingly to the algorithm being used.The request can either be processed synchronously or asynchronously (isCompleted set to True or false accordingly)Respond with a CID which will be used as a method to poll your side for completion.
24Process Request AsynchronouslyImplement the get operation ability in order to allow to query for the status of the execution request sent to you.

Additional Operational Functionality

The following outlines additional operational functionality that can be implemented, such as manual balance adjustments, providing asset balance and receipts, and providing functionality to request withdrawal of sale proceeds for issuers.

API ReferenceDescription
25Query ReceiptsUses GraphQL to either subscribe or query for the receipts that will serve as confirmation that the investment was executed and payment was processed.
26Monitor Execution Plan ProgressionAnd/or use the get execution plan details and continue to pool to see progress of the plan
27Provide ReceiptsAllow to request receipt details from your ledger.
28Provide Ledger Asset BalanceAllow to request the token balance for the given owner on the asset.
29Perform Balance AdjustmentsThis will allow you to make balance adjustments that were the result of activities performed outside of the Ownera scope of trading.
Request Fund Withdrawal
30Request Funds WithdrawalThe issuer has the option to withdraw the funds that are in the given account by putting in a request for withdrawal. This request is routed to the given payment service provider to process.
29Poll for Transaction CompletionIf the request is processed asynchronously, use the get operations to receive the response.

Allow for Asset Redeem

TBD.

Testing Your Integration

You can test your sell-side integration by requesting from Ownera a buy-side sandbox which will provide you with a test Investor App.

Sell Side Integration Example

The following is an example walkthrough for the sell side integration. The below are the assumed values that will be used through out the example:

ParameterDescriptionValue
Issuer Fin IDThe public key used in creating the user profile, which in turn will be used as the finID for the user when transacting.024c9f4cda13349113e312bfe6e8860a5186ab90b3d0987cfd43bcdc285303d93a
Issuer User IDThe finP2P resource ID for the given user created.bank-us:101:f09fa8ac-2b83-49de-8779-6ff954c5b181
Issuer Payments Service Org IDThe payments service organization that will be used to transact the investmentpayments-router
Asset IDThe asset ID assigned to the created asset.bank-us:102:631dd696-302b-4f6e-b91f-79cc7bf84f54
Primary Sale Intent IDThe Id assigned to the primary sale intent that is created.bank-us:105:3a360d7a-df60-40b2-9574-eccaa1ed1f08

Onboarding the Asset [Optional]

The following section is option, as the asset onboarding can be facilitated using the Ownera Admin application which would not require integration to this capability.

Create issuer user profile

curl --location --request POST 'http://<router url>/finapi/profiles/owner' \
--header 'Content-Type: application/json' \
--data-raw '{}'
{
    "isCompleted": true,
    "response": {
        "id": "bank-us:101:f09fa8ac-2b83-49de-8779-6ff954c5b181"
    },
    "type": "profile"
}

Bind the user to the given custodian:

Send a request to the custodian to onboard the investor on the custody platform, which will return the public key that will be used to identify the investor. The process is an asynchronous process, and therefore you will need to

curl --location --request POST '<router url>/finapi/profiles/owner/bank-us:101:f09fa8ac-2b83-49de-8779-6ff954c5b181/account' \
--header 'Content-Type: application/json' \
--data-raw '{ 
  "orgId": "custody-service"
}'
{
 "cid":"e3c59abb-f296-4556-a4c6-9c0e397ad6f9",
 "isCompleted":false,
 "type":"addAccount"
}

Poll the request until it is completed:

Poll for the completion of the custodian investor onboarding.

curl --location --request POST '<router url>/operations/status/e3c59abb-f296-4556-a4c6-9c0e397ad6f9' \
--header 'Content-Type: application/json' \
--data-raw '{}'
{
    "cid": "e3c59abb-f296-4556-a4c6-9c0e397ad6f9",
    "isCompleted": true,
    "response": {
        "custodyOrgId": "custody-service",
        "finId": "024c9f4cda13349113e312bfe6e8860a5186ab90b3d0987cfd43bcdc285303d93a"
    },
    "type": "account"
}

Attach certificate to the given user

curl --location --request POST 'http://<router url>/finapi/profiles/bank-us:101:f09fa8ac-2b83-49de-8779-6ff954c5b181/certificates' \
--header 'Content-Type: application/json' \
--data-raw '{
  "type": "ownerInfo",
  "issuanceDate": 1668598695,
  "expirationDate": 1700134695,
  "data": "{\"email\":\"[email protected]\",\"name\":\"Issuer1\",\"type\":\"issuer\"}"
}'
{
    "id": "ec634170-8c62-4d55-b324-0391eb30fac1"
}

Upload a document to the given certificate, pointing to a location of the file

curl --location --request POST 'http://<router url>/finapi/profiles/bank-us:101:f09fa8ac-2b83-49de-8779-6ff954c5b181/certificates/ec634170-8c62-4d55-b324-0391eb30fac1' \
--form 'kya doc=@"/kyc.pdf"'

Associate the user with the given payments service

curl --location --request POST 'http://<router url>/finapi/profiles/bank-us:101:f09fa8ac-2b83-49de-8779-6ff954c5b181\share' \
--header 'Content-Type: application/json' \
--data-raw '{
     "organizations": [
          "payements-service"
     ]
}'
n/a

Create the asset

The asset creation includes the providing of the intent types that are available for the given asset.

curl --location 'simulation.app.local.ownera.io/finapi/profiles/asset/' \
--header 'Content-Type: application/json' \
--data '{     "denomination": {
          "type": "fiat",
          "code": "USD"
     },
     "config": " ",
     "name": "Asset 001",
     "type": "basket",
     "issuerId": "simulation:101:a431ad7b-b963-43fc-8d8d-48a9fba7ff6d",
       "intentTypes": [
    "primarySale",
    "buyingIntent",
    "sellingIntent"
  ]
}'
{
    "isCompleted": true,
    "response": {
        "id": "bank-us:102:4b2fc630-bc23-4337-be44-97f12875f835"
    },
    "type": "profile"
}

Process the asset creation request

This endpoint that is required on the ledger adapter will process the notification that an asset has been onboarded on Ownera at your organization (e.g., will be invoked as a result of the asset profile creation).

If your process has the asset tokenized prior to onboarding on Ownera, just confirm the message, and/or you can use this call to perform your mapping between the asset id of Ownera provided in this message and your asset id (e.g., blockchain contract address).

If not, invoke your logic for tokenizing the assets and linking it to the Ownera asset id.

curl --location --request POST 'http://<adapter url>/assets/create' \
--header 'Content-Type: application/json' \
--data-raw '{
  "asset": {
    "type": "finp2p",
    "resourceId": "bank-us:102:4b2fc630-bc23-4337-be44-97f12875f835"
  }
}'
{
    "isCompleted": true
}

Attached a Know Your Asset (KYA) certificate to the asset

curl --location --request POST 'http://<router url>/finapi/profiles/bank-us:102:873e82a0-274a-4762-8535-7b9540cf680b/certificates' \
--header 'Content-Type: application/json' \
--data-raw '{

  "type": "KYA",
  "issuanceDate": 1668598695,
  "expirationDate": 1672399561,
  "data": "{\"publicName\":\"Public Asset Building 2\",\"officialName\":\"Official Asset Building 2\",\"description\":\"Description of the Asset Building 2.\",\"info\":[{\"type\":\"text\",\"name\":\"Location\",\"value\":\"NYC\"},{\"type\":\"link\",\"name\":\"Website\",\"value\":\"https://www.assetpage.com\"}]}"
}'

Optional: Attached images to the asset (examples below illustrate the setting of images in case you are using the Ownera App)

Note the naming convention for the images

curl --location --request POST 'http://<router url>/finapi/profiles/bank-us:102:873e82a0-274a-4762-8535-7b9540cf680b/certificates/b57732e7-a477-4769-8753-f761a1412a60/docs' \
--header 'Content-Type: application/json' \
--form 'asset icon=@"/icon-asset profle.png"'
curl --location --request POST 'http://localhost:62532/profiles/bank-us:102:873e82a0-274a-4762-8535-7b9540cf680b/certificates/b57732e7-a477-4769-8753-f761a1412a60/docs' \
--header 'Content-Type: application/json' \
--form 'asset logo=@"/logo-asset profle.png"'

Create a Primary Sale Intent

The intent below is an example of making 50 tokens available each at the price of 1 USD. The intent indicates the finId and the payments service organization that is going to be used for managing the issuance, and the destination for the payment for the investment.

curl --location --request POST 'http://<router url>/finapi/profiles/asset/bank-us:102:4b2fc630-bc23-4337-be44-97f12875f835/intent' \
--header 'Content-Type: application/json' \
--data-raw '{
     "assetTerm": {
          "asset": {
               "type": "finp2p",
               "resourceId": "bank-us:102:4b2fc630-bc23-4337-be44-97f12875f835"
          },
          "amount": "50"
     },
     "assetInstruction": {
          "account": {
               "account": {
                    "type": "finId",
                    "finId": "024c9f4cda13349113e312bfe6e8860a5186ab90b3d0987cfd43bcdc285303d93a",
                    "orgId": "payements-service"
               },
               "asset": {
                    "type": "finp2p",
                    "resourceId": "bank-us:102:4b2fc630-bc23-4337-be44-97f12875f835"
               }
          }
     },
     "settlementTerm": {
          "asset": {
               "type": "fiat",
               "code": "USD"
          },
          "unitValue": "1"
     },
     "intent": {
          "type": "primarySale",
          "settlementInstruction": {
               "type": "escrow",
               "destinationAccounts": [
                    {
                         "account": {
                              "type": "finId",
                              "finId": "024c9f4cda13349113e312bfe6e8860a5186ab90b3d0987cfd43bcdc285303d93a",
                              "orgId": "payements-service"
                         },
                         "asset": {
                              "type": "fiat",
                              "code": "USD"
                         }
                    }
               ]
          },
          "issuer": "bank-us:101:f09fa8ac-2b83-49de-8779-6ff954c5b181"
     },
     "start": 1671108000,
     "end": 1672399561
}'
{
    "id": "bank-us:105:cd3a32e0-da32-4161-a00b-d138a56712d6"
}

Example of Asset onboarding notification to tokenization platform

Receive a notification on asset onboarding request.

curl --location --request POST 'http://<adapter url>/assets/create' \
--header 'Content-Type: application/json' \
--data-raw '
{
  "asset": {
    "type": "finp2p",
    "resourceId": "bank-us:102:4b2fc630-bc23-4337-be44-97f12875f835"
  }
}'
{
  "cid": '12345',  
  "isCompleted": true
}

Example of Asset Tokenization and Trade Request Processing

Once a primary sale trade is requested, you will receive a notification message which indicates of a new execution plan submission for an asset in which is managed by your organization for issuance in which you will need to approve. If no decision making is required, you can approve immediately, otherwise acknowledge and process it asynchronously.

curl --location --request POST 'http://<adapter url>/plan/approve' \
--header 'Content-Type: application/json' \
--data-raw '
{
  "executionPlanId": "bank-uk:106:9909e355-df0e-4708-8121-cec192089418"
}'
{
  "cid": "12321321",
  "isCompleted": false,
}

{
  "cid": "12321321",
  "isCompleted": true,
  "approval": {
    "status": "approved"
  }
}

You can query the router for details on the execution plan outlining the full workflow for the execution of the given transaction.

curl --location 'http://<router url>/finapi/execution/bank-uk:106:9909e355-df0e-4708-8121-cec192089418' \
--header 'Content-Type: application/json' \
--data ''
Refer to the Execution Plan details at the bottom of this section.

Process request for status of execution plan approval

curl --location 'http://<router url>/operations/status/12321321' \
--header 'Content-Type: application/json' \
--data ''
{
  "cid": "12321321",
  "isCompleted": true,
  "approval": {
    "status": "approved"
  }
}
{
  "cid": "12321321",
  "isCompleted": true,
  "approval": {
     "status": "rejected",
  "failure": {
    "failureType": "validationFailure",
    "code": 1001,
    "message": "Invalid input data provided"
  }
  }
}

Receive and respond back to primary sale investment token issuance request

The message contains a reference to the execution plan you received. Respond to the process as indicated in order to process this request in an asynchronous manner. The cid you will return will be used next in the operational status polling to receive the progress and completion on processing of the issuance request.

Please note that "hasgroups" section is subject to change, and for up to date specification please refer to https://finp2p-docs.ownera.io/reference/signature-schemes. The signature can be used to verify in this case the signing of the investors on the issuance request commercials.

The executionPlanId provides you with the association of this request to the execution plan provided previously.

curl --location --request POST 'http://<adapter url>/assets/issue' \
--header 'Content-Type: application/json' \
--data-raw '
{
  "nonce": "7282551a6ffc938e58cdb9a32c7e7c2f60e2b0466b47800e0000000063e0c5bd",
  "asset": {
    "resourceId": "bank-us:102:4b2fc630-bc23-4337-be44-97f12875f835",
    "type": "finp2p"
  },
  "destination": {
    "finId": "03c7c9d6b96a678f549c4dd5407eabffc779cf665846846f1a8bb5d5e63cedc8e3",
    "type": "finId"
  },
  "quantity": "10000",
  "settlementRef": "",
  "executionContext": {
    "executionPlanId": "bank-uk:106:9909e355-df0e-4708-8121-cec192089418",
    "instructionSequenceNumber": 2
  },
"signature": {
    "signature": "db96110667579fd876c6b74d8fd848d29d0fb22f114c912202661010a27ef5087b3c9e33fc9af83e1f025e7d180612c7fc0c5f847a61e348dd35309855b29a44",
    "template": {
      "hash": "319581118dc6e2af7a5d92b5e149bed108bd03f2c214371ff28d9ca81206ad60",
      "hashGroups": [
        {
          "fields": [
            {
              "name": "nonce",
              "type": "bytes",
              "value": "16f56a399856b1a6243f5b9afb3e523ea73294be4c95ef0a0000000066d97261"
            },
            {
              "name": "operation",
              "type": "string",
              "value": "issue"
            },
            {
              "name": "assetType",
              "type": "string",
              "value": "finp2p"
            },
            {
              "name": "assetId",
              "type": "string",
              "value": "citi:102:d0c3eb56-0fff-4670-adfd-ad291a4314c3"
            },
            {
              "name": "dstAccountType",
              "type": "string",
              "value": "finId"
            },
            {
              "name": "dstAccount",
              "type": "string",
              "value": "02fd7923740a775c95ce17e9bb7239ff9096689f70db9263a7efb9a9ad08e9fed7"
            },
            {
              "name": "amount",
              "type": "string",
              "value": "1"
            }
          ],
          "hash": "faf3fd67e908cd840298a6f3523631716d4c8df06d69c9a32415f59eaa56825d"
        },
        {
          "fields": [
            {
              "name": "assetType",
              "type": "string",
              "value": "fiat"
            },
            {
              "name": "assetId",
              "type": "string",
              "value": "USD"
            },
            {
              "name": "srcAccountType",
              "type": "string",
              "value": "finId"
            },
            {
              "name": "srcAccount",
              "type": "string",
              "value": "02fd7923740a775c95ce17e9bb7239ff9096689f70db9263a7efb9a9ad08e9fed7"
            },
            {
              "name": "dstAccountType",
              "type": "string",
              "value": "finId"
            },
            {
              "name": "dstAccount",
              "type": "string",
              "value": "03c48631f1d9ca0c89d8da8c7268e4d44f4223737829a9316d940352da3b25c40d"
            },
            {
              "name": "amount",
              "type": "string",
              "value": "10"
            }
          ],
          "hash": "e8a6bc590ed71a70e2507ad842a237cf55bbb751abb38fca61c0c83c4b07bd5f"
        }
      ],
      "type": "hashList"
    }
  }
}
}'
{
    "cid": "6661b36bbc7ee21b182bd909f1e0cb14c40a8d9dd80badee0000000063db7cf9",
    "isCompleted": false,    
    "response": {              
    }
}

Process request for status of execution plan approval if you chose to handle approval asynchronously

Note: The error code and text should designate an exception that is meaningful for investigation of the processing failure.

curl --location --request POST 'http://<adapter_url>/operations/6661b36bbc7ee21b182bd909f1e0cb14c40a8d9dd80badee0000000063db7cf9' \
--header 'Content-Type: application/json' \
--data-raw '
{
}'
{
    "cid": "6661b36bbc7ee21b182bd909f1e0cb14c40a8d9dd80badee0000000063db7cf9",
    "isCompleted": false,    
    "response": {              
    }
}
{
  "type": "receipt",
  "operation": {
    "cid": "6661b36bbc7ee21b182bd909f1e0cb14c40a8d9dd80badee0000000063db7cf9",
    "isCompleted": true,
    "response": {
      "id": "1031C909828C9BB3ED572A0066B1565357A993409DE4330E8319D2D0B7553D64",
      "asset": {
        "type": "finp2p",
        "resourceId": "bank-us:102:4b2fc630-bc23-4337-be44-97f12875f835"
      },
      "quantity": "10000",
      "destination": {
        "finId": "03c7c9d6b96a678f549c4dd5407eabffc779cf665846846f1a8bb5d5e63cedc8e3",
        "account": {
          "type": "finId",
          "finId": "03c7c9d6b96a678f549c4dd5407eabffc779cf665846846f1a8bb5d5e63cedc8e3"
        }
      },      
      "transactionDetails": {
        "transactionId": "1031C909828C9BB3ED572A0066B1565357A993409DE4330E8319D2D0B7553D64"        
      },      
      "timestamp": 1702203549, 
      "operationType": "issue"            
    }
  }
}
{
  "type": "receipt",
  "operation": {
    "cid": "6661b36bbc7ee21b182bd909f1e0cb14c40a8d9dd80badee0000000063db7cf9",
    "isCompleted": true,
    "error": {
      "Code": 18,
      "Message": "Transfer operation failed"
    }
  }
}

You can query the execution plan endpoint to track on status of progression, including operations performed by other routers involved in the trade.

Refer to the Execution Plan API section at the bottom of this section.

Example: Processing Secondary Intent Execution Request

Receive a notification message which indicates of a new execution plan submission for an asset in which is managed by your organization for transfer of ownership between investors in which you will need to approve. If no decision making is required, you can approve immediately, otherwise acknowledge and process it asynchronously.

curl --location --request POST 'http://<adapter url>/plan/approve' \
--header 'Content-Type: application/json' \
--data-raw '
{
  "executionPlanId": "bank-uk:106:aa0ab7c6-3193-44c5-9760-c9e1e048e2a0"
}'
{
  "cid": "12321321",
  "isCompleted": false,
}

{
  "cid": "12321321",
  "isCompleted": true,
  "approval": {
    "status": "approved"
  }
}

You can request from the router for details on the execution plan outlining the full workflow for the execution of the given transaction

curl --location 'http://http://<router url>/finapi/execution/bank-uk:106:aa0ab7c6-3193-44c5-9760-c9e1e048e2a0' \
--header 'Content-Type: application/json' \
--data ''
Refer to Execution Plan details at the bottom of this section.

Process request for status of execution plan approval if you chose to handle approval asynchronously

curl --location 'http://<router url>/operations/status/12321321' \
--header 'Content-Type: application/json' \
--data ''
{
  "cid": "12321321",
  "isCompleted": true,
  "approval": {
    "status": "approved"
  }
}
{
  "cid": "12321321",
  "isCompleted": true,
  "approval": {
     "status": "rejected",
  "failure": {
    "failureType": "validationFailure",
    "code": 1001,
    "message": "Invalid input data provided"
  }
  }
}

Receive a message and respond back to secondary execution request for a transfer of tokens

The message contains a reference to the execution plan you received. Respond to the process as indicated in order to process this request in an asynchronous manner. The cid you will return will be used next in the operational status polling to receive the progress and completion on processing of the transfer request.

curl --location --request POST 'http://<adapter_url>/assets/transfer' \
--header 'Content-Type: application/json' \
--data-raw '{
  "asset": {
    "resourceId": "bank-uk:106:9909e355-df0e-4708-8121-cec192089418",
    "type": "finp2p"
  },
  "source": {
    "account": {
      "finId": "03c7c9d6b96a678f549c4dd5407eabffc779cf665846846f1a8bb5d5e63cedc8e3",
      "type": "finId"
    },
    "finId": "03c7c9d6b96a678f549c4dd5407eabffc779cf665846846f1a8bb5d5e63cedc8e3"
  },
  "destination": {
    "account": {
      "finId": "02ae39c9adaff2485deb65ac3749261089d268874c55ca73c5bd83815154b6ea9c",
      "type": "finId"
    },
    "finId": "02ae39c9adaff2485deb65ac3749261089d268874c55ca73c5bd83815154b6ea9c"
  },
  "executionContext": {
    "executionPlanId": "execution/bank-uk:106:aa0ab7c6-3193-44c5-9760-c9e1e048e2a0",
    "instructionSequenceNumber": 2
  },
  "nonce": "39fc89491a957fc72e12d7eb703c0bd23cd5c54ff612b97f0000000066d97bb6",
  "quantity": "10000",
  "settlementRef": "",
  "signature": {
    "signature": "b1444d7981bd543a24510a178a21a917ee261bcb531d4ef4dbee318e90a4992b30c995f232f87a3d993d8c7e4814cfe7552b6f9825de6dfe8b19b61ab7ffba0b",
    "template": {
      "hash": "5413f45cc5b03b0036f418813c96cbe469efe3f13395c19ff330955858636349",
      "hashGroups": [
        {
          "fields": [
            {
              "name": "nonce",
              "type": "bytes",
              "value": "39fc89491a957fc72e12d7eb703c0bd23cd5c54ff612b97f0000000066d97bb6"
            },
            {
              "name": "operation",
              "type": "string",
              "value": "transfer"
            },
            {
              "name": "assetType",
              "type": "string",
              "value": "finp2p"
            },
            {
              "name": "assetId",
              "type": "string",
              "value": "citi:102:d0c3eb56-0fff-4670-adfd-ad291a4314c3"
            },
            {
              "name": "srcAccountType",
              "type": "string",
              "value": "finId"
            },
            {
              "name": "srcAccount",
              "type": "string",
              "value": "02fd7923740a775c95ce17e9bb7239ff9096689f70db9263a7efb9a9ad08e9fed7"
            },
            {
              "name": "dstAccountType",
              "type": "string",
              "value": "finId"
            },
            {
              "name": "dstAccount",
              "type": "string",
              "value": "0354916de33408d1e30f638fc5920a57166867ded48c0f9098baf5f1a6c1c76676"
            },
            {
              "name": "amount",
              "type": "string",
              "value": "1"
            }
          ],
          "hash": "1d36e25dcd84e29597d9e923446cb13930a8e59bf6cbbca02ee5909e290443a2"
        },
        {
          "fields": [
            {
              "name": "assetType",
              "type": "string",
              "value": "fiat"
            },
            {
              "name": "assetId",
              "type": "string",
              "value": "USD"
            },
            {
              "name": "srcAccountType",
              "type": "string",
              "value": "finId"
            },
            {
              "name": "srcAccount",
              "type": "string",
              "value": "0354916de33408d1e30f638fc5920a57166867ded48c0f9098baf5f1a6c1c76676"
            },
            {
              "name": "dstAccountType",
              "type": "string",
              "value": "finId"
            },
            {
              "name": "dstAccount",
              "type": "string",
              "value": "02fd7923740a775c95ce17e9bb7239ff9096689f70db9263a7efb9a9ad08e9fed7"
            },
            {
              "name": "amount",
              "type": "string",
              "value": "1"
            }
          ],
          "hash": "e18bc18f23990e4a155bdce1afa9b15ef118624133b9af6401e84814a9d9bcf3"
        }
      ],
      "type": "hashList"
    }
  }
}'
{
    "cid": "08d53ff8f3aa9ec71476002facf319b567ddfbd80ab7c1d50000000063d7e00d",
    "isCompleted": false,    
    "response": {              
    }
}

Process polling request to check on status of execution

curl --location --request POST 'http://<adapter_url>/operations/08d53ff8f3aa9ec71476002facf319b567ddfbd80ab7c1d50000000063d7e00d' \
--header 'Content-Type: application/json' \
--data-raw '
{
}'
{
    "cid": "08d53ff8f3aa9ec71476002facf319b567ddfbd80ab7c1d50000000063d7e00d",
    "isCompleted": false,    
    "response": {              
    }
}
{
  "type": "receipt",
  "operation": {
    "cid": "08d53ff8f3aa9ec71476002facf319b567ddfbd80ab7c1d50000000063d7e00d",
    "isCompleted": true,
    "response": {
      "asset": {
        "resourceId": "bank-uk:102:f96240dc-8365-475b-84e2-9611bb5e5bc0",
        "type": "finp2p"
      },
      "id": "f86ea694-2638-4b8d-a407-bfe03217e07a",
      "quantity": "100000",
      "source": {
        "account": {
          "finId": "037fcf0db48dceb2195bd0fc24a4dab68c5731b5b8c141f63d017969a55570c4e9",
          "type": "finId"
        },
        "finId": "037fcf0db48dceb2195bd0fc24a4dab68c5731b5b8c141f63d017969a55570c4e9"
      },
      "destination": {
        "account": {
          "finId": "02af7088141665f96ce1eb3db1bb2b45af58a8b3a09ee0dd64ee921e1b197fe2d5",
          "type": "finId"
        },
        "finId": "02af7088141665f96ce1eb3db1bb2b45af58a8b3a09ee0dd64ee921e1b197fe2d5"
      },            
      "transactionDetails": {
        "transactionId": "1031C909828C9BB3ED572A0066B1565357A993409DE4330E8319D2D0B7553D64"        
      },
      "timestamp": 1702203549,
      "operationType": "transfer"            
    }
  }
}
{
  "type": "receipt",
  "operation": {
    "cid": "08d53ff8f3aa9ec71476002facf319b567ddfbd80ab7c1d50000000063d7e00d",
    "isCompleted": true,
    "error": {
      "Code": 15,
      "Message": "Transfer failed"
    }
  }
}

Process request for the balance of a given asset

curl --location --request GET 'http://<adapter_url>/assets/getBalance' \
--header 'Content-Type: application/json' \
--data-raw '
{
  "owner": {
    "account": {
      "type": "finId",
      "finId": "02d6fea8153a9a64d13e198379dfd4ea3945d03198770e0e5b94f556c4e69f6835"
    }
  },
  "asset": {
    "type": "finp2p",
    "resourceId": "bank-uk:102:f96240dc-8365-475b-84e2-9611bb5e5bc0"
  }
}'

{
  "asset": {
    "type": "finp2p",
    "resourceId": "bank-uk:102:f96240dc-8365-475b-84e2-9611bb5e5bc0"
  },
  "balance": "100000"
}

Process request for a receipt of a previously performed transaction

Firstly The get receipt will be sent, in which you can response with with acknowledgement and process the request asynchronously.

curl --location --request GET 'http://<adapter_url>/assets/getReceipt/73358f79-3b3a-4080-90c3-cbb7edd26668' \
--header 'Content-Type: application/json' \
--data-raw ''

{
    "cid": "08d53ff8f3aa9ec71476002facf319b567ddfbd80ab7c1d50000000063d7e00d",
    "isCompleted": false,    
    "response": {              
    }
}

And the response to the get status operation to provide receipt.

curl --location --request POST 'http://<adapter_url>/operations/08d53ff8f3aa9ec71476002facf319b567ddfbd80ab7c1d50000000063d7e00d' \
--header 'Content-Type: application/json' \
--data-raw '
{
}'
{
  "cid": "08d53ff8f3aa9ec71476002facf319b567ddfbd80ab7c1d50000000063d7e00d",
  "isCompleted": true,
  "response": {
    <Insert the receipt here the same as previously provided>
  }
}

Example: Importing Transactions Manually

The following allows you to send manual updates to Ownera for the case adjustments need to be performed on the user token holdings for the given asset.

The "source" section should be used to take out of the given account the specified amount. The "destination" section should be used to put into the given account the specified amount. Meaning, it incrementally increase or decreases the balance of the quantity specified.

transactionId should be the Id generated on the transacting system, e.g. blockchain ID. OperationID could be used to tie the operation of this import to a previous request that it might be related to, e.g., a deposit request that is related to this.

curl --location --request POST 'http://<router_url>finp2p/ledger/transaction/import' \
--header 'Content-Type: application/json' \
--data-raw '{
    "transactions": [
        {
            "id": "fa5e7391-fce9-4cf6-98e4-b53cdf38d79d",
            "asset": {
                "type": "finp2p",
                "resourceId": "bank-us:102:4b2fc630-bc23-4337-be44-97f12875f835"
            },
            "quantity": "10000",
            "timestamp": 1673863664,
            "destination": {
                "finId": "02ae39c9adaff2485deb65ac3749261089d268874c55ca73c5bd83815154b6ea9c",
                "account": {
                    "type": "finId",
                    "finId": "02ae39c9adaff2485deb65ac3749261089d268874c55ca73c5bd83815154b6ea9c",
                    "orgId": "bank-uk"
                }
            },
            "transactionDetails": {
                "transactionId": "73358f79-3b3a-4080-90c3-cbb7edd26668",
                "operationId": "cbb7edd26668-3b3a-4080-90c3-cbb7edd234668"
            }
        }
    ]
}'
curl --location --request POST 'http://<router_url>finp2p/ledger/transaction/import' \
--header 'Content-Type: application/json' \
--data-raw '{
    "transactions": [
        {
            "id": "fa5e7391-fce9-4cf6-98e4-b53cdf38d79d",
            "asset": {
                "type": "finp2p",
                "resourceId": "bank-us:102:4b2fc630-bc23-4337-be44-97f12875f835"
            },
            "quantity": "10000",
            "timestamp": 1673863664,
            "source": {
                "finId": "02ae39c9adaff2485deb65ac3749261089d268874c55ca73c5bd83815154b6ea9c",
                "account": {
                    "type": "finId",
                    "finId": "02ae39c9adaff2485deb65ac3749261089d268874c55ca73c5bd83815154b6ea9c",
                    "orgId": "bank-uk"
                }
            },
            "transactionDetails": {
                "transactionId": "73358f79-3b3a-4080-90c3-cbb7edd26668",
                "operationId": "cbb7edd26668-3b3a-4080-90c3-cbb7edd234668"
            }
        }
    ]
}'

Execution Plan Details

**Execution Plan**


FieldSub-FieldDescription
idExecution plan unique ID
intentIDThe intent ID in which was created by the trading platform processing the intent request.
instructionsThis section will have repeating sections with each describing the step and the details to perform the execution.
sequence The step in the execution plan, starting from 1.
typeThe operation being performed at the given instruction sequence number, as follows:
1The step in the execution plan which requests the hold of the funds for the transaction.
2The step in the execution plan which requests the issuance or transfer of the asset tokens.
3The step in the execution plan which requests the release of the funds to the issuer or seller.
OrganizationsSpecifies the organization(s) ID that are involved in performing the step in the execution plan.
ParticipantsThis part of the message will outline all the participants that are involved in the execution plan split into two roles:

Contributor - the participants respond to requests and perform actions.

Observers - the participants “listens” to execution plan progression (and can display progress to the end-user).
creationTimeStampThe time the execution plan was submitted, in epoch format.
currentInstructionSequenceProvides you with the current sequence number being waited on or executed.
executionPlanStatusProvides you with the overall status of the execution plan, which can be one of the following values:

Pending - pending start of execution plan or pending the specific sequence number in which the plan is at.
Approved - Plan is approved
Completed - Plan is fully successfully executed
Failed - Plan has failed in execution
Rejected - Plan was rejected by a given participant

Cryptographic Keys and Signature Verifications

FinP2P employs a standardized cryptographic identity (FinID) based on secp256k1 keys. However, integrating this identity across different DLTs, each with varying cryptographic capabilities, requires tailored strategies. Ownera has identified two major approaches, that can be implemented based on the blockchain in which the adapter will be developed against. These strategies prioritize the cryptographic security of both user and organizational operations, and can be combined to create custom solutions that best fit the specific DLT environment.

1. Ledger Cryptographic Strategy:

Description: This approach relies on the DLT built in support for secp256k1 keys. The user's FinP2P identity directly maps to their underlying identity on the DLT, allowing for direct verification and eliminating the need for additional key management by the organization.

When to use: When the DLT natively supports secp256k1 cryptography.

Requires: A FinP2P Operator smart contract deployment that will provide permissioning by the blockchain ledger to receive validate and transact for a given investor key. Including for the FinP2P off chain signature validation and verification that is sent in the payload by the router for the given transaction.

FinP2P Operator Contract Management:

  • User Interaction: FinP2P Sell Side router interacts with the operator contract, which acts as the DLT interface.
  • Forwarding and Verification: The operator contract receives the user's transaction, verifies their FinP2P signature, and transaction with the corresponding token contract.

Allowance in Operator Contracts: In the context of interacting with token contracts, such as ERC20, via the FinP2P operator contract, an essential step involves the establishment of an allowance. This procedure is fundamental for enabling the FinP2P operator contract, which acts as an intermediary, to manage token transactions on behalf of the investor. For more Details.

Examples of Blockchains: EVM type blockchains such as Etherum, Polygon, Tezos, Besu, Quorum and other networks.

2. Account Mapping Strategy:

Description: When the DLT does not support secp256k1 or connection to tokenization platform is via APIs, a local account needs to be created that will be used to map to the user FinP2P identity. The Adapter maintains the mapping between the FinP2P Identity and the tokenization unique identity, In addition optionally enforcing signature validation on chain, based on the FinP2P signature of the investor, Transactions are performed with the local account and validated on chain against the FinP2P Identity.

When to use: When the DLT does not support secp256k1 cryptography.

Requires: A Sell Side Organization to manage local account keys and to optionally add an on chain validation procedure.

FinP2P OnChain Signature Verification:
This strategy leverages smart contracts on DLTs that support them.
The token contract validates the off chain FinP2P cryptographic signature for the underlying action.

Examples of Blockchains: Corda, Canton and other blockchains.