Skip to content

FXRates Guide

This fxrates guide assumes that you have already completed the TheM>Getting Started>Quick Start guide and are familiar with TheM class, TheM submodule initialization, and creating/listening for custom events. This guide also assumes that you have already installed the amplifi_mobile_sdk package into your project and placed the following minified libraries in the /lib folder of your project: axios.min.js (Optional - fetch will be used if axios is not present), crypto-js.min.js, lz-string.min.js, moment.min.js, and socket.io.min.js. In addition, you should have completed the Onboarding Guide tutorial in order to create and onboard a user which can be logged into your ampliFi instance.

The ampliFi service does not store conversion rates on the server, but instead retrieves fresh fx rates data from applicable back-offices each time it is necessary. Since fxrates availability is dependent on back-office results, this guide includes an event that can be used to provide mock fxrates data locally for testing purposes.

1. In the src folder of your project (from the Quick Start guide of the TheM Getting Started section), create a new file called fxrates.js with the following code.

fxrates.js

import ClassTheM from "../node_modules/@PayGearsCorp/amplifi_mobile_sdk/TheM/them.mjs";

import { thisDevice } from "./android-demo-device.js"; //android device emulator for testing

const AMPLIFI_BASE_URL = "PUT_YOUR_INSTANCE_URL_HERE"; //Speak to a support representative to be issued a sandbox instance URL
const AMPLIFI_CORE_URL = `${AMPLIFI_BASE_URL}core/`;
const DEVICE_TAG = "PUT_YOUR_DEVICE_TAG_HERE"; //Use deviceTag obtained from onboarding tutorial for this device
const amount = 100;

const subClassesToInit = [
    //"accounts",
    //"attachments",
    //"beneficiaries",
    //"cards",
    //"cheques",
    "common",
    //"companies",
    //"externalAccounts",
    //"fdrs",
    //"fundstransfer",
    "fxrates",
    //"genericRequests",
    //"ious",
    //"onboarding",
    //"payees",
    //"remittance",
    //"restrictions",
    //"statics",
    "user"
];


export const fxratesTutorial = async (subClasses = "") => {
    TheM = new ClassTheM({
        config: {
            AFiInstanceId: "test",
            modulesFolder: "",
            modulesFolderOnboarding: "",
            webworkerFolder: "../TheM/",
            baseLibURL: "../demo/lib/",
            backEndURL: AMPLIFI_CORE_URL,
            socketURL: AMPLIFI_BASE_URL,
        },
        libs: {
        }
    });

    //Emulate user device before initializing TheM submodules
    TheM.thisDevice = {
        ...thisDevice,
        TheM,
        deviceTag: DEVICE_TAG,
    };

    //Initialize desired submodules
    //Some modules depend on others so must be initialized together
    //For instance, most submodules require the "common" subclass to be initialized
    await TheM.doInit(subClasses);

    //fxrates workflow to try
    //Uncomment to run the whole workflow or follow the instructions in the browser
    /*
    //Prepare for logging in
    //Log in using the instructions in the browser or use the doAuthenticate method from the device emulator we created during onboarding
    await TheM.thisDevice.doAuthenticate(DEVICE_TAG);

    //Check if the fxrates submodule is ready and set if necessary
    if (!TheM.fxrates.isReady) {
        TheM.fxrates.isReady = true;
    };

    //Pull fresh fxrates data from the server if necessary
    await TheM.fxrates.doUpdate();

    if (TheM.fxrates.length < 1) {
        //If no fxrates data exists, create mock fxrates locally through an event
        TheM.newEvent("modelBank fxrates pushed", {
            payload: {
                fxrates: [{
                    "rateId": "backOfficeIdUSDEUR",
                    "src": "USD",
                    "dst": "EUR",
                    "rate": 1.0048325,
                    "buy": 1.103262,
                    "sell": 0.906403,
                    "isCommon": true,
                    "backOfficeId": "backOfficeId",
                    "backOfficeName": "backOfficeName"
                }, {
                    "rateId": "backOfficeIdUSDJPY",
                    "src": "USD",
                    "dst": "JPY",
                    "rate": 73.373357,
                    "buy": 0.006815,
                    "sell": 146.739899,
                    "isCommon": true,
                    "backOfficeId": "backOfficeId",
                    "backOfficeName": "backOfficeName"
                }, {
                    "rateId": "backOfficeIdUSDGBP",
                    "src": "USD",
                    "dst": "GBP",
                    "rate": 1.03165,
                    "buy": 1.285228,
                    "sell": 0.778072,
                    "isCommon": true,
                    "backOfficeId": "backOfficeId",
                    "backOfficeName": "backOfficeName"
                }]
            }
        });
    }

    //Base currency
    console.log(`TheM.fxrates.baseCurrency: ${JSON.stringify(TheM.fxrates.baseCurrency)}\n\n`);

    //Try a conversion from USD to EUR
    if (!TheM.fxrates.isKnownCurrency("USD") || !TheM.fxrates.isKnownCurrency("EUR")) {
        throw "Cannot convert from USD to EUR or vice versa (unknown currency).";
    }
    console.log(`How much USD is needed to buy ${amount} EUR?: ${TheM.fxrates.doConvertCurrency("USD", amount, "EUR", "backOfficeId")}\n\n`);

    //Try a cross currency conversion
    if (!TheM.fxrates.isKnownCurrency("GBP") || !TheM.fxrates.isKnownCurrency("JPY")) {
        throw "Cannot convert to/from GBP or JPY (unknown currency).";
    }
    //10 of JPY is being sent from EUR account in back-office1 to GBP account in back-office2
    console.log(`Get converstion rates to transfer ${amount} JPY from a EUR account to a GBP account.`);
    const crossCurrResult = TheM.fxrates.doConvertCurrencyCross("EUR", "backOfficeId", amount, "JPY", "GBP", "backOfficeId");
    console.log(`Debit this much EUR from source account: ${crossCurrResult.Debit}`);
    console.log(`Credit this much GBP to destination account: ${crossCurrResult.Credit}`);
    console.log(`Equivalent amount in USD: ${crossCurrResult.Settlement}`);
    console.log(`Equivalent amount in JPY: ${amount}`);

    //Logout when finished
    //await TheM.user.doLogout();
    */
};

