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

Specify and implement Solana Pay Transaction Requests #77

Merged
merged 122 commits into from
Apr 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
122 commits
Select commit Hold shift + click to select a range
96b06b3
transaction request spec
jordaaash Feb 10, 2022
9f90e46
refactoring and transaction request implementation
jordaaash Feb 11, 2022
03dfc19
fix tests
jordaaash Feb 11, 2022
1f9ed6f
update dependencies
jordaaash Feb 11, 2022
3d0b53c
update yarn.lock
jordaaash Feb 11, 2022
f372fc0
update example
jordaaash Feb 11, 2022
104a4a1
Merge branch 'master' into link-request
jordaaash Feb 11, 2022
8aa2418
Merge branch 'master' into link-request
jordaaash Feb 12, 2022
fd25ac6
Merge branch 'master' into link-request
jordaaash Feb 12, 2022
9973f5d
transaction request implementation and refactoring
jordaaash Feb 12, 2022
8aed025
fix examples and tests
jordaaash Feb 12, 2022
726ecbb
add tweetnacl to verify sigs
jordaaash Feb 12, 2022
1284292
update yarn.lock
jordaaash Feb 12, 2022
388cfd7
don't use template strings for legibility
jordaaash Feb 12, 2022
bf57397
pluralize
jordaaash Feb 13, 2022
c6ccf94
use URLSearchParams
jordaaash Feb 13, 2022
9a39e3b
fix error message
jordaaash Feb 13, 2022
2a1bba9
fix findReference recursion
jordaaash Feb 13, 2022
bb68c17
spec language
jordaaash Feb 13, 2022
0c4722c
refactoring
jordaaash Feb 13, 2022
4238a57
fix tests / example
jordaaash Feb 13, 2022
7fc15d6
.com
jordaaash Feb 13, 2022
5bd45a7
refactoring
jordaaash Feb 13, 2022
0b2ff1a
doc comment
jordaaash Feb 13, 2022
386c5f9
doc comments
jordaaash Feb 13, 2022
39bead3
Merge branch 'master' into link-request
jordaaash Feb 13, 2022
f67e402
Merge branch 'master' into link-request
jordaaash Feb 13, 2022
032f144
move client to src/client
jordaaash Feb 13, 2022
ef41ad2
client fixes for updated core sdk
jordaaash Feb 13, 2022
cd057fc
move to client dir
jordaaash Feb 13, 2022
557aadd
update ignores
jordaaash Feb 13, 2022
829b3c2
add server
jordaaash Feb 13, 2022
47db2ca
core API refactoring
jordaaash Feb 14, 2022
fac6b41
handle transaction requests
jordaaash Feb 14, 2022
ab9a914
vercel fixes
jordaaash Feb 14, 2022
eabb2b5
fix encodeURL and add tests
jordaaash Feb 14, 2022
5d78d64
recent blockhash fixes
jordaaash Feb 14, 2022
f1e50f7
remove empty readme
jordaaash Feb 14, 2022
f63af4c
enable wallet connect
jordaaash Feb 14, 2022
c3cc0a0
fix link url
jordaaash Feb 14, 2022
d4e11fc
convert server API to Next
jordaaash Feb 14, 2022
edfa6e7
Merge branch 'master' into link-request
jordaaash Feb 19, 2022
519b501
Begin moving frontend RootRoute providers into Next _app
Mar 1, 2022
b3f45c9
Add global CSS with postcss-nesting
Mar 1, 2022
48af03d
Move remaining frontend RootRoute providers into Next _app
Mar 1, 2022
f405463
Add /new route to Next app
Mar 2, 2022
e88b1c7
Add /pending route to Next app
Mar 2, 2022
9287a9e
Add /transactions route to Next app
Mar 2, 2022
122e398
Add /confirmed route to Next app
Mar 2, 2022
fa9f0ea
Hide html using visibility hidden until theme is loaded
Mar 2, 2022
2a33717
Delete /client dir, move /server to point-of-sale top-level
Mar 2, 2022
90e19bb
Remove unneeded withSvgr
Mar 2, 2022
d33478e
Add tsc-esm as dev dependency to core
Mar 2, 2022
0d76122
Fix next build errors caused by different eslintconfig in Next
Mar 2, 2022
bbee3f1
Update @solana/spl-token to 0.2.0 in core and point-of-sale
Mar 2, 2022
fee9626
Refactor to use host header instead of BASE_URL environment variable
Mar 3, 2022
ba22c4f
Remove unneeded top-level yarn.lock
Mar 3, 2022
06ddb54
Add empty getServerSideProps to /pending to make getInitialProps run …
Mar 7, 2022
c66f4a7
refactoring
jordaaash Mar 9, 2022
97e9ffd
Merge pull request #95 from mcintyre94/cm/link-request-nextjs
jordaaash Mar 9, 2022
058b1ba
restore images
jordaaash Mar 9, 2022
1e98091
move images
jordaaash Mar 9, 2022
1d31eb8
spec changes
jordaaash Mar 9, 2022
bb1b348
grammar fix
jordaaash Mar 9, 2022
3f029b7
more details
jordaaash Mar 9, 2022
6917887
rel fix
jordaaash Mar 9, 2022
fca9207
add examples
jordaaash Mar 9, 2022
da9a7ad
add message to example
jordaaash Mar 9, 2022
4021222
move message first in examples
jordaaash Mar 9, 2022
bbbc631
move text
jordaaash Mar 9, 2022
1294c59
remove label and messsage from example
jordaaash Mar 9, 2022
313b4e0
head -> get
jordaaash Mar 9, 2022
a86421e
title -> label
jordaaash Mar 9, 2022
0820c1a
icon changes
jordaaash Mar 10, 2022
48b7b98
Handle the GET request to /api route
Mar 12, 2022
1abbb46
Add optional message param + use for the message from POST API response
Mar 12, 2022
6554218
Export getServerSideProps from pages/
Mar 12, 2022
2cf3bea
Merge pull request #103 from mcintyre94/cm/next-api-get
jordaaash Mar 16, 2022
c305ff0
update icon filename
jordaaash Mar 17, 2022
0cb87cd
minor refactor
jordaaash Mar 17, 2022
4174897
serialize and deserialize before signing
jordaaash Mar 17, 2022
fec707a
remove unused env var
jordaaash Mar 24, 2022
c7a0a4f
add yarn clean cmd
jordaaash Mar 24, 2022
777e74f
add solflare adapter
jordaaash Mar 24, 2022
dfd4a21
run prettier
jordaaash Mar 24, 2022
7d9f505
fix qr margin
jordaaash Mar 24, 2022
83f1387
serialize and deserialize
jordaaash Mar 24, 2022
0245f9d
update yarn.lock
jordaaash Mar 24, 2022
0813ad5
use transfer requests by default
jordaaash Mar 24, 2022
16e6853
update readme
jordaaash Mar 24, 2022
ef3c831
more readme updates
jordaaash Mar 24, 2022
d7b2740
fix minor issues
jordaaash Mar 27, 2022
4443b48
use example.com
jordaaash Mar 27, 2022
d0e4e0b
Merge branch 'master' into link-request
jordaaash Apr 6, 2022
1df7ff5
docs: add transaction request docs
cogoo Apr 13, 2022
a9fbae2
docs: update sidebar config
cogoo Apr 13, 2022
a99b959
fix(links): broken links due to restructure
cogoo Apr 13, 2022
9a53abd
docs: update overview w/ new links
cogoo Apr 13, 2022
e3ba95f
fix(example): update example to match new shape
cogoo Apr 20, 2022
7d90b02
docs: update merchant docs for transfer request
cogoo Apr 20, 2022
ffdb2e7
docs(update): wallet integration docs to match latest shape
cogoo Apr 20, 2022
b80bbc4
docs(spec): update spec on docs site
cogoo Apr 20, 2022
c7574ef
docs(overview): brief overview of transfer and transaction req
cogoo Apr 20, 2022
2b5ba49
docs(supporting wallets): move solflare to supporting wallets
cogoo Apr 20, 2022
f842211
docs(supporting wallets): add slope to supported wallets
cogoo Apr 20, 2022
96ae43c
docs(supporting wallets): add phantom android app
cogoo Apr 20, 2022
7bfb365
formatting
jordaaash Apr 22, 2022
2de47e4
section titles
jordaaash Apr 22, 2022
f7d0a31
remove comment
jordaaash Apr 22, 2022
d9677ab
Merge pull request #117 from cogoo/transaction-request
jordaaash Apr 22, 2022
eda3943
use local image link
jordaaash Apr 22, 2022
871126d
docs(images): pOS deployment reference images
cogoo Apr 23, 2022
99d1600
docs(point of sale): vercel deployment instructions for point of sale
cogoo Apr 23, 2022
1321987
chore(package): move next package to dev dependency
cogoo Apr 23, 2022
9fe460d
chore(env): remove error for missing env vars
cogoo Apr 28, 2022
e13c8ff
fix(connection): default cluster endpoint to devnet
cogoo Apr 28, 2022
cd58bf6
docs(readme): reword environment variables section
cogoo Apr 28, 2022
5fc1926
Merge pull request #123 from cogoo/feature/pos-deployment
jordaaash Apr 29, 2022
d35786d
remove env var config for now
jordaaash Apr 29, 2022
c56c701
fix(readme): image for configuration step
cogoo Apr 29, 2022
8563cc8
Merge pull request #125 from cogoo/docs/pos
jordaaash Apr 29, 2022
b5a0e88
update SDK dep to released version
jordaaash Apr 29, 2022
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
16 changes: 6 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,12 @@ The Solana blockchain confirms transactions in less than a second and costs on a

