-
Notifications
You must be signed in to change notification settings - Fork 131
[PAY-3386] Implement mobile pay with anything #9674
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,8 +9,10 @@ import { | |
| TransactionMessage | ||
| } from '@solana/web3.js' | ||
| import BN from 'bn.js' | ||
| import bs58 from 'bs58' | ||
| import { sumBy } from 'lodash' | ||
| import { takeLatest } from 'redux-saga/effects' | ||
| import nacl, { BoxKeyPair } from 'tweetnacl' | ||
| import { call, put, race, select, take } from 'typed-redux-saga' | ||
|
|
||
| import { userTrackMetadataFromSDK } from '~/adapters' | ||
|
|
@@ -66,6 +68,7 @@ import { | |
| CoinflowPurchaseMetadata, | ||
| coinflowOnrampModalActions | ||
| } from '~/store/ui/modals/coinflow-onramp-modal' | ||
| import { waitForValue } from '~/utils' | ||
| import { encodeHashId } from '~/utils/hashIds' | ||
| import { BN_USDC_CENT_WEI } from '~/utils/wallet' | ||
|
|
||
|
|
@@ -111,6 +114,23 @@ type GetPurchaseConfigArgs = { | |
| contentType: PurchaseableContentType | ||
| } | ||
|
|
||
| const serializeKeyPair = (value: BoxKeyPair) => { | ||
| const { publicKey, secretKey } = value | ||
| const encodedKeyPair = { | ||
| publicKey: bs58.encode(publicKey), | ||
| secretKey: bs58.encode(secretKey) | ||
| } | ||
| return JSON.stringify(encodedKeyPair) | ||
| } | ||
|
|
||
| const deserializeKeyPair = (value: string): BoxKeyPair => { | ||
| const { publicKey, secretKey } = JSON.parse(value) | ||
| return { | ||
| publicKey: bs58.decode(publicKey), | ||
| secretKey: bs58.decode(secretKey) | ||
| } | ||
| } | ||
|
|
||
| function* getContentInfo({ contentId, contentType }: GetPurchaseConfigArgs) { | ||
| const metadata = | ||
| contentType === PurchaseableContentType.ALBUM | ||
|
|
@@ -911,12 +931,30 @@ function* purchaseWithAnything({ | |
| throw new Error('Failed to fetch USDC user bank token account info') | ||
| } | ||
|
|
||
| // Get the solana wallet provider | ||
| const provider = window.solana | ||
| if (!provider) { | ||
| throw new Error('No solana provider / wallet found') | ||
| let sourceWallet: PublicKey | ||
|
|
||
| const isNativeMobile = yield* getContext('isNativeMobile') | ||
| const mobileWalletActions = yield* getContext('mobileWalletActions') | ||
| if (isNativeMobile && mobileWalletActions) { | ||
| const { connect } = mobileWalletActions | ||
| const getWalletConnectPublicKey = (state: any) => | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the first gross thing -- common needs to reach into mobile store here. ew. |
||
| state.walletConnect.publicKey | ||
| const dappKeyPair = nacl.box.keyPair() | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should create this and persist it via redux-persist, so you only have to "connect" once
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this can be a follow up |
||
| yield* put({ | ||
| type: 'walletConnect/setDappKeyPair', | ||
| payload: { dappKeyPair: serializeKeyPair(dappKeyPair) } | ||
| }) | ||
| yield* call(connect, dappKeyPair) | ||
| yield* call(waitForValue, getWalletConnectPublicKey) | ||
| sourceWallet = new PublicKey(yield* select(getWalletConnectPublicKey)) | ||
| } else { | ||
| // Get the solana wallet provider | ||
| const provider = window.solana | ||
| if (!provider) { | ||
| throw new Error('No solana provider / wallet found') | ||
| } | ||
| sourceWallet = (yield* call(provider.connect)).publicKey | ||
| } | ||
| const sourceWallet = yield* call(provider.connect) | ||
|
|
||
| let transaction: VersionedTransaction | ||
| if (inputMint === TOKEN_LISTING_MAP.USDC.address) { | ||
|
|
@@ -926,15 +964,15 @@ function* purchaseWithAnything({ | |
| sdk.services.paymentRouterClient.createTransferInstruction | ||
| ], | ||
| { | ||
| sourceWallet: sourceWallet.publicKey, | ||
| sourceWallet, | ||
| total: totalAmountWithDecimals, | ||
| mint: 'USDC' | ||
| } | ||
| ) | ||
| transaction = yield* call( | ||
| [sdk.services.solanaClient, sdk.services.solanaClient.buildTransaction], | ||
| { | ||
| feePayer: sourceWallet.publicKey, | ||
| feePayer: sourceWallet, | ||
| instructions: [instruction] | ||
| } | ||
| ) | ||
|
|
@@ -950,7 +988,7 @@ function* purchaseWithAnything({ | |
| ) | ||
| const externalTokenAccountPublicKey = getAssociatedTokenAddressSync( | ||
| new PublicKey(inputMint), | ||
| sourceWallet.publicKey | ||
| sourceWallet | ||
| ) | ||
|
|
||
| console.info('Calling jupiter API to get a quote') | ||
|
|
@@ -984,7 +1022,7 @@ function* purchaseWithAnything({ | |
| if (inputMint === TOKEN_LISTING_MAP.SOL.address) { | ||
| const amount = yield* call( | ||
| [connection, connection.getBalance], | ||
| sourceWallet.publicKey | ||
| sourceWallet | ||
| ) | ||
| hasEnoughTokens = amount >= BigInt(quote.inAmount) | ||
| } | ||
|
|
@@ -1000,7 +1038,7 @@ function* purchaseWithAnything({ | |
| const { swapTransaction } = yield* call([jup, jup.swapPost], { | ||
| swapRequest: { | ||
| quoteResponse: quote, | ||
| userPublicKey: sourceWallet.publicKey.toString(), | ||
| userPublicKey: sourceWallet.toString(), | ||
| destinationTokenAccount: paymentRouterTokenAccount.address.toString() | ||
| } | ||
| }) | ||
|
|
@@ -1076,7 +1114,25 @@ function* purchaseWithAnything({ | |
| transaction.message = message.compileToV0Message(addressLookupTableAccounts) | ||
|
|
||
| // Execute the swap by signing and sending the transaction | ||
| return yield* call([provider, provider.signAndSendTransaction], transaction) | ||
| if (isNativeMobile && mobileWalletActions) { | ||
| const { signAndSendTransaction } = mobileWalletActions | ||
| const getWalletConnectState = (state: any) => state.walletConnect | ||
| const { dappKeyPair, sharedSecret, session } = yield* select( | ||
| getWalletConnectState | ||
| ) | ||
| return yield* call(signAndSendTransaction, { | ||
| transaction, | ||
| dappKeyPair: deserializeKeyPair(dappKeyPair), | ||
| sharedSecret: new Uint8Array(bs58.decode(sharedSecret)), | ||
| session | ||
| }) | ||
| } else { | ||
| const provider = window.solana | ||
| return yield* call( | ||
| [provider, provider.signAndSendTransaction], | ||
| transaction | ||
| ) | ||
| } | ||
| } catch (e) { | ||
| console.error(`handlePayWithAnything | Error: ${e}`) | ||
| throw e | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this code is avail in mobile, put it into common util