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

Feature/make payment #197

Merged
merged 15 commits into from
Feb 15, 2024
Merged
27 changes: 13 additions & 14 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,19 @@ name: Build

on:
push:
branches: ['main']
branches: ['main']
pull_request:
branches: ['*']

branches: ['*']

jobs:
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: sonarsource/sonarqube-scan-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
build:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: sonarsource/sonarqube-scan-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ jobs:
VITE_HORIZON_NETWORK_PASSPHRASE: Test SDF Network ; September 2015
VITE_STELLAR_NETWORK: ${{ secrets.VITE_STELLAR_NETWORK }}
CYPRESS_SIMPLE_SIGNER_PRIVATE_KEY: ${{ secrets.SIMPLE_SIGNER_PRIVATE_KEY }}
VITE_HORIZON_URL: ${{ secrets.VITE_HORIZON_URL }}
test:
runs-on: ubuntu-latest
needs: install-cache
Expand Down
114 changes: 113 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ you want to contribute.

# How to implement Simple Signer on your website

Simple Signer provides two endpoints, `/connect` and `/sign` which allow some customisations to be made.
Simple Signer provides three endpoints, `/connect`, `/sign` and `/payment` which allow some customisations to be made.
ivanbelasich marked this conversation as resolved.
Show resolved Hide resolved

To see an example of all the implementation properties please take a look at the [test.html](./test.html) file provided
in this repo.
Expand Down Expand Up @@ -329,6 +329,118 @@ Sometimes it's useful to group operations together to explain what they are doin

---

## Making a payment

To make a payment using Simple Signer, you need to provide the necessary parameters either through the URL or using the `postMessage` method. Follow the steps below to integrate the payment functionality into your web application:

### Step 1: Specify Payment Parameters

You can pass the payment parameters such as the receiver's account, amount, asset type, and issuer through the URL or `postMessage` method. Here's an example of how you can do it:

```html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Simple Signer - Make Payment Demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script
src="https://cdnjs.cloudflare.com/ajax/libs/stellar-sdk/10.1.0/stellar-sdk.min.js"
integrity="sha512-EqNQsxKR6rZ5xKl29xXa+ez7xgtVSUpj9UDzZmTqoyF0wHbusLkrP8S7dOsKa9DmkoHbssoWUA4+n/0KYY1EAQ=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
></script>
</head>
<body>
<h1>Make Payment</h1>
<p>
This page demonstrates the process of making a payment using the
Simple Signer.
</p>
<h2>Usage</h2>
<p>Click the "Make Payment" button to initiate the payment process.</p>
<button onclick="makePayment()">Make Payment</button>

<script>
async function makePayment() {
// Define payment parameters
const receiver = 'Receiver public key';
const amount = '10';
const assetCode = 'native'; // 'native' for XLM, or asset code for other assets
const issuer = ''; // If assetCode is not 'native', provide issuer's public key

// Open payment window with payment parameters
const paymentWindow = window.open(
`${simpleSignerUrl}/payment/?receiver=${receiver}&amount=${amount}&assetCode=${assetCode}&issuer=${issuer}`,
'Payment_Window',
'width=360, height=700',
);

// Listen for payment completion message
window.addEventListener('message', async (event) => {
if (event.origin !== simpleSignerUrl) return;

const { type, message } = event.data;
if (type === 'onPayment') {
// Handle payment completion
console.log('Payment completed successfully:', message);
}
});
}
</script>
</body>
</html>
```

You may choose to pass the payment parameters to Simple Signer either via URL or via postMessage.

Via URL:

```javascript
const receiver = 'Receiver public key';
const amount = '10';
const assetCode = 'native'; // 'native' for XLM, or asset code for other assets
const issuer = ''; // If assetCode is not 'native', provide issuer's public key

const paymentWindow = window.open(
`https://sign.scalemote.io/payment/?receiver=${receiver}&amount=${amount}&assetCode=${assetCode}&issuer=${issuer}`,
'Payment_Window',
'width=360, height=700',
);
```

Via PostMessage:

Post Message has some advantages over the URL method which are covered in the Payment API section.

```javascript
const receiver = 'Receiver public key';
const amount = '10';
const assetCode = 'native'; // 'native' for XLM, or asset code for other assets
const issuer = ''; // If assetCode is not 'native', provide issuer's public key

