@tuwaio/payments-sdk 0.0.0-stage → 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +76 -2
  3. package/dist/OwnConnection-ET76SUMX-4JFMOO7Z.cjs +1 -0
  4. package/dist/OwnConnection-ET76SUMX-G7ZHJN57.js +1 -0
  5. package/dist/checkout-C05-kSiE.d.cts +1616 -0
  6. package/dist/checkout-C05-kSiE.d.ts +1616 -0
  7. package/dist/checkout.cjs +1 -0
  8. package/dist/checkout.d.cts +2 -0
  9. package/dist/checkout.d.ts +2 -0
  10. package/dist/checkout.js +1 -0
  11. package/dist/chunk-LB2KDA4M.js +2 -0
  12. package/dist/chunk-MJOZIUWN.cjs +1 -0
  13. package/dist/chunk-NQ26UU24.cjs +1 -0
  14. package/dist/chunk-TN5VGRRA.cjs +2 -0
  15. package/dist/chunk-UJ2TJGKY.js +1 -0
  16. package/dist/chunk-VTOKR3DS.js +1 -0
  17. package/dist/de-53SSE6O2-GWJEBBVJ.js +1 -0
  18. package/dist/de-53SSE6O2-SX2QT2XZ.cjs +1 -0
  19. package/dist/es-LP3HJ4KB-7RFRVGPQ.cjs +1 -0
  20. package/dist/es-LP3HJ4KB-JN7LQABB.js +1 -0
  21. package/dist/evm.cjs +1 -0
  22. package/dist/evm.d.cts +34 -0
  23. package/dist/evm.d.ts +34 -0
  24. package/dist/evm.js +1 -0
  25. package/dist/i18n.cjs +1 -0
  26. package/dist/i18n.d.cts +10 -0
  27. package/dist/i18n.d.ts +10 -0
  28. package/dist/i18n.js +1 -0
  29. package/dist/index.cjs +2 -0
  30. package/dist/index.d.cts +2979 -0
  31. package/dist/index.d.ts +2979 -0
  32. package/dist/index.js +2 -0
  33. package/dist/it-JJ5Z5EUF-2BNC5I2D.cjs +1 -0
  34. package/dist/it-JJ5Z5EUF-HOA77BWJ.js +1 -0
  35. package/dist/locales-DzMinYsr.d-DzMinYsr.d.cts +1221 -0
  36. package/dist/locales-DzMinYsr.d-DzMinYsr.d.ts +1221 -0
  37. package/dist/solana.cjs +1 -0
  38. package/dist/solana.d.cts +42 -0
  39. package/dist/solana.d.ts +42 -0
  40. package/dist/solana.js +1 -0
  41. package/dist/styles.css +1324 -0
  42. package/dist/types-Bp6JUt56.d-ByIsb1F7.d.cts +350 -0
  43. package/dist/types-Bp6JUt56.d-C5vQkYhR.d.ts +350 -0
  44. package/dist/uk-EI4N5BMM-5PL2AYKV.js +1 -0
  45. package/dist/uk-EI4N5BMM-UN76BFNO.cjs +1 -0
  46. package/dist/zhCN-BZBMKUUA-E7M3WG4Q.js +1 -0
  47. package/dist/zhCN-BZBMKUUA-VSNNE3YC.cjs +1 -0
  48. package/package.json +136 -3
  49. package/socket.json +17 -0
