Setting up the callbacks server

The callbacks server implements a set of endpoints that can be called by the other components of the bank infrastructure to fetch data from or update data to the bank's internal databases.

It implements the following endpoints:

  • /compliance/fetch_info: Fetches the customer's name, address, and date of birth when provided the friendlyID of the customer from the users table
  • /compliance/sanction: Validates whether the sender's financial institution is sanctioned to send transactions from the sanctions table
  • /compliance/ask_user: Checks whether the receiving bank will send the beneficiary's KYC details to the sending bank (fetch_info is then called to fetch the details)
  • /receive: Captures details about received payments and updates the beneficiary's balance

The first three are called by the compliance server for compliance checks. The last one is called by the bridge server whenever a payment is received. Let's get started:

  1. Let's start by writing our CallBack server. First, we will write the callbacks server for Bank A. Create a nodejs app called CallbacksA and declare your dependencies, as follows:
const express = require("express");
const bodyParser = require("body-parser");
const app = express();
const pg = require('pg');
const conString = "postgres://bankauser:bankauser@localhost:5432/banka";
const client = new pg.Client(conString);

We'll be using the pg client to connect with postgres. Notice how conString is set to the banka database URL. Make sure you install the dependencies in your nodejs environment.

  1. The following lines set up bodyParser so that it parses requests that are sent to the app:
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
  1. Next, we will declare a middleware layer to allow Cross-Origin Resource Sharing (CORS). This permits our other bank modules to interact with our callbacks server:
app.use(function (req, res, next) {

// Website you wish to allow to connect
res.setHeader('Access-Control-Allow-Origin', '*');

// Request methods you wish to allow
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');

// Request headers you wish to allow
res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');

// Set to true if you need the website to include cookies in the requests sent

// to the API (e.g. in case you use sessions)
res.setHeader('Access-Control-Allow-Credentials', true);

// Pass to next layer of middleware
next();
});
  1. Set up the server and the port as follows. I'm running the CallbacksA server on port 5000:
 var server = app.listen(process.env.PORT || 5000, function () {
var port = server.address().port;
console.log("App now running on port", port);
});
  1. We need to connect to the pg client to allow our services to interact with the database. To do so, use the following command:
client.connect();
  1. First, let's write the fetch_info endpoint. The fetch_info endpoint carries out the following steps:
    1. Extracts the address of the bank customer from the request body.
    2. Splits the address into 'friendlyID' and 'domain', delimited by '*'.
    3. Uses the friendlyID to run a select query on the users table and fetches the name, address, date of birth, and domain.
    4.  Marshalls the results of the query into JSON and returns the response to the requestor:
app.post('/compliance/fetch_info', function (request, response) {
var addressParts = request.body.address.split('*');
var friendlyId = addressParts[0];

// You need to create `accountDatabase.findByFriendlyId()`. It should look
// up a customer by their Stellar account and return account information.

client.query('SELECT name,address,dob,domain from users where friendlyid = $1', [friendlyId], (error, results) => {
if (error) {
throw error
}

if(results)
{
response.json({
name: results.rows[0].name,
address: results.rows[0].address,
date_of_birth: (results.rows[0].dob).toString(),
domain: results.rows[0].domain
});

response.end();

}});
});

The JSON response is sent to the requestor and is attached to the transaction when it is submitted to the blockchain network.

  1. Next, let's look at the following sanctions endpoint. The sanctions endpoint carries out the following steps:
    1. Extracts the domain of the sender's address from the JSON request.
    2. Checks the sanction database to ensure the domain and the financial institution are allowed to send payments by running a select query against the sender's domain.
    3. If the domain owner, that is, the financial institution is sanctioned to send payments, send a 200 (OK) status in the response. If the entry does not exist, send an error 403 status with the message FI not sanctioned:
app.post('/compliance/sanctions', function (request, response) {
var sender = JSON.parse(request.body.sender)
client.query('SELECT * from sanction where domain = $1', [sender.domain], (error, results) => {
if (error) {
response.status(403).end("FI not sanctioned");
}
if (results)
{
response.status(200).end();
}
})
});
  1. Next, we have the following ask_user endpoint, which is the last compliance endpoint. The ask_user endpoint is similar to the sanctions endpoint. It carries out one additional step – it checks whether the receiving bank will share KYC details of the beneficiary with the compliance server of the sending bank. If this value is set to true, the fetch_info endpoint is called to fetch the details of the beneficiary.

The ask_user endpoint carries out the following steps:

  1. Fetches the sender's domain from the request.
  2. Checks whether the domain is sanctioned to send payments in the sanctions database.
  3. If it is not sanctioned, an error message with a 403 status is sent to indicate that the bank domain is not sanctioned. The message that's sent is FI not sanctioned.
  1. If the domain is sanctioned, the endpoint checks the 'kyc' column against the entry of the domain in the sanctions database. If it is set to true, that means that the receiving bank will share the kyc details of the beneficiary. Thus, a response status of 200 (OK) is returned.
  2. If kyc is set to false, a response status of 403 with the message KYC request denied is returned to the requestor:
app.post('/compliance/ask_user', function (request, response) {
var sender = JSON.parse(request.body.sender)


client.query('SELECT * from sanction where domain = $1', [sender.domain], (error, results) => {
if (error) {
response.status(403).end("FI not sanctioned");
}
if (results)
{

if(results.rows[0].kyc == true)
{
response.status(200).end();
}
else
{
response.status(403).end("KYC request denied");
}
}
})
});

