Deploy a Production Version on Mainnet
Once the test server is live and you have tested the payment flow with a SA, it's time to deploy a productionized version of the test server on mainnet.
The RA server code deployed to each environment should be the same, and additional functionality offered in production should be enabled via environment variables. This is called code parity, which significantly reduces operational and deployment complexity. It also allows RAs to use the Testnet service as a staging environment for debugging or new features and allows the SAs to test their client code before integrating with the RA's mainnet service.
Deploying a Secure Environment
Make sure to keep the test server up, and deploy the production (mainnet) system in a separate environment. Having two deployments allows you to validate new features on the testnet before deploying to production.
To switch to Stellar's public (mainnet) network, all you have to do is change the network passphrase (for authenticating requests) and the Horizon URL. Stellar SDKs have all the built-in logic to switch from test to public with minor changes to the codebase.
If you're issuing your own asset in addition of offering an on/off ramp, make sure you follow best practices for asset issuance by creating a distribution account that is separate from the issuing account before distributing real assets on the public network. The issuing account secret key should be highly secured via means such as cold storage or multi-signature, and should only be used to send (and, consequently, issue) assets to the distribution account. The distribution account will be used by the RA server to receive assets from other accounts programmatically.
Since the distribution account will be managed programmatically, it should only have a balance necessary to keep operations running for a short period of time. The issuing account should send small amounts of an asset to the distribution account frequently to represent the expected deposit volume for a given period. You should set up the transfer from the issuing account to the distribution account once day (or once a week week) to make sure the distribution account only has the minimum necessary balance to keep the operation functional in that short period.
Validating Real KYC
Most anchors need to collect Know Your Customer information to comply with local regulations before honoring payments. In SEP-31, the SA controls the UX for the SU. Typically, the SA will offer an online or in-app UX, but physical remittance locations are also acceptable. Its also important for SAs to be able to contact SUs when information must be updated or when the transaction succeeded.
How the RA complies with their local regulations by validating KYC information is up the RA: there are many services that provide KYC solutions through APIs that validate the input data against governmental databases to verify requirements. Each jurisdiction has specific KYC requirements, and they differ from jurisdiction to jurisdiction, so it's best to find a country-specific KYC provider that meets your needs. Many RA organizations can validate the KYC data collected without using a third-party service.
Some countries require different KYC fields depending on the payment amount. If that's the case in an RA's jurisdiction, the RA needs to expect and support different KYC
type values in
GET /customer requests. Only one
type value can be specified in the
/info response per-customer, so a different large-payment
type value will have to be documented and communicated to the RA's partner SAs outside the SEP.
KYC information should be linked to the
id returned by the
PUT /customer calls, so you only need to ask the SU for it once as long as the data provided is valid.
Note: The SDF encourages anchors to have the same KYC collection process on the Testnet server and Mainnet server. However, validation of KYC data on Testnet is unnecessary and prevents third parties from testing your service. KYC validation should only be supported on Mainnet unless the field uses a well-known format like email addresses.
Connecting to Real Banking Rails
Fiat-backed token anchors are expected to manage a full reserve. That means there's a 1:1 relationship between Stellar-network tokens and money in the bank. Since each fiat token on Stellar is backed by, and can be redeemed for, an underlying, real-world asset, anchors of fiat-backed tokens need to connect to real banking rails to make payments to receiving users (generally through bank transfers). This applies to both issuing and non-issuing anchors.
Once Stellar payment transactions have been detected and matched to an internal transaction record using the memo of the payment, RAs must attempt the off-chain payment (typically using a bank transfer).
Make sure to do a full security audit on your systems when banking rails connections are in place. Some banks provide a testing API that can be used for development and deployment to testnet or staging environments, which means you can test and audit the codebase before moving to a final production-ready bank integration.
Once your application is fully functional, it's a good idea to test different scenarios and edge cases to make sure the system is behaving as expected.
The SDF offers an anchor validation test suite and UI for testnet and mainnet testing. SEP-24 and SEP-31 are supported, containing a growing list of tests to assess your service's compliance with the protocol. While the coverage is good, the SDF does not claim that it is complete.
Below are some tests that the suite does not and will not cover.
- Check that the issuing account is set up with the correct home domain, and that the website on that home domain has branding visuals, content about your company, clear language telling users how to report problems, and a method for contacting you to seek support.
- Ensure distribution is done through a dedicated distribution account (not the issuing account)
- Ensure market making is done through a dedicated account (not the issuing account)
- Make sure all authenticated endpoints are not accessible without the JWT token