## Supporting Wallets

* Phantom ([iOS](https://apps.apple.com/us/app/phantom-solana-wallet/id1598432977))
* Crypto Please ([iOS](https://apps.apple.com/us/app/crypto-please/id1559625715), [Android](https://play.google.com/store/apps/details?id=com.pleasecrypto.flutter))
* FTX ([iOS](https://apps.apple.com/us/app/ftx-trade-btc-eth-shib/id1095564685), [Android](https://play.google.com/store/apps/details?id=com.blockfolio.blockfolio))
* Glow ([iOS](https://apps.apple.com/app/id1599584512))

### Coming Soon

* Slope
* Solflare
* Reactor Wallet
- Phantom ([iOS](https://apps.apple.com/us/app/phantom-solana-wallet/id1598432977), [Android](https://play.google.com/store/apps/details?id=app.phantom&hl=en_US&gl=US))
- Solflare ([iOS](https://apps.apple.com/us/app/solflare/id1580902717), [Android](https://play.google.com/store/apps/details?id=com.solflare.mobile))
- Glow ([iOS](https://apps.apple.com/app/id1599584512))
- Slope ([iOS](https://apps.apple.com/us/app/slope-wallet/id1574624530), [Android](https://play.google.com/store/apps/details?id=com.wd.wallet&hl=en_US&gl=US))
- Crypto Please ([iOS](https://apps.apple.com/us/app/crypto-please/id1559625715), [Android](https://play.google.com/store/apps/details?id=com.pleasecrypto.flutter))
- FTX ([iOS](https://apps.apple.com/us/app/ftx-trade-btc-eth-shib/id1095564685), [Android](https://play.google.com/store/apps/details?id=com.blockfolio.blockfolio))

## How to use Solana Pay

Expand Down
220 changes: 192 additions & 28 deletions SPEC.md

Large diffs are not rendered by default.

38 changes: 17 additions & 21 deletions core/example/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { createAssociatedTokenAccount } from '@solana/spl-token';
import { clusterApiUrl, Connection, Keypair, LAMPORTS_PER_SOL } from '@solana/web3.js';
import BigNumber from 'bignumber.js';
import { createTransaction, encodeURL, findTransactionSignature, parseURL, validateTransactionSignature } from '../src';
import { clusterApiUrl, Connection, Keypair, LAMPORTS_PER_SOL, sendAndConfirmRawTransaction } from '@solana/web3.js';
import { createTransfer, encodeURL, findReference, parseURL, TransferRequestURL, validateTransfer } from '../src';

(async function () {
const cluster = 'devnet';
Expand Down Expand Up @@ -34,7 +33,9 @@ import { createTransaction, encodeURL, findTransactionSignature, parseURL, valid
console.log(originalURL);

// Wallet gets URL from deep link / QR code
const { recipient, amount, splToken, reference, label, message, memo } = parseURL(originalURL);
const { recipient, amount, splToken, reference, label, message, memo } = parseURL(
originalURL
) as TransferRequestURL;

// Apps can encode the URL from the required and optional parameters
const encodedURL = encodeURL({ recipient, amount, splToken, reference, label, message, memo });
Expand All @@ -53,28 +54,24 @@ import { createTransaction, encodeURL, findTransactionSignature, parseURL, valid
}

// Create a transaction to transfer native SOL or SPL tokens
const transaction = await createTransaction(connection, wallet.publicKey, recipient, amount!, {
const transaction = await createTransfer(connection, wallet.publicKey, {
recipient,
amount,
splToken,
reference,
memo,
});

// Sign and send the transaction
transaction.feePayer = wallet.publicKey;
transaction.recentBlockhash = (await connection.getRecentBlockhash()).blockhash;
// Sign, send, and confirm the transaction
transaction.sign(wallet);

const rawTransaction = transaction.serialize();
const signature = await sendAndConfirmRawTransaction(connection, rawTransaction);

const signature = await connection.sendRawTransaction(rawTransaction);

// Confirm the transaction
const result = await connection.confirmTransaction(signature, 'confirmed');

console.log(result);
console.log(signature);

// Merchant app locates the transaction signature from the unique reference address it provided in the transfer link
const found = await findTransactionSignature(connection, originalReference);
const found = await findReference(connection, originalReference);

// Matches the signature of the transaction
console.log(found.signature);
Expand All @@ -83,12 +80,11 @@ import { createTransaction, encodeURL, findTransactionSignature, parseURL, valid
console.log(found.memo);

// Merchant app should always validate that the transaction transferred the expected amount to the recipient
const response = await validateTransactionSignature(
connection,
found.signature,
const response = await validateTransfer(connection, found.signature, {
recipient,
amount!,
amount,
splToken,
reference
);
reference,
memo,
});
})();
20 changes: 4 additions & 16 deletions core/example/payment-flow-merchant/main.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
import { LAMPORTS_PER_SOL } from '@solana/web3.js';
import BigNumber from 'bignumber.js';
import {
encodeURL,
findTransactionSignature,
FindTransactionSignatureError,
validateTransactionSignature,
} from '../../src';
import { encodeURL, findReference, FindReferenceError, validateTransfer } from '../../src';
import { MERCHANT_WALLET } from './constants';
import { establishConnection } from './establishConnection';
import { simulateCheckout } from './simulateCheckout';
Expand Down Expand Up @@ -76,12 +71,12 @@ async function main() {
const interval = setInterval(async () => {
console.count('Checking for transaction...');
try {
signatureInfo = await findTransactionSignature(connection, reference, undefined, 'confirmed');
signatureInfo = await findReference(connection, reference, { finality: 'confirmed' });
console.log('\n 🖌 Signature found: ', signatureInfo.signature);
clearInterval(interval);
resolve(signatureInfo);
} catch (error: any) {
if (!(error instanceof FindTransactionSignatureError)) {
if (!(error instanceof FindReferenceError)) {
console.error(error);
clearInterval(interval);
reject(error);
Expand All @@ -105,14 +100,7 @@ async function main() {
console.log('\n6. 🔗 Validate transaction \n');

try {
await validateTransactionSignature(
connection,
signature,
MERCHANT_WALLET,
amount,
undefined,
reference
);
await validateTransfer(connection, signature, { recipient: MERCHANT_WALLET, amount });

// Update payment status
paymentStatus = 'validated';
Expand Down
12 changes: 5 additions & 7 deletions core/example/payment-flow-merchant/simulateWalletInteraction.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import { Connection, LAMPORTS_PER_SOL, sendAndConfirmTransaction } from '@solana/web3.js';
import BigNumber from 'bignumber.js';
import { createTransaction, parseURL } from '../../src';
import { TransferRequestURL } from '../../lib/types';
import { createTransfer, parseURL } from '../../src';
import { CUSTOMER_WALLET } from './constants';

export async function simulateWalletInteraction(connection: Connection, url: string) {
export async function simulateWalletInteraction(connection: Connection, url: URL) {
/**
* For example only
*
* The URL that triggers the wallet interaction; follows the Solana Pay URL scheme
* The parameters needed to create the correct transaction is encoded within the URL
*/
const { recipient, message, memo, amount, reference, label } = parseURL(url);
const { recipient, amount, reference, label, message, memo } = parseURL(url) as TransferRequestURL;
console.log('label: ', label);
console.log('message: ', message);

Expand All @@ -24,10 +25,7 @@ export async function simulateWalletInteraction(connection: Connection, url: str
/**
* Create the transaction with the parameters decoded from the URL
*/
const tx = await createTransaction(connection, CUSTOMER_WALLET.publicKey, recipient, amount as BigNumber, {
reference,
memo,
});
const tx = await createTransfer(connection, CUSTOMER_WALLET.publicKey, { recipient, amount, reference, memo });

/**
* Send the transaction to the network
Expand Down
20 changes: 12 additions & 8 deletions core/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@solana/pay",
"version": "0.1.3",
"version": "0.2.0",
"author": "Solana Maintainers <[email protected]>",
"repository": "https://github.com/solana-labs/solana-pay",
"license": "Apache-2.0",
Expand Down Expand Up @@ -37,18 +37,21 @@
},
"dependencies": {
"@solana/qr-code-styling": "^1.6.0-beta.0",
"@solana/spl-token": "^0.2.0-alpha.1",
"@solana/web3.js": "^1.31.0",
"bignumber.js": "^9.0.2"
"@solana/spl-token": "^0.2.0",
"@solana/web3.js": "^1.36.0",
"bignumber.js": "^9.0.2",
"cross-fetch": "^3.1.5",
"js-base64": "^3.7.2",
"tweetnacl": "^1.0.3"
},
"devDependencies": {
"@types/eslint": "^8.2.1",
"@types/eslint-plugin-prettier": "^3.1.0",
"@types/jest": "^27.4.0",
"@types/node": "^16.11.14",
"@types/prettier": "^2.4.2",
"@typescript-eslint/eslint-plugin": "^5.9.0",
"@typescript-eslint/parser": "^5.9.0",
"@typescript-eslint/eslint-plugin": "^5.14.0",
"@typescript-eslint/parser": "^5.14.0",
"eslint": "^8.6.0",
"eslint-config-prettier": "^8.3.0",
"eslint-plugin-prettier": "^4.0.0",
Expand All @@ -57,9 +60,10 @@
"prettier": "^2.5.1",
"shx": "^0.3.3",
"ts-jest": "^27.1.2",
"ts-node": "^10.4.0",
"ts-node": "^10.7.0",
"tsc-esm": "^1.0.4",
"tslib": "^2.3.1",
"typedoc": "^0.22.10",
"typedoc": "^0.22.13",
"typescript": "^4.5.4",
"typescript-esm": "^2.0.0"
}
Expand Down
5 changes: 4 additions & 1 deletion core/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ import { PublicKey } from '@solana/web3.js';
import BigNumber from 'bignumber.js';

/** @internal */
export const URL_PROTOCOL = 'solana:';
export const SOLANA_PROTOCOL = 'solana:';

/** @internal */
export const HTTPS_PROTOCOL = 'https:';

/** @internal */
export const MEMO_PROGRAM_ID = new PublicKey('MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr');
Expand Down
14 changes: 7 additions & 7 deletions core/src/createQR.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,22 @@ import QRCodeStyling, {
/**
* Create a QR code from a Solana Pay URL.
*
* @param url - The URL to encode in the QR code.
* @param size - Size of canvas in `px`.
* @param background - Background color for QR code.
* @param color - Color for QR code pattern.
* @param url - The URL to encode.
* @param size - Width and height in pixels.
* @param background - Background color, which should be light for device compatibility.
* @param color - Foreground color, which should be dark for device compatibility.
*/
export function createQR(url: string, size = 512, background = 'white', color = 'black'): QRCodeStyling {
export function createQR(url: string | URL, size = 512, background = 'white', color = 'black'): QRCodeStyling {
return new QRCodeStyling(createQROptions(url, size, background, color));
}

/** @ignore */
export function createQROptions(url: string, size = 512, background = 'white', color = 'black'): Options {
export function createQROptions(url: string | URL, size = 512, background = 'white', color = 'black'): Options {
return {
type: 'svg' as DrawType,
width: size,
height: size,
data: url,
data: String(url),
margin: 16,
qrOptions: {
typeNumber: 0 as TypeNumber,
Expand Down
Loading