This brings us to the last endpoint of our callbacks server, which is /receive. This endpoint is called every time a payment is received by the bridge server. It carries out a series of steps:

  1. Extracts the received amount and the identifier of the customer from the request. In our case, this is the friendlyID, which is unique for every customer, but it could be a bank account number or customer ID in the traditional banking system. This is available in the request as request.body.route. We also extract the transactionid and the sender's friendlyID, as well as the sender's KYC details from the attachment field in the request.
  2. These details are captured in the transactions table in the Bank A database, which logs all received transactions.
  1. After successfully logging the transaction to the transactions database, we need to update the balance of the beneficiary. We fetch the current balance from the users table in the Bank A database.
  2. The user's current balance is then updated with the amount that was received in the transaction. After successfully updating the balance, we send a success (response 200 OK) message back to the user:
app.post('/receive', function (request, response) {
var amount = parseInt(Number(request.body.amount).toFixed(2));
var friendlyid = request.body.route;
var SendObj = JSON.parse(request.body.data);
var kycObj = JSON.parse(SendObj.attachment);
client.query('INSERT INTO transactions(txid, sender, receiver, amount, currency, kyc_info) VALUES ($1,$2,$3,$4,$5,$6)',
[request.body.transaction_id,SendObj.sender,request.body.route,amount,request.body.asset_code,kycObj.transaction.sender_info], (error, results) => {
if (error) {
console.log(error);
response.status(500).end("Error inserting transaction");
}
if(results)
{
client.query('SELECT balance from users where friendlyid = $1', [friendlyid], (error, results) => {
if (error) {
console.log(error);
response.status(500).end("Not found");
}
if (results)
{
var balance = Number(results.rows[0].balance)
balance = balance + + amount;

client.query('UPDATE users set balance = $1 where friendlyid = $2', [balance, friendlyid], (error, results) => {

if (error) {
console.log(error);
response.status(500).end("Not found");
}
if (results)
{
response.status(200).end();
}
})
}
})
}
})
});

That brings us to the end of the callbacks server for Bank A. Create a copy of this Node.js application for Bank B as well. Make sure that you change the port and the bank's internal database URL. For my callbacksB application, my port is 5100 and the database URL is postgres://bankbuser:bankbuser@localhost:5432/bankb.

That completes the backend infrastructure of our remittance platform. You can actually submit payment requests to the bridge server payment endpoint (http://banka.com:8006/payment) and follow the steps as payment is executed.

To try it out, simply submit a request with the following parameters:

  • id: <Random transaction ID>
  • amount: <Amount you want to send, such as 1000>
  • asset_code: USD
  • asset_issuer: <USD asset issuer account, such as  GAIHBCB57M2SDFQYUMANDBHW4YYMD3FJVK2OGHRKKCNF2HBZIRBKRX6E>,
  • destination: <receiver, such as janesmith*bankb.com>
  • sender: <sender, such as johndoe*bankb.com>
  • use_compliance: true

The request should go through. If you check the console for the compliance, bridge, and federation server, you should be able to observe that the following steps are carried out:

  1. The bridge server for Bank A receives the payment request. It checks that the transaction request is syntactically correct and that the transaction is not a duplicate against the bridge database. Next, it checks the stellar.toml file hosted at the domain of the receiver (www.bankb.com/.wellknown/stellar.toml) to find the federation server for the receiving bank.
  2. The bridge server for Bank A submits a request to the federation server of Bank B. The federation server of Bank B resolves the janesmith*bankb.com address into the receiving Stellar account (Bank B—GBETQAVAWJJIQ7CZPXWLXKZO6BELLACNR3E7BRD4WTYEANAGGR62VP6Q), the contents of the memo in the transaction (janesmith), and the memotype('text'), and returns to the bridge of Bank A.
  1. Next, the bridge server of Bank A submits the payment request to the Bank A compliance server. The compliance server calls the fetch_info endpoint of the internal callbacks server for Bank A. Then, the fetch_info endpoint returns the details of the sender.
  2. The compliance server of Bank A calls the compliance server of Bank B for a handshake. It checks the stellar.toml file of the receiving bank for the external endpoint of the compliance server of Bank B.
  3. The compliance server of Bank A forwards the details of the transaction, including the sender's KYC, to the compliance server of Bank B.
  4. The compliance server of Bank B calls the sanctions and the ask_user endpoints of the internal callbacks server of Bank B. It verifies whether the banka.com domain is sanctioned to send payments to Bank B and whether the KYC details of the beneficiary will be shared. If the KYC details of the beneficiary will be shared, it calls fetch_info to get the receiver's details.
  5. The compliance server of Bank B sends its response to the compliance server of Bank A.
  6. The compliance server of Bank A checks that it has received a go-ahead from Bank B and whether it has received the KYC details of the beneficiary. Then, it submits its response to the bridge server of Bank A.
  7. Once the bridge server of Bank A gets the go-ahead, it creates a new payment transaction request with the requisite details, including the amount, currency, receiver's details, and sender's details. This transaction request is then submitted to the blockchain.
  8. The bridge server of Bank B is constantly listening for incoming payments to Bank B's stellar account. On receiving payment, it will simply pick up the payment request and submit it to the /receive endpoint of the internal callbacks server of Bank B.
  9. The /receive endpoint of the callbacks server will add the payment to the transactions table and update the beneficiary's balance.

That completes the end-to-end payment flow. Let's put a small bank portal on top that Bank A and Bank B customers can use to submit a payment request and that the admin can use to view the KYC details of the customer.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.196.172