# What is the Verified Network

A Decentralized Finance (Defi) network of licensed financial intermediaries and investors

## Welcome to the Verified Network

The Verified Network provides software infrastructure to&#x20;

* issue tokenized securities that are regulation compliant for distribution&#x20;
* create liquidity pools for primary issues, secondary trading and margin trading that are connected to offchain brokerages and multi-lateral trade facilities
* offer order management and settlement of trades
* pair tokenized securities with tokenized cash issued by electronic money institutions
* manage corporate actions such as distributions of dividends and interest income

## Using the Verified SDK

The Verified SDK provides Javascript APIs to connect web and mobile applications to the Verified Network.

{% content-ref url="/pages/HQypR8UJmiRu8XjnztMa" %}
[Verified SDK](/reference/verified-sdk)
{% endcontent-ref %}

## Using Verified REST APIs

If you want to use liquidity pools for tokenized securities on chain and access market, order and user data, you can use our REST APIs.

{% content-ref url="/pages/rJwxqWHfeHbBs8bmWdX8" %}
[Verified REST API](/reference/verified-rest-api)
{% endcontent-ref %}


# How to use it

Getting started

## Verified SDK

The best way to interact with our API is to use the Verified SDK that enables third party applications to use both gas less and regular transactions that use gas to execute transactions on the ethereum protocol supported chains such as the Ethereum mainnet and L2 networks such as Polygon, Gnosis, Binance chain and Avalanche.

{% tabs %}
{% tab title="Node" %}

```
# Install via NPM
npm install --save @verified-network/verified-sdk
```

{% endtab %}
{% endtabs %}

## Verified REST API

Your REST API requests are authenticated using API keys. Any request that doesn't include an API key will return an error.

You can generate an API key by requesting Verified Network admin here.

## Make your first request