@@ -0,0 +1 @@
1
+ 'use strict';var chunkMJOZIUWN_cjs=require('./chunk-MJOZIUWN.cjs'),kit=require('@solana/kit'),system=require('@solana-program/system'),token=require('@solana-program/token'),orbitCore=require('@tuwaio/sdk/orbit'),orbitSolana=require('@tuwaio/solana-sdk/orbit'),pulsarCore=require('@tuwaio/sdk/pulsar');var I=kit.address("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"),S=5000n,W=165n;function y(r){if(r.family!=="solana")throw new Error(`${r.chainId} is not a Solana chain`);return r}function w(r){if(!r.startsWith("solana:"))throw new Error(`${r} is not a Solana chain`);return orbitSolana.getCluster({cluster:r})}var q=/blockhash ?not ?found/i;function Q(r){let s=new Set;for(let d=r;typeof d=="object"&&d!==null&&!s.has(d);){if(s.add(d),kit.isSolanaError(d,kit.SOLANA_ERROR__TRANSACTION_ERROR__BLOCKHASH_NOT_FOUND))return true;let{message:f,cause:g}=d;if(typeof f=="string"&&q.test(f))return true;d=g;}return false}var O=(r,s)=>s?{...r,accounts:[...r.accounts??[],{address:kit.address(s),role:kit.AccountRole.READONLY}]}:r;function ee({rpcUrls:r}={}){let s=e=>orbitSolana.createSolanaClientWithCache({rpcUrlOrMoniker:w(e),rpcUrls:r}).rpc,d=async(e,t)=>{let{value:a}=await s(e).getAccountInfo(t,{encoding:"jsonParsed"}).send();if(!a)throw new Error(`${t} is not a token mint`);if(a.owner===token.TOKEN_PROGRAM_ADDRESS)return token.TOKEN_PROGRAM_ADDRESS;if(a.owner!==I)throw new Error(`${t} is not a token mint`);if(a.data.parsed?.info?.extensions?.find(n=>n.extension==="transferHook")?.state?.programId)throw new chunkMJOZIUWN_cjs.a("unsupported","A token with a transfer hook is paid with the QR code");return I},f=async e=>{let t=kit.address(e.token),a=await d(e.chainId,t),[n]=await token.findAssociatedTokenPda({owner:kit.address(e.to),mint:t,tokenProgram:a});return {mint:t,tokenProgram:a,account:n}},g=async(e,t)=>{let a=BigInt(e.amount);if(e.token==="native"){let o=system.getTransferSolInstruction({source:t,destination:kit.address(e.to),amount:a});return [O(o,e.reference)]}let{mint:n,tokenProgram:i,account:c}=await f(e),[p]=await token.findAssociatedTokenPda({owner:t.address,mint:n,tokenProgram:i}),u=token.getCreateAssociatedTokenIdempotentInstruction({payer:t,ata:c,owner:kit.address(e.to),mint:n,tokenProgram:i}),m=token.getTransferCheckedInstruction({source:p,mint:n,destination:c,authority:t,amount:a,decimals:e.decimals},{programAddress:i});return [u,O(m,e.reference)]};return {family:"solana",getBalance:async({chainId:e,account:t,token:a})=>{let n=s(e);if(a==="native")return (await n.getBalance(kit.address(t)).send()).value;let i=kit.address(a),{value:c}=await n.getTokenAccountsByOwner(kit.address(t),{mint:i},{encoding:"jsonParsed"}).send(),p=await d(e,i),[u]=await token.findAssociatedTokenPda({owner:kit.address(t),mint:i,tokenProgram:p}),m=c.find(o=>o.pubkey===u);return BigInt(m?.account.data.parsed.info.tokenAmount.amount??0)},estimateFee:async({instructions:e})=>{let t=y(e);if(t.token==="native")return {amount:S,decimals:9,symbol:"SOL"};let{account:a}=await f(t),n=s(t.chainId),{value:i}=await n.getAccountInfo(a,{encoding:"base64"}).send(),c=i?0n:await n.getMinimumBalanceForRentExemption(W).send();return {amount:S+c,decimals:9,symbol:"SOL"}},sendTransfer:async({instructions:e,account:t,connection:a})=>{let n=y(e),i=a?.connectedAccount;if(!i||i.address!==t)throw new chunkMJOZIUWN_cjs.a("unsupported","No connected Solana account to sign with");let c;try{c=orbitSolana.createSolanaTransactionSendingSigner(i,w(n.chainId));}catch(o){throw new chunkMJOZIUWN_cjs.a("unsupported","The wallet cannot send this transaction",{cause:o})}let p=await g(n,c),{value:u}=await s(n.chainId).getLatestBlockhash({commitment:"confirmed"}).send(),m=kit.pipe(kit.createTransactionMessage({version:0}),o=>kit.setTransactionMessageFeePayerSigner(c,o),o=>kit.setTransactionMessageLifetimeUsingBlockhash(u,o),o=>kit.appendTransactionMessageInstructions(p,o));try{return kit.getBase58Decoder().decode(await kit.signAndSendTransactionMessageWithSigners(m))}catch(o){throw Q(o)?await s(n.chainId).isBlockhashValid(u.blockhash,{commitment:"confirmed"}).send().then(({value:E})=>E).catch(()=>true)?new chunkMJOZIUWN_cjs.a("wrongNetwork",`The wallet is not on ${n.chainId}`,{cause:o}):new chunkMJOZIUWN_cjs.a("failed","The transaction expired in the wallet",{cause:o}):o}},explorerUrl:({chainId:e,txKey:t})=>orbitSolana.getSolanaExplorerLink(`/tx/${t}`,w(e)),explorerAddressUrl:({chainId:e,address:t})=>orbitSolana.getSolanaExplorerLink(`/address/${t}`,w(e)),pulsarTransaction:({txKey:e,instructions:t,account:a,connectorType:n,title:i,description:c,payload:p})=>{let u=y(t),m=r?.[w(u.chainId)];return {adapter:orbitCore.OrbitAdapter.SOLANA,tracker:pulsarCore.TransactionTracker.Solana,txKey:e,chainId:u.chainId,...m?{rpcUrl:m}:{},from:a,type:"payment",connectorType:n,title:i,description:c,payload:p,pending:true,localTimestamp:Math.floor(Date.now()/1e3),isTrackedModalOpen:false}}}}exports.paymentsSolanaAdapter=ee;
@@ -0,0 +1,42 @@
1
+ import { SolanaClusterMoniker } from '@tuwaio/solana-sdk/orbit';
2
+ import { PaymentsAdapter } from './index.cjs';
3
+ import '@tuwaio/sdk/pulsar';
4
+ import './checkout-C05-kSiE.cjs';
5
+ import 'zustand/vanilla';
6
+
7
+ /** Options of {@link paymentsSolanaAdapter}. */
8
+ interface PaymentsSolanaAdapterOptions {
9
+ /** RPC URLs by cluster (`devnet`, `mainnet`…); the public endpoint of a cluster without one. */
10
+ rpcUrls?: Partial<Record<SolanaClusterMoniker, string>>;
11
+ }
12
+ /**
13
+ * The adapter that pays Solana methods of a Nova Payments checkout from the Wallet Standard wallet connected through
14
+ * Satellite Connect. It reads balances and estimates fees on the network, and sends SOL with a system transfer or a
15
+ * token with `transferChecked` to the merchant's associated token account (created when missing), in the token's own
16
+ * program (Token or Token-2022), with the Solana Pay reference key of the quote (a refund has none). A Token-2022
17
+ * mint with a transfer hook is refused: a Solana Pay wallet pays it with the QR code. A transfer the network refuses
18
+ * for an unknown blockhash, because the wallet sent it on another cluster (Solana wallets choose their network
19
+ * themselves), throws `PaymentWalletError` with the kind `wrongNetwork`: nothing was paid. Pass it in `adapters` of
20
+ * `NovaPaymentsProvider`.
21
+ *
22
+ * Side effects: RPC reads (the URLs of `rpcUrls`, else the public endpoints of the clusters); wallet prompts.
23
+ *
24
+ * @param options - See {@link PaymentsSolanaAdapterOptions}.
25
+ * @returns The Solana adapter.
26
+ *
27
+ * @example
28
+ * ```tsx
29
+ * import { NovaPaymentsProvider } from '@tuwaio/payments-sdk';
30
+ * import { paymentsSolanaAdapter } from '@tuwaio/payments-sdk/solana';
31
+ *
32
+ * const adapters = [paymentsSolanaAdapter({ rpcUrls: { devnet: 'https://api.devnet.solana.com' } })];
33
+ *
34
+ * export function Payments({ children }: { children: React.ReactNode }) {
35
+ * return <NovaPaymentsProvider adapters={adapters}>{children}</NovaPaymentsProvider>;
36
+ * }
37
+ * ```
38
+ */
39
+ declare function paymentsSolanaAdapter({ rpcUrls }?: PaymentsSolanaAdapterOptions): PaymentsAdapter;
40
+
41
+ export { paymentsSolanaAdapter };
42
+ export type { PaymentsSolanaAdapterOptions };
@@ -0,0 +1,42 @@
1
+ import { SolanaClusterMoniker } from '@tuwaio/solana-sdk/orbit';
2
+ import { PaymentsAdapter } from './index.js';
3
+ import '@tuwaio/sdk/pulsar';
4
+ import './checkout-C05-kSiE.js';
5
+ import 'zustand/vanilla';
6
+
7
+ /** Options of {@link paymentsSolanaAdapter}. */
8
+ interface PaymentsSolanaAdapterOptions {
9
+ /** RPC URLs by cluster (`devnet`, `mainnet`…); the public endpoint of a cluster without one. */
10
+ rpcUrls?: Partial<Record<SolanaClusterMoniker, string>>;
11
+ }
12
+ /**
13
+ * The adapter that pays Solana methods of a Nova Payments checkout from the Wallet Standard wallet connected through
14
+ * Satellite Connect. It reads balances and estimates fees on the network, and sends SOL with a system transfer or a
15
+ * token with `transferChecked` to the merchant's associated token account (created when missing), in the token's own
16
+ * program (Token or Token-2022), with the Solana Pay reference key of the quote (a refund has none). A Token-2022
17
+ * mint with a transfer hook is refused: a Solana Pay wallet pays it with the QR code. A transfer the network refuses
18
+ * for an unknown blockhash, because the wallet sent it on another cluster (Solana wallets choose their network
19
+ * themselves), throws `PaymentWalletError` with the kind `wrongNetwork`: nothing was paid. Pass it in `adapters` of
20
+ * `NovaPaymentsProvider`.
21
+ *
22
+ * Side effects: RPC reads (the URLs of `rpcUrls`, else the public endpoints of the clusters); wallet prompts.
23
+ *
24
+ * @param options - See {@link PaymentsSolanaAdapterOptions}.
25
+ * @returns The Solana adapter.
26
+ *
27
+ * @example
28
+ * ```tsx
29
+ * import { NovaPaymentsProvider } from '@tuwaio/payments-sdk';
30
+ * import { paymentsSolanaAdapter } from '@tuwaio/payments-sdk/solana';
31
+ *
32
+ * const adapters = [paymentsSolanaAdapter({ rpcUrls: { devnet: 'https://api.devnet.solana.com' } })];
33
+ *
34
+ * export function Payments({ children }: { children: React.ReactNode }) {
35
+ * return <NovaPaymentsProvider adapters={adapters}>{children}</NovaPaymentsProvider>;
36
+ * }
37
+ * ```
38
+ */
39
+ declare function paymentsSolanaAdapter({ rpcUrls }?: PaymentsSolanaAdapterOptions): PaymentsAdapter;
40
+
41
+ export { paymentsSolanaAdapter };
42
+ export type { PaymentsSolanaAdapterOptions };
package/dist/solana.js ADDED
@@ -0,0 +1 @@
1
+ import {a}from'./chunk-VTOKR3DS.js';import {address,pipe,createTransactionMessage,setTransactionMessageFeePayerSigner,setTransactionMessageLifetimeUsingBlockhash,appendTransactionMessageInstructions,getBase58Decoder,signAndSendTransactionMessageWithSigners,isSolanaError,SOLANA_ERROR__TRANSACTION_ERROR__BLOCKHASH_NOT_FOUND,AccountRole}from'@solana/kit';import {getTransferSolInstruction}from'@solana-program/system';import {findAssociatedTokenPda,TOKEN_PROGRAM_ADDRESS,getCreateAssociatedTokenIdempotentInstruction,getTransferCheckedInstruction}from'@solana-program/token';import {OrbitAdapter}from'@tuwaio/sdk/orbit';import {getSolanaExplorerLink,createSolanaTransactionSendingSigner,createSolanaClientWithCache,getCluster}from'@tuwaio/solana-sdk/orbit';import {TransactionTracker}from'@tuwaio/sdk/pulsar';var I=address("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"),S=5000n,W=165n;function y(r){if(r.family!=="solana")throw new Error(`${r.chainId} is not a Solana chain`);return r}function w(r){if(!r.startsWith("solana:"))throw new Error(`${r} is not a Solana chain`);return getCluster({cluster:r})}var q=/blockhash ?not ?found/i;function Q(r){let s=new Set;for(let d=r;typeof d=="object"&&d!==null&&!s.has(d);){if(s.add(d),isSolanaError(d,SOLANA_ERROR__TRANSACTION_ERROR__BLOCKHASH_NOT_FOUND))return true;let{message:f,cause:g}=d;if(typeof f=="string"&&q.test(f))return true;d=g;}return false}var O=(r,s)=>s?{...r,accounts:[...r.accounts??[],{address:address(s),role:AccountRole.READONLY}]}:r;function ee({rpcUrls:r}={}){let s=e=>createSolanaClientWithCache({rpcUrlOrMoniker:w(e),rpcUrls:r}).rpc,d=async(e,t)=>{let{value:a$1}=await s(e).getAccountInfo(t,{encoding:"jsonParsed"}).send();if(!a$1)throw new Error(`${t} is not a token mint`);if(a$1.owner===TOKEN_PROGRAM_ADDRESS)return TOKEN_PROGRAM_ADDRESS;if(a$1.owner!==I)throw new Error(`${t} is not a token mint`);if(a$1.data.parsed?.info?.extensions?.find(n=>n.extension==="transferHook")?.state?.programId)throw new a("unsupported","A token with a transfer hook is paid with the QR code");return I},f=async e=>{let t=address(e.token),a=await d(e.chainId,t),[n]=await findAssociatedTokenPda({owner:address(e.to),mint:t,tokenProgram:a});return {mint:t,tokenProgram:a,account:n}},g=async(e,t)=>{let a=BigInt(e.amount);if(e.token==="native"){let o=getTransferSolInstruction({source:t,destination:address(e.to),amount:a});return [O(o,e.reference)]}let{mint:n,tokenProgram:i,account:c}=await f(e),[p]=await findAssociatedTokenPda({owner:t.address,mint:n,tokenProgram:i}),u=getCreateAssociatedTokenIdempotentInstruction({payer:t,ata:c,owner:address(e.to),mint:n,tokenProgram:i}),m=getTransferCheckedInstruction({source:p,mint:n,destination:c,authority:t,amount:a,decimals:e.decimals},{programAddress:i});return [u,O(m,e.reference)]};return {family:"solana",getBalance:async({chainId:e,account:t,token:a})=>{let n=s(e);if(a==="native")return (await n.getBalance(address(t)).send()).value;let i=address(a),{value:c}=await n.getTokenAccountsByOwner(address(t),{mint:i},{encoding:"jsonParsed"}).send(),p=await d(e,i),[u]=await findAssociatedTokenPda({owner:address(t),mint:i,tokenProgram:p}),m=c.find(o=>o.pubkey===u);return BigInt(m?.account.data.parsed.info.tokenAmount.amount??0)},estimateFee:async({instructions:e})=>{let t=y(e);if(t.token==="native")return {amount:S,decimals:9,symbol:"SOL"};let{account:a}=await f(t),n=s(t.chainId),{value:i}=await n.getAccountInfo(a,{encoding:"base64"}).send(),c=i?0n:await n.getMinimumBalanceForRentExemption(W).send();return {amount:S+c,decimals:9,symbol:"SOL"}},sendTransfer:async({instructions:e,account:t,connection:a$1})=>{let n=y(e),i=a$1?.connectedAccount;if(!i||i.address!==t)throw new a("unsupported","No connected Solana account to sign with");let c;try{c=createSolanaTransactionSendingSigner(i,w(n.chainId));}catch(o){throw new a("unsupported","The wallet cannot send this transaction",{cause:o})}let p=await g(n,c),{value:u}=await s(n.chainId).getLatestBlockhash({commitment:"confirmed"}).send(),m=pipe(createTransactionMessage({version:0}),o=>setTransactionMessageFeePayerSigner(c,o),o=>setTransactionMessageLifetimeUsingBlockhash(u,o),o=>appendTransactionMessageInstructions(p,o));try{return getBase58Decoder().decode(await signAndSendTransactionMessageWithSigners(m))}catch(o){throw Q(o)?await s(n.chainId).isBlockhashValid(u.blockhash,{commitment:"confirmed"}).send().then(({value:E})=>E).catch(()=>true)?new a("wrongNetwork",`The wallet is not on ${n.chainId}`,{cause:o}):new a("failed","The transaction expired in the wallet",{cause:o}):o}},explorerUrl:({chainId:e,txKey:t})=>getSolanaExplorerLink(`/tx/${t}`,w(e)),explorerAddressUrl:({chainId:e,address:t})=>getSolanaExplorerLink(`/address/${t}`,w(e)),pulsarTransaction:({txKey:e,instructions:t,account:a,connectorType:n,title:i,description:c,payload:p})=>{let u=y(t),m=r?.[w(u.chainId)];return {adapter:OrbitAdapter.SOLANA,tracker:TransactionTracker.Solana,txKey:e,chainId:u.chainId,...m?{rpcUrl:m}:{},from:a,type:"payment",connectorType:n,title:i,description:c,payload:p,pending:true,localTimestamp:Math.floor(Date.now()/1e3),isTrackedModalOpen:false}}}}export{ee as paymentsSolanaAdapter};