Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build a basic payment app #185

Merged
merged 52 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
a5eb2d9
add new app example tutorial
briwylde08 Jul 17, 2023
e7238fa
fix links
briwylde08 Jul 17, 2023
4e7a8ef
fix link
briwylde08 Jul 17, 2023
a40a71c
testing image
briwylde08 Jul 18, 2023
ba58438
testing image 2
briwylde08 Jul 18, 2023
cf22fed
testing image 3
briwylde08 Jul 18, 2023
9cd9725
add image
briwylde08 Jul 20, 2023
7792448
screenshots that actually work!
briwylde08 Jul 20, 2023
a132303
Adding some install steps to app tutorial, and adding a page to
ElliotFriend Jul 24, 2023
215a3a1
markdown formatting
ElliotFriend Jul 24, 2023
1a188fa
More progress on tutorial application steps
ElliotFriend Jul 24, 2023
f857773
Update confirmation-modal.mdx
briwylde08 Jul 31, 2023
8e87505
update copy
briwylde08 Jul 31, 2023
339e5e0
update user experience copy
briwylde08 Jul 31, 2023
681fdae
add screenshots
briwylde08 Jul 31, 2023
adf7d2b
update payment page
briwylde08 Aug 4, 2023
4264c20
update manage trust page
briwylde08 Aug 4, 2023
53f8d89
update path payment page
briwylde08 Aug 4, 2023
28ce356
Code implementation for manage trust, and some other minor changes
ElliotFriend Aug 8, 2023
03f7fae
Adding payment and path payment examples
ElliotFriend Aug 8, 2023
f6e941a
querying data page
ElliotFriend Aug 8, 2023
f30125e
Adding sources to each code sample, using `title` instead of `file`
ElliotFriend Aug 14, 2023
03b7b3d
Start on the anchor integration steps from the technical side
ElliotFriend Aug 14, 2023
9c6e107
Merge branch 'main' of github.com:stellar/stellar-docs into build-a-b…
ElliotFriend Aug 14, 2023
cff066b
linting an error or two in a disbursement platform file?
ElliotFriend Aug 14, 2023
4296c14
Fixing a broken link
ElliotFriend Aug 14, 2023
76dd534
overview updates
briwylde08 Aug 15, 2023
80b0e7d
update account creation
briwylde08 Aug 15, 2023
adabfd6
update confirmation modal
briwylde08 Aug 15, 2023
df0f9a7
Merge branch 'build-a-basic-payment-app' of https://github.com/stella…
briwylde08 Aug 15, 2023
d166bbd
update contacts list
briwylde08 Aug 15, 2023
0dd20a8
update manage trust
briwylde08 Aug 15, 2023
abe0da2
update payment section
briwylde08 Aug 15, 2023
79f6944
udpate path payments
briwylde08 Aug 15, 2023
6bdc23a
SEP-6 portion looking pretty good?
ElliotFriend Aug 15, 2023
50a4f90
update anchor integration
briwylde08 Aug 15, 2023
808295d
Create _category_.json
briwylde08 Aug 15, 2023
bcb045b
Merge branch 'build-a-basic-payment-app' of https://github.com/stella…
briwylde08 Aug 15, 2023
2c13824
update querying data
briwylde08 Aug 15, 2023
07946cd
update SEP6
briwylde08 Aug 15, 2023
1692c15
add screenshots to sep6 and sep10
briwylde08 Aug 16, 2023
f7b906e
clearing up some wording with home domain asset types
ElliotFriend Aug 18, 2023
4975fca
Clarifying the description of the Stellar Expert query we make
ElliotFriend Aug 18, 2023
be390b0
More consistent use of source links, and removing HTML from samples
ElliotFriend Aug 18, 2023
99b1960
editorial
briwylde08 Aug 18, 2023
52fafe3
SEP-24 instructions and technical walkthrough
ElliotFriend Aug 18, 2023
6f65096
Merge branch 'build-a-basic-payment-app' of github.com:stellar/stella…
ElliotFriend Aug 18, 2023
ea945c6
Adding some more detail to SEP-6 page
ElliotFriend Aug 18, 2023
64a71e7
sep24 tweaks
briwylde08 Aug 18, 2023
63bbff4
Removing the svelte prism highlighter
ElliotFriend Aug 18, 2023
7bb8cd9
Merge branch 'build-a-basic-payment-app' of github.com:stellar/stella…
ElliotFriend Aug 18, 2023
9cfcabe
Merge branch 'main' of github.com:stellar/stellar-docs into build-a-b…
ElliotFriend Aug 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/anchoring-assets/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Stellar has anchor services operating worldwide. View the [Anchor Directory](htt

Anchors can issue their own assets on the Stellar network, or they can honor assets that already exist. To learn about issuing assets, check out the [Issue Assets section](https://developers.stellar.org/docs/category/issue-assets).

This documentation will instruct you on how to become an anchor. To understand how to integrate anchor services into your blockchain-based application, check out the [Build Apps section](/docs/category/deposit-and-withdraw-from-anchors) and [Connect to Anchors section][/docs/category]. If you’re looking specifically for MoneyGram Access, see the [Integrate with MoneyGram Access tutorial](https://developers.stellar.org/docs/tutorials/moneygram-access-integration-guide).
This documentation will instruct you on how to become an anchor. To understand how to integrate anchor services into your blockchain-based application, check out the [Build Apps section](/docs/building-apps/example-application-tutorial/anchor-integration/setup) and [Connect to Anchors section][/docs/category]. If you’re looking specifically for MoneyGram Access, see the [Integrate with MoneyGram Access tutorial](https://developers.stellar.org/docs/tutorials/moneygram-access-integration-guide).

## Stellar Ecosystem Proposals (SEPs) and interoperability

Expand Down
12 changes: 6 additions & 6 deletions docs/building-apps/example-application-tutorial/_category_.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"position": 55,
"label": "Example Application Tutorial",
"link": {
"type": "generated-index"
}
}
"position": 55,
"label": "Example Application Tutorial",
"link": {
"type": "generated-index"
}
}
195 changes: 195 additions & 0 deletions docs/building-apps/example-application-tutorial/account-creation.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
---
title: Account Creation
sidebar_position: 20
---

Accounts are the central data structure in Stellar and can only exist with a valid keypair (a public and secret key) and the required minimum balance of XLM. Read more in the [Accounts section].

## User experience

To start, we'll have our user create an account. In BasicPay, the signup page will display a randomized public and secret keypair that the user can select with the option to choose a new set if preferred.

:::info

Since we are building a [non-custodial application], the encrypted secret key will only ever live in the browser. It will never be shared with a server or anybody else.

:::

![public and private keys](/assets/public-and-private-keys.png)

Next, we'll trigger the user to submit a pincode to encrypt their secret key before it gets saved to their browser's `localStorage` (this is handled by the [`js-stellar-wallets` SDK]). The user will need to remember their pincode for future logins and to submit transactions.

With BasicPay, when the user clicks the “Signup” button, they will be asked to confirm their pincode. When they do, the `create_account` operation is triggered, and the user's account is automatically funded with XLM for the minimum balance (starting with 10,000 XLM).

![funded account](/assets/funded-account.png)

When you're ready to move the application to Pubnet, accounts will need to be funded with real XLM. This is something the application can cover itself by depositing XLM into the user's account, with the use of [sponsored reserves], or the user can cover the required balance with their own XLM.

## Code implementation

We will create a Svelte `store` to interact with our user's randomly generated keypair. The store will take advantage of some of the `js-stellar-wallets` SDK to encrypt/decrypt the keypair, as well as sign transactions.

### Creating the `walletStore` store

Our `walletStore` will make a few things possible throughout our application.

1. We can "register" a keypair, which encrypts the keypair, stores it in the browser's storage, and keeps track of that keypair's `keyId`.
2. We can "sign" transactions by providing the pincode to decrypt the keypair.
3. We can "confirm" the pincode is valid for the stored keypair (or that it matches for signups).

```js title="/src/lib/stores/walletStore.js"
import { persisted } from "svelte-local-storage-store";
import { KeyManager, KeyManagerPlugins, KeyType } from "@stellar/wallet-sdk";
import { TransactionBuilder } from "stellar-sdk";
import { error } from "@sveltejs/kit";
import { get } from "svelte/store";

// We are wrapping this store in its own function which will allow us to write
// and customize our own store functions to maintain consistent behavior
// wherever the actions need to take place.
function createWalletStore() {
// Make a `persisted` store that will determine which `keyId` the
// `keyManager` should load, when the time comes.
const { subscribe, set } = persisted("bpa:walletStore", {
keyId: "",
publicKey: "",
});

return {
subscribe,

// Registers a user by storing their encrypted keypair in the browser's
// `localStorage`.
register: async ({ publicKey, secretKey, pincode }) => {
try {
// Get our `KeyManager` to interact with stored keypairs
const keyManager = setupKeyManager();

// Use the `keyManager` to store the key in the browser's local
// storage
let keyMetadata = await keyManager.storeKey({
key: {
type: KeyType.plaintextKey,
publicKey: publicKey,
privateKey: secretKey,
},
password: pincode,
encrypterName: KeyManagerPlugins.ScryptEncrypter.name,
});

// Set the `walletStore` fields for the `keyId` and `publicKey`
set({
keyId: keyMetadata.id,
publicKey: publicKey,
// Don't include this in a real-life production application.
// It's just here to make the secret key accessible in case
// we need to do some manual transactions or something.
devInfo: {
secretKey: secretKey,
},
});
} catch (err) {
console.error("Error saving key", err);
throw error(400, { message: err.toString() });
}
},

// Compares a submitted pincode to make sure it is valid for the stored, encrypted keypair.
confirmCorrectPincode: async ({
pincode,
firstPincode = "",
signup = false,
}) => {
// If we are not signing up, make sure the submitted pincode successfully
// decrypts and loads the stored keypair.
if (!signup) {
try {
const keyManager = setupKeyManager();
let { keyId } = get(walletStore);
await keyManager.loadKey(keyId, pincode);
} catch (err) {
throw error(400, { message: "invalid pincode" });
}
// If we are signing up for the first time (thus, there is no stored
// keypair), just make sure the first and second pincodes match.
} else {
if (pincode !== firstPincode) {
throw error(400, { message: "pincode mismatch" });
}
}
},

// Sign and return a Stellar transaction
sign: async ({ transactionXDR, network, pincode }) => {
try {
// Get our `keyManager` to interact with stored keypairs
const keyManager = setupKeyManager();

// Use the `keyManager` to sign the transaction with the
// encrypted keypair
let signedTransaction = await keyManager.signTransaction({
transaction: TransactionBuilder.fromXDR(transactionXDR, network),
id: get(walletStore).keyId,
password: pincode,
});
return signedTransaction;
} catch (err) {
console.error("Error signing transaction", err);
throw error(400, { message: err.toString() });
}
},
};
}

// We export `walletStore` as the variable that can be used to interact with the wallet store.
export const walletStore = createWalletStore();

// Configure a `KeyManager` for use with stored keypairs.
const setupKeyManager = () => {
// We make a new `KeyStore`
const localKeyStore = new KeyManagerPlugins.LocalStorageKeyStore();

// Configure it to use `localStorage` and specify a(n optional) prefix
localKeyStore.configure({
prefix: "bpa",
storage: localStorage,
});

// Make a new `KeyManager`, that uses the previously configured `KeyStore`
const keyManager = new KeyManager({
keyStore: localKeyStore,
});

// Configure the `KeyManager` to use the `scrypt` encrypter
keyManager.registerEncrypter(KeyManagerPlugins.ScryptEncrypter);

// Return the `KeyManager` for use in other functions
return keyManager;
};
```

**Source:** https://github.com/stellar/basic-payment-app/blob/main/src/lib/stores/walletStore.js

### Creating the account on the Stellar network

After we've registered the user, we need to fund the account on the Stellar network. As discussed previously, there are multiple ways to accomplish this task, but we are using Friendbot to ensure the user has some Testnet XLM to experiment with.

```js title="/src/lib/stellar/horizonQueries.js"
// Fund an account using the Friendbot utility on the Testnet.
export async function fundWithFriendbot(publicKey) {
console.log(`i am requesting a friendbot funding for ${publicKey}`);
await server.friendbot(publicKey).call();
}
```

Source: https://github.com/stellar/basic-payment-app/blob/main/src/lib/stellar/horizonQueries.js

### Using the `walletStore` store

Our `walletStore` is used in a ton of places in our application, especially in the confirmation modal when asking a user to input their pincode. Read on to see how we've done that.

[accounts section]: ../../fundamentals-and-concepts/stellar-data-structures/accounts
[non-custodial application]: ../application-design-considerations#non-custodial-service
[`js-stellar-wallets` sdk]: https://github.com/stellar/js-stellar-wallets
[sponsored reserves]: ../../encyclopedia/sponsored-reserves
[contacts list]: ./contacts-list
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"position": 60,
"label": "Anchor Integration",
"link": {
"type": "generated-index"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
---
title: "SEP-1: Stellar TOML"
sidebar_position: 20
---

The [stellar.toml file](https://developers.stellar.org/docs/issuing-assets/publishing-asset-info#completing-your-stellartoml) is a common place where the Internet can find information about an organization’s Stellar integration. Regardless of which type of transfer we want to use (SEP-6 or SEP-24), we'll need to start with SEP-1.

For anchors, we’re interested in the `CURRENCIES` they issue, the `TRANSFER_SERVER` and/or `TRANSFER_SERVER_SEP0024` keywords that indicate if the anchor supports SEP-6, SEP-24, or both, and the `WEB_AUTH_ENDPOINT` which allows a wallet to set up an authenticated user session.

BasicPay is interoperating with the testing anchor located at `testanchor.stellar.org` and you can view its toml file [here](https://testanchor.stellar.org/.well-known/stellar.toml).

```js title=/src/lib/stellar/sep1.js
import { StellarTomlResolver } from "stellar-sdk";

// Fetches and returns the stellar.toml file hosted by a provided domain.
export async function fetchStellarToml(domain) {
let stellarToml = await StellarTomlResolver.resolve(domain);
return stellarToml;
}
```

**Source:** https://github.com/stellar/basic-payment-app/blob/main/src/lib/stellar/sep1.js

Strictly speaking, the `StellarTomlResolver` function from the JavaScript SDK is the only function we _need_ to retrieve and use the information provided by the anchor (heck, we could even just write our own `fetch`-based function, and bypass the SDK altogether). However, we've created quite a few "helper" functions to make the rest of our queries a bit more verbose and clear as to what we're looking for from the anchor server. Make sure to check out the `sep1.js` source file linked above!

Using the `stellar.toml` information for an asset with a `home_domain`, we can display to the user some options (depending on the available infrastructure). We'll start with SEP-10 authentication.
Loading