To make your first request, you can use our [Postman collection](https://documenter.getpostman.com/view/1898892/2s9YJaX43s).


# Verified SDK

For payments, investments and financing

The Verified SDK enables integration of any third party application to the Verified Network for executing payment transactions, issuing of tokenized securities and their trading.&#x20;

The Verified Network is a blockchain based network of regulated financial service providers that bridge traditional financial services (Cefi/Tradfi) to decentralized financial services (Defi). They provide the on/off ramps between traditional and decentralized financial services by undertaking activities such as creation of tokenized investment products such as shares, bonds and futures/options, issue of tokenized securities for investment products, fiat pay in to cash tokens and fiat pay out from cash tokens, pairing of tokenized securities with cash tokens and other stablecoins to set up liquidity pools, issuing cards that use cash token balances in Verified wallets, custody of tokenized securities, managing orders on liquidity pools connected to offchain brokerages and exchanges, and servicing assets by reporting corporate actions.  &#x20;

Web3 Applications (Dapps) integrated with the Verified Network using the Verified SDK interface with individual and business users, who can pay, invest and finance using their blockchain wallets KYCed by licensed KYC/AML agents on the Verified Network.


# Using the SDK

Getting Started with Verified Sdk.

The Verified SDK has been used to create web and mobile applications.

To install the Verified SDK, [install nodejs and the node package manager](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm). And then install the Verified SDK.&#x20;

```
D:\Code\your-project>npm install @verified-network/verified-sdk
```

Once installed, you should see the Verified SDK in dependencies in the package.json file in your project.

The Verified SDK provides access to Verified Network contracts deployed on ethereum test networks such as Sepolia. You can use the SDK to develop applications and test them.

To interact with Verified Sdk and integrate it into your project:

```javascript
//Common Js
const {VerifiedWallet, Provider, contractAddress} = require('@verified-network/verified-sdk');
//ES Module
import {VerifiedWallet, Provider, contractAddress} from '@verified-network/verified-sdk';
```

Once ready, you can connect your applications to the production deployment of the Verified Network which is a permissionless network of licensed financial intermediaries.&#x20;

Users of applications on the Verified Network do not incur gas fees and instead pay fees using cash tokens for products and services consumed on the Verified Network.


# Wallet and Contracts

Creating wallets and using contracts

Verified wallets for users can be created either using a dynamically generated mnemonic or by importing mnemonics for an existing private key for the user on a supported ethereum network.

<pre class="language-javascript"><code class="lang-javascript">//Common Js
<strong>const { VerifiedWallet, Provider } = require('@verified-network/verified-sdk'); 
</strong>//ES Module
import { VerifiedWallet, Provider } from '@verified-network/verified-sdk'

/** Step 1: Create Verified Wallet **/
    //Option 1: Generate new Mnemonics and Wallet
    const investorMnemonics = await VerifiedWallet.generateMnemonics()
    const investorWallet = await VerifiedWallet.importWallet(menmonics)
   
     //Option 2: using existing wallet mnemonics
    const investorMnemonics = 'your wallet mnemonics'
    const investorWallet = await VerifiedWallet.importWallet(investorMnemonics); 
    
/** Step 2: Set Provider for Wallet **/ 
    //Option 1: using Default Providers by ethers.js(for networks like mainnet, sepolia, ropstan, polygon e.t.c)
    const defaultProviderNetwork = 'sepolia' // or any other default provider network of your choice.
    //Network/chain id(number) can be used in place of network name, for example:
<strong>    const defaultProviderNetwork = 11155111 // where number 11155111 is chain id for sepolia. any other chain id of default provider network can be used.    
</strong><strong>    const investorWalletProvider = investorWallet.setProvider(
</strong>        Provider.defaultProvider(defaultProviderNetwork)
    )
    
    //Option 2: using custom providers(infura and alchemy)
    const network = 'sepolia' // or any other network of your choice.
    //Network/chain id(number) can be used in place of network name, for example:
    const network = 11155111 // where number 11155111 is chain id for sepolia, any other chain id can be used.
    
    //For infura; to get api key and enable networks checout: https://www.infura.io/
    const INFURA_API_KEY = 'your infura api key'
    const investorWalletProvider = investorWallet.setProvider(
        Provider.infuraProvider(network, INFURA_API_KEY)
    )
    
    //For alchemy; to get api key and enable networks checout: https://www.alchemy.com/
    const ALCHEMY_API_KEY = 'your alchemy api key'
    const investorWalletProvider = investorWallet.setProvider(
        Provider.alchemyProvider(network, ALCHEMY_API_KEY)
    )
</code></pre>

Above, the investor wallet provider can be used to initialize Verified contracts and interact with them by calling various functions on contracts.&#x20;

<pre class="language-javascript"><code class="lang-javascript">/** Import contract **/

//Common Js
const { Client, contractAddress } = require('@verified-network/verified-sdk'); 
//ES Module
import { Client, contractAddress } from '@verified-network/verified-sdk'

/** get chainId **/
<strong>    const conectedNetwork = await investorWalletProvider.getNetwork();
</strong><strong>    const chainId = conectedNetwork.chainId;
</strong><strong>/** fetch contract address **/
</strong><strong>//All verified contracts addresses can be fetched from contractAddress object
</strong>    const networkContractAddresses = contractAddress[chainId]; //All verified contract addresses on connected network
    const clientContractaddress = networkContractAddresses.Client; //Client contract address
/** Initialize Contract **/
    const clientContract = new Client(investorWalletProvider, clientContractaddress);
/** Interact with contract **/
    const investorAddres = await investorWallet.getAddress() //get user address
    await clientContract.getRole(investorAddres);
</code></pre>

\
Wallets from web brower extensions/wallets of any choice like Metamask, Coinbase wallet e.t.c  can be used with Verified Sdk to interact with Verified Contracts.

<pre class="language-javascript"><code class="lang-javascript"><strong>/** install ethers: npm install --save ethers **/
</strong>
//Common Js
const { ethers } = require('ethers');
//ES Module
import { ethers } from 'ethers';

/** Step 1: Get Proider from browser wallet **/
    //MetaMask injects provider as window.ethereum
    //Any provider by web wallet of choice can be used
    const webWalletProvider = window.ethereum; 
    //convert to ethers.js provider
    const provider = new ethers.providers.Web3Provider(webWalletProvider);
    //other ethers provider methods exists that will work 
    //with any provider of choice checkout: https://docs.ethers.org/v5/getting-started/
    
/** Step 2: Connect and get signer to initialise contracts **/
    // MetaMask requires requesting permission to connect users accounts
    //Any connection method for any web browser of choice can be used;
    const connectedAccounts = await provider.send("eth_requestAccounts", []); 
    const signer = provider.getSigner()
</code></pre>

Above, the signer can be used to initialize Verified contracts and interact with them by calling various functions on contracts.&#x20;

```javascript
/** Import contract **/

//Common Js
const { Client, contractAddress } = require('@verified-network/verified-sdk'); 
//ES Module
import { Client, contractAddress } from '@verified-network/verified-sdk'

/** get chainId **/
    const conectedNetwork = await provider.getNetwork();
    const chainId = conectedNetwork.chainId;
/** fetch contract address **/
//All verified contracts addresses can be fetched from contractAddress object
    const networkContractAddresses = contractAddress[chainId]; //All verified contract addresses on connected network
    const clientContractaddress = networkContractAddresses.Client; //Client contract address
/** Initialize Contract **/
    const clientContract = new Client(signer, clientContractaddress);
/** Interact with contract **/
    const investorAddres = connectedAccounts[0] //get first account connected from web wallet
    await clientContract.getRole(investorAddres);
```

Certain contracts are proxies that indirect calls to concrete implementations. For example, cash tokens representing different currencies all have the same behavior and are produced by a cash token factory. In such cases, the contract needs to be parameterized (in this case, with a currency contract's address) before use.

```javascript
const cashUSDIssuer = new CashContract(issuerWallet, VXUSD);
await cashUSDIssuer.payIn('10', investorWallet.address, 'VXUSD')
```

Optionally, all the contract Calls take in an additional parameter: `options?: { gasPrice: number, gasLimit: number }` You can configure the gasPrice and gasLimit using this parameter as the last parameter to the contractCall function. Example: `contract.function(arg 1, arg2, options)` Where, options = {gasPrice: XXX, gasLimit: YYY}


# Know your Customer

KYC for users, investors and issuers

KYC is required for all users on the Verified Network. The amount of information required varies from regular users to investors and issuers.

Basic KYC requires application developers to collect identity and address proof of users and send them to the KYC Contract signed by the user's KYC Manager. KYC Manager is a role delegated to regulated financial service providers that are authorized to do KYC/AML checks such as AMLD5 in Europe. Photo and Video files need to be encrypted, stored in IPFS and a hash of the files sent to the KYC contract signed by the KYC Manager.

To get user's KYC status on Verified Network, call getClientKYC function on Client Contract and decode the output

```javascript
/** Import Client contract **/

//Common Js
const { Client, contractAddress } = require('@verified-network/verified-sdk'); 
//ES Module
import { Client, contractAddress } from '@verified-network/verified-sdk'

const chainId = 'chain id(number) of connected network'
/** fetch contract address **/
//All verified contracts addresses can be fetched from contractAddress object
    const networkContractAddresses = contractAddress[chainId]; //All verified contract addresses on connected network
    const clientContractaddress = networkContractAddresses.Client; //Client contract address
/** Initialize Client Contract **/
    const providerOrSigner = 'provider or signer'  //can be investorWalletProvider from previous page or Signer from web wallets
    const clientContract = new Client(providerOrSigner, clientContractaddress);
/** call getClientKYC function **/
    const userAddress = 'address of user to get kyc status for'
    const userKycResult = await clientContract.getClientKYC(userAddress);
/** decode getClientKYC response/output **/
    const decodedResult = userKycResult.response.result;
    const kycStatus = Number(decodedResult[3]);
```

KYC status can have the following values&#x20;

* 0 - KYC has not been initiated.&#x20;
* 1 - KYC approval is pending.
* 2 - KYC is rejected.
* 3 - KYC is accepted by delegated KYC Manager.

Individual investors require basic KYC and authorization from the investor to obtain financial data from the investor's banks using open banking connectors. Investors are categorized based on net worth and income and their suitability is assessed before they can invest in tokenized financial products on the Verified Network.

Qualified (institutional) investors require the following KYC data to be collected.

* Certified Company register extract
* List of shareholders with 10% or more up to the UBO. The list must:\
  a. Include Each layer of ownership – e.g. all shareholders with 10% or more\
  b. Include The exact full legal name and country of domicile of the shareholder\
  c. Include The exact name and country of nationality of the UBO\
  d. Be dated and signed by authorized signatories of the company
* Latest Articles and Memorandum of Association
* Latest audited annual report/financial statements
* List of authorized signatories <1y
* Certified and valid IDs of authorized signatories
* Certified and valid IDs of the beneficial owners (BOs) (if any)
* Certified and valid IDs of the directors
* Proof of domicile for directors and BOs

&#x20;The following KYC data is required for issuers on the Verified Network.

* Certified Company register extract
* List of shareholders with 10% or more up to the UBO. The list must:\
  a. Include Each layer of ownership – e.g. all shareholders with 10% or more\
  b. Include The exact full legal name and country of domicile of the shareholder\
  c. Include The exact name and country of nationality of the UBO\
  d. Be dated and signed by authorized signatories of the company
* Latest Articles and Memorandum of Association
* Latest audited annual report/financial statements
* List of authorized signatories <1y
* Certified and valid IDs of authorized signatories
* Certified and valid IDs of the beneficial owners (BOs) (if any)
* Certified and valid IDs of the directors
* Proof of domicile for directors and BOs
* CV of BO and directors
* Source and composition of wealth of the UBO incl. milestones of wealth generation
* Source of funds of the company – expected to be available in the audited annual report and/or financial statements.
* Proof of business activity of the company – if not available in the audited annual report and/or financial statements
* Certified regulatory authorization or license applicable to services provided


# Using the KYC plugin

Using Sumsub Plugin with React

Use the KYC Plugin when onboarding new clients.

This integration embeds the KYC flow into your application, allowing users to complete identity verification. Once the user submits their information and the verification is completed, their details are automatically registered with Verified Network.

Recommended use case:

1. Onboarding new customers.
2. Collecting KYC information from users who have not yet been registered with your organization.
3. Providing a seamless verification experience directly within your application.

Registering existing users? See the [Webhook Integration Guide](/reference/verified-sdk/know-your-customer/using-kyc-webhooks).

\
Please note that the Sumsub app token needs to be generated by the Verified Network support team for any third party integration that uses the KYC/AML process of the Verified Network. Contact Verified Team on Discord: <https://discord.com/invite/N5xYeePjmt>\
\
The app tokens from Verified Team are needed to make request to Sumsub API to generate access token that the KYC plugin needs to work. To generate access token from Sumsub Api:

```javascript
/** install ethers, axios and crypto-js: npm i ethers axios crypto-js **/

//Import ethers, axios e.t.c
import { ethers } from 'ethers';
import axios from 'axios';
import hmacSHA256 from 'crypto-js/hmac-sha256';
import hex from 'crypto-js/enc-hex';

const abiCoder = new ethers.utils.AbiCoder();
const userAddress = 'address of user for kyc';
const networkId = 'chain id(string) of network connected to';
const hashedAddress = abiCoder.encode(
  ["string", "string"],
  [userAddress, networkId]
);
const userId = hashedAddress + Math.random().toString(36).substr(2, 9); //id verified uses
const baseUrl = 'https://api.sumsub.com'; //sumsub base url. note: without '/'
const secondUrl = `/resources/accessTokens?userId=${userId}&levelName=contact-details&ttlInSecs=1200`; //note: starts with '/'
const sumsubAppToken = 'your sumsub app token'; //contact Verified Network Team on Discord to get this
const sumsubSecretKey = 'your sumsub secret key'; //contact Verified Network Team on Discord to get this
const ts = Math.floor(Date.now() / 1000); //format current time
const hmacMessage = ts + "POST" + secondUrl; //combine ts, request method(POST) and second url
const signature = hmacSHA256(hmacMessage, sumsubSecretKey); //hash the message with sumsub secret key

//note: url = baseUrl + secondUrl;
//api url to use is 'https://api.sumsub.com/resources/accessTokens?userId=${userId}&levelName=contact-details&ttlInSecs=1200'
const generateSumsubAccessToken = async (url) => {
  return await axios({
    method: "POST",
    url: url,
    headers: {
      Accept: "application/json",
      "X-App-Token": sumsubAppToken,
      "X-App-Access-Ts": ts,
      "X-App-Access-Sig": hex.stringify(signature), 
    },
  })
    .then((res) => {
      const response = res.data;
      return response.token; //return access token
    })
    .catch((err) => {
      //handle request error
      console.error(`Post request to url: ${url} failed with error: ${err}`);
      return;
    });
};

const url = baseUrl + secondUrl;
const accessToken = await generateSumsubAccessToken(url);
```

Access token above will be used with KYC plugin to handle users KYC Verifications

```javascript
/** install websdk-react: npm i @sumsub/websdk-react --save **/

//Import SumsubWebSdk
import { useState } from "react"
import SumsubWebSdk from '@sumsub/websdk-react'

const [isCompleted, setIsCompleted] = useState(false);

//render/display plugin using html/jsx
const accessToken = 'sumsub access token generated above'
<>
<SumsubWebSdk
  accessToken={accessToken}
  expirationHandler={() => Promise.resolve(accessToken)}
  config={{
    lang: "en",
    i18n: {
      document: {
        subTitles: {
          IDENTITY: "Upload a document that proves your identity",
        },
      },
    },
    onMessage: (type, payload) => {
      console.log("WebSDK onMessage", type, payload);
    },
    //customCss can be configured to best suit UI/UX
    uiConf: {
      customCssStr:
        ":root {\n  --black: #000000;\n   --grey: #F5F5F5;\n  --grey-darker: #B2B2B2;\n  --border-color: #DBDBDB;\n}\n\np {\n  color: var(--black);\n  font-size: 16px;\n  line-height: 24px;\n}\n\nsection {\n  margin: 40px auto;\n}\n\ninput {\n  color: var(--black);\n  font-weight: 600;\n  outline: none;\n}\n\nsection.content {\n  background-color: var(--grey);\n  color: var(--black);\n  padding: 40px 40px 16px;\n  box-shadow: none;\n  border-radius: 6px;\n}\n\nbutton.submit,\nbutton.back {\n  text-transform: capitalize;\n  border-radius: 6px;\n  height: 48px;\n  padding: 0 30px;\n  font-size: 16px;\n  background-image: none !important;\n  transform: none !important;\n  box-shadow: none !important;\n  transition: all 0.2s linear;\n}\n\nbutton.submit {\n  min-width: 132px;\n  background: none;\n  background-color: var(--black);\n}\n\n.round-icon {\n  background-color: var(--black) !important;\n  background-image: none !important;\n}",
    },
    onError: (error) => {
      //log error on console to better explain it
      console.error("WebSDK onError", error);
    },
   }
  }
  options={{ addViewportTag: false, adaptIframeHeight: true 
  }}
  onMessage={(type, payload) => {
    console.log("onMessage", type, payload);
    if (type === "idCheck.applicantStatus") {
    //check kyc review status
      if (
        payload.reviewStatus === "pending" ||
        payload.reviewStatus === "completed"
      ) {
        //status is pending or user has completed verification
        //set a state to keep track of this or redirect/render to new page
        setIsCompleted(true);
      }
    }
  }
  }
  onError={(data) => console.log("onError", data)}
/>
{isCompleted && (
//customise this as helper modal to let users know kyc is completed
<div>KYC Completed. You will receive an email after your KYC submission is approved<div>
)}
</>

```


# Using KYC webhooks

Use the Webhook Integration when your clients have already been onboarded and you want to register their existing information with your organization.

Instead of asking users to complete the KYC process again, your system sends their existing customer details to the webhook. The webhook validates and registers the customer with Verified Network, ensuring clients records remain synchronized without requiring another onboarding flow.

Recommended use case:

1. Migrating existing customers to our platform.
2. Registering users who have already completed onboarding in your own system with Verified Network&#x20;
3. Synchronizing users records between your platform and Verified Network.

Onboarding new users? See the [KYC Plugin Guide](/reference/verified-sdk/know-your-customer/using-the-kyc-plugin)

\
**Prerequisites**

Before the webhook integration can be enabled, the following setup is required:

1. You must provide a restricted, read-only Sumsub App Token with permission to retrieve individual applicant details only.
2. We will onboard your organization on our platform and provide you with a unique Organization ID.

\
*Important*: The Organization ID must be included in every webhook request. Requests submitted without a valid Organization ID will be rejected.

\
Contact Verified Team on Discord: <https://discord.com/invite/N5xYeePjmt>&#x20;

\
**Webhook Limitations**

The webhook is designed only to register an existing user on our platform.

When a registration request is successful:

The user is registered on Verified Network with initial KYC status is set to 1 (Pending Approval).

\
The webhook cannot:

1. Verify or approve a user's KYC status on our platform.
2. Update or block a user's KYC status.
3. Perform any KYC management actions.

\
These operations are restricted to authorized KYC managers on our platform.

**KYC Requirement Differences**

A user may have successfully passed KYC within your platform but still not satisfy our platform's KYC requirements.

To handle these cases, an agreed communication process must be established before integration. Depending on the agreed workflow, we may:

1. Contact the user directly using the email address provided during registration, or
2. Notify your team so that you can communicate the additional requirements to the user.

\
This ensures any outstanding compliance requirements can be completed before the user's verification is finalized on our platform.

**KYC Questionnaire**

In addition to the applicant information submitted, users are also required to complete a KYC questionnaire.

The required questionnaire varies depending on the type of user being onboarded. The questionnaire requirements are described in the Know Your Customer (KYC) documentation.

During the integration phase, after your organization has been successfully configured on our platform, we will provide the list of questionnaire fields applicable to your organization user types. These fields should be included as additional data in your webhook requests.

This allows both the applicant information and questionnaire responses to be processed together during user registration.

Note: The KYC questionnaire schema is provided only after your organization has been successfully onboarded and configured on our platform.

**Integration**

Once your organization has been successfully configured on our webhook and we received read-only Sumsub token, we will provide:

1. Your Organization ID.
2. Webhook authentication details.
3. Sample code and integration snippets demonstrating how to submit existing customer details to the webhook.


# Delegated permissions

KYC Manager, Custodian, Depository participant, Asset manager

There are a number of roles that are played by appropriately regulated financial service providers on the Verified Network. These are&#x20;

* KYC Manager - authorized to do KYC/AMLA checks.
* Custodian - licensed custodians and payment institutions that can keep securities and customer deposits in custody, and initiate and settle payments.
* Depository participant - licensed registrar and transfer agents that can register securities, transfer them and settle payments against transfers.
* Asset manager - licensed managers that make and manage investments.

A user can be delegated any of these roles based on their KYC approved by an already existing manager in that country. A manager is set for every user on the Client contract.


# Investment products

Algorithmic contracts for securities

The Verified Network uses a standard that ensures algorithmic progression of an investment product's lifecycle starting from creation of obligations for counterparties, triggering actions based on market data on the product, and corporate actions.

The architecture comprising of all the components is shown below.

<figure><img src="/files/xqoQ0ENurzjobjn2Aytt" alt=""><figcaption></figcaption></figure>

A subset of the contracts, the Product Engines such as ANN engine for an annuity bond implement the contract for the product. Its main features are creation of asset schedules from contract terms and computing state progression. The remaining contracts facilitate asset registration, connection to external data (oracles), tokenization and other aspects related to the lifecycle of an asset on Ethereum.


# Product lifecycle

Handling the lifecycle of an investment product

To understand how the investment product components work together, let's go through a couple of exemplary tasks and discuss them using the illustration below. The tasks have been simplified for this purpose but they nevertheless should give you a good general feeling of the inner workings.

<figure><img src="/files/juoVaSCWlzpbqgKRzinL" alt=""><figcaption></figcaption></figure>

When issuing an asset, a transaction calls the initialize method of the Asset Actor containing the asset terms, ownership information and the address of a Product engine . The exact parameters vary slightly between the contract types. Progressing through the lifecycle of the asset is done via the progress method of the Asset Actor . It retrieves the terms and the current state of the asset from the Asset Registry and uses the Product engines to derive the requirements for the state transition of the asset. For example if a payment is necessary to progress the asset's state, it is executed by the Asset Actor (assuming allowances were set at time of execution). Market Data Providers are whitelisted Ethereum accounts, e.g. decentralized oracles or trusted third parties that can publish data to the Data Registry using the publishDataPoint method. They provide external data points needed for example for rate resets, determining the market value of underlying assets.


# Example of a Product

A Tracker certificate

This product reflects an open-ended performance certificate on an exchange-traded, underlying asset such a Treasury bill. The product offers the investor a bi-monthly redemption option.

The Settlement token in this example can be any cash token such as USDC which is supported by the Verified Network. The Security token in this example is the fund distribution token which is used to parameterize the investment product. Holders of the Security token can withdraw funds from the investment product, which in this case is a Certificate.

```typescript
import Web3 from 'web3';
import BigNumber from 'bignumber.js'; 
import fs from 'fs';

import { AP, APTypes } from '@verified-network/protocol';
import ADDRESS_BOOK from '@verified-network/protocol/ap-chain/addresses.json';

import CERTFTerms from './CERTFTerms.json';
import { keys, rpcURL } from './secret.json';

import SettlementTokenArtifact from '@verified-network/protocol/build/contracts/contracts/tokens/SettlementToken.sol/SettlementToken.json';

(async () => {

    const web3 = new Web3(new Web3.providers.HttpProvider(rpcURL));
    const SecurityTokenArtifact = JSON.parse(fs.readFileSync('./abi/Security.json', 'utf8'));
    const fdt = new web3.eth.Contract(SecurityTokenArtifact.abi, '0xd74109546668c7Fb97a093D9E888D6BF65eadfF0');

    // setup accounts
    keys.forEach((pk: string) => web3.eth.accounts.wallet.add(web3.eth.accounts.privateKeyToAccount(pk)));
    
    const creator = (await web3.eth.getAccounts())[5]; // creator of the asset
    const manager = (await web3.eth.getAccounts())[6]; // manager of the asset
    const anyone = (await web3.eth.getAccounts())[2]; // used to make calls that could be made by any address
    const holder = (await web3.eth.getAccounts())[3]; // future holder of FDTs created by asset manager

    // initialize AP with web3 object and addressBook
    const ap = await AP.init(web3, ADDRESS_BOOK);

    // Deploy Settlement Token
    // @ts-ignore
    const settlementToken = await (new web3.eth.Contract(SettlementTokenArtifact.abi)).deploy(
        { data: SettlementTokenArtifact.bytecode }
    ).send({ from: creator, gas: 2000000 });


    // create the term sheet by setting the currency to the Settlement Token contract we just deployed
    const terms = { ...CERTFTerms };

    // set up ownership
    const ownership = {
        creatorObligor: manager, // account which has to fulfill investor obligations (such as the initial exchange)
        creatorBeneficiary: manager, // account which receives positive cashflows for the investor (such as redemptions)
        counterpartyObligor: creator, // account which has to fulfill issuer obligations (such as paying redemptions)
        counterpartyBeneficiary: creator, //account which receives positive cashflows for the issuer (such as the principal)
    };

    // create new CERTF asset
    const initializeAssetTx = await ap.contracts.certfActor.methods.initialize(
        terms, 
        [], // optionally pass custom schedule, 
        ownership, 
        ap.contracts.certfEngine.options.address, 
        ap.utils.constants.ZERO_ADDRESS,
        ap.utils.constants.ZERO_ADDRESS
    ).send({ from: creator, gas: 2000000 });

    // retrieve the AssetId from the transaction event logs
    const assetId = initializeAssetTx.events.InitializedAsset.returnValues.assetId;
    console.log('AssetId: ' + assetId);

    // get asset terms
    console.log('Terms: ', ap.utils.conversion.parseWeb3Response<APTypes.UTerms>(
        await ap.contracts.certfRegistry.methods.getTerms(assetId).call())
    );

    // get asset state
    console.log('State: ', ap.utils.conversion.parseWeb3Response<APTypes.UState>(
        await ap.contracts.certfRegistry.methods.getState(assetId).call())
    );

    // get next scheduled event for the asset from the CERTF Registry and decode it
    const nextScheduledEvent = await ap.contracts.certfRegistry.methods.getNextScheduledEvent(assetId).call();
    const decodedEvent = ap.utils.schedule.decodeEvent(nextScheduledEvent);
    // in our case that the IED (Initial Exchange event for transferring the principal from the investor to the issuer)
    console.log('Next scheduled event: ', decodedEvent);
    
    //compute pay off using engine
    const payoff = 
        await ap.contracts.certfEngine.methods.computePayoffForEvent(
            await ap.contracts.certfRegistry.methods.getTerms(assetId).call(),
            await ap.contracts.certfRegistry.methods.getState(assetId).call(),
            nextScheduledEvent,
            web3.eth.abi.encodeParameter('uint256', decodedEvent.scheduleTime)
        ).call();
      
    console.log("Pay off: ", payoff);

    // approve actor to execute settlement payment (must be called before progressing the asset)
    // manager has to give allowance to the actor to transfer the principal to the issuer
    await ap.contracts.erc20(terms.currency).methods.approve(
        ap.contracts.certfActor.options.address,
        payoff
    ).send({ from: manager, gas: 2000000 });

    // progress the asset - can be called by any account
    await ap.contracts.certfActor.methods.progress(assetId).send({ from: manager, gas: 2000000 });

    const isEventSettled = await ap.contracts.certfRegistry.methods.isEventSettled(
        web3.utils.toHex(assetId), nextScheduledEvent
    ).call();

    console.log("Is event settled: ", isEventSettled);

    const projectedNextState = 
        await ap.contracts.certfEngine.methods.computeStateForEvent(
            await ap.contracts.certfRegistry.methods.getTerms(assetId).call(),
            await ap.contracts.certfRegistry.methods.getState(assetId).call(),
            nextScheduledEvent,
            web3.utils.toHex(0)
        ).call();
    console.log("Projected next state: ", projectedNextState);
    
    // creator sells 50% of his FDTs to a third party
    await fdt.methods.transfer(
        holder,
        new BigNumber(await fdt.methods.balanceOf(manager).call()).dividedBy(2).toString()
    ).send({ from: manager, gas: 1000000 });

    // set FDT contract as new beneficiary for asset
    // in our case the FDT will receive and distribute all future payments
    await ap.contracts.certfRegistry.methods.setCreatorBeneficiary(
        assetId,
        fdt.options.address
    ).send({ from: manager, gas: 2000000 });
    
    // approve actor to execute settlement payment
    // debtor has to give allowance to the Actor to transfer the first payment
    await settlementToken.methods.approve(
        ap.contracts.certfActor.options.address,
        '25479452054794518000'
    ).send({ from: creator, gas: 2000000 });
    
    // update internal balances in the FDT (can be called by any account)
    await fdt.methods.updateFundsReceived().send({ from: holder, gas: 2000000 })

    // check withdrawable funds for fractional owner after calling updateFundsReceived
    const withdrawableAmount = await fdt.methods.withdrawableFundsOf(holder).call()
    // Holder received 50% of the first interst payment
    console.log('Withdrawable Balance of Holder: ' + withdrawableAmount.toString());
    
})();

```

The Certificate's terms that need to be specified by an application user is in the following format.

```
{
  "contractType": "CERTF",
  "calendar": "MF",
  "contractRole": "BUY",
  "dayCountConvention": "AA",
  "businessDayConvention": "CSF",
  "endOfMonthConvention": "EOM",
  "couponType": "NOC",
  "currency": "0x1c36690810ad06fb15552657c7a8ff653eb46f76",
  "settlementCurrency": null,
  "issueDate": "2020-06-18T00:00:00.000Z",
  "statusDate": "2020-06-18T00:00:00.000Z",
  "initialExchangeDate": null,
  "maturityDate": null,
  "cycleAnchorDateOfRedemption": "2020-07-18T00:00:00.000Z",
  "cycleAnchorDateOfTermination": null,
  "cycleAnchorDateOfCoupon": null,
  "nominalPrice": "1000",
  "issuePrice": "987.14",
  "quantity": "1000",
  "denominationRatio": "1",
  "couponRate": "0",
  "gracePeriod": "10D",
  "delinquencyPeriod": "90D",
  "settlementPeriod": "2D",
  "fixingPeriod": "0D",
  "redemptionRecordPeriod": "1D",
  "cycleOfRedemption": "1M-",
  "cycleOfTermination": "0D-",
  "cycleOfCoupon": "0D-",
  "contractStructure": {
    "contractReference": [
      {
        "object": "0x43483232337276325f5246445f5241",
        "object2": "0x756e646566696e6564",
        "type": "MOC",
        "role": "UDL"
      },
      {
        "object": "0x43483232337276325f5246445f5154",
        "object2": "0x756e646566696e6564",
        "type": "MOC",
        "role": "UDL"
      }
    ]
  }
}
```


# Security tokens

Tokenizing investment products

Investment product contracts consume and generate cash flows that are owed to or by holders of securities. For example, a shareholder holds a share token that owes the shareholder dividends generated by the share. Similarly, a bond holder holds a bond token that is owed interest by the issuer of the bond.&#x20;

A security token is therefore nothing but a contract that has the rights and obligations of an underlying registered security which is defined by an investment product's smart contract. The holder of a security token for an investment product therefore has the rights to and obligations for any cash transfers required or generated by the investment product.

Request to issue a security token can be made by calling the `issueSecurity` function on the Securities Factory contract. `getHolder` returns the issuer of a security token. `getSecurity` returns the investment product address for a security token. `getSecurityToken` returns ISIN, company, currency and a boolean whether a security token is accessible to retail or qualified investors. &#x20;

The requests to issue security tokens are assessed by Registrar and Transfer agents on the Verified Network which decides on its approval. Only approved security tokens are operational on the Verified Network. Only a Registrar and Transfer agent or the issuer of a security token can whitelist its holders. Only whitelisted security token holders can call the `approve`, `transfer`, `transferFrom` functions in a security token.&#x20;

The Registrar and Transfer agent is responsible for administering corporate actions on the security token.&#x20;


# Issuing functions

Requesting issue of security tokens and querying them

The following functions are to be called on the Securities Factory contract.&#x20;

### **Request issue of a Security token**

```typescript
issueSecurity(  _security: string,
                _category: string,
                _company: string, 
                _isin: string, 
                _currency: string, 
                _issuer: string,
                _intermediary: string,                
                _restrictions: string,
                _country: string,
                _qualified: string
                )
```

| \_security     | address of associated investment product                                |
| -------------- | ----------------------------------------------------------------------- |
| \_category     | string product category (eg, Shares)                                    |
| \_company      | string issuing business                                                 |
| \_currency     | address of settlement token                                             |
| \_issuer       | address of issuer wallet requesting issue                               |
| \_intermediary | address of registrar and transfer agent                                 |
| \_restrictions | bytes encoded array of restricted countries                             |
| \_country      | string country of issuer                                                |
| \_qualified    | boolean indicating access of security token to only qualified investors |

### **Query issuer of a Security token**

```
getHolder(_token: string)
```

### **Query investment product for a Security token**

```typescript
getSecurity(_token: string)
```

### **Query other attributes of a Security token**

```typescript
getSecurityToken(_token: string, _issuer: string)
```

| \_token  | address of security token issued |
| -------- | -------------------------------- |
| \_issuer | address of security token issuer |


# Liquidity pools

How to swap security tokens

To Buy/Sell security tokens, Edit/Cancel orders and Settle trades on Verified Network, user needs to call swap or batchSwap function on Verified Pool contract. The "userData" , "asset in", "asset out" arguments passed to either swap or batchSwap determine the type of swap.

For Buying or Selling of Security Tokens: Asset in is either Currency token address for Buy orders or Security  token address for Sell orders. Asset out is Pool address(VPT token address of the pool) for both.&#x20;

```javascript
/** Import Pool contract and ethers **/

//Common Js
const { Pool } = require('@verified-network/verified-sdk'); 
const { ethers } = require('ethers');
//ES Module
import { Pool } from '@verified-network/verified-sdk'
import { ethers } from 'ethers';

/** Initialize Pool Contract and abi encoder**/
    const providerOrSigner = 'provider or signer'  //can be investorWalletProvider from Wallet and Contracts page or Signer from web wallets
    const poolContract = new Pool(providerOrSigner);
    const abiCoder = new ethers.utils.AbiCoder();

/** Format Swap Arguments **/
 //Argument 1: Swap
    const swapType = 'Market or Limit' //type of swap
    const poolId = 'id of pool to swap from in bytes' //e.g 0x1c54eb0a8bea5eeaf07b1b6d2238baf4bf6d6a4800000000000000000000009a
    const swapKind = 'number 0 or 1' //SwapExactIn = 0 or SwapExactOun = 1;
    const assetIn = 'address of token to swap in(token from)' //when security address is token in it means Sell order, when currency address is token in it means Buy order
    const assetOut = 'address of token out' //same as poolAddress(VPT token) e.g 0x1c54eb0a8BEa5eEaf07b1b6d2238BAf4BF6D6a48
    const amount = 'number(amount) of token in' //must be in same decimal places with token in.
    let userData;
    //There are 2 types of swap.
    // 1. Market: swap without price will be traded at current market price.
    if(swapType === "Market") {
        userData = "0x" //null abi encoded parameter of [bytes32, uint]
        //same as abiCoder.encode(["bytes32", "uint"],[]);
    }
    // 2. Limit: swap with price, will be traded at price specified.
    if(swapType === "Limit") {
        const priceWei = 'number(amount) of price in wei'
        userData = abiCoder.encode(
          ["bytes32", "uint256"],
          [ethers.utils.formatBytes32String("Limit"), priceWei]
        );
    }
    //This type of swap with 'kind' works for swap, for batchSwap it does not have 'kind'.
     const swap = {
         poolId: poolId,
         kind: swapKind,
         assetIn: assetIn,
         assetOut: assetOut,
         amount: amount,
         userData: userData
     }
 //Argument 2: Funds
    const funds = {
        sender: 'investor/sender address', //address of swap sender
        fromInternalBalance: false, //boolean must be false not to use internal balance
        recipient: 'investor/sender address', //address of swap receiver
        toInternalBalance: false, //boolean must be false not to use internal balance
     }
 //Argument 3: limit
     const limit = 'number of amountIn limit' //e.g 0 or amount of token in
 //Argument 4: Deadline
     const deadline = 'number deadline of transaction' //e.g 999999999999999999(infinity) or very high number
     
/** Call swap or batchSwap on Pool contract **/
    //Swap: for single swap
    await poolContract.swap(swap, funds, limit, deadline).then((res) => {
        const swapResponse = res.response;
        if(swapResponse.status === 0) { 
            //status 0 means succesful transaction
            console.log("swap successful with transaction hash: ", swapResponse.hash)
        }else{
            //status 1 means failed transaction
            console.error("Unexpected error occured while calling swap function with message: ", swapResponse.message || swapResponse.reason)
        }
    }).catch((err) => {
        console.error("Swap failed with error: ", err)
    })
    
    //batchSwap: single and multiple swaps. cost less gas
    //call getPoolTokens to get pool tokens list.
    const poolTokensResponse = await poolContract.getPoolTokens(poolId);
    const assests = poolTokensResponse.response.result; //array of tokens address(includes security, currency and pool addrress)
    const assetInIndex = assests.findIndex((tkn) => {
        return tkn.toLowerCase() === assetIn.toLowerCase();
    });//batchswap takes assetInindex(index of tokenIn in assests array) unlike swap with assetIn(address of token in)
    const assetOutIndex = poolTokens.tokens.findIndex((tkn) => {
    return tkn.toLowerCase() === assetOut.toLowerCase();
    });//batchswap takes assetOutindex(index of token out in assests array) unlike swap with assetOut(address of token out)
    let limits = new Array(3).fill(0); //batchswap takes limits in array of numbers unlike swap with limit as number
    limits[assetInIndex] = amount; //update the limit for index of token in.
    let batchSwap = {
        poolId: poolId, //the same with poolId above
        assetInIndex: assetInIndex,
        assetOutIndex: assetOutIndex,
        amount: amount, //the same with amount above.
        userData: userData //the same with userData above
    } //does not have 'kind' like swap argument
    
    const swaps = [batchSwap] //batchSwap takes swaps in array. add more swap for multiple swaps
    await poolContract.batchswap(swapKind, swaps, assests, funds, limits, deadline).then((res) => {
        const batchSwapResponse = res.response;
        if(batchSwapResponse.status === 0) {
             //status 0 means succesful transaction
            console.log("batchswap successful with transaction hash: ", batchSwapResponse.hash)
        }else{
            //status 1 means failed transaction
            console.error("Unexpected error occured while calling batchswap function with message: ", batchSwapResponse.message || batchSwapResponse.reason)
        }
    }).catch((err) => {
        console.error("Batchswap failed with error: ", err)
    }
```

For Cancel/Edit Orders: Asset in is Pool address(VPT token address of the pool) for Cancel order or Currency/Security token address for Edit order. Asset out is Security/Currency token address for Cancel Order or Pool address(VPT token address of the pool) for Edit order.

```javascript
/** Import Pool contract and ethers **/

//Common Js
const { Pool } = require('@verified-network/verified-sdk'); 
const { ethers } = require('ethers');
//ES Module
import { Pool } from '@verified-network/verified-sdk'
import { ethers } from 'ethers';

/** Initialize Pool Contract and abi encoder**/
    const providerOrSigner = 'provider or signer'  //can be investorWalletProvider from Wallet and Contracts page or Signer from web wallets
    const poolContract = new Pool(providerOrSigner);
    const abiCoder = new ethers.utils.AbiCoder();

/** Format Swap Arguments **/
 //Argument 1: Swap
    const poolId = 'id of pool in bytes' //e.g 0x1c54eb0a8bea5eeaf07b1b6d2238baf4bf6d6a4800000000000000000000009a
    const swapKind = 'number 0 or 1' //SwapExactIn = 0 or SwapExactOun = 1;
    const assetIn = 'address of token to swap in(token from)' // pool address for cancel order, security/currency address for edit order
    const assetOut = 'address of token out' // security/currency address for cancel order. pool address for edit  order
    const amount = 'number(amount) of token in' //must be in same decimal places with token in.
    const orderReference = 'order reference of order to cancel or edit in bytes32'
    const price = 'number(amount) of new price' //0 for cancel order
    //for cancel order
    const userData = abiCoder.encode(
      ["bytes32", "uint256"],
      [orderReference, 0]
    );
    //for edit order
    const userData = abiCoder.encode(
      ["bytes32", "uint256"],
      [orderReference, price]
    );
    //This type of swap with 'kind' works for swap, for batchSwap it does not have 'kind'.
     const swap = {
         poolId: poolId,
         kind: swapKind,
         assetIn: assetIn,
         assetOut: assetOut,
         amount: amount,
         userData: userData
     }
 //Argument 2: Funds
    const funds = {
        sender: 'investor/sender address', //address of swap sender
        fromInternalBalance: false, //boolean must be false not to use internal balance
        recipient: 'investor/sender address', //address of swap receiver
        toInternalBalance: false, //boolean must be false not to use internal balance
     }
 //Argument 3: limit
     const limit = 'number of amountIn limit' //e.g 0 or amount of token in
 //Argument 4: Deadline
     const deadline = 'number deadline of transaction' //e.g 999999999999999999(infinity) or very high number
     
/** Call swap or batchSwap on Pool contract **/
    //Swap: for single swap
    await poolContract.swap(swap, funds, limit, deadline).then((res) => {
        const swapResponse = res.response;
        if(swapResponse.status === 0) { 
            //status 0 means succesful transaction
            console.log("swap successful with transaction hash: ", swapResponse.hash)
        }else{
            //status 1 means failed transaction
            console.error("Unexpected error occured while calling swap function with message: ", swapResponse.message || swapResponse.reason)
        }
    }).catch((err) => {
        console.error("Swap failed with error: ", err)
    })
    
    //batchSwap: single and multiple swaps. cost less gas
    //call getPoolTokens to get pool tokens list.
    const poolTokensResponse = await poolContract.getPoolTokens(poolId);
    const assests = poolTokensResponse.response.result; //array of tokens address(includes security, currency and pool addrress)
    const assetInIndex = assests.findIndex((tkn) => {
        return tkn.toLowerCase() === assetIn.toLowerCase();
    });//batchswap takes assetInindex(index of tokenIn in assests array) unlike swap with assetIn(address of token in)
    const assetOutIndex = poolTokens.tokens.findIndex((tkn) => {
    return tkn.toLowerCase() === assetOut.toLowerCase();
    });//batchswap takes assetOutindex(index of token out in assests array) unlike swap with assetOut(address of token out)
    let limits = new Array(3).fill(0); //batchswap takes limits in array of numbers unlike swap with limit as number
    limits[assetInIndex] = amount; //update the limit for index of token in.
    let batchSwap = {
        poolId: poolId,
        assetInIndex: assetInIndex,
        assetOutIndex: assetOutIndex,
        amount: amount, //the same with amount above.
        userData: userData //the same with userData above
    } //does not have 'kind' like swap argument
    const swaps = [batchSwap] //batchSwap takes swaps in array. add more swap for multiple swaps
    await poolContract.batchswap(swapKind, swaps, assests, funds, limits, deadline).then((res) => {
        const batchSwapResponse = res.response;
        if(batchSwapResponse.status === 0) {
             //status 0 means succesful transaction
            console.log("batchswap successful with transaction hash: ", batchSwapResponse.hash)
        }else{
            //status 1 means failed transaction
            console.error("Unexpected error occured while calling batchswap function with message: ", batchSwapResponse.message || batchSwapResponse.reason)
        }
    }).catch((err) => {
        console.error("Batchswap failed with error: ", err)
    }
```

To Settle trades: Asset in is Pool address(VPT token address of the pool). Asset out is either Security token address for Buy orders or Currency token address for Sell orders.

```javascript
/** Import Pool contract and ethers **/

//Common Js
const { Pool } = require('@verified-network/verified-sdk'); 
const { ethers } = require('ethers');
//ES Module
import { Pool } from '@verified-network/verified-sdk'
import { ethers } from 'ethers';

/** Initialize Pool Contract and abi encoder**/
    const providerOrSigner = 'provider or signer'  //can be investorWalletProvider from Wallet and Contracts page or Signer from web wallets
    const poolContract = new Pool(providerOrSigner);
    const abiCoder = new ethers.utils.AbiCoder();

/** Format Swap Arguments **/
 //Argument 1: Swap
    const poolId = 'id of pool in bytes' //e.g 0x1c54eb0a8bea5eeaf07b1b6d2238baf4bf6d6a4800000000000000000000009a
    const swapKind = 'number 0 or 1' //SwapExactIn = 0 or SwapExactOun = 1;
    const assetIn = 'address of token to swap in(token from)' // pool address(vpt token address of the pool)
    const assetOut = 'address of token out' // security address for buy orders and currency address for sell orders
    const amount = 'number(amount) to settle' //must be in same decimal places with token in.
    const tradeTime = 'number(timestamp) of trade' //time trade to settle was created
    const userData = abiCoder.encode(
      ["bytes32", "uint256"],
      [ethers.utils.formatBytes32String(""), tradeTime]
    );
    //This type of swap with 'kind' works for swap, for batchSwap it does not have 'kind'.
     const swap = {
         poolId: poolId,
         kind: swapKind,
         assetIn: assetIn,
         assetOut: assetOut,
         amount: amount,
         userData: userData
     }
 //Argument 2: Funds
    const funds = {
        sender: 'investor/sender address', //address of swap sender
        fromInternalBalance: false, //boolean must be false not to use internal balance
        recipient: 'investor/sender address', //address of swap receiver
        toInternalBalance: false, //boolean must be false not to use internal balance
     }
 //Argument 3: limit
     const limit = 'number of amountIn limit' //e.g 0 or amount of token in
 //Argument 4: Deadline
     const deadline = 'number deadline of transaction' //e.g 999999999999999999(infinity) or very high number
     
/** Call swap or batchSwap on Pool contract **/
    //Swap: for single swap
    await poolContract.swap(swap, funds, limit, deadline).then((res) => {
        const swapResponse = res.response;
        if(swapResponse.status === 0) { 
            //status 0 means succesful transaction
            console.log("Settle trade successful with transaction hash: ", swapResponse.hash)
        }else{
            //status 1 means failed transaction
            console.error("Unexpected error occured while settling trade with message: ", swapResponse.message || swapResponse.reason)
        }
    }).catch((err) => {
        console.error("Settle trade failed with error: ", err)
    })
    
    //batchSwap: single and multiple swaps. cost less gas
    //call getPoolTokens to get pool tokens list.
    const poolTokensResponse = await poolContract.getPoolTokens(poolId);
    const assests = poolTokensResponse.response.result; //array of tokens address(includes security, currency and pool addrress)
    const assetInIndex = assests.findIndex((tkn) => {
        return tkn.toLowerCase() === assetIn.toLowerCase();
    });//batchswap takes assetInindex(index of tokenIn in assests array) unlike swap with assetIn(address of token in)
    const assetOutIndex = poolTokens.tokens.findIndex((tkn) => {
    return tkn.toLowerCase() === assetOut.toLowerCase();
    });//batchswap takes assetOutindex(index of token out in assests array) unlike swap with assetOut(address of token out)
    let limits = new Array(3).fill(0); //batchswap takes limits in array of numbers unlike swap with limit as number
    limits[assetInIndex] = amount; //update the limit for index of token in.
    let batchSwap = {
        poolId: poolId,
        assetInIndex: assetInIndex,
        assetOutIndex: assetOutIndex,
        amount: amount, //the same with amount above.
        userData: userData //the same with userData above
    } //does not have 'kind' like swap argument
    const swaps = [batchSwap] //batchSwap takes swaps in array. add more swap for multiple swaps
    await poolContract.batchswap(swapKind, swaps, assests, funds, limits, deadline).then((res) => {
        const batchSwapResponse = res.response;
        if(batchSwapResponse.status === 0) {
             //status 0 means succesful transaction
            console.log("settle trade successful with transaction hash: ", batchSwapResponse.hash)
        }else{
            //status 1 means failed transaction
            console.error("Unexpected error occured while settling trade with message: ", batchSwapResponse.message || batchSwapResponse.reason)
        }
    }).catch((err) => {
        console.error("Settle trade failed with error: ", err)
    }
```


# Buy and Sell Orders workflow

From the previous page(Liquidity pools) we discussed how to create Buy and Sell Orders for Market and Limit order type. We also discussed how to Edit, Cancel and Claim/Settle Orders.

All the actions/functions above are all connected with a simple Buy and Sell Orders workflow, For both Buy and Sell orders the asset/token out is VPT (Verified Pool Token). VPT is Verified Pool Token it has the same address as the pool address, and for every pool created on verified network a VPT is created. So all Verified pools have 3 tokens/assets:

1. **VPT(Verified Pool Token):** created when the pool is created and have same address with pool address.
2. **Security Token**
3. **Currency Token**

You can consider VPT as a reward token for a particular pool because for every Buy and Sell orders/swaps in the pool the token given out/received like a reward is VPT(Verified Pool Token).&#x20;

For example if I intended to buy some Verified Security from a Verified Pool using the paired Currency in the pool. I will need to:

1. &#x20;Have the paired currency I want to buy security with in my wallet(faucets can be used to get this for testnet, for mainnet various ways can be used).
2. Create a Buy order by calling swap or batchSwap function on Verified Pool Contract using Verified SDK as explained in previous page. The Buy Order can either be Market(order without price, it will buy at market price) or Limit(order with price, will only buy at the maximum price specified or at price below specified price).

A successful Buy Order will deposit the amount of paired currency i specified when creating the order in the Verified Pool and equivalent amount(done by series of calculation) of VPT will be sent to me, hence why the token/asset out is VPT and token/asset in is Currency for all Buy orders.

Similarly if I intended to sell some Verified Security from a Verified Pool to get back the paired currency. I will need to:

1. &#x20;Have the security to sell in my wallet, this can be achieved through 2 different ways:

&#x20;          i. Get it transferred to me from the issuer/creator of the security or any other allowed(whitelisted) parties.

&#x20;          ii. Claim Security with the VPT: this is the ideal way most users/investors will get verified securities, by claiming security using VPT(Verified Pool Token), hence why VPT can be called a reward token in the sense that it can redeemed to get either security or currency to complete an order. To claim Security using VPT a claim order will be created by calling swap or batchSwap on Verified Pool Contract using Verified SDK as explain in previous page. A successful claim trade order will deposit the VPT Pool and withdraw/send security token to user's wallet.

2. Create a Sell order by calling swap or batchSwap function on Verified Pool Contract using Verified SDK as explained in previous page.

A successful Sell Order will deposit the amount security i specified when creating the order in the Verified Pool and equivalent amount(done by series of calculation) of VPT will be sent to me, hence why the token/asset out is VPT and token/asset in is Security for all Sell orders. The Sell Order can either be Market(order without price, it will sell at market price) or Limit(order with price, will only sell at the minimum price specified or price above specified price).

\
Examples above shows that Buy/Sell Orders are not complete orders, because you get VPT(Verified Pool Token) instead of the desired tokens you wanted to buy or sell. To complete the order a Claim trade order needs to be done which will deposit received VPT to give out either Currency or Security depending on the type of trade claimed, then the trade is Completed(Settled). For every trades claimed on Verified Networks they are marked as Settled trades, hence why Settle trade can be used in place of Claim trade.\
\
If you noticed 'trade/trades' were used in place of 'order/orders' in the summary above, this is because for an order to be claimed/settled it needed to first become a trade. A trade is a matched order on Verified network. The normal Buy/Sell orders created are orders waiting to be matched.

Just like most regular orderbooks, a buy order is matched with a sell order and the orders are filled if they meet their respective requirement(prices and amount). Buy and Sell orders are matched on Verified networks and when this happens the orders are marked as Matched orders(trade) because a trade occurs when 2 orders matched with each other. After a trade occurs users can then claim such trade using VPT to get any desired token from the trade as explained above.\
\
In summary, a complete swap on Verified Network takes places in 3 steps:

1. User will need to have Currency/Security to create Buy/Sell order respectively and VPT will be sent to the user.&#x20;
2. The created order will matched with opposite orders to create a Trade.&#x20;
3. The received VPT from step 1 will be used to settle the Trade in step 2 to complete swap and receive either Security/Currency.

Other actions/functions on Verified Pool Contract are Edit and Cancel Order. These are used to edit and cancel an existing Buy/Sell Order before they are matched.&#x20;


# Buy and Sell Order Complete workflow example

From previous page Buy/Sell orders workflow was explained theoretically, this page will show various examples of a complete workflow using codes. Make sure you have read and understand previous page.

Since Currency is needed to create Buy order and Security is needed to create Sell Order and Getting Currency token is easier from various faucet for testnet and markets for mainnets. We will start the workflow with a Buy Order(to buy security using currency gotten from faucet or bought) then proceed to Claim the Buy order that has been Matched(Trade) to get Security then creating a Sell order(to sell the security and get currency back) and finally Claim the Matched Sell Order(Trade) to get back Currency. please read previous page if you don't understand how all these steps are connected in the workflow.

```javascript
/** Import Pool and ERC20 contract and ethers **/

//Common Js
const { Pool, ERC20 } = require('@verified-network/verified-sdk'); 
const { ethers } = require('ethers');
//ES Module
import { Pool } from '@verified-network/verified-sdk'
import { ethers } from 'ethers';

/** Initialize Pool Contract and abi encoder**/
    const providerOrSigner = 'provider or signer'  //can be investorWalletProvider from Wallet and Contracts page or Signer from web wallets
    const poolContract = new Pool(providerOrSigner);
    const abiCoder = new ethers.utils.AbiCoder();

/** Format Swap Arguments **/
//note arguments marked as general arguments are arguments that are needed for both swap and batchSwap
    //general arguments
    const swapType = 'Market or Limit' //type of swap best to use 'Market' (so it will trade faster for this example)
    const poolId = 'id of pool to swap from in bytes' //e.g 0x1c54eb0a8bea5eeaf07b1b6d2238baf4bf6d6a4800000000000000000000009a
    const swapKind = 'string 0 or 1' //SwapExactIn = 0 or SwapExactOun = 1; best to use '0' all the time
    const assetIn = 'address of token to swap in(token from)' //will be currency since it's buy order
    const assetOut = 'address of token out' //same as poolAddress(VPT token) e.g 0x1c54eb0a8BEa5eEaf07b1b6d2238BAf4BF6D6a48
    const amount = 'string(amount) of token in' //must be in same decimal places with token in. see best calculation below
    //const amount = (amountRaw * 10 ** assetInDecimals).toString(); where amountRaw = whole number like 1, 2 and assetInDecimals is result of decimals() call on assest in ERC20 contract.  
    let userData;
    //There are 2 types of swap.
    // 1. Market: swap without price will be traded at current market price.
    if(swapType === "Market") {
        userData = "0x" //null abi encoded parameter of [bytes32, uint]
        //same as abiCoder.encode(["bytes32", "uint"],[]);
    }
    // 2. Limit: swap with price, will be traded at price specified.
    if(swapType === "Limit") {
        const priceWei = 'number(amount) of price in wei' //must be in 18 decimals(wei decimals)
        userData = abiCoder.encode(
          ["bytes32", "uint256"],
          [ethers.utils.formatBytes32String("Limit"), priceWei]
        );
    }
    //general argument 4: Deadline
     const deadline = 'string deadline of transaction' //e.g '999999999999999999'(infinity) or very high number in string
    const funds = {
        sender: 'investor/sender address', //address of swap sender
        fromInternalBalance: false, //boolean must be false not to use internal balance
        recipient: 'investor/sender address', //address of swap receiver
        toInternalBalance: false, //boolean must be false not to use internal balance
     }
/** Call approve on assest in contract so vault can have access to it **/
const assetInContract = new ERC20(providerOrSigner, assetIn);
const balancerVault = '0xBA12222222228d8Ba445958a75a0704d566BF2C8' //general vault address for all network
let isApproved = false;
 await assetInContract
    .approve(balancerVault, amount)
    .then((res) => {
      if (res && res.status === 0) {
        //handle successful approve
        console.log("approve succesful with hash: ", res.response.hash);
        isApproved = true;
      }
    })
    .catch((err) => {
      //handle approve error
      console.error("approve failed with error: ", err);
    });
/**Call swap or batchSwap on Pool contract **/
    //Option 1: Swap: for single swap
    //Option 1(swap) argument 1: This type of swap with 'kind' works for swap, for batchSwap it does not have 'kind'.
     const swap = {
         poolId: poolId,
         kind: swapKind,
         assetIn: assetIn,
         assetOut: assetOut,
         amount: amount,
         userData: userData
     }
     //Option 1(swap) argument 2:
     const limit = 'string of amountIn limit' //e.g '0' or amount of token in(can be the same as amount or leave it as '0')
    if(isApproved) {
        //begining of parameters needed for web wallet(metamsk) only//
      const VPTAddress = 'VPT address the same with pool address'
      const accountAddress = 'user/investor address' 
      const VPTContract = new ERC20(providerOrSigner, VPTAddress);
      const VPTBalanceBeforeSwap = await VPTContract.balanceOf(accountAddress);
       //end of parameters needed for web wallet(metamsk) only//
        await poolContract.swap(swap, funds, limit, deadline).then((res) => {
        const swapResponse = res.response;
        if(swapResponse.status === 0) { 
            //status 0 means succesful transaction
            console.log("swap successful with transaction hash: ", swapResponse.hash)
            //the code below is for project using web wallets(metamask) only
            //it will add VPT to users token lists.
            if (Number(VPTBalanceBeforeSwap.response.result) <= 0) {
              const provider = 'web wallet(metamask) provider' //it must be web wallet provider signer won't work.
              await provider.request({
                method: "wallet_watchAsset",
                params: {
                  type: "ERC20",
                  options: {
                    address: VPTAddress,
                    symbol: "VPT",
                    decimals: 18,
                  },
                },
              }).then((_res) => {
                  console.log("VPT added to token list succesfully")
              }).catch((err) => {
                  console.error("Error while adding VPT to token list: ", err)
              });
        }else{
            //status 1 means failed transaction
            console.error("Unexpected error occured while calling swap function with message: ", swapResponse.message || swapResponse.reason)
        }
    }).catch((err) => {
        console.error("Swap failed with error: ", err)
    })
    }
    
    //=======================//
    
    //Option 2: (batchSwap): single and multiple swaps. reconmended it cost less gas **/
    //call getPoolTokens to get pool tokens list.
    const poolTokensResponse = await poolContract.getPoolTokens(poolId);
    const assests = poolTokensResponse.response.result; //array of tokens address(includes security, currency and pool addrress)
    const assetInIndex = assests.findIndex((tkn) => {
        return tkn.toLowerCase() === assetIn.toLowerCase();
    });//batchswap takes assetInindex(index of tokenIn in assests array) unlike swap with assetIn(address of token in)
    const assetOutIndex = poolTokens.tokens.findIndex((tkn) => {
    return tkn.toLowerCase() === assetOut.toLowerCase();
    });//batchswap takes assetOutindex(index of token out in assests array) unlike swap with assetOut(address of token out)
    //Option2(batchSwap) argument 1:
    let batchSwap = {
        poolId: poolId, //the same with poolId above
        assetInIndex: assetInIndex.toString(), //string of token in index
        assetOutIndex: assetOutIndex.toString(), //string of token out index
        amount: amount, //the same with amount above.
        userData: userData //the same with userData above
    } //does not have 'kind' like swap argument
    //Option 2(batchSwap) argument 2:
    let limits = new Array(3).fill("0"); //batchswap takes limits in array of number(as string) unlike swap with limit as on number(as string)
    limits[assetInIndex] = amount; //update the limit for index of token in. amount must be string
    const swaps = [batchSwap] //batchSwap takes swaps in array. add more swap for multiple swaps
    if(isApproved) {
      //begining of parameters needed for web wallet(metamsk) only//
      const VPTAddress = 'VPT address the same with pool address'
      const accountAddress = 'user/investor address' 
      const VPTContract = new ERC20(providerOrSigner, VPTAddress);
      const VPTBalanceBeforeSwap = await VPTContract.balanceOf(accountAddress);
       //end of parameters needed for web wallet(metamsk) only//
      await poolContract.batchswap(swapKind, swaps, assests, funds, limits, deadline).then((res) => {
        const batchSwapResponse = res.response;
        if(batchSwapResponse.status === 0) {
             //status 0 means succesful transaction
            console.log("batchswap successful with transaction hash: ", batchSwapResponse.hash)
            //the code below is for project using web wallets(metamask) only
            //it will add VPT to users token lists.
            if (Number(VPTBalanceBeforeSwap.response.result) <= 0) {
              const provider = 'web wallet(metamask) provider' //it must be web wallet provider signer won't work.
              await provider.request({
                method: "wallet_watchAsset",
                params: {
                  type: "ERC20",
                  options: {
                    address: VPTAddress,
                    symbol: "VPT",
                    decimals: 18,
                  },
                },
              }).then((_res) => {
                  console.log("VPT added to token list succesfully")
              }).catch((err) => {
                  console.error("Error while adding VPT to token list: ", err)
              });
            }
        }else{
            //status 1 means failed transaction
            console.error("Unexpected error occured while calling batchswap function with message: ", batchSwapResponse.message || batchSwapResponse.reason)
        }
    }).catch((err) => {
        console.error("Batchswap failed with error: ", err)
    }  
    }
```

The Above code will create a Buy Market or Limit order, depending on the userData used, and after that user will received VPT(Verified Pool Token). Now user will wait till the order created is matched and a trade occurs to move to next step which is Settling Buy Trade(claiming Security token using VPT)

```javascript
/** Import Pool contract and ethers **/

//Common Js
const { Pool, ERC20 } = require('@verified-network/verified-sdk'); 
const { ethers } = require('ethers');
//ES Module
import { Pool } from '@verified-network/verified-sdk'
import { ethers } from 'ethers';

/** Initialize Pool Contract and abi encoder**/
    const providerOrSigner = 'provider or signer'  //can be investorWalletProvider from Wallet and Contracts page or Signer from web wallets
    const poolContract = new Pool(providerOrSigner);
    const abiCoder = new ethers.utils.AbiCoder();

/** Get User all trades and format swap and batchSwap arguments **/
//note arguments marked as general arguments are arguments that are needed for both swap and batchSwap
    //general arguments
    const poolAddress = 'pool address'
    const account = 'user/sender address'
    const securityAddress = 'address of security to claim'
    const verifiedPoolAbi 'array of verified pool abi' //contact verified Network team for this
    const verifiedOrderBookAbi = 'array of verified orderbook abi' //contact verified Network team for this
    const verifiedPoolContract = new ethers.Contract(poolAddress, verifiedPoolAbi, providerOrSigner);
    const verifiedOrderBookAddress = await verifiedPoolContract._orderbook();
    const verifiedOrderBookContract = new ethers.Contract(verifiedOrderBookAddress, verifiedOrderBookAbi, providerOrSigner);
    let allTradesTime = awaitsverifiedOrderBookContract.getTrades();
    allTradesTime = allTrades.filter((val) => val !== "0");
    const lastTradeTime = allTradesTime[allTradesTime.length - 1];
    const lastTradeInfo = await verifiedOrderBookContract.getOrder(account, Number(lastTradeTime));
    const isParty = lastTradeInfo.partyAddress.toLowerCase() === account.toLowerCase();
    const orderRef = isParty ? lastTradeInfo.partyRef: lastTradeInfo.counterpartyRef;
    const lastTradeDetails = await verifiedOrderBookContract.getOrder(orderRef)
    const isSecurityTokenIn = lastTradeDetails.tokenIn.toLowerCase() === securityAddress.toLowerCase();
    const amount = isSecurityTokenIn ? lastTradeInfo.securityTraded.toString() : lastTradeInfo.currencyTraded.toString();
    const poolId = 'id of pool to swap from in bytes' //e.g 0x1c54eb0a8bea5eeaf07b1b6d2238baf4bf6d6a4800000000000000000000009a
    const swapKind = 'string 0 or 1' //SwapExactIn = 0 or SwapExactOun = 1; best to use '0' all the time
    const assetIn = 'VPT address same as pool address' //same as poolAddress(VPT token) e.g 0x1c54eb0a8BEa5eEaf07b1b6d2238BAf4BF6D6a48
    const assetOut = 'Security address' //since we want to settle buy order asset out is security, if we want to a settle sell order it will be currency
    const userData = abiCoder.encode(
      ["bytes32", "uint"],
      [ethers.utils.formatBytes32String(""), lastTradeInfo.dt]
    );
   const deadline = 'string deadline of transaction' //e.g '999999999999999999'(infinity) or very high number in string
    const funds = {
        sender: 'investor/sender address', //address of swap sender
        fromInternalBalance: false, //boolean must be false not to use internal balance
        recipient: 'investor/sender address', //address of swap receiver
        toInternalBalance: false, //boolean must be false not to use internal balance
     }
/** Call approve on assest in contract so vault can have access to it **/
const assetInContract = new ERC20(providerOrSigner, assetIn);
const balancerVault = '0xBA12222222228d8Ba445958a75a0704d566BF2C8' //general vault address for all network
let isApproved = false;
 await assetInContract
    .approve(balancerVault, amount)
    .then((res) => {
      if (res && res.status === 0) {
        //handle successful approve
        console.log("approve succesful with hash: ", res.response.hash);
        isApproved = true;
      }
    })
    .catch((err) => {
      //handle approve error
      console.error("approve failed with error: ", err);
    });
/**Call swap or batchSwap on Pool contract **/
    //Option 1: Swap: for single swap
    //Option 1(swap) argument 1: This type of swap with 'kind' works for swap, for batchSwap it does not have 'kind'.
     const swap = {
         poolId: poolId,
         kind: swapKind,
         assetIn: assetIn,
         assetOut: assetOut,
         amount: amount,
         userData: userData
     }
     //Option 1(swap) argument 2:
     const limit = 'string of amountIn limit' //e.g '0' or amount of token in(can be the same as amount or leave it as '0')
     
/** Call swap or batchSwap on Pool contract **/
    //Swap: for single swap
    await poolContract.swap(swap, funds, limit, deadline).then((res) => {
        const swapResponse = res.response;
        if(swapResponse.status === 0) { 
            //status 0 means succesful transaction
            console.log("Settle trade successful with transaction hash: ", swapResponse.hash)
        }else{
            //status 1 means failed transaction
            console.error("Unexpected error occured while settling trade with message: ", swapResponse.message || swapResponse.reason)
        }
    }).catch((err) => {
        console.error("Settle trade failed with error: ", err)
    })
    
    //batchSwap: single and multiple swaps. cost less gas
    //call getPoolTokens to get pool tokens list.
    const poolTokensResponse = await poolContract.getPoolTokens(poolId);
    const assests = poolTokensResponse.response.result; //array of tokens address(includes security, currency and pool addrress)
    const assetInIndex = assests.findIndex((tkn) => {
        return tkn.toLowerCase() === assetIn.toLowerCase();
    });//batchswap takes assetInindex(index of tokenIn in assests array) unlike swap with assetIn(address of token in)
    const assetOutIndex = poolTokens.tokens.findIndex((tkn) => {
    return tkn.toLowerCase() === assetOut.toLowerCase();
    });//batchswap takes assetOutindex(index of token out in assests array) unlike swap with assetOut(address of token out)
    let limits = new Array(3).fill("0"); //batchswap takes limits in array of numbers unlike swap with limit as number
    limits[assetInIndex] = amount; //update the limit for index of token in.
    let batchSwap = {
        poolId: poolId,
        assetInIndex: assetInIndex.toString(),
        assetOutIndex: assetOutIndex.toString(),
        amount: amount, //the same with amount above.
        userData: userData //the same with userData above
    } //does not have 'kind' like swap argument
    const swaps = [batchSwap] //batchSwap takes swaps in array. add more swap for multiple swaps
    await poolContract.batchswap(swapKind, swaps, assests, funds, limits, deadline).then((res) => {
        const batchSwapResponse = res.response;
        if(batchSwapResponse.status === 0) {
             //status 0 means succesful transaction
            console.log("settle trade successful with transaction hash: ", batchSwapResponse.hash)
        }else{
            //status 1 means failed transaction
            console.error("Unexpected error occured while settling trade with message: ", batchSwapResponse.message || batchSwapResponse.reason)
        }
    }).catch((err) => {
        console.error("Settle trade failed with error: ", err)
    }
```

The Above code will create a Claim Trade Order which will settle the previous Buy Order created. User will receive Security after the order is successful. For next step we will create a Buy order with the security received from this Settle trade.

&#x20;

```javascript
/** Import Pool and ERC20 contract and ethers **/

//Common Js
const { Pool, ERC20 } = require('@verified-network/verified-sdk'); 
const { ethers } = require('ethers');
//ES Module
import { Pool } from '@verified-network/verified-sdk'
import { ethers } from 'ethers';

/** Initialize Pool Contract and abi encoder**/
    const providerOrSigner = 'provider or signer'  //can be investorWalletProvider from Wallet and Contracts page or Signer from web wallets
    const poolContract = new Pool(providerOrSigner);
    const abiCoder = new ethers.utils.AbiCoder();

/** Format Swap Arguments **/
//note arguments marked as general arguments are arguments that are needed for both swap and batchSwap
    //general arguments
    const swapType = 'Market or Limit' //type of swap best to use 'Market' (so it will trade faster for this example)
    const poolId = 'id of pool to swap from in bytes' //e.g 0x1c54eb0a8bea5eeaf07b1b6d2238baf4bf6d6a4800000000000000000000009a
    const swapKind = 'string 0 or 1' //SwapExactIn = 0 or SwapExactOun = 1; best to use '0' all the time
    const assetIn = 'address of token to swap in(token from)' //will be security address since it's a sell order
    const assetOut = 'address of token out' //same as poolAddress(VPT) e.g 0x1c54eb0a8BEa5eEaf07b1b6d2238BAf4BF6D6a48
    const amount = 'string(amount) of token in' //must be in same decimal places with token in. see best calculation below
    //const amount = (amountRaw * 10 ** assetInDecimals).toString(); where amountRaw = whole number like 1, 2 and assetInDecimals is result of decimals() call on assest in ERC20 contract.  
    let userData;
    //There are 2 types of swap.
    // 1. Market: swap without price will be traded at current market price.
    if(swapType === "Market") {
        userData = "0x" //null abi encoded parameter of [bytes32, uint]
        //same as abiCoder.encode(["bytes32", "uint"],[]);
    }
    // 2. Limit: swap with price, will be traded at price specified.
    if(swapType === "Limit") {
        const priceWei = 'number(amount) of price in wei' //must be in 18 decimals(wei decimals)
        userData = abiCoder.encode(
          ["bytes32", "uint256"],
          [ethers.utils.formatBytes32String("Limit"), priceWei]
        );
    }
    //general argument 4: Deadline
     const deadline = 'string deadline of transaction' //e.g '999999999999999999'(infinity) or very high number in string
    const funds = {
        sender: 'investor/sender address', //address of swap sender
        fromInternalBalance: false, //boolean must be false not to use internal balance
        recipient: 'investor/sender address', //address of swap receiver
        toInternalBalance: false, //boolean must be false not to use internal balance
     }
/** Call approve on assest in contract so vault can have access to it **/
const assetInContract = new ERC20(providerOrSigner, assetIn);
const balancerVault = '0xBA12222222228d8Ba445958a75a0704d566BF2C8' //general vault address for all network
let isApproved = false;
 await assetInContract
    .approve(balancerVault, amount)
    .then((res) => {
      if (res && res.status === 0) {
        //handle successful approve
        console.log("approve succesful with hash: ", res.response.hash);
        isApproved = true;
      }
    })
    .catch((err) => {
      //handle approve error
      console.error("approve failed with error: ", err);
    });
/**Call swap or batchSwap on Pool contract **/
    //Option 1: Swap: for single swap
    //Option 1(swap) argument 1: This type of swap with 'kind' works for swap, for batchSwap it does not have 'kind'.
     const swap = {
         poolId: poolId,
         kind: swapKind,
         assetIn: assetIn,
         assetOut: assetOut,
         amount: amount,
         userData: userData
     }
     //Option 1(swap) argument 2:
     const limit = 'string of amountIn limit' //e.g '0' or amount of token in(can be the same as amount or leave it as '0')
    if(isApproved) {
        //begining of parameters needed for web wallet(metamsk) only//
      const VPTAddress = 'VPT address the same with pool address'
      const accountAddress = 'user/investor address' 
      const VPTContract = new ERC20(providerOrSigner, VPTAddress);
      const VPTBalanceBeforeSwap = await VPTContract.balanceOf(accountAddress);
       //end of parameters needed for web wallet(metamsk) only//
        await poolContract.swap(swap, funds, limit, deadline).then((res) => {
        const swapResponse = res.response;
        if(swapResponse.status === 0) { 
            //status 0 means succesful transaction
            console.log("swap successful with transaction hash: ", swapResponse.hash)
            //the code below is for project using web wallets(metamask) only
            //it will add VPT to users token lists.
            if (Number(VPTBalanceBeforeSwap.response.result) <= 0) {
              const provider = 'web wallet(metamask) provider' //it must be web wallet provider signer won't work.
              await provider.request({
                method: "wallet_watchAsset",
                params: {
                  type: "ERC20",
                  options: {
                    address: VPTAddress,
                    symbol: "VPT",
                    decimals: 18,
                  },
                },
              }).then((_res) => {
                  console.log("VPT added to token list succesfully")
              }).catch((err) => {
                  console.error("Error while adding VPT to token list: ", err)
              });
        }else{
            //status 1 means failed transaction
            console.error("Unexpected error occured while calling swap function with message: ", swapResponse.message || swapResponse.reason)
        }
    }).catch((err) => {
        console.error("Swap failed with error: ", err)
    })
    }
    
    //=======================//
    
    //Option 2: (batchSwap): single and multiple swaps. reconmended it cost less gas **/
    //call getPoolTokens to get pool tokens list.
    const poolTokensResponse = await poolContract.getPoolTokens(poolId);
    const assests = poolTokensResponse.response.result; //array of tokens address(includes security, currency and pool addrress)
    const assetInIndex = assests.findIndex((tkn) => {
        return tkn.toLowerCase() === assetIn.toLowerCase();
    });//batchswap takes assetInindex(index of tokenIn in assests array) unlike swap with assetIn(address of token in)
    const assetOutIndex = poolTokens.tokens.findIndex((tkn) => {
    return tkn.toLowerCase() === assetOut.toLowerCase();
    });//batchswap takes assetOutindex(index of token out in assests array) unlike swap with assetOut(address of token out)
    //Option2(batchSwap) argument 1:
    let batchSwap = {
        poolId: poolId, //the same with poolId above
        assetInIndex: assetInIndex.toString(), //string of token in index
        assetOutIndex: assetOutIndex.toString(), //string of token out index
        amount: amount, //the same with amount above.
        userData: userData //the same with userData above
    } //does not have 'kind' like swap argument
    //Option 2(batchSwap) argument 2:
    let limits = new Array(3).fill("0"); //batchswap takes limits in array of number(as string) unlike swap with limit as on number(as string)
    limits[assetInIndex] = amount; //update the limit for index of token in. amount must be string
    const swaps = [batchSwap] //batchSwap takes swaps in array. add more swap for multiple swaps
    if(isApproved) {
      //begining of parameters needed for web wallet(metamsk) only//
      const VPTAddress = 'VPT address the same with pool address'
      const accountAddress = 'user/investor address' 
      const VPTContract = new ERC20(providerOrSigner, VPTAddress);
      const VPTBalanceBeforeSwap = await VPTContract.balanceOf(accountAddress);
       //end of parameters needed for web wallet(metamsk) only//
      await poolContract.batchswap(swapKind, swaps, assests, funds, limits, deadline).then((res) => {
        const batchSwapResponse = res.response;
        if(batchSwapResponse.status === 0) {
             //status 0 means succesful transaction
            console.log("batchswap successful with transaction hash: ", batchSwapResponse.hash)
            //the code below is for project using web wallets(metamask) only
            //it will add VPT to users token lists.
            if (Number(VPTBalanceBeforeSwap.response.result) <= 0) {
              const provider = 'web wallet(metamask) provider' //it must be web wallet provider signer won't work.
              await provider.request({
                method: "wallet_watchAsset",
                params: {
                  type: "ERC20",
                  options: {
                    address: VPTAddress,
                    symbol: "VPT",
                    decimals: 18,
                  },
                },
              }).then((_res) => {
                  console.log("VPT added to token list succesfully")
              }).catch((err) => {
                  console.error("Error while adding VPT to token list: ", err)
              });
            }
        }else{
            //status 1 means failed transaction
            console.error("Unexpected error occured while calling batchswap function with message: ", batchSwapResponse.message || batchSwapResponse.reason)
        }
    }).catch((err) => {
        console.error("Batchswap failed with error: ", err)
    }  
    }
```

The Above code will create a Sell Market or Limit order, depending on the userData used, and after that user will received VPT(Verified Pool Token). Now user will wait till the sell order created is matched and a trade occurs to move to the final step of the workflow which is Settling Sell Trade(claiming Currency token using VPT)

```javascript
/** Import Pool contract and ethers **/

//Common Js
const { Pool, ERC20 } = require('@verified-network/verified-sdk'); 
const { ethers } = require('ethers');
//ES Module
import { Pool } from '@verified-network/verified-sdk'
import { ethers } from 'ethers';

/** Initialize Pool Contract and abi encoder**/
    const providerOrSigner = 'provider or signer'  //can be investorWalletProvider from Wallet and Contracts page or Signer from web wallets
    const poolContract = new Pool(providerOrSigner);
    const abiCoder = new ethers.utils.AbiCoder();

/** Get User all trades and format swap and batchSwap arguments **/
//note arguments marked as general arguments are arguments that are needed for both swap and batchSwap
    //general arguments
    const poolAddress = 'pool address'
    const account = 'user/sender address'
    const securityAddress = 'address of security to claim'
    const verifiedPoolAbi 'array of verified pool abi' //contact verified Network team for this
    const verifiedOrderBookAbi = 'array of verified orderbook abi' //contact verified Network team for this
    const verifiedPoolContract = new ethers.Contract(poolAddress, verifiedPoolAbi, providerOrSigner);
    const verifiedOrderBookAddress = await verifiedPoolContract._orderbook();
    const verifiedOrderBookContract = new ethers.Contract(verifiedOrderBookAddress, verifiedOrderBookAbi, providerOrSigner);
    let allTradesTime = awaitsverifiedOrderBookContract.getTrades();
    allTradesTime = allTrades.filter((val) => val !== "0");
    const lastTradeTime = allTradesTime[allTradesTime.length - 1];
    const lastTradeInfo = await verifiedOrderBookContract.getOrder(account, Number(lastTradeTime));
    const isParty = lastTradeInfo.partyAddress.toLowerCase() === account.toLowerCase();
    const orderRef = isParty ? lastTradeInfo.partyRef: lastTradeInfo.counterpartyRef;
    const lastTradeDetails = await verifiedOrderBookContract.getOrder(orderRef)
    const isSecurityTokenIn = lastTradeDetails.tokenIn.toLowerCase() === securityAddress.toLowerCase();
    const amount = isSecurityTokenIn ? lastTradeInfo.securityTraded.toString() : lastTradeInfo.currencyTraded.toString();
    const poolId = 'id of pool to swap from in bytes' //e.g 0x1c54eb0a8bea5eeaf07b1b6d2238baf4bf6d6a4800000000000000000000009a
    const swapKind = 'string 0 or 1' //SwapExactIn = 0 or SwapExactOun = 1; best to use '0' all the time
    const assetIn = 'VPT address same as pool address' //same as poolAddress(VPT token) e.g 0x1c54eb0a8BEa5eEaf07b1b6d2238BAf4BF6D6a48
    const assetOut = 'Currency address' //since we want to settle sell order asset out is currency, if we want to settle a buy order it will be security
    const userData = abiCoder.encode(
      ["bytes32", "uint"],
      [ethers.utils.formatBytes32String(""), lastTradeInfo.dt]
    );
   const deadline = 'string deadline of transaction' //e.g '999999999999999999'(infinity) or very high number in string
    const funds = {
        sender: 'investor/sender address', //address of swap sender
        fromInternalBalance: false, //boolean must be false not to use internal balance
        recipient: 'investor/sender address', //address of swap receiver
        toInternalBalance: false, //boolean must be false not to use internal balance
     }
/** Call approve on assest in contract so vault can have access to it **/
const assetInContract = new ERC20(providerOrSigner, assetIn);
const balancerVault = '0xBA12222222228d8Ba445958a75a0704d566BF2C8' //general vault address for all network
let isApproved = false;
 await assetInContract
    .approve(balancerVault, amount)
    .then((res) => {
      if (res && res.status === 0) {
        //handle successful approve
        console.log("approve succesful with hash: ", res.response.hash);
        isApproved = true;
      }
    })
    .catch((err) => {
      //handle approve error
      console.error("approve failed with error: ", err);
    });
/**Call swap or batchSwap on Pool contract **/
    //Option 1: Swap: for single swap
    //Option 1(swap) argument 1: This type of swap with 'kind' works for swap, for batchSwap it does not have 'kind'.
     const swap = {
         poolId: poolId,
         kind: swapKind,
         assetIn: assetIn,
         assetOut: assetOut,
         amount: amount,
         userData: userData
     }
     //Option 1(swap) argument 2:
     const limit = 'string of amountIn limit' //e.g '0' or amount of token in(can be the same as amount or leave it as '0')
     
/** Call swap or batchSwap on Pool contract **/
    //Swap: for single swap
    await poolContract.swap(swap, funds, limit, deadline).then((res) => {
        const swapResponse = res.response;
        if(swapResponse.status === 0) { 
            //status 0 means succesful transaction
            console.log("Settle trade successful with transaction hash: ", swapResponse.hash)
        }else{
            //status 1 means failed transaction
            console.error("Unexpected error occured while settling trade with message: ", swapResponse.message || swapResponse.reason)
        }
    }).catch((err) => {
        console.error("Settle trade failed with error: ", err)
    })
    
    //batchSwap: single and multiple swaps. cost less gas
    //call getPoolTokens to get pool tokens list.
    const poolTokensResponse = await poolContract.getPoolTokens(poolId);
    const assests = poolTokensResponse.response.result; //array of tokens address(includes security, currency and pool addrress)
    const assetInIndex = assests.findIndex((tkn) => {
        return tkn.toLowerCase() === assetIn.toLowerCase();
    });//batchswap takes assetInindex(index of tokenIn in assests array) unlike swap with assetIn(address of token in)
    const assetOutIndex = poolTokens.tokens.findIndex((tkn) => {
    return tkn.toLowerCase() === assetOut.toLowerCase();
    });//batchswap takes assetOutindex(index of token out in assests array) unlike swap with assetOut(address of token out)
    let limits = new Array(3).fill("0"); //batchswap takes limits in array of numbers unlike swap with limit as number
    limits[assetInIndex] = amount; //update the limit for index of token in.
    let batchSwap = {
        poolId: poolId,
        assetInIndex: assetInIndex.toString(),
        assetOutIndex: assetOutIndex.toString(),
        amount: amount, //the same with amount above.
        userData: userData //the same with userData above
    } //does not have 'kind' like swap argument
    const swaps = [batchSwap] //batchSwap takes swaps in array. add more swap for multiple swaps
    await poolContract.batchswap(swapKind, swaps, assests, funds, limits, deadline).then((res) => {
        const batchSwapResponse = res.response;
        if(batchSwapResponse.status === 0) {
             //status 0 means succesful transaction
            console.log("settle trade successful with transaction hash: ", batchSwapResponse.hash)
        }else{
            //status 1 means failed transaction
            console.error("Unexpected error occured while settling trade with message: ", batchSwapResponse.message || batchSwapResponse.reason)
        }
    }).catch((err) => {
        console.error("Settle trade failed with error: ", err)
    }
```


# Secondary issues

Secondary trading of security tokens with market cap

Licensed Registrar and Transfer agents can create liquidity pools for secondary trading of tokenized securities. These can be security tokens that have closed a primary issue on the Verified Network or can be security tokens that have a market cap offchain.

Secondary pools on the Verified Network support market and limit order matching entirely on chain.&#x20;

Orders can be [added](/reference/verified-rest-api/order-management/add-order), [edited](/reference/verified-rest-api/order-management/edit-order) and [cancelled](/reference/verified-rest-api/order-management/cancel-order) by users on the Verified Network. Trades (Orders that are matched) need to be settled by the counterparties to the trade (ie, by both the buyer and seller). [Market data](/reference/verified-rest-api/market-data), data on [orders](/reference/verified-rest-api/market-data/get-orderbook) and [trades](/reference/verified-rest-api/order-data/query-trades-info) for secondary pools can also be fetched using the REST APIs.&#x20;


# Primary issues

Raising capital for new issues of tokenized securities

When a security token is first issued, an opening balance of the security token can be created by the issuer either for itself or for a nominee. The issuer or its nominee can then offer their security tokens to a Primary issue manager contract on the Verified Network that creates a liquidity pool which sets a price curve for subscriptions to the new issue.

Subscribers to a primary issue can purchase the security token from the liquidity pool created by swapping in the currency token paired with the security token with the `Offer` function called on the Primary Issue Manager contract.

The offer of security tokens in a liquidity pool can be underwritten by licensed Asset Managers on the Verified Network. Registrar and Transfer agents for the security token can then start the issue and also set an end date for the primary issue. Once the primary issue ends, Registrar and Transfer agents can make allotments of security tokens to subscribers, refund subscriptions back to those whose subscriptions are not accepted, and settle subscription capital to issuers of the security token for which primary issue was run.


# Primary offer function

Raising capital for new issues

The following function is to be called on the Primary issue manager contract in the SDK.&#x20;

### **Offering security tokens for a Primary issue**

```typescript
offer( owned: string, 
       isin: string, 
       offered:string, 
       tomatch:string, 
       desired:string, 
       min:string, 
       issuer: string,
       docs: string
   )
```

| owned   | address of security token offered                                                       |
| ------- | --------------------------------------------------------------------------------------- |
| isin    | string identifier of security token offered                                             |
| offered | amount of security token offered for sale                                               |
| tomatch | address of cash token to be paired in liquidity pool for primary issue                  |
| desired | amount of subscription capital to be raised which sets the upper bound on price curve   |
| min     | minimum subscription capital acceptable to issuer which sets lower bound on price curve |
| issuer  | address of issuer that makes the primary offer                                          |
| docs    | string with ipfs url of offering documents                                              |

Please note that the application user that calls the above function should first `approve` the security token for an amount offered.


# Margin traded issues

Trading derivatives

Investment products such as derivatives require traders to put up margin money which is a fraction of the value of any trade. Since trading is entirely on chain and traders can suffer a loss, the Margin issue manager contract on the Verified Network also requires traders to specify a stop loss price on the products they trade. A collateral amount that is calculated based on the stop loss is also required to be staked by the trader in the Margin issue manager contract.

Margin traded products can be fulfilled offchain and settlement of profit and loss on trading accounts is done by issuers of margin traded products.&#x20;

Both market and limit orders are supported in Margin issue pools on the Verified Network. Orders can be [added](/reference/verified-rest-api/order-management/add-order), [edited](/reference/verified-rest-api/order-management/edit-order) and [cancelled](/reference/verified-rest-api/order-management/cancel-order) by users on the Verified Network. Trades (Orders that are matched) need to be settled by the counterparties to the trade (ie, by both the buyer and seller). [Market data](/reference/verified-rest-api/market-data), data on [orders](/reference/verified-rest-api/market-data/get-orderbook) and [trades](/reference/verified-rest-api/order-data/query-trades-info) for margin pools can also be fetched using the REST APIs.&#x20;


# Offering collateral

Margin money and Stop loss collateral

The following function is called on the Margin issue manager contract in the Verified SDK.

### **Offering collateral for a Margin issue**

```typescript
offerCollateral( 
        currency: string, 
        amount: string,
        security: string
        )
```

| currency | address of cash token offered as collateral |
| -------- | ------------------------------------------- |
| amount   | amount of cash token offered as collateral  |
| security | address of security in margin issue pool    |


# Adding money to wallet

Top up a Verified wallet

A user may add both crypto and fiat currencies to its Verified account. An application may therefore enable a user to transfer ether to its Verified wallet and to pay in supported fiat currencies against which ERC20 compatible Verified cash tokens of equivalent value are issued to the user's wallet. Verified cash tokens are used for payments and settlements on the Verified Network and can also be used outside the Verified Network on the ethereum mainnet and on ethereum compatible blockchains like Polygon.

### Transferring ether to the Verified wallet

A user can transfer ether to the Verified wallet from any ERC20 compatible ethereum wallet such as MetaMask, Ledger and Mew. All that is required for a transfer of ether is the address of the user's Verified wallet.&#x20;

### Pay in of ether for issue of cash tokens

Users can send ether from their Verified wallets to the Verified cash contract address for a currency that the user wants cash tokens to be issued in. For example, if a user wants Verified USD cash tokens, it has to send ether to the Verified USD cash contract address. Verified cash tokens are currently issued for the US dollar, British pounds, Euro, Japanese Yen, Mexican Peso, HongKong dollar, Canadian dollar, Singapore dollar, and the Australian dollar.&#x20;

Verified cash token addresses can be obtained from the Factory contract. An example of how this works is [shown here](broken://pages/BBc9IfEbbuD7ZidDA95x).

### Pay in of fiat from bank accounts and cards

Users can pay in a variety of supported currencies from their card and bank accounts into their Verified accounts. Custodians on the Verified Network keep custody of paid in fiat currencies and issue Verified cash tokens to wallets of users that pay in fiat.&#x20;

Application developers can use any fiat payment gateway supporting a currency of choice for paying in to Custodian accounts.


# Paying in supported tokens

For issue of Verified cash tokens

The following code snippet uses etherjs to send ether to the Verified cash contract address.

```javascript
const factoryContract = new FactoryContract(investorWallet);

await factoryContract.getTokenCount()
.then(async(resp)=>{
console.log("Number of tokens returned by factory " + resp.response.result[0]);
num = resp.response.result[0];

for (count=0; count<10; count++){
    await factoryContract.getToken(count)
    .then(async(resp)=>{
        console.log("Token address iterated " + resp.response.result[0]);
        token = resp.response.result[0];
        
        await factoryContract.getNameAndType(token)
        .then(async(resp)=>{
            console.log("Token name " + ethers.utils.parseBytes32String(resp.response.result[0]));
            console.log("Token type " + ethers.utils.parseBytes32String(resp.response.result[1]));

            if(ethers.utils.parseBytes32String(resp.response.result[1])=="ViaCash"){
                if(ethers.utils.parseBytes32String(resp.response.result[0])=="VXUSD")
                    VCUSD = token;
                if(ethers.utils.parseBytes32String(resp.response.result[0])=="VXEUR")
                    VCEUR = token;
            }            
        })
    })
}

const cashUSDInvestor = new CashContract(investorWallet, VCUSD);

await investorWallet.sendTransaction({
    to: VCUSD,
    value: ethers.utils.parseEther('0.01')
}).then(async()=>{
    console.log('Sent some ether for issuing cash tokens');
    cashUSDInvestor.notifyCashIssue(async()=>{
        await cashUSDInvestor.balanceOf(investorWallet.address)
        .then(async(balance)=>{
            console.log("VCUSD balance in investor wallet " + investorWallet.address + " is " + balance.response.result[0]);
        })
    })
})
```


# Issuing cash tokens

Issuing and Exchange

### Issuing of Verified cash tokens

Application users can request for issue of Verified cash tokens in exchange of ether and permitted ERC20 tokens such as USDC that they pay in from their Verified wallet or any other ERC20 compatible Ethereum wallet. Fiat currencies paid into Custodian accounts are retrieved using the payment gateway's functions and for every approved payment, the Custodian's application has to call the [pay in function](broken://pages/-MRKr02k5-EzLIN5zI3t#request-issue-of-verified-cash-token-for-fiat-paid-in) on the Cash contract signed by its Verified wallet key.

Applications can call the `notifyCashIssue` function in the SDK's cash contract and pass a callback function which is invoked when cash tokens are issued on the Verified Network.

### Conversion of Verified cash tokens

Users can also request issue of Verified cash tokens in a currency of choice by paying in another Verified cash token of a different currency. For example, a user can request for issue of Verified USD cash tokens by paying in Verified EUR cash tokens. This is achieved using the [transfer function](broken://pages/-MRKr02k5-EzLIN5zI3t#request-exchange-of-verified-cash-tokens) which applications should call by passing the currency and amount to debit, and the currency to issue Verified cash in. Doing this converts the amount in the currency to debit into an equivalent amount in the currency to issue in and then credits that amount into the user's Verified wallet.

Applications can call the `notifyCashExchange` function in the SDK's cash contract and pass a callback function which is invoked when cash tokens are exchanged on the Verified Network.


# Issuing and Exchange functions

Function definitions

Both functions are to be called on the Cash contract.&#x20;

### **Request issue of Verified cash token for fiat paid in**

`payIn(_tokens, _payer, _currency)`

| Function parameter | Description                             |
| ------------------ | --------------------------------------- |
| \_tokens           | number of cash tokens to issue          |
| \_payer            | address of user paying in fiat currency |
| \_currency         | name of fiat currency paid in           |

### **Request exchange of Verified cash tokens**&#x20;

`transferFrom(_fromCurrency, _toCurrency, _amount)`

<table data-header-hidden><thead><tr><th width="323.81975071907954">Function parameter</th><th>Description</th></tr></thead><tbody><tr><td>Function parameter</td><td>Description</td></tr><tr><td>_fromCurrency</td><td>address of Verified cash token to debit and convert from</td></tr><tr><td>_toCurrency</td><td>address of Verified cash token to exchange to and credit</td></tr><tr><td>_amount</td><td>name of the cash tokens to debit and convert</td></tr></tbody></table>


# Making payments

Tokenized cash transfers

### Peer to Peer transfers

Users can request peer to peer transfers of Verified cash tokens to other users with a Verified account or an ERC20 compatible Ethereum wallet. User facing applications should call the [`transferFrom`](broken://pages/-MRL-iF6vgF4Yqpt_tMA#request-transfer-of-cash-tokens-in-a-currency-to-recipient) function with parameters for amount to transfer, address of the recipient, and the address of the sender to debit Verified cash from.

The function call needs to be made on the Cash contract and signed by the sender. Applications can wait on the `notifyCashTransfer` callback which is invoked when the transfer is made on the Verified Network.

### Cross border transfers

Any peer to peer transfer of Verified cash tokens, whether it is a transfer of Verified cash in the same currency or whether it involves the conversion of Verified cash in a currency to Verified cash in another currency before it is transferred, are free of cost. The latter case where transfer of one currency and credit in another is a two step process that requires the application to first call the [`transferFrom`](broken://pages/-MRKr02k5-EzLIN5zI3t#request-exchange-of-verified-cash-tokens) function to convert the currency Verified cash is to be transferred into the currency Verified cash is to be credited, followed by calling the [`transferFrom`](broken://pages/-MRL-iF6vgF4Yqpt_tMA#request-transfer-of-cash-tokens-in-a-currency-to-recipient) function.&#x20;


# Transferring cash tokens

Verified cash token transfer

### **Request transfer of cash tokens in a currency to recipient**&#x20;

`transferFrom(_sender, _recipient, _amount)`

| Function parameter | Description                                         |
| ------------------ | --------------------------------------------------- |
| \_amount           | amount of cash tokens paid in the currency to debit |
| \_recipient        | account address of the recipient                    |
| \_sender           | account address of the sender                       |


# Withdrawals

Redeeming cash tokens for fiat currency and crypto paid in

### Redeeming cash tokens for crypto currencies

Users can redeem Verified cash tokens in their Verified account and get back what was paid in to issue those cash tokens. For example, if any ether was paid in for issue of Verified cash tokens, the user will get back ether equivalent to amount of cash tokens that is in balance on the user's Verified account. If Verified cash tokens of another currency was paid in for issue of a Verified cash token, redemption returns an amount of cash tokens paid in that is left in balance on the Verified account.&#x20;

The user facing application should call the [`transferFrom`](broken://pages/-MRL59Zh1MVRcb_ZoQaw#request-redemption-of-cash-tokens) function for redemption of cash tokens. Here, cash tokens of a currency is sent to the Cash contract of the same currency and the application can pass a callback function to `notifyCashRedemption` which is invoked when the redemption is successfully done on the Verified Network.&#x20;

### Redeeming cash tokens for fiat currencies

In case fiat currency is paid in to issue Verified cash tokens, their redemption will automatically call the fiat pay out functions that will debit the Custodian's bank account and credit the user's bank account.&#x20;


# Redeeming cash tokens

Verified cash token redemption function

### **Request redemption of cash tokens**&#x20;

`transferFrom(_fromCurrency, _toCashContract, _amount)`

<table data-header-hidden><thead><tr><th width="323.81975071907954">Function parameter</th><th>Description</th></tr></thead><tbody><tr><td>Function parameter</td><td>Description</td></tr><tr><td>_fromCurrency</td><td>address of Verified cash token to debit and redeem</td></tr><tr><td>_toCashContract</td><td>address of Verified cash contract for the currency of cash token being redeemed</td></tr><tr><td>_amount</td><td>name of the cash tokens to debit and redeem</td></tr></tbody></table>


# Custody of Assets

MPC based self custody

Signing transactions on a blockchain such as the Verified Network requires users to manage their own private keys. Securely storing private keys is a challenge. To get around this, custodians offer secure storage for private keys, and often, this is based on the multi-party compute paradigm where the custodian and the user each retain a part of the key, often referred to a key shard. However, MPC based custody means a custodian's security can get compromised and a custodian can freeze assets belonging to a user by refusing to share its key shard for signing transactions.

Since the Verified Network is decentralized financial infrastructure, it provides smart contracts to create vaults for key shards, and the coordination mechanism by which multiple parties can confirm a transaction so that once quorum is reached, their key shards are assembled at run time to sign transactions. In this way, the user does not have the key in custody, and no co-signatories have the ability to block transactions since minimum quorum may not require all co-signatories to confirm a transaction.

### Creating a key vault and defining quorum

The first step involves a user creating a key vault for itself. For this, the application needs to call the [`createVault`](broken://pages/-MRTOGAjZ-XE0CQml4rJ#create-vault) function on the Vault contract on the Verified Network signed by the user wallet. Once a key vault is created, the user can define a quorum by calling the [`defineQuorum`](broken://pages/-MRTOGAjZ-XE0CQml4rJ#define-quorum) function on the Vault contract.

### Adding nominee co-signatories and their confirmation

The user who has created a key vault can add any number of nominees as co-signatories. Usually, this is at least one and less than five other users who act as nominees. An application needs to call the [`addParticipant`](broken://pages/-MRTOGAjZ-XE0CQml4rJ#add-participant) function on the Vault contract to add a nominee for a user that has signed the call with its wallet. This sends a notification from the Verified Network to the nominee that confirms itself as a co-signatory by calling the [`confirmParticipant`](broken://pages/-MRTOGAjZ-XE0CQml4rJ#confirmation-by-participant) function on the Vault contract by setting a unique PIN for itself.

### Signing transactions

A user can initiate the transaction signing process by calling the [`promptSignatures`](broken://pages/-MRTOGAjZ-XE0CQml4rJ#prompt-co-signatories) function on the Vault contract. This notifies the co-signatories nominated by the user who confirm the transaction by calling the [`signTransaction`](broken://pages/-MRTOGAjZ-XE0CQml4rJ#sign-transaction) function on the Vault contract where each co-signatory pass their unique PIN used to confirm their participation earlier.

### Checking quorum and assembling private key

A user can check quorum of co-signatories by calling the [`checkQuorum`](broken://pages/-MRTOGAjZ-XE0CQml4rJ#check-quorum) function on the Vault contract. The user facing application then need to call `getShards` function on the Vault contract to retrieve shards securely and use a MPC algorithm to assemble the user's private key at run time. The Verified SDK uses Shamir's secret algorithm to assemble the user's key to sign transactions when the [`getShards`](broken://pages/-MRTOGAjZ-XE0CQml4rJ#retrieve-shards) function is called on the SDK's vault contract by the application.


# Custody functions

Function definitions

### Create vault

`createVault(_creator, _id)`

| Function parameter | Description                                                                      |
| ------------------ | -------------------------------------------------------------------------------- |
| \_creator          | human readable unique identifier for user such as its email address              |
| \_id               | a messaging token for the user such as a firebase or azure cloud messaging token |

### Define quorum

`defineQuorum(_creator, _id, _minParticipants)`

| Function parameter | Description                                      |
| ------------------ | ------------------------------------------------ |
| \_creator          | unique identifier for user                       |
| \_id               | messaging token for user                         |
| \_minParticipants  | minimum number of co-signatories to reach quorum |

### Add participant

`addParticipant(_creator, _id, _participant)`

| Function parameter | Description                        |
| ------------------ | ---------------------------------- |
| \_creator          | unique identifier for user         |
| \_id               | messaging token for user           |
| \_participant      | unique identifier for co-signatory |

### Confirmation by participant

`confirmParticipant(_creator, _participant, _id)`

| Function parameter | Description                        |
| ------------------ | ---------------------------------- |
| \_creator          | unique identifier for user         |
| \_id               | messaging token for user           |
| \_participant      | unique identifier for co-signatory |

### Prompt co-signatories

`promptSignatures(_creator, _id)`

| Function parameter | Description                                                                      |
| ------------------ | -------------------------------------------------------------------------------- |
| \_creator          | human readable unique identifier for user such as its email address              |
| \_id               | a messaging token for the user such as a firebase or azure cloud messaging token |

### Sign transaction

`signTransaction(_creator, _participant, _id, _tx, _pin)`

| Function parameter | Description                                                                                         |
| ------------------ | --------------------------------------------------------------------------------------------------- |
| \_creator          | unique identifier for user                                                                          |
| \_participant      | unique identifier for co-signatory                                                                  |
| \_id               | messaging token for co-signatory                                                                    |
| \_tx               | unique transaction identifier that co-signatories receive by notification from the Verified Network |
| \_pin              | PIN of co-signatory                                                                                 |

### Check quorum

`checkQuorum(_creator, _id, _participant, _txid)`

| Function parameter | Description                                                                                |
| ------------------ | ------------------------------------------------------------------------------------------ |
| \_creator          | unique identifier for user                                                                 |
| \_id               | messaging token for user                                                                   |
| \_participant      | unique identifier for co-signatory                                                         |
| \_tx               | unique transaction identifier that users receive by notification from the Verified Network |

### Retrieve shards

`getShards(_creator, _id, _txid)`

| Function parameter | Description                                                                        |
| ------------------ | ---------------------------------------------------------------------------------- |
| \_creator          | unique identifier for user                                                         |
| \_id               | messaging token for user                                                           |
| \_txid             | unique identifier for transaction that needs to be signed by assembling key shards |


# Staking to invest

Invest in liquidity to earn an income

Investors may stake digital assets such as crypto currencies, stable coins and [Verified cash tokens](broken://pages/-MR9NK6fo0od2Uguz_gP#issuing-of-verified-cash-tokens) that are allocated to asset managers for investments in tokenized securities such as tokenized equity, bonds and structured products. This yields a return on investment for such investors we will refer to as liquidity providers.

Liquidity providers can stake in two ways. The first way is to stake digital assets on the Verified Liquidity contract that issues Verified Liquidity tokens to liquidity providers they can trade for capital gains. Assets staked on the Verified Liquidity contract are allocated by Verified governance to licensed asset managers that invest staked assets in tokenized securities to yield a return on investment which is shared with Verified Liquidity token holders.

The second way is for liquidity providers to stake assets on Verified market maker contracts that provide liquidity to liquidity pools of specific tokenized security and cash pairs. In this case also, Verified market maker contracts issue Verified liquidity tokens to liquidity providers. The difference between staking assets in Verified market maker contracts vis a vis staking in Verified liquidity contracts is that the underwriting risk is borne by liquidity providers in the former (market maker contracts) case, while underwriting risk is borne by asset managers in the latter (liquidity contracts) case.&#x20;

### **Staking in Verified liquidity**

Applications can check tokens accepted for staking with the [`getSupportedTokens`](broken://pages/CsO3EsJ5XwIPItN1RtGD#check-accepted-tokens) function, or check the support for a specific token with the [`checkSupportForToken`](broken://pages/CsO3EsJ5XwIPItN1RtGD#check-support-for-token) function. Accepted tokens can be staked with the [`buy`](broken://pages/CsO3EsJ5XwIPItN1RtGD#buy-tokens) function. The number of Verified liquidity tokens issued to an liquidity providers can be checked with the [`balance`](broken://pages/CsO3EsJ5XwIPItN1RtGD#check-balance-of-verified-liquidity-tokens) function.&#x20;

### Staking in Market makers

Applications can let liquidity providers check the number of available liquidity pools by calling the [`getPlatforms`](broken://pages/uz4t8m2ONcK1UUIeRjvh#get-list-of-liquidity-pool-managers) function which returns the market maker name, address and the ISIN of the tokenized security in the liquidity pool. Liquidity providers can then call the [`offer`](broken://pages/uz4t8m2ONcK1UUIeRjvh#offer-liquidity) function on the market maker contract.&#x20;


# Liquidity functions

Liquidity contract functions

### &#x20;**tokens**

`buy(_token, _amount)`

| Function parameter | Description                                   |
| ------------------ | --------------------------------------------- |
| \_token            | address of digital asset offered as liquidity |
| \_amount           | amount of digital asset offered as liquidity  |

### **Check balance of Verified liquidity tokens**&#x20;

`balance(_investor)`

<table data-header-hidden><thead><tr><th width="323.81975071907954">Function parameter</th><th>Description</th></tr></thead><tbody><tr><td>Function parameter</td><td>Description</td></tr><tr><td>_investor</td><td>wallet address of liquidity provider for which balance of Verified liquidity tokens is returned</td></tr></tbody></table>


# Market maker functions

Liquidity pool manager contract functions

List of liquidity pool managers is returned by the [`getPlatforms`](#check-accepted-tokens) function on the Liquidity contract. Making the offer of liquidity is by calling the [`offer`](#request-exchange-of-verified-cash-tokens) function on the Liquidity pool manager contracts  that are deployed for each connected Defi platform such as Balancer.&#x20;

### **Get list of Liquidity pool managers**

`getPlatforms()`

this function returns a tuple of liquidity providers with each element containing an array comprising of &#x20;

| Return parameter | Description                                    |
| ---------------- | ---------------------------------------------- |
| \_platformName   | name of connected Defi platform                |
| \_address        | address of liquidity pool manager              |
| \_isin           | identifier of security token in liquidity pool |

### **Offer liquidity**&#x20;

`offer(_owned, _isin, _offered, _tomatch, _desired, _min)`

<table data-header-hidden><thead><tr><th width="323.81975071907954">Function parameter</th><th>Description</th></tr></thead><tbody><tr><td>Function parameter</td><td>Description</td></tr><tr><td>_owned</td><td>address of offered asset</td></tr><tr><td>_isin</td><td>identifier of security token for which offer of liquidity is made</td></tr><tr><td>_offered</td><td>amount of asset offered as liquidity</td></tr><tr><td>_tomatch</td><td>address of security token for which offer of liquidity is made</td></tr><tr><td>_desired</td><td>amount of security tokens desired in exchange for offered liquidity</td></tr><tr><td>_min</td><td>minimum amount of security tokens desired in exchange for offered liquidity</td></tr></tbody></table>


# Staking to borrow

Issuing, Redemption and Transfer

Users with collateral supported on the Verified Network such as stETH (staked ether) can buy tokenized bonds on the Verified Network that are backed by real world assets such as loan portfolios.&#x20;

Borrowers on the Verified Network can therefore issue tokenized bonds that users with collateral can buy. The collateral from bond sales can be staked into liquidity sources such as Compound, Aave and Maker to borrow USDC or DAI or other supported forms of liquidity.&#x20;

Bonds issued on the Verified Network are zero coupon bonds, so the par value of a bond is discounted by borrowing rates to price the bond that users can purchase.


# Bond issuing function

Function definition

### Issuing Via bonds for ether

`requestIssueForEther(_viaBondToIssue, _amount)`

| Function parameter | Description                                                            |
| ------------------ | ---------------------------------------------------------------------- |
| \_viaBondToIssue   | 3 letter ISO code of the currency in which Via bond is to be issued in |
| \_amount           | float number of ether to stake for issue                               |

### Purchase of Via bonds with Via cash

`requestIssueForViaCash(_amount, _viaBondToIssue, _currencyToDebit)`

| Function parameter | Description                                                         |
| ------------------ | ------------------------------------------------------------------- |
| \_amount           | float number of amount to purchase                                  |
| \_viaBondToIssue   | address of Via bond to purchase                                     |
| \_currencyToDebit  | 3 letter ISO code of currency of Via cash to purchase Via bond with |

### Transfer of Via bonds

`requestTransfer(_amount, _recipient, _bondToTransfer)`

| Function parameter | Description                                                 |
| ------------------ | ----------------------------------------------------------- |
| \_amount           | float number amount of Via bond to transfer                 |
| \_recipient        | address of recipient to which Via bond is to be transferred |
| \_bondToTransfer   | address of Via bond to transfer                             |

### Redemption of Via bonds by investor

`redemptionByInvestor(_amount, _bondToRedeem)`

| Function parameter | Description                               |
| ------------------ | ----------------------------------------- |
| \_amount           | float number amount of Via bond to redeem |
| \_bondToRedeem     | address of Via bond to redeem             |

### Redemption of Via bonds by issuer

`function redemptionByIssuer(_amount, _bondToRedeem, _currencyToRedeemBond)`

| Function parameter     | Description                                                       |
| ---------------------- | ----------------------------------------------------------------- |
| \_amount               | float number of amount to redeem                                  |
| \_bondToRedeem         | address of Via bond to redeem                                     |
| \_currencyToRedeemBond | 3 letter ISO code of currency of Via cash to redeem Via bond with |


# Lending

Users with collateral supported on the Verified Network such as stETH (staked ether) can purchase tokenized bonds issued on the Verified Network to lend money to borrowers that issue tokenized bonds.&#x20;

Lenders get bond tokens after they purchase tokenized bonds, and such bond tokens can be used for redeeming bonds.


# Bond purchase function


# Repayments

Issuers of tokenized bonds on the Verified Network can make repayments after the term of the bonds is over. Repayments are made in supported currencies (cash tokens) on the Verified Network such as USDC.&#x20;

Repayments made by issuers are distributed to purchasers of the bond that provide collateral to the bond issuing contract. The bond contract stakes collateral on liquidity sources like Compound to borrow stablecoins for the bond issuer.&#x20;


# Bond redemption function


# Claiming collateral

Tokenized bonds can be purchased with collateral supported on the Verified Network such as stETH (staked ether). Such collateral is staked by borrowers using the issuing bond contract on liquidity sources such as Compound to borrow stablecoins such as USDC.&#x20;

Lenders get bond tokens when they purchase bonds and such bond tokens can be used to redeem bonds. Redemption of a bond returns the collateral to the lender or bond purchaser and extinguishes (burns) the bond tokens used to claim collateral by redeeming bonds.


# Defaults and Unsold bonds


# Returns on Investment


# Manager and Platform returns


# Verified REST API

Dive into the specifics of each API endpoint by checking out our complete documentation.

## Market Data

All the methods associated with fetching asset data.&#x20;

{% content-ref url="/pages/Vv55Ys3dWXuzbCtifYZi" %}
[Market data](/reference/verified-rest-api/market-data)
{% endcontent-ref %}

## Order data

Methods for fetching order and trade data, and account balances.

{% content-ref url="/pages/WyHblllQubWtjLJCFwgO" %}
[Order data](/reference/verified-rest-api/order-data)
{% endcontent-ref %}

## **Order Management**

Methods for adding, editing and cancelling orders.

{% content-ref url="/pages/lgXfIaNnWrO32xCVLMAN" %}
[Order Management](/reference/verified-rest-api/order-management)
{% endcontent-ref %}


# Market data

Api endpoints to fetch current market data

## List of API endpoints&#x20;

1. Fetch all assets
2. Fetch all tradable asset pairs
3. Fetch ticker information (by security symbol)
4. Fetch Orderbook(complete market depth)

## &#x20;


# Get all assets

The assets endpoint is to provide a detailed summary for each security-currency available.

### API endpoint

```
/api/assets
```

### Request Samples

<pre><code><strong> GET https://verified-api.azurewebsites.net/api/assets
</strong></code></pre>

#### Response Samples

Content type

> &#x20;application/json

```json
[
  {
    "poolId": "0x2e867a8376ef5c8fc82fdcbf34b31acaf2fb7e1400000000000000000000084b",
    "poolAddress": "0x2e867a8376ef5c8fc82fdcbf34b31acaf2fb7e14",
    "poolType": "PrimaryIssue",
    "swapFee": "0.01",
    "minimumPrice": "0.666666666666666666",
    "securityOffered": "7500000",
    "cutoffTime": "1687338408",
    "offeringDocs": "QmUxyeywfQqqiVY34yJMBS8MQQn2teJWEnBj9C3Prxj4iS",
    "minimumOrderSize": "1",
    "currencyToken": {
      "address": "0x07865c6e87b9f70255377e024ace6630c1eaa37f",
      "symbol": "USDC",
      "balance": "62.000035",
      "decimals": 6
    },
    "securityToken": {
      "address": "0x95d02d8c67825ee0cfaa0d3ff21a10df9e9f73cd",
      "symbol": "ROMNEY",
      "balance": "7499982",
      "decimals": 18
    }
  }
]
```

###


# Get Tradable Asset Pairs

Tradeable asset pair endpoint to fetch pool details as per security-currency pair

### API endpoint

```
/api/assetPair/?pair={securitySymbol}-{currencySymbol}
```

### Request Samples

<pre class="language-html"><code class="lang-html"><strong> GET https://verified-api.azurewebsites.net/api/assetPair?pair=HMREFG-USDC
</strong></code></pre>

#### Response Samples

Content type

> &#x20;application/json

```json
{
  "poolId": "0xa7442cccb1632fd417eb0d27b62d6307346bdb8100000000000000000000083b",
  "poolAddress": "0xa7442cccb1632fd417eb0d27b62d6307346bdb81",
  "poolType": "PrimaryIssue",
  "swapFee": "0.01",
  "minimumPrice": "0.222222222222222222",
  "securityOffered": "900",
  "cutoffTime": "1686989166",
  "offeringDocs": "QmeowXcrtz7588e1xsjfBP6onrvcSqKF3V34i3gzPo7QBM",
  "minimumOrderSize": "1",
  "currencyToken": {
    "address": "0x07865c6e87b9f70255377e024ace6630c1eaa37f",
    "symbol": "USDC",
    "balance": "0",
    "decimals": 6
  },
  "securityToken": {
    "address": "0xee606de96bf2c37a7440afa3f93f7a6bff371534",
    "symbol": "HMREFG",
    "balance": "0",
    "decimals": 18
  }
}
```

###


# Get Ticker Information

The ticker endpoint is to provide a 24-hour pricing and volume summary for each market pair available on the exchange.

### API endpoint

```
/api/ticker?symbol={securitySymbol}
```

### Request Samples

<pre class="language-css"><code class="lang-css"><strong> GET https://verified-api.azurewebsites.net//api/ticker?symbol=zyiina
</strong></code></pre>

#### Response Samples

Content type

> &#x20;application/json

```json
{
  "address": "0xcd3495b17d92480676a082195ae26a09cc5b01b7",
  "symbol": "DH12036",
  "balance": "5438329829832",
  "decimals": 18
}
```

###


# Get Orderbook

The order book endpoint is to provide a complete order book (arranged by best asks/bids) with full depth returned for a given poolID

### API endpoint

<pre><code><strong>/api/fetchOrderBook?poolId={poolID}
</strong></code></pre>

### Request Samples

<pre class="language-css"><code class="lang-css"><strong> GET https://verified-api.azurewebsites.net/api/fetchOrderBook?poolId=0x748acd5263c4c21dfe63f675ddb01b1ab44690a7000000000000000000000852
</strong></code></pre>

#### Response Samples

Content type

> &#x20;application/json

```json
{
  "buyData": [
    {
      "bid": "5.00",
      "amountOffered": "7.00",
      "timestamp": "1686034140"
    }
  ],
  "sellData": [
    {
      "offer": "3.00",
      "amountOffered": "10.00",
      "timestamp": "1686031848"
    }
  ]
}
```

###


# Order data

Api endpoints to fetch detailed order data

## List of API endpoints&#x20;

1. Fetch account balance
2. Fetch trade balance
3. Fetch open market orders
4. Fetch closed orders
5. Query Orders details
6. Query Trade details
7. Fetch Trades history


# Get Account Balance

Fetch all balances of different assets in an account

### API endpoint

```
/api/fetchAccountBalance?accountId={accountId}
```

### Request Samples

<pre class="language-css"><code class="lang-css"><strong> GET https://verified-api.azurewebsites.net/api/fetchAccountBalance?accountId=0xaA0d06ed9CeFb0B26ef011363c9d7880feda8f08
</strong></code></pre>

#### Response Samples

Content type

> &#x20;application/json

```json
{
  "result": [
    {
      "currencySymbol": "USDC",
      "currencyTokenDecimals": 6,
      "totalAmount": 4.4
    }
  ]
}
```

###


# Get Trade Balance

Fetch trade balance

### API endpoint

```
/api/fetchTradeBalance?accountId={accountId}
```

### Request Samples

<pre class="language-css"><code class="lang-css"><strong> GET https://verified-api.azurewebsites.net/api/fetchTradeBalance?accountId=0xaA0d06ed9CeFb0B26ef011363c9d7880feda8f08
</strong></code></pre>

#### Response Samples

Content type

> &#x20;application/json

```
{
  "result": [
    {
      "security": "0x53c9d69ed3ebae420c1c27542a7c0cfd0dd4bce4",
      "issuer": "0x0c8e84b66729eaa51f9a1b353bda996f95d8cd99",
      "currency": "0x07865c6e87b9f70255377e024ace6630c1eaa37f",
      "securityId": "HBAJSA2",
      "cashSwapped": "12.00",
      "timestamp": 1687497948,
      "securitySwapped": "3.52"
    },
    {
      "security": "0xf2a9060d2959d6aebb0c9916ff1a15f7e1bce0e8",
      "issuer": "0xaa0d06ed9cefb0b26ef011363c9d7880feda8f08",
      "currency": "0x07865c6e87b9f70255377e024ace6630c1eaa37f",
      "securityId": "ZYIINA",
      "cashSwapped": "4.40",
      "timestamp": 1687497156,
      "securitySwapped": "10.00"
    }
  ]
}
```

###


# Get Open Orders

Fetch orderbok data with latest bid and ask price

### API endpoint

```
/api/openOrders?poolId={poolId}&accountId={accountId}
```

### Request Samples

<pre class="language-css"><code class="lang-css"><strong> GET https://verified-api.azurewebsites.net/api/openOrders?poolId=0x7ad0d3a9cda33d2fc7af57436a57951ce9701297000000000000000000000821&#x26;accountId=0xaA0d06ed9CeFb0B26ef011363c9d7880feda8f08
</strong></code></pre>

#### Response Samples

Content type

> &#x20;application/json

```json
{
  "result": [
    {
      "amountOffered": "2",
      "priceOffered": "0",
      "orderReference": "0x02b448270f09015cd96a96413621e8462fb7465b1860ecc24bab1a5cfef151f7",
      "timestamp": "1686640356",
      "creator": "0xaa0d06ed9cefb0b26ef011363c9d7880feda8f08",
      "tokenIn": "0x07865c6e87b9f70255377e024ace6630c1eaa37f",
      "tokenOut": "0x7ad0d3a9cda33d2fc7af57436a57951ce9701297",
      "orderType": "Buy"
    }
  ]
}
```

###


# Get Closed Orders

Fetch orderbok data with latest bid and ask price

### API endpoint

```
/api/closedOrders?poolId={poolId}&accountId={accountId}
```

### Request Samples

<pre class="language-css"><code class="lang-css"><strong> GET https://verified-api.azurewebsites.net/api/openOrders?poolId=0x7ad0d3a9cda33d2fc7af57436a57951ce9701297000000000000000000000821&#x26;accountId=0xaA0d06ed9CeFb0B26ef011363c9d7880feda8f08
</strong></code></pre>

#### Response Samples

Content type

> &#x20;application/json

```json
{
  "result": [
    {
      "orderType": "Buy",
      "orderReference": "0xdf4dbd059c81ca121e22524bd5db1abf8bb892537e5bb4f45f2ff04c8591ac81",
      "amountOffered": "2.142857142857142857",
      "priceOffered": "7",
      "partyAddress": "0xaa0d06ed9cefb0b26ef011363c9d7880feda8f08",
      "timestamp": "1687440049",
      "counterPartyAddress": "0xaaa22bdf2a31e0d4669c7e65def34f9d61b34f97"
    }
  ]
}
```

###


# Query Orders Info

Fetch orderbok data with latest bid and ask price

### API endpoint

```
/api/fetchOrder?orderId={orderId}
```

### Request Samples

<pre class="language-css"><code class="lang-css"><strong> GET https://verified-api.azurewebsites.net/api/fetchOrder?orderId=0x1304da051a2a05348cdca919b180c158a429844700f7795a8835257984632925
</strong></code></pre>

#### Response Samples

Content type

> &#x20;application/json

```json
{
  "result": {
    "amountOffered": "20",
    "priceOffered": "6",
    "orderReference": "0x1304da051a2a05348cdca919b180c158a429844700f7795a8835257984632925",
    "timestamp": "1687497432",
    "creator": "0xaa0d06ed9cefb0b26ef011363c9d7880feda8f08",
    "tokenIn": "0x53c9d69ed3ebae420c1c27542a7c0cfd0dd4bce4",
    "tokenOut": "0xf13a0e8ff25b8931ba9eded29027951464f53b62",
    "orderType": "Sell"
  }
}
```

###


# Query Trades Info

Fetch orderbok data with latest bid and ask price

### API endpoint

```
/api/fetchTrade?tradeId={tradeId}
```

### Request Samples

<pre class="language-css"><code class="lang-css"><strong> GET https://verified-api.azurewebsites.net/api/fetchTrade?tradeId=0x1e143ed274a8d26986a05ddd482db05542c6d211aa725930d80fa2125d7f1bb8
</strong></code></pre>

#### Response Samples

Content type

> &#x20;application/json

```json
{
  "result": {
    "orderType": "Buy",
    "orderReference": "0x1e143ed274a8d26986a05ddd482db05542c6d211aa725930d80fa2125d7f1bb8",
    "amountOffered": "0.333333333333333333",
    "priceOffered": "6.000000000000000006",
    "partyAddress": "0xaa0d06ed9cefb0b26ef011363c9d7880feda8f08",
    "timestamp": "1687497793",
    "counterPartyAddress": "0xaaa22bdf2a31e0d4669c7e65def34f9d61b34f97"
  }
}
```

###


# Get Trades History

Fetch orderbok data with latest bid and ask price

### API endpoint

```
/api/trades?poolId={poolId}&accountId={accountId}
```

### Request Samples

<pre class="language-css"><code class="lang-css"><strong> GET https://verified-api.azurewebsites.net/api/trades?poolId=0x748acd5263c4c21dfe63f675ddb01b1ab44690a7000000000000000000000852&#x26;accountId=0xaA0d06ed9CeFb0B26ef011363c9d7880feda8f08
</strong></code></pre>

#### Response Samples

Content type

> &#x20;application/json

```json
{
  "result": [
    {
      "amountOffered": 7.857142857142858,
      "priceOffered": 7,
      "orderReference": "0x09f1dd2b1ffe94c3d3b0fb95a03dcfdb07167e85abde4a91314700658e4bd7ac",
      "timestamp": "1687439928",
      "creator": "0xaa0d06ed9cefb0b26ef011363c9d7880feda8f08",
      "tokenIn": "0x40cf81a59ba9ce0d93763c3373cf0a9fe2a62887",
      "tokenOut": "0x748acd5263c4c21dfe63f675ddb01b1ab44690a7",
      "orderType": "Sell"
    }
  ]
}
```

###


# Order Management

Api endpoints to fetch detailed user data

## List of API endpoints&#x20;

1. Add Orders
2. Edit Orders
3. Cancel Orders


# Add Order

Fetch orderbok data with latest bid and ask price

### API endpoint

```
/api/createOrder
```

### Request Samples

<pre class="language-css"><code class="lang-css"><strong> POST <a data-footnote-ref href="#user-content-fn-1">https://</a>verified-api.azurewebsites.net/api/createOrder
</strong></code></pre>

#### Body Params

```javascript
{
    "securityAddress": "string",
    "currencyAddress": "string",
    "quantity": "string",
    "swapType": "string",
    "poolId": "string",
    "secret_key": "string"
}
```

### Sample Body params

```
{
    "securityAddress": "0x7395e5201ed7a841d1a1b04e8c19ab80dd72ab81",
    "currencyAddress": "0x07865c6e87b9f70255377e024ace6630c1eaa37f",
    "quantity": "1",
    "swapType": "Sell",
    "poolId": "0xfe94f5cea565935aa092d66b8540b03a4de05872000000000000000000000860",
    "secret_key": "153eb0b3726764d204aedc9062974ee82edcca2bc536f3742149511d0e455306"
}
```

### Encryption of Secret key

```
Algorithm : AES-256-CBC
Secretkey (32 bytes data) = "verified@API"
initVector (16 bytes data) = wallletAddress 
```

###

#### Response Samples

Content type

> &#x20;application/json

```json
{
    "status": ok
}
```

###

[^1]:


# Edit Order

Fetch orderbok data with latest bid and ask price

### API endpoint

```
/api/editOrder
```

### Request Samples

<pre class="language-css"><code class="lang-css"><strong> POST <a data-footnote-ref href="#user-content-fn-1">https://</a>verified-api.azurewebsites.net/api/editOrder
</strong></code></pre>

#### Response Samples

Content type

> &#x20;application/json

#### Body Params

```json
{
    "securityAddress": "string",
    "currencyAddress": "string",
    "quantity": "string",
    "newPrice": "string",
    "swapType": "string",
    "poolId": "string",
    "secret_key": "string",
    "orderRef": "string"
}
```

### Sample body request

```
{
    "securityAddress": "0x7395e5201ed7a841d1a1b04e8c19ab80dd72ab81",
    "currencyAddress": "0x07865c6e87b9f70255377e024ace6630c1eaa37f",
    "quantity": "1",
    "newPrice": "10",
    "swapType": "Sell",
    "poolId": "0xfe94f5cea565935aa092d66b8540b03a4de05872000000000000000000000860",
    "secret_key": "153eb0b3726764d204aedc9062974ee82edcca2bc536f3742149511d0e455306",
    "orderRef": "0x02b448270f09015cd96a96413621e8462fb7465b1860ecc24bab1a5cfef151f7"
}
```

> ### Encryption of Secret key
>
> ```
> Algorithm : AES-256-CBC
> Secretkey (32 bytes data) = "verified@API"
> initVector (16 bytes data) = wallletAddress 
> ```

### Response

```json
{
    "status": ok
}
```

###

[^1]:


# Cancel Order

Fetch orderbok data with latest bid and ask price

### API endpoint

```
/api/cancelOrder
```

### Request Samples

<pre class="language-css"><code class="lang-css"><strong> POST <a data-footnote-ref href="#user-content-fn-1">https://</a>verified-api.azurewebsites.net/api/cancelOrder
</strong></code></pre>

#### Response Samples

Content type

> &#x20;application/json

#### Params

```
{
    "securityAddress": "string",
    "currencyAddress": "string",
    "quantity": "string",
    "swapType": "string",
    "poolId": "string",
    "secret_key": "string",
    "orderRef": "string"
}
```

### Sample body request

```
{
    "securityAddress": "0x7395e5201ed7a841d1a1b04e8c19ab80dd72ab81",
    "currencyAddress": "0x07865c6e87b9f70255377e024ace6630c1eaa37f",
    "quantity": "1",
    "swapType": "Sell",
    "poolId": "0xfe94f5cea565935aa092d66b8540b03a4de05872000000000000000000000860",
    "secret_key": "153eb0b3726764d204aedc9062974ee82edcca2bc536f3742149511d0e455306",
    "orderRef": "0x02b448270f09015cd96a96413621e8462fb7465b1860ecc24bab1a5cfef151f7"
}
```

> ### Encryption of Secret key
>
> ```
> Algorithm : AES-256-CBC
> Secretkey (32 bytes data) = "verified@API"
> initVector (16 bytes data) = walletAddress 
> ```

### Response

```json
{
    "status": ok
}
```

###

[^1]:


# Verified Subgraphs

Querying data from the Verified Network

Subgraphs are published for Verified smart contract deployments on the Ethereum and Base main nets for production use, and Gnosis for development use. There are two sets of subgraphs -

1. Verified Liquidity pools - these are custom pools that are implemented using the Balancer protocol. The Balancer Vault does the accounting for Verified Liquidity pools.
2. Verified Wallet - these index tokenized products, issuances, investors and aspects of servicing issuers and investors.

The subgraphs are available on&#x20;

1. Gnosis
   1. Vault - <https://api.studio.thegraph.com/query/77016/vault-gnosis/version/latest>
   2. Wallet - <https://api.studio.thegraph.com/query/77016/wallet-gnosis/version/latest>
2. Ethereum mainnet
   1. Vault - <https://gateway.thegraph.com/api/b8a85dbf6f1f1111a5d83b479ee31262/subgraphs/id/DcVx37MBsmRXinhAeTssAyVuZtn9m8bcvcCCZVSt7bQW>
   2. Wallet - <https://gateway.thegraph.com/api/b8a85dbf6f1f1111a5d83b479ee31262/subgraphs/id/9phMoFdBZGRKVWfsgmzCaEBCo1jZLX22FuqQU1JwWfW8>
3. Base mainnet
   1. Vault - <https://gateway.thegraph.com/api/b8a85dbf6f1f1111a5d83b479ee31262/subgraphs/id/HESgHTG2RE8F74MymKrdXKJw2u4s8YBJgbCjHuzhpXeC>
   2. Wallet - <https://gateway.thegraph.com/api/b8a85dbf6f1f1111a5d83b479ee31262/subgraphs/id/2aGD2WDR6ncrTvGU4wEaME2Ywke1ookuNucMNJmcnrz5>


# Verified Applications

On Web and Mobile

There are several applications on the Verified Network for different stakeholders - investors, issuers, asset managers, servicers (registrars, cash managers), custodians, compliance managers. Most of these applications are web applications, except investor facing applications which are implemented for iOS (apple) and android phones.&#x20;

Applications on the Verified Network can also be implemented by third parties using the APIs that are documented here.


# Doing KYC

All users on the Verified Network have to get their KYC approved by authorized Anti-money laundering officers before they can transact.&#x20;

{% embed url="<https://youtu.be/AsN5CuXwIH0?si=EsYfWtb2-x8LQMgS>" %}

There are 4 KYC levels&#x20;

1. Retail investor (includes individual investors)
2. Professional / Accredited investor
3. Financial Institutions / Institutional investor
4. Other businesses (for example, issuers, borrowers, etc)


# Creating wallet

To use Verified Network Applications a blockchain wallet is required. To create wallet or use an existing wallet click on Connect Wallet button and follow the instructions on the connect wallet popup.

Click Connect Wallet Button&#x20;

<figure><img src="/files/XUJvK6HfThl4K5ZPlcHA" alt=""><figcaption><p>Verified Networks Homepage</p></figcaption></figure>

Choose wallet of your choice.[ Metamask](https://metamask.io/download/) is recommended

<figure><img src="/files/Uh0ZthEvkplyRvI5CKmr" alt=""><figcaption><p>Connect Wallet Modal</p></figcaption></figure>

Follow Instructions on the modal to create new wallet or connect an existing wallet

<figure><img src="/files/0U1RfwPRCCYldwdUYx7Z" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/VVOP5VvYJl1pe7ldqje1" alt=""><figcaption></figcaption></figure>


# Using the Verified Dapp

After wallet creation, users can interact with Verified Dapp by connecting the newly created wallet or an existing wallet.

<figure><img src="/files/BegfXpDktLNdeHgqn04R" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/zbIxjV1MIPPz0QGXskuF" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/8qx9IPyHYLdiMR2zpKUc" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/0wtPelfXFAsB8NRA2pMN" alt=""><figcaption></figcaption></figure>


# Doing KYC

To transact on the Verified Network, KYC is required. Users can verify KYC using Verified applications.

<figure><img src="/files/xNEgK52IhIGFUiZo86l4" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/Gy4b3cbPvb0HrZVSFJfn" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/JuQT1ep2kXwbJAMOi0pS" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/wjhQ0u0R1SX1XfhEPiOf" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/r9kWjUgOyUWnceDKRkua" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/qkyx9Vb4LJQEFisrBhq6" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/3hncDsYnDpwvtGE5TqLQ" alt=""><figcaption></figcaption></figure>


# Primary issues

Primary issues are offers to investors by businesses that want to raise capital. Primary issues may be open to all investors, or to investors in specific countries, and of a specific category (eg, accredited investors).

{% embed url="<https://youtu.be/iXOx7hKmvzg>" %}


# Creating a new issue

To Create Primary Issue, click on the Issue New button from the New Issues menu on the Verified web application. Fill the Issue Creation form and follow instruction to the final step.

<figure><img src="/files/Of6ZzJTaqnLgWxanMudb" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/76Pl6C1PZYzLCXB5DLYs" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/E8f3gbdDKPA78phU2W5S" alt=""><figcaption><p>Note : Issue managers are licensed financial intermediaries that review and approve issues on the Verified Network</p></figcaption></figure>

<figure><img src="/files/fhKEKpZPNjWigJu4eqhy" alt=""><figcaption><p>Note : Target clients can be retail investors, accredited investors or institutional investors</p></figcaption></figure>

<figure><img src="/files/USaqXFpCTqisdjtEDPP7" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/S2BKc2TLrf5tro8tPtQH" alt=""><figcaption><p>Note : The ratio between target investment and issued amount determines the target price for the offer. The ratio between the minimum investment and the issued amount determines the minimum price for the offer.</p></figcaption></figure>

<figure><img src="/files/uSd7qChAQIMPulJNaEnP" alt=""><figcaption></figcaption></figure>


# Subscribing to issue

To Subscribe to a Primary Issue, a User needs to create an order in a Primary Pool by selecting an active primary pool in the New Issues menu.

<figure><img src="/files/QimucBSBBbrcUjKLowJl" alt=""><figcaption></figcaption></figure>

Users need to have enough currency (eg, USDC) balance in their wallets to subscribe to a primary issue.

<figure><img src="/files/BqXnUqnv2wRSeN1Vhok0" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/M06Ax31OxDsfjUGuo3Hm" alt=""><figcaption></figcaption></figure>

After Order has been created successfully, user can see list of all orders in Orders submenu on Account Statement menu

<figure><img src="/files/FbLrQytfhUcKgKzHMUcR" alt=""><figcaption></figcaption></figure>

If the order shows as subscribed, it means user has successfully subscribed to the issue.


# Closing issue

To close a primary issue, the licensed issue manager assigned by the pool creator needs to handle pool closure.

<figure><img src="/files/FwxNdPZDjk2ntThAvJFa" alt=""><figcaption></figcaption></figure>


# Secondary trading

Investors can trade security tokens they hold with secondary liquidity pools that support market and limit orders.

{% embed url="<https://youtu.be/MTo9CkP0PJI>" %}


# Market orders

To create Market orders on Verified Secondary Pools, click on any Verified Secondary Pool from the list of Secondary Pools on Secondaries Menu in the web application.

Choose Secondary Pool and select Market as Type for both Buy and Sell Order. Market orders get filled on the best price available at that time. For buyers, best prices would mean the lowest prices available from sellers. And for sellers, best prices would mean the highest offers from buyers.

<figure><img src="/files/htZxiDxIxsk7X5up8oHh" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/2c1d2qfBMntM1VIkycWY" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/vYxGtJMwfUkIK3pTJn93" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/uLrcgDZewAG7YBNhTBv7" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/Bwru4e9AwVGxcqaX0Bwn" alt=""><figcaption></figcaption></figure>


# Limit orders

To create Limit orders on Verified Secondary Pools, click on any Verified Secondary Pool from the list of Secondary Pools on Secondaries Menu in the web application.

Choose Secondary Pool and select Limit as Type for both Buy and Sell Order. Limit orders lets users set a price at which an order can execute.

<figure><img src="/files/fTB6FLrbT8YSCyhvKD2V" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/5BROgaV3gIGqdp2AaJHv" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/oNPF0813nvB23CepdLnh" alt=""><figcaption></figcaption></figure>


# Edit, Cancel, Settle orders

To Manage Orders created from previous page, users can Edit or Cancel an order on Orders submenu under Account Statement menu.

<figure><img src="/files/6uckz0TAEEVVO9bXsrxf" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/3QxQJPAQXHVaIO2kZIjc" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/4snhyPK1wcaiTsdCDbnE" alt=""><figcaption></figcaption></figure>

Similarly, users can settle filled orders (trades) on Trades submenu under Account Statement menu by clicking on claim button to settle trades. Settling trades transfers security tokens to buyers, and cash tokens to sellers.

<figure><img src="/files/j7jAuDkf8KBG7So40pAn" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/BVZnfQf19ixmrvQkQBr7" alt=""><figcaption></figcaption></figure>


# Margin trading

Margin trading allows users to trade by staking collateral to cover margin money, financing cost and potential losses on trades. Users can margin trade by putting a fraction of value of the trade as margin money. Profit and Loss settlement is daily and traders lose money if prices go down and vice versa.

{% embed url="<https://youtu.be/cGn9B0VLM-k>" %}


# Post Margin collateral

To post Collateral to a Margin Pool, click on the Post Collateral button on Margin Traded Products menu in the web application. Collateral covers margin money, financing costs and potential losses.

Select Security and Currency pair to post collateral to

<figure><img src="/files/TTIl0OWsJoHCWBlRmkWU" alt=""><figcaption></figcaption></figure>

Enter amount of collateral to post and click Offer Collateral button. Note: The collateral amount is the amount of the currency token selected.

<figure><img src="/files/yO0XpvVBZM2gox0oHr9F" alt=""><figcaption></figcaption></figure>


# Swaps

To Create swaps/orders in a Margin pool, user need to post collateral to the margin pool as explained in previous page.

To create Market Order for both Buy and Sell, choose margin pool from the list of margin pools on Margin Trading Products menu and select Market as order Type

<figure><img src="/files/ADx9eUjOfGhGzxBSSyWH" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/bL3hrosuHYjCIRP8buwz" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/CLZ7oqcg64o1XfWI0ZJ2" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/V29cDvcLG9AhyDkOqHCA" alt=""><figcaption></figcaption></figure>

To create Limit Order for both Buy and Sell, select Limit as order Type and input Price and Amount

<figure><img src="/files/eNlBWFE4FAvDnvupEqpn" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/yGUmn8GkqtCtoVNcHfzG" alt=""><figcaption></figcaption></figure>


# Edit, Cancel, Settle orders


# Portfolio

A portfolio statement of a user shows all the credit and debit transactions for that user across currencies and time.&#x20;


# Account statement

An account statement for a user on the Verified web application is his portfolio statement that shows asset balances, transactions, etc.

<figure><img src="/files/lE8Fiah7s2OMuzF4JAGU" alt=""><figcaption></figcaption></figure>


# Corporate actions

Corporate actions are either Resolutions that investors are requested to vote on, or else Corporate actions are distributions of income to investors such as dividends and interest.

<figure><img src="/files/nW3jxJ4B3TzWj3kR870Z" alt=""><figcaption></figcaption></figure>


# Underwriting liquidity

To provide Liquidity to underwrite issues on the Verified web application, click Provide Liquidity button on Underwriting Liquidity menu.

<figure><img src="/files/Xr2duRt2hmLQ0TpSalwg" alt=""><figcaption></figcaption></figure>

Selected Currency Token to provide.

<figure><img src="/files/vy8CbUaUZ1LkBC1Sw8DT" alt=""><figcaption></figcaption></figure>


