GithubHelp home page GithubHelp logo

anza-xyz / solana-pay Goto Github PK

View Code? Open in Web Editor NEW
1.2K 1.2K 442.0 10.24 MB

A new standard for decentralized payments.

Home Page: https://solanapay.com

License: Apache License 2.0

TypeScript 99.75% JavaScript 0.25%

solana-pay's People

Contributors

akshatcoder-hash avatar alxnddr avatar anmolm96 avatar antoineherzog avatar benmills avatar cogoo avatar danqing avatar flodef avatar gitbolt avatar intelliot avatar jacobcreech avatar jcstein avatar jordaaash avatar juanrdbo avatar lukepuplett avatar mahnunchik avatar marc2332 avatar mcintyre94 avatar niten619 avatar ojshua avatar pancrisp avatar samheutmaker avatar soltoshi avatar sunitroy2703 avatar valentinmadrid avatar vunderkind avatar xavek avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

solana-pay's Issues

Error while building

I'm trying to build my backend project and when I'm trying to build the files i'm getting this error:

declare module '@solana/web3.js' {
  ~~~~~~~

  node_modules/@solana/web3.js/lib/index.d.ts:2:1
    2 declare module '@solana/web3.js' {
      ~~~~~~~
    Conflicts are in this file.

node_modules/@solana/web3.js/lib/index.d.ts:2:1 - error TS6200: Definitions of the following identifiers conflict with those in another file: Struct, Enum, SOLANA_SCHEMA, MAX_SEED_LENGTH, PublicKeyInitData, PublicKeyData, PublicKey, Account, Blockhash, BPF_LOADER_DEPRECATED_PROGRAM_ID, EpochSchedule, NONCE_ACCOUNT_LENGTH, NonceAccount, Keypair, MessageHeader, CompiledInstruction, MessageArgs, Message, TransactionSignature, AccountMeta, TransactionInstructionCtorFields, SerializeConfig, TransactionInstruction, SignaturePubkeyPair, NonceInformation, Transaction, ClientSubscriptionId, TokenAccountsFilter, Context, SendOptions, ConfirmOptions, ConfirmedSignaturesForAddress2Options, SignaturesForAddressOptions, RpcResponseAndContext, Commitment, Finality, LargestAccountsFilter, GetLargestAccountsConfig, GetSupplyConfig, SignatureStatusConfig, ContactInfo, VoteAccountInfo, VoteAccountStatus, InflationGovernor, InflationReward, EpochInfo, LeaderSchedule, Version, SimulatedTransactionAccountInfo, SimulatedTransactionResponse, ParsedInnerInstruction, TokenBalance, ParsedConfirmedTransactionMeta, ParsedTransactionMeta, CompiledInnerInstruction, ConfirmedTransactionMeta, TransactionResponse, ConfirmedTransaction, PartiallyDecodedInstruction, ParsedMessageAccount, ParsedInstruction, ParsedMessage, ParsedTransaction, ParsedConfirmedTransaction, ParsedTransactionWithMeta, BlockResponse, ConfirmedBlock, BlockSignatures, BlockProduction, GetBlockProductionConfig, PerfSample, Supply, TokenAmount, TokenAccountBalancePair, AccountBalancePair, SlotUpdate, SlotInfo, ParsedAccountData, StakeActivationData, DataSlice, MemcmpFilter, DataSizeFilter, GetProgramAccountsFilter, GetProgramAccountsConfig, GetParsedProgramAccountsConfig, GetMultipleAccountsConfig, AccountInfo, KeyedAccountInfo, AccountChangeCallback, ProgramAccountChangeCallback, SlotChangeCallback, SlotUpdateCallback, SignatureResultCallback, SignatureStatusNotification, SignatureReceivedNotification, SignatureSubscriptionCallback, SignatureSubscriptionOptions, RootChangeCallback, Logs, LogsFilter, LogsCallback, SignatureResult, TransactionError, TransactionConfirmationStatus, SignatureStatus, ConfirmedSignatureInfo, HttpHeaders, FetchMiddleware, ConnectionConfig, Connection, BPF_LOADER_PROGRAM_ID, BpfLoader, ComputeBudgetInstruction, ComputeBudgetInstructionType, RequestHeapFrameParams, ComputeBudgetProgram, CreateEd25519InstructionWithPublicKeyParams, CreateEd25519InstructionWithPrivateKeyParams, Ed25519Program, Loader, STAKE_CONFIG_ID, Authorized, Lockup, CreateStakeAccountParams, CreateStakeAccountWithSeedParams, InitializeStakeParams, DelegateStakeParams, AuthorizeStakeParams, AuthorizeWithSeedStakeParams, SplitStakeParams, SplitStakeWithSeedParams, WithdrawStakeParams, DeactivateStakeParams, MergeStakeParams, StakeInstruction, StakeInstructionType, StakeAuthorizationType, StakeAuthorizationLayout, StakeProgram, CreateAccountParams, TransferParams, AssignParams, CreateAccountWithSeedParams, CreateNonceAccountParams, CreateNonceAccountWithSeedParams, InitializeNonceParams, AdvanceNonceParams, WithdrawNonceParams, AuthorizeNonceParams, AllocateParams, AllocateWithSeedParams, AssignWithSeedParams, TransferWithSeedParams, DecodedTransferInstruction, DecodedTransferWithSeedInstruction, SystemInstruction, SystemInstructionType, SystemProgram, CreateSecp256k1InstructionWithPublicKeyParams, CreateSecp256k1InstructionWithEthAddressParams, CreateSecp256k1InstructionWithPrivateKeyParams, Secp256k1Program, PACKET_DATA_SIZE, SIGNATURE_LENGTH_IN_BYTES, VALIDATOR_INFO_KEY, Info, ValidatorInfo, VOTE_PROGRAM_ID, Lockout, EpochCredits, AuthorizedVoter, PriorVoter, BlockTimestamp, VoteAccount, VoteInit, CreateVoteAccountParams, InitializeAccountParams, AuthorizeVoteParams, WithdrawFromVoteAccountParams, VoteInstruction, VoteInstructionType, VoteAuthorizationType, VoteAuthorizationLayout, VoteProgram, SYSVAR_CLOCK_PUBKEY, SYSVAR_EPOCH_SCHEDULE_PUBKEY, SYSVAR_INSTRUCTIONS_PUBKEY, SYSVAR_RECENT_BLOCKHASHES_PUBKEY, SYSVAR_RENT_PUBKEY, SYSVAR_REWARDS_PUBKEY, SYSVAR_SLOT_HASHES_PUBKEY, SYSVAR_SLOT_HISTORY_PUBKEY, SYSVAR_STAKE_HISTORY_PUBKEY, SendTransactionError, Cluster, LAMPORTS_PER_SOL

2 declare module '@solana/web3.js' {
  ~~~~~~~

  node_modules/@solana/pay/node_modules/@solana/web3.js/lib/index.d.ts:2:1
    2 declare module '@solana/web3.js' {
      ~~~~~~~
    Conflicts are in this file.


Found 2 errors in 2 files.

Errors  Files
     1  node_modules/@solana/pay/node_modules/@solana/web3.js/lib/index.d.ts:2
     1  node_modules/@solana/web3.js/lib/index.d.ts:2

Adding Icons

Is there an easier way to add icons instead of using svg files? I have tried to add some custom icons and it doesn't seem to work properly (maybe I am formatting incorrectly).
Can the Solana icon inside the QR code be changed as well?
Thanks

[spec, possibly code] Rejecting excessive decimal places on `amount`

From the spec:

If the number of decimal places exceed what's supported for SOL (9) or the SPL token (mint specific), the wallet must reject the URL as malformed.

I noticed that the official @solana/pay JavaScript SDK will not reject a URL with more than the maximum decimal places in amount. It's not obvious from the spec, although it is totally understandable - it's impossible to implement this without on-chain data (at least in the SPL token case). Perhaps the spec should emphasize that this validation, both when generating and reading URLs, is the client's responsibility?

Still, regardless of the spec, there's no way for a downstream user of @solana/pay to detect the number of decimal places provided in the URL and thus reject any which are malformed. The amount field of ParsedURL is encoded as a BigNumber. That's an arbitrary-precision numerical representation, so it's possible to detect excessive nonzero digits. But as a parsing concern, these two URLs are indistinguishable:

solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?amount=123.012
solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?amount=123.01200000000000000000000000000000000000000

It is a reasonable interpretation of the current spec to only consider nonzero digits, but considering that clients are required to validate the number of decimal places anyways, my opinion is that the second case should be explicitly forbidden.

Mobile merchant app integration demo

Hi thanks for the work, could you put in the doc an example of how to integrate solana pay in a mobile app, in the doc specify that the integration between a mobile app and a mobile wallet would be through deep linking but there is no demo as if there is for integration with the web and I think it is not very clear how it is.

BufferLayout error when using createTransfer module to create a transaction

I ran into this bug when writing tests for the link-request branch. You can check out my code here. Please check out the sdk-tests branch

Error
TypeError: b must be a Uint8Array

  127 |
  128 |     // Create an instruction to transfer native SOL
> 129 |     return SystemProgram.transfer({
      |                          ^
  130 |         fromPubkey: sender,
  131 |         toPubkey: recipient,
  132 |         lamports,

  at checkUint8Array (node_modules/@solana/web3.js/node_modules/@solana/buffer-layout/src/Layout.ts:149:11)
  at uint8ArrayToBuffer (node_modules/@solana/web3.js/node_modules/@solana/buffer-layout/src/Layout.ts:157:3)
  at UInt.Object.<anonymous>.UInt.encode (node_modules/@solana/web3.js/node_modules/@solana/buffer-layout/src/Layout.ts:610:5)
  at Structure.encode (node_modules/@solana/web3.js/node_modules/@solana/buffer-layout/src/Layout.ts:1311:26)
  at encodeData (node_modules/@solana/web3.js/src/instruction.ts:25:15)
  at Function.transfer (node_modules/@solana/web3.js/src/system-program.ts:695:14)
  at createSystemInstruction (src/createTransfer.ts:129:26)
  at createTransfer (src/createTransfer.ts:64:11)
  at Object.<anonymous> (test/createTransfer.test.ts:62:25)

● createTransfer › should return an spl transaction

TypeError: b must be a Uint8Array

  168 |
  169 |     // Create an instruction to transfer SPL tokens, asserting the mint and decimals match
> 170 |     return createTransferCheckedInstruction(senderATA, splToken, recipientATA, sender, tokens, mint.decimals);
      |                                            ^
  171 | }
  172 |

  at checkUint8Array (node_modules/@solana/buffer-layout/src/Layout.ts:149:11)
  at uint8ArrayToBuffer (node_modules/@solana/buffer-layout/src/Layout.ts:157:3)
  at UInt.encode (node_modules/@solana/buffer-layout/src/Layout.ts:588:5)
  at Structure.encode (node_modules/@solana/buffer-layout/src/Layout.ts:1205:26)
  at createTransferCheckedInstruction (node_modules/@solana/spl-token/src/instructions/transferChecked.ts:63:36)
  at createSPLTokenInstruction (src/createTransfer.ts:170:44)
  at createTransfer (src/createTransfer.ts:63:11)
  at Object.<anonymous> (test/createTransfer.test.ts:74:25)

error with Layout.ts

I'm trying to integrate Solana Pay, making a pop up form that would generate an customized qr code for payments.
I get the following error (1) when import of sol-pay is enabled and the console points towards the line import (2)
Installation of package was done using npm

Is there a Solution?

(1)

image

(2)

image

image

[feature] NFC support

Hey all, Solana Pay looks really exciting, well done. Low-cost, low-friction IRL payments will solve a bunch of problems as we go fully cashless.

Firstly, is this the right place for this kind of question?

My question is around what's needed to build a contactless terminal for payments that feels to consumers like Apple Pay. Will wallet developers be encouraged to register the solana: scheme so that scanning a URL in an NFC tag launches the wallet? Has anyone experimented with this, yet?

The Chinese are apparently big users of QR codes but many other nations don't really get it (yet) but do understand contactless card, phone and wearables payments. It's also easier to just wave your phone over a pad and have it do the right thing.

Cheers!

Point of Sale - No progress circle or recent transactions on Mainnet Transactions

Hello! I'm trying out Solana Pay by using a forked version the point-of-sale demo, and I've found that the progress circle doesn't show up when doing Mainnet "real world" transactions.

The transactions go through correctly, but the application does not show the transaction history, or the progress circle.

Everything works as intended on Devnet however.

I would appreciate any guidance or help, and I'm willing to try to fix the issue myself if I'm pointed in the right direction, thanks!

Incorrect SPEC - multiple public keys for "reference"

According to the official spec we are allowed to use multiple public keys for reference, and indeed the encodeURL API from Solana Pay allows us to pass an array of public keys for this.

However, while trying to find the transaction signature - we use the getSignaturesForAddress API from Solana which expects this field to be a single public key.

Due to this, the findTransactionSignature API from Solana pay only accepts a single public key. This means that we can't effectively use multiple public keys for the reference field 😦

Is this correct? If so, the documentation need to be corrected.

Need API for payments via Android on my apps

I want to integrate solana pay on my apps, how can i do that?
And if possible these are the following i would prefer

  1. Connect an users wallet
    2)Add money via systems like razorpay
    2.1) With the help of razorpay it'll be transferred to some wallet (this is my job) then it'll be transferred to the persons wallet(this will be done via api)
  2. Then the person can use it from within my app as a money transfer service.

In short - paypal of Crypto world with bare minimum fees

[question] SPL Token transaction to wallet with no previous history

https://github.com/solana-labs/solana-pay/blob/6224ccf15f1889ad722929cb662dd4936a50c24d/core/src/validateTransactionSignature.ts#L59

Hello! I have a question regarding transactions with SPL Tokens:

In case the recipient wallet has never been funded with an SPL Token the line referenced above would cause the very first transaction validation to fail even though the transaction actually finished successfully. Is there any reason against considering the preAmount value 0 when no preBalance is found ?

Thanks!

[feature] Plugin for Saleor Headless Ecommerce

Hi team,

I am working on a Solana based NFTs project. We happen to use Saleor headless e-commerce platform for our shop.
I think it would be great to integrate Saleor as one of the e-commerce platform to integrate Solana Pay with.

Let me know what you think.

Cheers

[rfc] Spec Proposal: Transaction Request (formerly Request Link)

Update

This proposal has changed. A specification and implementation now exists in #77

Abstract

This is a new proposal for an extension to the Solana Pay specification.

This proposal draws in part from https://en.bitcoin.it/wiki/BIP_0072, relying on HTTPS for transmitting and authenticating arbitrary transaction payloads.

Motivation

There are a some significant shortcomings of the simple BIP21-based payment link scheme described in the Solana Pay specification.

1. It only describes simple native SOL and SPL token transfers.

Merchants, service providers, and apps may wish to mint NFTs or transfer reward tokens with purchases, invoke programs, pay gas for customer transactions, and enable many other use cases that may be developed with arbitrary transactions.

Transactions on Solana must specify the accounts that will be included in the transaction upfront. Most useful instructions require the wallet signer address, their auxiliary token account address, etc.

This requires knowing the wallet address and being able to generate PDAs from it, which cannot be known when the link is created. In short, it's missing a sessionless "connect wallet" function.

2. Payment requests are not authenticated.

We may expect that payment links will be maliciously or accidentally misused. Without knowing who a receiving address belongs to, it's not possible to determine from the URL who is requesting the payment.

A mechanism such as an HTTPS link allows the wallet to authenticate the source of the request. There may be other mechanisms we should consider.

Proposal

I propose to add an optional request=<url-encoded-url> query parameter to the specification.

An interactive protocol between the merchant and wallet follows:

  1. The merchant presents a QR code with the following payment link:
solana:<recipient>?request=https%3A%2F%2Fmerchant.com%2Fsolanapay

Any of the parameters of the spec can also be included. <recipient> could be considered optional. Perhaps an invalid address (e.g. a, x, or _) could be provided for compatibility.

Regardless, it must not be used by the wallet if request is provided, so providing an invalid recipient address ensures a wallet will not prompt a user to make a payment unless it can handle the request parameter.

  1. The customer scans the QR code and opens their wallet app.

  2. The wallet parses link and prompts the user to make a request to https://merchant.com/solanapay.

This is analogous to connecting a wallet to a dapp, so obtaining the user's permission is important for privacy.

  1. If permitted, the wallet makes a request to
https://merchant.com/solanapay?from=<wallet>&<...params>

The wallet should include any parameters from the URL provided, except for the request parameter.

  1. The merchant responds with a JSON object:
{"transaction":"<transaction>"}

The transaction property value must be a base64-encoded serialized transaction.

The feePayer, recentBlockhash, nonceInfo, and signatures fields are optional but may be included. If they are included, the wallet must use them in the final transaction, since the transaction may be partially signed and subsidized by the merchant.

The wallet should allow additional fields in the JSON object, which may be added by future specifications.

  1. The wallet deserializes the transaction, simulates it, and presents it for signing.

The wallet may wish to display the domain the request came from, and may wish to show payment requests not including a request parameter as unauthenticated.

  1. The user signs the transaction and the wallet sends and confirms it.

  2. The merchant discovers the transaction through the reference parameter, if provided.

[report] TypeError: Invalid URL: [object Object]↵ at URLImpl

Trying to import this library and use it in react-native but I get this error whenever i try to call parseURL.

I have all other polyfills installed for react-native, so this could be an issue with the implementation of @solana/pay.

I'll be looking into this issue on both sides in the coming week or two, but I wont be back in town for a few days so I wanted to document this here.

Phantom wallet App

Generating url by encodeURL function always open FTX(blockfolio) app. Is there a way to choose app or directly create a link to open only phantom wallet app ? Thanks.

Testing the in-browser user experience

I'd like to integrate Solana Pay on my website via a button and I'd like to demo it to my team. How are people testing the start to end user flow?

I've gotten as far as a button that displays the QR code when clicked. I'm on Android and the only way I've found of scanning the qr code is with the ftx app, using real funds.

Can't include in VueJS Project

Hey guys,
Im trying to add Solana Pay in my VueJS project. I tried a lot of things, but whenever I install @solana/pay its giving this error:

* @solana/web3.js in ./node_modules/@solana/buffer-layout-utils/lib/esm/web3.mjs, ./node_modules/@solana/pay/lib/esm/constants.mjs

To install it, you can run: npm install --save @solana/web3.js

@solana/web3.js is installed I tried running it without @solana/pay and it works really good, same with @solana/spl-token, but when I install Solana Pay, @solana/spl-token also gives an error that web3.js cannot be found. I'm pretty sure that's a problem with the library. I also tried removing yarn cache, yarn.lock and reinstalling all packages.

package.json before @solana/pay installation:

{
  "name": "luxnode",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build"
  },
  "dependencies": {
    "@mdi/font": "^6.5.95",
    "@solana/spl-token": "^0.2.0",
    "@solana/web3.js": "^1.36.0",
    "axios": "^0.26.0",
    "core-js": "^3.6.5",
    "sass": "^1.49.8",
    "sass-loader": "10",
    "vue": "^2.6.11",
    "vue-router": "3.5",
    "vuescroll": "^4.17.3",
    "vuetify": "^2.4.0",
    "vuex": "^3.4.0"
  },
  "devDependencies": {
    "@vue/cli-plugin-babel": "~4.5.15",
    "@vue/cli-plugin-router": "~4.5.15",
    "@vue/cli-plugin-vuex": "~4.5.15",
    "@vue/cli-service": "~4.5.15",
    "sass": "~1.32.0",
    "sass-loader": "^10.0.0",
    "vue-cli-plugin-vuetify": "~2.4.5",
    "vue-template-compiler": "^2.6.11",
    "vuetify-loader": "^1.7.0"
  }
}

[feature] Solana Pay on WooCommerce

Hello Solana,
Thank you for making this amazing technology available to web developers around the world.

I am interested in building the WooCommerce plugin that will utilize Solana Pay. For that reason, is there a repo where I can contribute or the project is still on hold?

Thank you.

[docs] Further Documentation on using NFT's in Transactions.

Solana's example when introducing Solana Pay was that it is possible to add an NFT to the transaction as a merchant and return it to the buyer. These could be digital copies of the product or even a receipt.
This feature is one of the most important that comes with Solana but isn't talked about in the Docs.
It would be great to have a documentation for this.

Have a great day,
Valentin.

Generated QR code not working

After having followed all the steps for the merchant account and the generation of a QR code which the customer has to scan, the QR code simply does not work.

This is an example of QR code generated through the createQR method imported from @solana/pay

Immagine 2022-05-06 151217

Am I doing something wrong or is it a global issue?

Vuejs having issue importing parseURL

Uncaught TypeError: fields must be array of Layout instances
    at new Structure (webpack-internal:///./node_modules/@solana/pay/node_modules/@solana/buffer-layout/lib/Layout.js:1183:13)
    at exports.struct (webpack-internal:///./node_modules/@solana/pay/node_modules/@solana/buffer-layout/lib/Layout.js:2862:56)
    at eval (webpack-internal:///./node_modules/@solana/pay/node_modules/@solana/spl-token/lib/esm/instructions/initializeMint.mjs:23:100)
    at Module../node_modules/@solana/pay/node_modules/@solana/spl-token/lib/esm/instructions/initializeMint.mjs (chunk-vendors.js:4148:1)
    at __webpack_require__ (app.js:315:33)
    at fn (app.js:617:21)
    at eval (webpack-internal:///./node_modules/@solana/pay/node_modules/@solana/spl-token/lib/esm/instructions/index.mjs:94:77)
    at Module../node_modules/@solana/pay/node_modules/@solana/spl-token/lib/esm/instructions/index.mjs (chunk-vendors.js:4102:1)
    at __webpack_require__ (app.js:315:33)
    at fn (app.js:617:21)
 

Hit error above when try to add the example code in vue example project

const testparse = async () =>{
  const url =
    'solana:mvines9iiHiQTysrwkJjGf2gb9Ex9jXJX8ns3qwf2kN?amount=0.01&reference=82ZJ7nbGpixjeDCmEhUcmwXYfvurzAgGdtSMuHnUgyny&label=Michael&message=Thanks%20for%20all%20the%20fish&memo=OrderId5678';
  const { recipient, amount, splToken, reference, label, message, memo } = parseURL(url);

}

using packages below

  "dependencies": {
    "@solana/pay": "^0.1.1",
    "@solana/spl-token": "^0.1.8",
    "@solana/web3.js": "^1.31.0",
    "bs58": "^4.0.1",
    "core-js": "^3.8.3",
    "tweetnacl": "^1.0.3",
    "vue": "^3.2.6"
  },
  "devDependencies": {
    "@typescript-eslint/eslint-plugin": "^4.15.1",
    "@typescript-eslint/parser": "^4.15.1",
    "@vue/cli-plugin-babel": "~5.0.0-beta.4",
    "@vue/cli-plugin-eslint": "~5.0.0-beta.4",
    "@vue/cli-plugin-typescript": "~5.0.0-beta.4",
    "@vue/cli-service": "~5.0.0-beta.4",
    "@vue/compiler-sfc": "^3.2.6",
    "@vue/eslint-config-typescript": "^7.0.0",
    "eslint": "^7.20.0",
    "eslint-plugin-vue": "^7.2.0",
    "stream-browserify": "^3.0.0",
    "typescript": "~4.1.5"
  }

Failed to find wallet-adapter-react-ui/styles.css'

Guys pls help with poin of sale app

parcel/transformer-postcss: Failed to find '../node_modules/@solana/wallet-adapter-react-ui/styles.css' in [ /user/solana-pay/point-of-sale/src ]
Error: Failed to find '../node_modules/@solana/wallet-adapter-react-ui/styles.css'
in [
/user/solana-pay/point-of-sale/src

Can Solana point-of-sale work as a webhook?

I was really impressed with this project.

I have a question, and if you look at the contents of "4.1 Retries" in the current solana docs, pos uses the polling strategy to check whether a transaction has been confirmed.
Is there no way to implement this as a webhook?

If there is a way, please let me know how it can be done.
I think it would be more appropriate to use a webhook rather than polling.

[docs] A better Merchant Explanation

Hey, first of all thanks for your work!

I wanna create a store of merch on my webpage and I wanna use Solana Pay. I use React and I am trying to follow the docs and looking in the code. I created the connection and the URL but now I stuck on this point https://github.com/solana-labs/solana-pay/blob/master/core/example/payment-flow-merchant/main.ts#L46 where it says that the interaction will be handled by a wallet provider. How can we launch that interaction? In the docs I only see the QR option (https://docs.solanapay.com/core/merchant-integration#3-encode-link-into-a-qr-code) but I would like to prompt a response with the wallet, as when minting a NFT or something like that, right?

Privacy Concerns with using Solana Pay

I was wondering if there are privacy issues with using Solana Pay since both the merchant and customer are now aware of each other's wallet addresses? I think this means each could peruse through the other's transaction history. Please let me know if this is already addressed somehow.

findTransactionSignature() not finding the transaction by the provided reference

Hey guys. I am testing solana pay to build a payment module based on it but I haven't been able to successfully finalize a payment based on the payment-flow-merchant example!
Steps that I follow:

  1. Successful connection to devnet
Connection to cluster established: https://api.devnet.solana.com { 'feature-set': 3246413280, 'solana-core': '1.9.9' }
  1. Simulate Checkout using my test merchant wallet and generate the payment URL:
solana:GrH51Zbp6czGypTUe2gcU6B6eB9BjTERx7K6XYoXE9au?amount=0.01&reference=4ZQAj72fPDzy99UNWZdupTd5rKMeoXn7r1nguzT5hxKA&label=MORTIE-PAY&message=MORTIE-PAY%20-%20your%20order%20-%20%23001234&memo=JC%234098
  1. I then convert the URL to QR code and scan it with my second test wallet made on Slope Wallet (Android) while the network is set to devnet. Transaction succeeds and gets fully confirmed. I can see the reference and the message added to the URL shown while approving the transaction on my wallet.
    https://solscan.io/tx/5TukQF9AEYjf7oDdPxpP7Bc6nNezzcANt8ooa5ztT8t36S4yfX8opmsLJYwwwxS8aQhwSYXSjFFBzgHL4dEiYgiy?cluster=devnet
  2. Now at this stage, findTransactionSignature() never finds the transaction using the randomly generated reference key. I can't actually see this transaction using the reference on Solscan as well.

Can you help me with this, please?
Should I find that reference key somewhere in the transaction description in Solescan?
Thank you!

[bug] Dependency `stream-browserify` is not installed (Solana Pay PoS)

Expected Behavior

yarn install installs all dependencies

Current Behavior

yarn install does not install dependency stream-browserify

Possible Solution

This is easy enough to fix by running npm install stream-browserify before running yarn start. But maybe it should be added to the dependency list.

Steps to Reproduce

  1. Clean installation of yarn/npm on MacOS Monterey 12.2
  2. Follow setup instructions as defined in https://github.com/solana-labs/solana-pay/tree/master/point-of-sale README.md (commit ebe5ad9dce68dfcafd426be02ebe2e34f90cd056)

[feature] Plugin for Prestashop CMS

The CMS Prestashop not listed on commerce Solution.
We are Prestashop's Developpers from 12 years so we can develop the Solana Pay plugin for Prestashop if you think its a good idea to contribute to Solana Pay project ?

[help] How to get the browser extension to pop up

I realize this is a dupe of #86, but was unable to really figure out that thread. I also apologize that is probably out of the scope of this project, but figure I'd ask here anyways as I can't get into the discord as their SMS verification never works for me so I am locked out of that discord.

My question is how do we get the browser extension to popup and sign/send transactions?
For Phantom, I have followed the instructions here https://docs.phantom.app/integrating/sending-a-transaction and can get it to popup no problem.

For Solflare, I can follow their own specific code as well and get it to popup.

I'm a little confused how the solana-pay library fits into the flow with a browser extension. Let's take a use case, for example - that I want to accept SOL on my website in a variety of desktop browser extension wallets.

Would I be implementing specific code for each specific wallet? That is my assumption. To me it seems that the strength of this library is that it spits out a deep-link URL for mobile wallets. But for desktop wallets, I'm not seeing the use case.

In a perfect world, I would envision just using a library and not giving a hoot what wallet they use. That kinda seems how it is for mobile wallets that are listed (Phantom, FTX) - but not for browser wallets.

By the way, great stuff. Thanks for building this repo and thanks for putting up the sample app! Really good stuff. Again, apologies for opening this as an issue as this is more of a question.

[docs]In person POS terminal [feature]

it's my raw idea about a terminal
please share your idea and support it if you are into it
the challenges are 1-design a simple case to put the hardware together in a box and 2- an image that installs a pre-config lightweight Linux +java+solana pay.
** it can also include GUI to switch between the currency(USDC, USDT, SOL) and maybe merch

See attached file
In person POS terminal.md

Proposal: Solana Auth

Summary:

We propose an expansion on the Solana Pay Standard to provide an authentication standard using any crypto wallet.

Background:

There are two fundamentally different flows for a dapp to interact with a user’s wallet:

- Provider Injection: the wallet is a browser extension that injects a global object, like window.solana, which our dapp can interact with. This works best for web-apps running on a desktop browser. Mobile browsers do not currently support browser extensions (except for mobile-Safari, which added its own browser-extensions on iOS 15, although there are no crypto-wallets available yet). To get around this, MetaMask and Phantom have built browsers within their mobile apps; users visit a dapp from this in-app browser, allowing for global provider injection.

- Deep-Linking: we use the Solana URL scheme “solana:...” to open the user’s wallet-app on their device, approve a transaction request, and then redirect back to our app or website with the response as query params. This works best for web-apps running on mobile-Safari or mobile-Chrome, within native mobile apps, and for kiosks / terminals / any app that runs on an external device. You could also remove desktop browser-extensions entirely; for example, if a dapp on my laptop needed to submit a transaction it could present me with a QR code which I could scan with my phone camera, redirect me into Phantom, and allow me to verify the transaction.

Problems with ‘solana:’ URL scheme and how to fix Deep-Linking:

  • On iOS it’s ambiguous what will happen if multiple apps register to handle the same URL scheme. Currently when I scan a QR code with ‘solana:...’ my iPhone will open my FTX US app, which does nothing. If I uninstall FTX, reboot my phone, and try again, it still won’t open my Phantom Wallet app for some reason–has Phantom app not registered the Solana URL scheme yet? (This may work better on Android, which features disambiguation screens for links–not that Phantom is on Android yet.) But the point is that if I were clicking a ‘solana:’ deep-link in an iOS app as a user, I would have no way of making sure that this request is directed to my preferred wallet app.
  • I would recommend using Universal Links on iOS and Android App Links on Android. Each mobile wallet app should register their own url, something like https://phantom.app/code?<params>
  • This provides a better UX, because if the user has no apps installed that handle the ‘solana:’ url, they will simply get an unintuitive ‘no usable data found’ message when they try to use it. However if the user scans a deep-link like https://phantom.app/code… they will be directed to phantom’s website in their browser, and phantom’s website can prompt the user to install their wallet from the app store.
  • When using a mobile browser or using a mobile app, we can add some UI that allows users to select their wallet. Example: tap a button which says ‘Send 0.1 SOL’ > this pops up a dialogue listing supported wallets > user clicks Phantom, which opens https://phantom.app/code?... routing the user to their phantom wallet app > user confirms transaction > user is routed back to the original app specified in a redirect_uri. The user’s wallet preference can be remembered for future interactions to skip this step. Ideally this could be used for in-app purchases that circumvent Apple’s 30% tax.
  • Apple v Epic Games Court Ruling
  • When such a user-selection is not possible (such as a fixed QR code or a fixed NFC link), the payment url can direct to a merchant-specific Linktree page; a url that opens a page that allows users to select their preferred wallet. This page will contain a list of supported wallets and a deep like to those wallets, like https://phantom.app/code?<params>. As a last resort, we can use the Solana URL scheme ‘solana:’ and hope this routes the user somewhere useful. However the above wallet-specific url and linktree methods should always be preferred. That is, the 'solana:' URL scheme should only be used as a last resort.
  • To accommodate deep links, I propose adding a request= query param to the standard, which has a URL-encoded URI to which the wallet will make a transaction request.

How signMessage authentication currently works with Provider Injection:

  • signMessage is currently only possible with global provider injection.
  • Upon approving the connection, the client app is provided with the user’s pubkey and a signMessage() method.
  • The user’s wallet receives a signature request, with an arbitrary Uint8Array
  • The user’s wallet uses the private key to create a signature of that arbitrary Uint8Array
  • The client-app verifies that the signature is legit, by comparing the signature with the original message and pubkey. This proves to the client-app that the person they’re talking to does indeed control that pubkey.

Security Problems:

  • Every website I’ve seen using this signMessage method for authentication is insecure, including magiceden.io. Fortunately these insecure sites are mostly obscure NFT projects, with no major data at risk yet.
  • It’s trivially easy to construct a message that is actually an arbitrary transaction. The user will simply see a bunch of garbled characters in its signMessage request, and not understand that they are signing a transaction.

Solana Auth Proposal:

How to adapt signMessage to work with Deep Linking:

  1. On a mobile web browser or in a mobile app, the user clicks a ‘Sign in with solana’ button which deep-links to the user’s wallet, OR the user opens their mobile camera-app and scans a QR code. The merchant presents the following auth link:
solana:https%3A%2F%2Fmerchant.com%2Fsolanaauth?label=merchant&message=sign%20this%20please
https://phantom.app/code?request=https%3A%2F%2Fmerchant.com%2Fsolanapay&label=merchant&message=sign%20this%20please
  • The addition of a request= query param to the spec allows for us to use deep links.
  • This URL format is meant to be identical to the Solana Pay spec. The server responding to the request should understand from the route that a challenge is being requested rather than a transaction.
  1. The wallet parses the link and optionally prompts the user for permission to make the request; this should be considered the same as a wallet-connect. The label and message params can optionally be displayed, but more importantly the wallet should display the url of the server to which the request will be directed. The permission step can be skipped if the wallet has connected to this domain before.

  2. If permitted, the wallet makes a POST request to the specified url (which will be referred to as the authentication server from here on out). The label and message params will not be used again. The JSON body should have a { “account”: <pubkey> } format
    Example url: https://merchant.com/solanapay?auth=true

  3. The authentication-server generates a nonce and a message, and then generates a challenge, which is a 3-part comma separated utf-8 string, with the format:
    ${origin},${nonce},${pubkey}
    where origin should match the origin of the redirect URI, the nonce is a randomly generated alphanumeric string, and the pubkey is the pubkey being requested for authentication. The pubkey-portion should be considered optional in this format.
    Example:
    https://merchant.com,GCQLiawuDQbaaxFUAKcGpvQxfSxddZwGDp8p4Q57DfoX,17FaeoyXD2
    This will be returned as a Uint8Array. The authentication server then saves the pubkey and challenge as a key-value pair, with an expiry time after which the pair will be discarded from memory. It also adds a redirect_uri and an expiry time that is an epoch time value in the future. It then returns the following (signed or unsigned)) JWT response, with this being the JSON body:

{ “message”: utf-8 string (optional),
“challenge”: <challenge> Uint8Array,
"redirect_uri": URI,
"expiry": epoch time value }
  1. The user’s wallet displays the redirect_uri domain and message, and optionally prompts the user to sign the undisplayed challenge. If granted, the user’s wallet generates a signature using the private key, and immediately redirects to the specified URI, including the pubkey and signature as query params:
<redirect-uri>&from=<pubkey>&signature=<signature>
https://merchant.com/solanaauth?&param1=value&from=GCQLiawuDQbaaxFUAKcGpvQxfSxddZwGDp8p4Q57DfoX&signature=<sig>
  • It’s important that the user’s wallet should examine the challenge and verify that the challenge is NOT a transaction. Currently (March 2022) it is trivial to trick Phantom into signing an arbitrary transaction without the user’s knowledge using the signMessage method.
  • It is important for the wallet to verify that the origin included in the challenge matches the origin of the authentication server to which it will be sent (the redirect URI). If these origins do not match, reject this authentication-attempt as malicious before asking the user for a signature. This prevents an authentication forwarding-attack; for example, suppose pubkey123 sends a request to malicious.com to authenticate, but at the same time behind the scenes malicious.com asks to authenticate pubkey123 at magiceden.io, and then forwards that challenge to our user. In that case, if the user signed it, they thought they were authenticating with malicious.com, but actually they just gave malicious.com authentication to their pubkey123’s magiceden.io account. However, if we include the domains in the challenge to sign this is not possible; the wallet will clearly see that magiceden.io !== malicious.com, and reject the request. If malicious.com modifies the magiceden.io authentication request it got to add its own name as the origin, then when our wallet signs it and returns it to malicious.com, malicious.com will not be able to use this to authenticate on magiceden.io because magiceden.io will see that the signature returned does not match the challenge it sent.
  • It is important to use a nonce to prevent replay attacks; even if this signature was intercepted and saved, this signature cannot be used to authenticate a second time because the authentication server will issue a different challenge every time. Additionally it is impossible for an attacker to predict what the challenge will be.
  • Including the pubkey in the challenge ensures that the challenge can only be used to authenticate by the pubkey for which the challenge was generated. However the pubkey should be considered to be an optional part of the challenge template.
  • Including an optional expiry date in the challenge ensures that the authentication challenge can not be used indefinitely into the future authenticate.
  • If the user has already logged into this website before, the connect and signing message steps can be skipped entirely. If this spec is followed there is nothing malicious that can be done by signing the challenge.
  1. The authentication-server receives the pubkey and signature as query params, along with anything else included in its predefined redirect uri. It looks up the challenge it sent to that pubkey (if it’s unable to find the message, it rejects the request), and verifies that the challenge, pubkey, and signature match. If the signature is legitimate, the server grants authorization (such as by giving the user’s browser a session-cookie and redirecting the user to a protected route, or whatever system it uses). After which the authentication server discards the pubkey and challenge from its memory.

Notes:

In oauth, this is called a ‘front channel communication’. A ‘back channel communication’ would be if the wallet sent the signature directly to the authentication-server, rather than including it in the redirect uri. Back channel communications are considered more secure because the two parties share an oauth credential, and if there was some piece of malicious software on the user’s device that could observe the redirect uri, that malicious software could authenticate itself before we get the chance to. However, the main point of this authentication flow is for the authentication server to place an authentication cookie in the user’s browser, so I think front channel communication is the simplest and overall best solution.

Alternate flow with stateless authentication server:

  1. Same as above, except that the server signs the JWT it returns using a secret it controls.
  2. When the wallet redirects to the specified redirect_uri, it also includes the original signed JWT in the authorization header, and optionally skips the pubkey as a query param (we will not use it).
  3. The authentication-server receives its original JWT, and also the signature as query params. It first verifies that the JWT was not tampered with by examining the JWT signature. It then verifies that the challenge has not expired by checking the expiry time on the JWT. It then grabs the base58-encoded pubkey from the challenge string. It then takes the challenge, pubkey, and signature and verifies that the signature is legitimate. If all of these pass, the authentication-server grants authorization to the user.
  • It is important that the challenge has a short expiry time (around 5 minutes). If this JWT and signature were intercepted by someone malicious, they could use it to authenticate an arbitrary number of times, and our stateless authentication-server has no way of revoking these challenges other than letting them expire.

Proposed Changes to Wallet Interfaces:

  • Wallets should expose a more robust method; requestAuth({ challenge: string, display?: string } ) => resp: { signature: Uint8Array }. This method works just like signing a message, except that the wallet verifies that the challenge is not actually a transaction, and that the origin inside of the challenge is the origin of the currently connected website before it presents it to the user to sign. This adds an extra layer of security on top of the signMessage() method.

  • This opens up the possibility of wallets creating an 'authenticated connect' method, something Glow App is already building. The purpose is to not only get the user's pubkey, but also a proof that the user owns their pubkey as they claim. This method would be an overload of the current window.solana.connect() method, except that the client-app provides a server-generated nonce: window.solana.connect({ nonce: string }) => resp with the resp object extended to contain a challenge: string and signature: Uint8Array param. The client-app will first fetch a nonce from the server, call the connect method supplying the nonce, and then return the response object to the server. The server will first examine the validity of the challenge-string, which is should be ${origin},${nonce},${pubkey}, then compare that to the pubkey and signature. If it all checks out, the server will respond with an authentication token to the client.

  • Ideally users should be able to auto-connect and auto-authenticate in one method call, without any user interaction or permission required.

Alternate flow without authentication:

  • If authentication is not required, and the app simply wanted to request your public key so it can look up info about you, the authentication server can simply return everything in its JWT as null / undefined except for the redirect_uri. The entire user signature-requesting step can then be skipped and the wallet can immediately redirect to the url as from=<pubkey>&signature=<blank>

Examples:

  • Vending machine: you want to buy something from a kiosk, however this kiosk displays private information and wants to authenticate you first (such as when checking into a flight). OR this kiosk is restricted to only owners of a certain NFT. OR you want to be able to select which tokens you will pay with first. OR this kiosk remembers users based on their pubkey and gives returning users a discount. The kiosk presents a QR code, which you scan on your mobile phone. It opens your Phantom wallet, which unlocks using your face. You push ‘sign message’, are redirected to a success page, and then within seconds the kiosk identifies you and prompts you to proceed.
  • Mobile login: you want to sign-in to a website on your phone, which uses Solana pubkeys as an auth factor. You click ‘sign in using Solana’ and the website redirects you to your mobile wallet, which unlocks using your face. You click ‘sign message’ and are then redirected to the website, signed in.
  • Desktop login using mobile wallet: you want to sign onto a website on your desktop computer which uses Solana pubkeys as an auth factor. You click ‘sign in using Solana’, and the website displays a QR code. You pull out your phone, scan the QR code, are redirected to your Phantom wallet, which unlocks using your face, and press ‘sign message’, and then your desktop computer redirects to a protected route.
  • AR glasses: wearing AR glasses you look at a wall with a virtual object embedded in it. It’s a virtual kiosk; however only the members of your DAO can use this kiosk. You interact with the virtual-kiosk using a hand gesture, and your AR glasses open a deep link that opens up Phantom on your mobile phone. You unlock your phone and press ‘sign message’, after which the kiosk unlocks and allows you to interact with it.

Why Solana wallets (like Phantom) should build this:

The above has very broad applicability; even for users who have no interest in crypto, they can still use their wallet application as their preferred authentication method for any website, app, or kiosk that supports it. This greatly expands the use cases of Phantom, for example, beyond Solana. Even people with no interest in Solana could use this system.

This is a zero-knowledge authentication system, in the sense that the user does not have to share any secret information with a remote server. In contrast, when you login using a password and username you are sending that server your password in plaintext, possibly compromising your password if the server mishandles it (such as leaving it in a log file).

Furthermore, this authentication system is non-custodial, and doesn’t require the permission and service availability of a 3rd party resource-provider (such as Google or Facebook…), for either the user or the developer implementing it into their service.

Future expansions:

Solana Auth with scopes

One of the beauties of the oAuth / OpenId Connect standard is the ability for the client (application) to request pre-verified information about the resource-owner (user), in addition to just authenticating, which can be used to expedite purchase flows and registration flows. For example, if you’re buying a product online, you can authenticate and give the application your full shipping information in one click.

oAuth calls this a ‘scope’ request. To implement this, in the JWT response containing the server’s request, the authentication-server can add a scope parameter to the body, like:

{ scope: [name, email, shipping_address, phone_number], …}

Where each scope is a request for a specific piece of information about you. This information can be stored by your wallet or stored on-chain and encrypted using your pubkey. Your wallet app can then display a message like ‘merchant.com is requesting the following information: name, email, shipping address, and phone number’, and the user can granularly choose which pieces of information it wants to expose.

Transaction requests superseed authorization requests, because the signature for a transaction can already be used to authenticate a user. However, we can combine scopes and transactions to do some interesting things. For example, a kiosk could display a QR code, which when scanned responds with the following transaction request:

{ transaction: <transaction>,
scope: [name, email] }

This transaction could authorize the kiosk to charge us an unspecified amount within the next few minutes (after I checkout). The scope provided gives the kiosk an email address to mail the receipt to, and the name gives the restaurant owners a name to associate with my order.

In Denver there's a restaurant called Bird Call, and they have a kiosk that does exactly this with my credit card; I swipe it once and then it (1) recognizes me by name, so the restaurant employees know who to give my order to, (2) it emails me a receipt, and (3) it charges my card for however much I ordered when I checkout. I’ve seen several kiosks that now use credit cards for authentication in addition to charging for purchases, such as airport check-in kiosks.

Point of Sale app never progresses past the QR screen

I followed the instructions in the README

1) git clone https://github.com/solana-labs/solana-pay.git
2) cd solana-pay/point-of-sale
3) yarn install
4) yarn start
5) http://localhost:1234?recipient=caPsEFqXeu4upjqorwqhhTjmnhtob9EBUsAx7HbXpqw&label=Your+Store+Name
6) Scan QR code with Phantom iOS wallet
7) Send SOL