await fxratesTutorial(subClassesToInit.join(" "));

2. The fxrates module expects the user to be using some type of device so make sure the android-demo-device.js file used during onboarding is still in your /src folder.

3. Create a new file in the /demo folder of your project called fxrates.html with the following code.

fxrates.html

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />

    <title>ampliFi</title>

    <script>
        var TheM;
        var TheM_config;
    </script>

    <script src="../lib/socket.io.min.js"></script>
    <script src="../lib/lz-string.min.js"></script>
    <script src="../lib/moment.min.js"></script>
    <script src="../lib/axios.min.js"></script>
    <script src="../lib/crypto-js.min.js"></script>
    <script type="module" src="/../src/fxrates.js"></script>

    <style>
        html {
            color: white;
            background-color: black;
        }
    </style>
</head>


<body>
    <div>
        Hit F12 to open the browser console.
        Start working with TheM by typing "TheM" into the browser console.
    </div>
    <br />
    <br />
    <div>
        1. In order to log a user in, we will need to prepare the user credentials using the encryptedServerSecret stored locally during onboarding the company. Type the following to retrieve the encryptedServerSecret. (Or skip steps 1-5 by using the doAuthenticate method in the device emulator like so, `await TheM.thisDevice.doAuthenticate(DEVICE_TAG);`.)
        <br /><br />
        <code>let { encryptedServerSecret } = await TheM.thisDevice.retrieveLocally("encryptedServerSecret", true);</code>
        <br /><br />
        Type <code>encryptedServerSecret</code> into the browser console and hit enter to view the encryptedServerSecret
        value.
        <br /><br />
        2. Since we are using an emulated android device to log in, we need to get the cryptotext value like so.
        <br /><br />
        <code>
            let _SUPER_SECRET = "0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000";<br />
            let _dtsValueString = (new Date()).valueOf().toString();<br />
            let serverSecret = CryptoJS.AES.decrypt(encryptedServerSecret, _SUPER_SECRET).toString(CryptoJS.enc.Utf8);<br />
            let cryptotext = CryptoJS.AES.encrypt((TheM.thisDevice.deviceTag) + _dtsValueString, serverSecret).toString(); 
        </code>
        <br /><br />
        3. Set a socket connection for bidirectional communication.
        <br /><br />
        <pre><code>TheM.thisDevice.halfRef = TheM.common.GetRandomSTR(40);<br />let manager = new TheM.io.Manager(TheM.config.socketURL + "?halfRef=" + TheM.thisDevice.halfRef, {<br />  autoConnect: false<br />});<br />let socket = manager.socket("/");</code></pre>
        <br />
        4. Open the socket connection.
        <br /><br />
        <pre><code>manager.connect(function (data) {<br />  console.log("established real-time comm channel for onboarding");<br />  TheM.thisDevice.isRealTimeCommAvailable = true;<br />});</code></pre>
        <br />
        5. Log the user in using the deviceTag obtained during onboarding and the newly created cryptotext.
        <br /><br />
        <pre><code>const credentials = {<br />  "dtsValueString": _dtsValueString,<br />  "deviceTag": "PUT_DEVICE_TAG_HERE",<br />  "deviceData": TheM.thisDevice.data,<br />  "channel": TheM.thisDevice.platform,<br />  "dynamicScreensVersion": TheM.thisDevice.dynamicScreensVersion,<br />  "socket": {<br />    halfRef: TheM.thisDevice.halfRef<br />  },<br />  "pushMessToken": TheM.thisDevice.pushMessToken,<br />  "cryptotext": cryptotext<br />};<br />await TheM.user.doLogin(credentials);</code></pre>
        <br />
        6. After authentication, check if the fxrates submodule is ready and set if necessary.
        <br /><br />
        <code>
            TheM.fxrates.isReady = true;
        </code>
        <br /><br />
        7. Pull fresh data from the server if necessary.
        <br /><br />
        <code>await TheM.fxrates.doUpdate();</code>
        <br /><br />
        8. If no fxrates data exists, create mock fxrates locally through an event (for testing only).
        <br /><br />
        <pre><code>if (TheM.fxrates.length < 1) {<br />  TheM.newEvent("modelBank fxrates pushed", {<br />    payload: {<br />      fxrates: [{<br />        "rateId": "backOfficeIdUSDEUR",<br />        "src": "USD",<br />        "dst": "EUR",<br />        "rate": 1.0048325,<br />        "buy": 1.103262,<br />        "sell": 0.906403,<br />        "isCommon": true,<br />        "backOfficeId": "backOfficeId",<br />        "backOfficeName": "backOfficeName"<br />      }, {<br />        "rateId": "backOfficeIdUSDJPY",<br />        "src": "USD",<br />        "dst": "JPY",<br />        "rate": 73.373357,<br />        "buy": 0.006815,<br />        "sell": 146.739899,<br />        "isCommon": true,<br />        "backOfficeId": "backOfficeId",<br />        "backOfficeName": "backOfficeName"<br />      }, {<br />        "rateId": "backOfficeIdUSDGBP",<br />        "src": "USD",<br />        "dst": "GBP",<br />        "rate": 1.03165,<br />        "buy": 1.285228,<br />        "sell": 0.778072,<br />        "isCommon": true,<br />        "backOfficeId": "backOfficeId",<br />        "backOfficeName": "backOfficeName"<br />      }]<br />    }<br />  });<br />}</code></pre>
        <br />
        9. Get the base currency.
        <br /><br />
        <code>TheM.fxrates.baseCurrency;</code>
        <br /><br />
        10. Try a conversion from USD to EUR.
        <br /><br />
        <pre><code>if (!TheM.fxrates.isKnownCurrency("USD") || !TheM.fxrates.isKnownCurrency("EUR")) {<br />  throw "Cannot convert from USD to EUR or vice versa (unknown currency).";<br />}<br />console.log(`How much USD is needed to buy ${amount} EUR?: ${TheM.fxrates.doConvertCurrency("USD", amount, "EUR", "backOfficeId2")}\n\n`);</code></pre>
        <br />
        11. Try a cross currency conversion.
        <br /><br />
        <pre><code>if (!TheM.fxrates.isKnownCurrency("GBP") || !TheM.fxrates.isKnownCurrency("JPY")) {<br />  throw "Cannot convert to/from GBP or JPY (unknown currency).";<br />}<br />//10 of JPY is being sent from EUR account in back-office1 to GBP account in back-office2<br />console.log(`Get converstion rates to transfer ${amount} JPY from a EUR account to a GBP account.`);<br />const crossCurrResult = TheM.fxrates.doConvertCurrencyCross("EUR", "backOfficeId", amount, "JPY", "GBP", "backOfficeId");<br />console.log(`Debit this much EUR from source account: ${crossCurrResult.Debit}`);<br />console.log(`Credit this much GBP to destination account: ${crossCurrResult.Credit}`);<br />console.log(`Equivalent amount in USD: ${crossCurrResult.Settlement}`);<br />console.log(`Equivalent amount in JPY: ${amount}`);</code></pre>
        <br />
        12. Keep exploring TheM.fxrates properties and methods and log out when finished.
        <br /><br />
        <code>
            await TheM.user.doLogout();
        </code>
        <br /><br />
    </div>
</body>

</html>

4. Start a server in the root folder of your project.

py -m http.server 8000

5. Open a browser and enter the following URL: http://localhost:8000/demo/

6. Click on the link for "fxrates.html" and follow the instructions to log in, test the fxrates submodule, and log out.