Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
aurelienshz committed Jun 25, 2021
0 parents commit 3e64b8b
Show file tree
Hide file tree
Showing 5 changed files with 422 additions and 0 deletions.
72 changes: 72 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Javascript SDK

The JS SDK is the frontend SDK, designed to be used in your HTML pages or Single-Page Apps, served in the Pi Browser.

In order to enable the SDK to function correctly, you need to declare your apps on the Developer Portal (open
develop.pi in the Pi Browser to access the Developer Portal).

This SDK is **not** for a server-side NodeJS app.


## Installation

Add the following `script` tag to all pages where you need the SDK to be available:

```html
<script src="https://sdk.minepi.com/pi-sdk.js"></script>
```

This will load the Pi Network JS SDK as a global `window.Pi` object.

## Usage

### Authenticate a user

You cannot perform any user-related operations (e.g read the user's info, request a payment from them) until you
have successfully authenticated the user. The first time, they will be presented with a dialog asking for
their consent to share their data with your app.

```javascript
// Identify the user with their username / unique network-wide ID, and get permission to request payments from them.
const scopes = ['username', 'payments'];
function onOpenPaymentFound(payment) { /* ... */ }; // Read more about this in the SDK reference

Pi.authenticate(scopes, onOpenPaymentFound).then(function(auth) {
console.log(`Hello ${auth.user.username}. Your unique ID is ${auth.user.pi_id}`);
}).catch(function(error) {
console.error(error);
});
```

### Request a payment

The `createPayment` method enables you to request a payment from the current user to your app's account.

The user will be prompted with a modal provided by the Pi Wallet, enabling them to sign the
transaction and submit it to the Pi blockchain.

```javascript

const payment = Pi.createPayment({
amount: 3.14, // Amount of π to be paid
reason: "Please pay for your order #1234", // User-facing explanation of the payment
metadata: { orderId: 1234, itemIds: [11, 42, 314] }, // Developer-facing metadata
}, { // Read more about those callbacks in the details docs linked below.
onPaymentIdReceived: onPaymentIdReceived,
onTransactionSubmitted: onTransactionSubmitted,
onPaymentCancelled: onPaymentCancelled,
onPaymentError: onPaymentError,
});

```

This code block is a **simplified example** to give you a sense of how it works.

In order to make sure that all involved parties (your app, your server, the Pi servers, and the Pi blockchain) are in sync,
the payment needs to go through a **Server-Side Approval** flow and a **Server-Side Completion** flow.

Please refer to:
* [the full Payments documentation](./payments.md) to learn about the complete payment flow
* [the Platform API documentation](./platform_API.md) to learn how to confirm the payment and acknowledge it from your
server
* the Demo App (coming soon!) to view an example of how you can implement the various required flows in your app's code.
162 changes: 162 additions & 0 deletions SDK_reference.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# Client SDK reference:

## Authentication

```typescript
Pi.authenticate(scopes: Array<string>, onIncompletePaymentFound: Function<PaymentDTO>): Promise<PiAuth>
```

Return value:

```typescript
type AuthResult {
accessToken: string,
user: {
uid: string,
pi_id: string,
username: string
}
}
```

### `scopes`

> **Not yet implemented**
>
> Currently, all calls to the `authenticate` method will assume all scopes have been requested.
Here is a breakdown of various keys available on the `PiAuth['user']` object, and the scopes required for those keys
to be present:

| Field | Description | Required Scope |
| -------------: | ------------- | :-------------: |
| `uid` | An app-local identifier for the user. This is specific to this user, and this app. It will change if the user revokes the permissions they granted to your app. | (none) |
| `username` | The user's Pi username. | `username` |
| `pi_id` | A network-wide identifier for this user. This will stay the same across all apps used by this user. | `username` |


### `onIncompletePaymentFound`

Signature: `(payment: PaymentDTO) => void`

Every time the user is authenticated, and when they try to start a new payment flow, the SDK checks that there is no incomplete payment for this user. An incomplete payment, in this context, is a payment which has been submitted to the Pi blockchain, but where `status.developer_completed` is still `false` (i.e. the developer has not called the `/complete` endpoint on this payment).

If an incomplete payment is found, this callback will be invoked with the payment's `PaymentDTO`.

When this callback is invoked, it is your responsibility to complete the corresponding payment (you should most likely send the payment DTO to your server, and process it according to your business logic). You'll need to do so before you can request a new payment from the user.


## Payments

Create a new payment:

```typescript
type PaymentData = {
amount: number,
reason: string,
metadata: Object,
};

type PaymentCallbacks = {
onPaymentIdReceived: (paymentId: string) => void,
onTransactionSubmitted: (paymentId: string, txid: string) => void,
onPaymentCancelled: (paymentId: string) => void,
onPaymentError: (error: Error, payment?: PaymentDTO) => void,
};

Pi.createPayment(paymentData: PaymentData, callbacks: PaymentCallbacks): void;
```

The `createPayment` method takes two argument: `paymentData` and `callbacks`.

It will immediately start the payment flow, which will open on top of your app, enabling the user to review
the payment and submit the blockchain transaction, or reject it.

> **Warning: concurrent payments:**
>
> When creating a new payment, if there is already an open payment with your app for the current user:
> * If the user has not yet made the blockchain transaction, the open payment will be cancelled.
> * If the user has already made the blockchain transaction, the new payment will be rejected
> (`onPaymentError` will be called) and the `onOpenPaymentFound` method will be called with the
> existing payment (use this callback to resolve the situation, e.g by completing the previous
> payment from your backend).


## `paymentData` keys:

### `amount`

This is the amount that the user is requested to pay to your app.

Example: `3.1415`.

### `reason`

The reason for this payment. This will be visible to the user.

Example: `Please pay for order #1234`.

### `metadata`

An arbitrary object that you can attach to this payment. This is for your own use, and it won't
be shown to the user. You should use this object as a way to link this payment with your internal
business logic.

Example: `{ orderId: 1234, itemIds: [11, 42, 314] }`

## `callbacks` keys:

### `onPaymentIdReceived`

Signature: `(paymentId: string) => void`

This is called when the payment identifier (paymentId) is obtained from Pi Servers.

Use this callback to send the paymentId to your backend for **Server-Side Approval**.
Read more about Server-Side Approval and the full payment flow in the dedicated
[Payments](payments.md) page.

### `onTransactionSubmitted`

Signature: `(paymentId: string, txid: string) => void`

This is called when the user has submitted the transaction to the Pi blockchain.

Use this callback to send the blockchain transaction identifier (txid), along with the paymentId
to your backend for **Server-Side Completion**.
Read more about Server-Side Completion and the full payment flow in the dedicated
[Payments](payments.md) page.

### `onPaymentCancelled`

Signature: `(paymentId: string) => void`

This is called when the payment is cancelled (by a user action, or programmatically).

The payment may be cancelled either because the user manually rejected it, or because
of some other blocking situation: the user doesn't have enough funds on their account
to make the payment, another payment has been created concurrently...

### `onPaymentError`

Signature: `(error: Error, payment?: PaymentDTO) => void`

This is called when an error occurs and the payment cannot be made. If the payment has been
created, the second argument will be present and you may use it to investigate the error.
Otherwise, only the first argument will be provided.


## Share dialog

Open a native share dialog:

```typescript
Pi.openShareDialog(title: string, message: string): void;
```

Use this method to open a native Share dialog (provided by the phone's OS), enabling your users to share
content from your app with their friends.

* `title`: the title of the message being shared
* `message`: the message that will be sent when the user picks a target app in the Share flow
Binary file added img/payment_flow.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
66 changes: 66 additions & 0 deletions payments.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Payments

Payments are wrappers around blockchain transactions, which enable your app,
the Pi blockchain, and the Pi Servers to be all synchronized when the user
submits a blockchain transaction to pay for something in your app.

They enable you, the developer of the app, to have full confidence that the
user has actually made the transaction, while not having to
bother with the technicalities involved when interacting with the Pi blockchain.


## The Payment flow

After they're created, payments go through 3 major phases:

1. Payment creation and Server-Side Approval
2. User interaction and blockchain transaction
3. Server-Side Completion


![Payment flow](./img/payment_flow.jpg)

**Phase I - Payment creation and Server-Side Approval**

1. `createPayment`: Your app's frontend creates the payment. The Payment Flow UI opens, but cannot be interacted with until the payment is approved by your server.

2. `onPaymentIdReceived`: The JS SDK has obtained the payment identifier (PaymentID) and is passing it to your app for Server-Side approval.

3. Your app's frontend sends the PaymentID to your app's server. This implementation is your responsibility.

4. Server-Side Approval: Your app's server approves the payment with Pi Servers through the `/approve` API call. This enables the user to submit the blockchain transaction.

**Phase II - User interaction and blockchain transaction**

At this stage, the payment dialog becomes interactive and enables the
user to confirm the transaction, sign it, and submit it to the Pi blockchain.

You do not have anything to do at this stage, everything is handled by the Pi
Apps Platform and the Pi Wallet.

After the blockchain transaction is submitted, the payment flow will not close.
You need to acknowledge the payment through Server-Side completion before your
app is visible again.


**Phase III - Server-Side Completion**

5. `onTransactionSubmitted`: The JS SDK passes the blockchain transaction identifier (TxID) to your app's frontend. You need this value for the Server-Side Completion flow.

6. Your app's frontend sends the TxID to your app's server. This implementation is your responsibility.

7. Server-Side Completion: Your app's server acknowledges the payment with Pi Servers through the `/complete` API call. This enables you to check whether the blockchain transaction has actually happened, and to let Pi know that
you're aware of it.

8. The payment flow closes. Your app is now visible to the user again.
Your app's server and your app's frontend can exchange data, and
update the app interface to show a confirmation screen to the user.
This implementation is your responsibility.


> **The user might be lying to your app!**
>
> Users might be running a hacked version of the SDK, pretending that they
> have made a payment. If the API call for Server-Side completion
> returns a non-200 error code, **do not** mark the payment as complete on your
> side, and **do not** deliver whatever the user was trying to buy.
Loading

0 comments on commit 3e64b8b

Please sign in to comment.