The SOL gets sent, I can see the transaction just fine on my phantom wallet, however, the Point of Sale app never leaves the QR code page. I am assuming it is supposed to show a spinner or a confirmation page at this point.

Thank for you for any help and apologies if I misunderstood what that PoS app is supposed to do !

[improvement] Can't read the QR Code generated by `point-of-sale`

Hello

I am unable to read any QR Code generated by the point-of-sale website. I think this is my phone's issue tho. For some reason, I can't read the QR code if it has a dark background.

image

Left = Original
Right = Tweaked by me

The left doesn't work, but, by tweaking the colors a bit (right) my phone is able to read it.

Maybe adding some kind of Dark/Light theme switcher would be helpful for those who can't read with the dark theme :))

btw, solana pay is awesome 💪🏻

[spec] Leading `+` character when parsing `amount`

@chitalian and I are working on a Rust port of the @solana/pay JavaScript SDK. Many float implementations, including the one in the Rust standard library and the BigNumber library used by the official SDK, consider a leading + to be valid when parsing numbers. We noticed that the description in the spec does not address the behavior of a leading + character. For reference, it looks like the official SDK happens to forbid a leading +, although it's unclear from the code whether or not it's intentional. Forbidding a leading + feels like the correct choice, but it would be great to have that clarified in the spec.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.