The user should send the deposit request to the server. The deposit request should have the currency and amount being transferred.
// Express post endpoint to receive deposit requestsapp.post('/plugins/bank/deposit',toolsLib.security.verifyBearerTokenExpressMiddleware(['user']), (req, res) => {... });
Step 2
The server creates a unique key (UUID) for the deposit. This UUID will ensure that this transaction occurs only once.
After creating the UUID, the deposit data (amount, currency, user ID, UUID) should be stored on Redis. We recommend setting the UUID as the key. It's also a good idea to give the data an expiry time.
consttransferUuid=// generate uuidconstamount,currency=// deposit data from requestconstuser_id=// ID of user making requestconstpayload= { amount, currency, user_id};// store transfer data on redis with uuid as keyawaittoolsLib.database.client.setAsync(transferUuid,JSON.stringify(payload));
Step 3
After the deposit is given a UUID and is stored on Redis, the server should then forward the payment request to the payment service. The payment service should receive the amount, currency, and UUID of the requested deposit.
Step 4
Once the request from the server is received, the payment service will prompt the user to complete the payment. This can be handled by the server or by the payment service directly via a redirect.
This step will differ based on which service is used but will ultimately end up with the user being asked to complete the payment.
Phase 2: User completes deposit
Phase 3: Payment service notifies the server of completed deposit
Step 1
Once the user completes the payment, the service will notify the server of the completed payment. The way notifications are handled will depend on the payment service used. This notification should come with the amount and currency of the completed deposit. It should also provide the UUID the server created for this deposit in Phase 1.
// Express post endpoint to receive deposit notifications// Accepts uuid as path parameterapp.post('/plugins/bank/:uuid', (req, res) => {... });
Step 2
Once the server receives the notification, it should first check Redis to make sure the UUID is valid.
If no data is found on Redis with the received UUID, the deposit should be rejected.
If data is found with the UUID, that data should be deleted from Redis. After deletion, the server should verify that the amount and currency of the deposit received from the payment service matches the ones found on Redis.
If the user paid less than the required amount or used a different currency, the deposit should be rejected.
constuuid=// uuid received in notificationconstamount,currency=// deposit data from notification// get transfer data from Redis using uuid conststoredDepositData=awaittoolsLib.database.client.getAsync(uuid);// if no data found on Redis, reject transferif (!storedDepositData) {throw err;}// Delete data from RedisawaittoolsLib.database.client.delAsync(uuid);// If deposit amount or currency don't match data found on redis, reject transferif (storedDepositData.amount !== amount||storedDepositData.currency !== currency) {throw err;}
Step 3
Once everything is validated, the server should mint the asset to the user. This completes the deposit flow.
Code Example
For this example, we will use a redirect for prompting the user to complete the payment and receive a notification of the completed payment via a callback URL. The process for both may be different for some payment services but the overall flow should remain the same.
// PHASE 1: RECEIVE DEPOSIT REQUEST FROM USERapp.post('/plugins/bank/deposit',toolsLib.security.verifyBearerTokenExpressMiddleware(['user']), (req, res) => {const { currency,amount } =req.body;constuser_id=req.auth.sub.id;// Create UUID for this depositconsttransactionId=uuid();// Callback url for payment notificationconstcallback_url=`${toolsLib.getKitConfig().info.url}/plugins/bank/${transactionId}`;constpayload= { amount, currency, callback_url, user_id,// user_id added for callback expires:moment().add(5,'minutes') // if payment occurs 5 minutes after expires, deny transfer };// Store deposit data in RedisawaittoolsLib.database.client.setAsync(transferUuid,JSON.stringify(payload));// PAYMENT_SERVICE is the payment service being usedconsttransferResponse=awaitPAYMENT_SERVICE.deposit(payment);// Redirect user for completing the paymentreturnres.redirect(transferResponse.url);});// PHASE 3: RECEIVE NOTIFICATION OF COMPLETED DEPOSIT FROM PAYMENT SERVICEapp.post('/plugins/bank/:uuid', (req, res) => {const { uuid } =req.params;const { amount,currency,transaction_id } =req.body;// Get deposit data from Redis via uuidconststoredDepositData=awaittoolsLib.database.client.getAsync(uuid);// If data is not found, reject depositif (!storedDepositData) {returnres.status(400).json({ message:`No deposit found with UUID ${uuid}` }); } storedDepositData =JSON.parse(storedDepositData);// Delete data from RedisawaittoolsLib.database.client.delAsync(uuid);// If deposit occured after expiry time, reject the depositif (moment().isAfter(storedDepositData.expires)) {returnres.status(400).json({ message:'Deposit is expired' }); }// If deposit amount or currency don't match ones stored on Redis, reject the depositif (amount !==storedDepositData.amount || currency !==storedDepositData.currency) {returnres.status(400).json({ message:'Incorrect amount or currency given' }); }// All checks passed, mint the asset with the transaction ID obtained from serivce providerconstmintResponse=awaittoolsLib.wallet.mintAssetByKitId(storedDepositData.user_id,// User kit idstoredDepositData.currency,// currencystoredDepositData.amount,// amount { description:'Bank Deposit',// description transactionId: transaction_id // transaction id } );returnres.json(mintResponse);});