const simpleSignerUrl = 'https://sign.scalemote.io';
const paymentWindow = window.open(
`${simpleSignerUrl}/payment`,
'Payment_Window',
'width=360, height=700',
);

window.addEventListener('message', (e) => {
if (
e.origin !== simpleSignerUrl &&
e.data.type === 'onReady' &&
e.data.page === 'payment'
) {
paymentWindow.postMessage(
{ receiver, amount, assetCode, issuer },
simpleSignerUrl,
);
}
});
```

## Language selection

By default, Simple Signer will detect the browser's language and serve Simple Signer using this configuration. If the
Expand Down
6 changes: 6 additions & 0 deletions cypress/fixtures/payment.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"destinationAccount": "GCECUYXE32PPYKPVYOSILACOCUGMEZSDO7GYERC2GKAG2HM34BLMMOMB",
"amountToSend": 100,
"assetCode": "native",
"issuer": "none"
}
14 changes: 14 additions & 0 deletions cypress/integration/ui/events_spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/// <reference types="cypress" />
/// <reference types="@testing-library/cypress"/>
import { operationsXdr } from '../../fixtures/operations.json';
import { amountToSend, assetCode, destinationAccount, issuer } from '../../fixtures/payment.json';

const operationGroupTitle = 'Payment';
const operationGroupDescription = 'This is a merge account operation';
Expand Down Expand Up @@ -37,4 +38,17 @@ describe('Events', () => {
cy.get('.tx-operation-container').should('have.length', 2);
cy.get('.tx-description-container').contains(operationDescription);
});

it('should render a payment operation', () => {
cy.visit('/payment');
cy.window().then((win) => {
win.postMessage({
receiver: destinationAccount,
issuer,
amount: amountToSend,
assetCode,
});
});
cy.get('.receiver').should('have.length', 1);
});
});
9 changes: 9 additions & 0 deletions cypress/integration/ui/logout_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,13 @@ describe('logout', () => {
cy.get('.logout-active').contains('Logout').click();
cy.url().should('include', '/connect');
});

it('Should logout on /payment', () => {
cy.visit('/payment');
window.localStorage.setItem('wallet', 'xbull');
cy.wait(5000);
cy.get('.logout-button').click();
cy.get('.logout-active').contains('Logout').click();
cy.url().should('include', '/connect');
});
});
29 changes: 29 additions & 0 deletions cypress/integration/ui/payment_spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/// <reference types="cypress" />
/// <reference types="@testing-library/cypress"/>
import { amountToSend, assetCode, destinationAccount, issuer } from '../../fixtures/payment.json';

describe('checks that the /payment component works', () => {
const BASE_URL = '/payment';

it('should visit /payment with payment information but user is not connected', () => {
cy.visit(
`${BASE_URL}?receiver=${destinationAccount}&amount=${amountToSend}&assetCode=${assetCode}&issuer=${issuer}`,
);
cy.get('.user-not-connected').contains('User is not connected');
cy.get('.payment-btn').click();
cy.url().should('include', '/connect');
});

it('should render payment information if payment parameters are valid', () => {
window.localStorage.setItem('wallet', 'xbull');
cy.visit(
`${BASE_URL}?receiver=${destinationAccount}&amount=${amountToSend}&assetCode=${assetCode}&issuer=${issuer}`,
);
cy.get('.simple-signer').contains(`You are paying ${amountToSend} XLM to the account ${destinationAccount}.`);
});

it('should render an error if payment parameters was not provided', () => {
cy.visit(`${BASE_URL}?receiver=${destinationAccount}`);
cy.get('.simple-signer').contains("Sorry, the recipient's data wasn't provided.");
});
});
Loading
Loading