UNPKG

@notifi-network/notifi-react-wallet-target-plugin

Version:

The Wallet Target Plugin context provider for @notifi-network/notifi-react

1 lines 17.6 kB
{"version":3,"sources":["../lib/context/NotifiWalletTargetContext.tsx","../lib/hooks/useXmtp.ts","../lib/utils/xmtp.ts","../lib/utils/signature.ts","../lib/context/NotifiContextProviderWithWalletTargetPlugin.tsx","../../notifi-react/lib/context/GlobalStateContext.tsx"],"sourcesContent":["import {\n NotifiFrontendClient,\n WalletWithSignParams,\n} from '@notifi-network/notifi-frontend-client';\nimport { Types } from '@notifi-network/notifi-graphql';\nimport React, { FC } from 'react';\n\nimport { useXmpt } from '../hooks';\n\nexport type SignCoinbaseSignature = (\n frontendClient: NotifiFrontendClient,\n web3TargetId: Types.Web3Target['id'],\n senderAddress: string,\n) => Promise<Types.Web3TargetFragmentFragment | undefined>;\n\nexport type NotifiWalletTargetContextType = {\n isLoading: boolean;\n error: Error | null;\n signCoinbaseSignature: SignCoinbaseSignature;\n};\n\nconst NotifiWalletTargetContext =\n React.createContext<NotifiWalletTargetContextType>({\n isLoading: false,\n error: null,\n signCoinbaseSignature: async () => {\n console.error(\n 'NotifiWalletTargetProvider: ERROR - signCoinbaseSignature not implemented',\n );\n return undefined;\n },\n });\n\nexport type NotifiWalletTargetProviderProps = {\n walletWithSignParams: WalletWithSignParams;\n};\n\nexport const NotifiWalletTargetContextProvider: FC<\n React.PropsWithChildren<NotifiWalletTargetProviderProps>\n> = ({ children, walletWithSignParams }) => {\n const contextValue: NotifiWalletTargetContextType = useXmpt({\n walletWithSignParams,\n });\n\n return (\n <NotifiWalletTargetContext.Provider value={contextValue}>\n {children}\n </NotifiWalletTargetContext.Provider>\n );\n};\n\nexport const useWalletTargetContext = () =>\n React.useContext(NotifiWalletTargetContext);\n","import {\n NotifiFrontendClient,\n isUsingEvmBlockchain,\n} from '@notifi-network/notifi-frontend-client';\nimport { Types } from '@notifi-network/notifi-graphql';\nimport { useClient } from '@xmtp/react-sdk';\nimport React from 'react';\n\nimport { NotifiWalletTargetProviderProps } from '../context';\nimport {\n createCoinbaseNonce,\n getMessage,\n reformatSignature,\n subscribeCoinbaseMessaging,\n} from '../utils';\n\nexport type UseXmptInput = NotifiWalletTargetProviderProps;\n\nexport const useXmpt = (input: UseXmptInput) => {\n const { walletWithSignParams } = input;\n const [isLoading, setIsLoading] = React.useState(false);\n const [error, setError] = React.useState<Error | null>(null);\n const authMethod =\n walletWithSignParams.walletBlockchain === 'OFF_CHAIN'\n ? walletWithSignParams.signIn\n : walletWithSignParams.signMessage;\n const xmtp = useClient();\n\n const getSignature = React.useCallback(\n async (message: Uint8Array | string) => {\n if (walletWithSignParams.walletBlockchain === 'OFF_CHAIN') {\n setError(Error('.getSignature: ERROR - OFF_CHAIN is not supported'));\n return '.getSignature: ERROR - OFF_CHAIN is not supported';\n }\n\n let signature: Uint8Array | string = '';\n\n if (typeof message === 'string') {\n const encoder = new TextEncoder();\n message = encoder.encode(message);\n }\n\n if (isUsingEvmBlockchain(walletWithSignParams)) {\n signature = await walletWithSignParams.signMessage(message);\n } else {\n setError(Error('.getSignature: ERROR - This chain is not supported'));\n console.error('.getSignature: ERROR - This chain is not supported');\n }\n return reformatSignature(signature);\n },\n [authMethod],\n );\n\n const xmtpXip42Impl = React.useCallback(\n async (senderAddress: string) => {\n if (walletWithSignParams.walletBlockchain === 'OFF_CHAIN') {\n setError(Error('.getSignature: ERROR - OFF_CHAIN is not supported'));\n return '.getSignature: ERROR - OFF_CHAIN is not supported';\n }\n type XmtpInitOption = (typeof xmtp.initialize extends (a: infer U) => void\n ? U\n : never)['options'];\n\n const options: XmtpInitOption = {\n persistConversations: false,\n env: 'production',\n };\n const address = walletWithSignParams.walletPublicKey;\n\n const signer = {\n getAddress: (): Promise<string> => {\n return new Promise((resolve) => {\n resolve(address);\n });\n },\n signMessage: async (message: Uint8Array | string): Promise<string> => {\n return getSignature(message);\n },\n };\n // NOTE: 1st signature: init XMTP with user wallet (need sign every time)\n const client = await xmtp.initialize({ options, signer });\n if (!client) {\n throw Error(\n 'xmtpXip42Impl: ERROR - XMTP client is uninitialized. Please try again.',\n );\n }\n // NOTE: 2nd signature: create a new XMTP conversation with the tenant sender (will skip if ever signed before)\n const conversation =\n await client.conversations.newConversation(senderAddress);\n\n await client.contacts.allow([senderAddress]);\n\n return conversation.topic.split('/')[3];\n },\n [xmtp, getSignature],\n );\n\n const signCoinbaseSignature = React.useCallback(\n async (\n frontendClient: NotifiFrontendClient,\n web3TargetId: Types.Web3Target['id'],\n senderAddress: string,\n ): Promise<Types.Web3TargetFragmentFragment | undefined> => {\n if (walletWithSignParams.walletBlockchain === 'OFF_CHAIN') {\n setError(Error('.getSignature: ERROR - OFF_CHAIN is not supported'));\n return;\n }\n setIsLoading(true);\n try {\n const conversationTopic = await xmtpXip42Impl(senderAddress);\n if (!conversationTopic)\n throw Error('Unable to get the conversation topic');\n\n const address = walletWithSignParams.walletPublicKey;\n const nonce = await createCoinbaseNonce();\n\n const message = getMessage(address, senderAddress, nonce);\n\n // NOTE: 3rd signature: sign the notifi message above to sync with Notifi BE\n const signature = await getSignature(message);\n\n if (!signature)\n throw Error('Unable to sign the wallet. Please try again.');\n\n const payload = {\n address,\n nonce,\n signature: signature as `0x${string}`,\n isActivatedViaCb: true,\n partnerAddress: senderAddress,\n conversationTopic,\n };\n await subscribeCoinbaseMessaging(payload);\n const walletVerifyResult =\n await frontendClient.verifyXmtpTargetViaXip42({\n input: {\n web3TargetId: web3TargetId,\n accountId: address,\n conversationTopic,\n },\n });\n\n return walletVerifyResult.verifyXmtpTargetViaXip42.web3Target;\n } catch (e) {\n console.error('.signCoinbaseSignature: ERROR - ', e);\n setError(\n e instanceof Error\n ? {\n ...e,\n message: '.signCoinbaseSignature: ERROR - ' + e.message,\n }\n : Error('.signCoinbaseSignature: ERROR - please try again.'),\n );\n return;\n } finally {\n setIsLoading(false);\n }\n },\n [xmtpXip42Impl],\n );\n return {\n isLoading,\n error,\n signCoinbaseSignature,\n };\n};\n","const coinbaseEndpoint = 'https://broadcast.coinbase.com/api/rpc';\n\ninterface PubKey {\n readonly type: string;\n readonly value: string;\n}\ninterface StdSignature {\n readonly pub_key: PubKey;\n readonly signature: string;\n}\ninterface StdSignature {\n readonly pub_key: PubKey;\n readonly signature: string;\n}\n\nexport type SubscribeMessageType = {\n address: string;\n isActivatedViaCb: boolean;\n nonce: string;\n partnerAddress: string;\n signature: `0x${string}` | StdSignature;\n conversationTopic: string;\n};\n\nexport const createCoinbaseNonce = async () => {\n const { result } = await fetch(`${coinbaseEndpoint}/createNonce`, {\n method: 'POST',\n }).then((v) => v.json());\n\n return result?.nonce as string;\n};\n\nexport const subscribeCoinbaseMessaging = async (\n payload: SubscribeMessageType,\n) => {\n const response = await fetch(`${coinbaseEndpoint}/messaging/subscribe`, {\n method: 'POST',\n body: JSON.stringify(payload),\n headers: {\n 'Content-Type': 'text/plain',\n },\n });\n\n return await response.json();\n};\n","export const getMessage = (\n address: string,\n senderAddress: string,\n nonce: string,\n) =>\n `Coinbase Wallet Messaging subscribe\\nAddress: ${address}\\nPartner Address: ${senderAddress}\\nNonce: ${nonce}`;\n\nexport const reformatSignature = (signature: Uint8Array | string) => {\n if (!signature) return '';\n\n let hexString = '0x';\n\n Object.values(signature).forEach(\n (v) => (hexString += v.toString(16).padStart(2, '0')),\n );\n\n return hexString;\n};\n","import {\n NotifiContextProviderProps,\n NotifiFrontendClientContextProvider,\n NotifiHistoryContextProvider,\n NotifiTargetContextProvider,\n NotifiTenantConfigContextProvider,\n NotifiTopicContextProvider,\n NotifiUserSettingContextProvider,\n} from '@notifi-network/notifi-react';\n\n/** NOTE: ⬇ Internal context, only available within notifi-sdk-ts workspace */\nimport { GlobalStateContextProvider } from 'notifi-react/lib/context/GlobalStateContext';\nimport React, { FC, PropsWithChildren } from 'react';\n\nimport { useXmpt } from '../hooks';\n\nexport type NotifiContextProviderWithWalletTargetPluginProps =\n NotifiContextProviderProps;\n\nexport const NotifiContextProviderWithWalletTargetPlugin: FC<\n PropsWithChildren<NotifiContextProviderProps>\n> = ({ children, ...params }) => {\n const {\n tenantId,\n env,\n storageOption,\n isEnabledLoginViaTransaction,\n ...walletWithSignParams\n } = params;\n const contextValue = useXmpt({\n walletWithSignParams,\n });\n return (\n <NotifiFrontendClientContextProvider {...params}>\n <NotifiTenantConfigContextProvider\n cardId={params.cardId}\n inputs={params.inputs}\n >\n <NotifiTargetContextProvider\n toggleTargetAvailability={params.toggleTargetAvailability}\n plugin={{ walletTarget: contextValue }}\n >\n <NotifiTopicContextProvider>\n <NotifiHistoryContextProvider\n notificationCountPerPage={params.notificationCountPerPage}\n unreadCountScope={params.unreadCountScope}\n >\n <NotifiUserSettingContextProvider>\n <GlobalStateContextProvider>\n {children}\n </GlobalStateContextProvider>\n </NotifiUserSettingContextProvider>\n </NotifiHistoryContextProvider>\n </NotifiTopicContextProvider>\n </NotifiTargetContextProvider>\n </NotifiTenantConfigContextProvider>\n </NotifiFrontendClientContextProvider>\n );\n};\n","import React, {\n Dispatch,\n FC,\n PropsWithChildren,\n SetStateAction,\n createContext,\n useContext,\n useState,\n} from 'react';\n\nexport type GlobalLoading = {\n isLoading: boolean;\n loadingData?: string; // Allowing to pass custom string data to be parsed by JSON.parse\n};\n\nexport type GlobalError = {\n error: Error;\n errorData?: string; // Allowing to pass custom string data to be parsed by JSON.parse\n};\n\nexport type Cta = 'onClose';\n\nexport type GlobalCtas = Record<Cta, () => void>;\n\nexport type GlobalStateContextType = {\n globalLoading: GlobalLoading;\n setGlobalLoading: Dispatch<SetStateAction<GlobalLoading>>;\n globalError: GlobalError | null;\n setGlobalError: Dispatch<SetStateAction<GlobalError | null>>;\n globalCtas: GlobalCtas | null;\n setGlobalCtas: Dispatch<SetStateAction<GlobalCtas | null>>;\n};\n\nconst GlobalStateContext = createContext<GlobalStateContextType>({\n globalLoading: { isLoading: false },\n setGlobalLoading: () => undefined,\n globalError: null,\n setGlobalError: () => undefined,\n globalCtas: null,\n setGlobalCtas: () => undefined,\n});\n\nexport const GlobalStateContextProvider: FC<PropsWithChildren> = ({\n children,\n}) => {\n const [globalLoading, setGlobalLoading] = useState<GlobalLoading>({\n isLoading: false,\n });\n\n const [globalError, setGlobalError] = useState<GlobalError | null>(null);\n\n const [globalCtas, setGlobalCtas] = useState<GlobalCtas | null>(null);\n\n return (\n <GlobalStateContext.Provider\n value={{\n globalLoading,\n setGlobalLoading,\n globalError,\n setGlobalError,\n globalCtas,\n setGlobalCtas,\n }}\n >\n {children}\n </GlobalStateContext.Provider>\n );\n};\n\nexport const useGlobalStateContext = () => useContext(GlobalStateContext);\n"],"mappings":";AAKA,OAAOA,YAAmB;;;ACL1B;AAAA,EAEE;AAAA,OACK;AAEP,SAAS,iBAAiB;AAC1B,OAAO,WAAW;;;ACNlB,IAAM,mBAAmB;AAwBlB,IAAM,sBAAsB,YAAY;AAC7C,QAAM,EAAE,OAAO,IAAI,MAAM,MAAM,GAAG,gBAAgB,gBAAgB;AAAA,IAChE,QAAQ;AAAA,EACV,CAAC,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC;AAEvB,SAAO,QAAQ;AACjB;AAEO,IAAM,6BAA6B,OACxC,YACG;AACH,QAAM,WAAW,MAAM,MAAM,GAAG,gBAAgB,wBAAwB;AAAA,IACtE,QAAQ;AAAA,IACR,MAAM,KAAK,UAAU,OAAO;AAAA,IAC5B,SAAS;AAAA,MACP,gBAAgB;AAAA,IAClB;AAAA,EACF,CAAC;AAED,SAAO,MAAM,SAAS,KAAK;AAC7B;;;AC5CO,IAAM,aAAa,CACxB,SACA,eACA,UAEA;AAAA,WAAiD,OAAO;AAAA,mBAAsB,aAAa;AAAA,SAAY,KAAK;AAEvG,IAAM,oBAAoB,CAAC,cAAmC;AACnE,MAAI,CAAC,UAAW,QAAO;AAEvB,MAAI,YAAY;AAEhB,SAAO,OAAO,SAAS,EAAE;AAAA,IACvB,CAAC,MAAO,aAAa,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AAAA,EACrD;AAEA,SAAO;AACT;;;AFCO,IAAM,UAAU,CAAC,UAAwB;AAC9C,QAAM,EAAE,qBAAqB,IAAI;AACjC,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAAS,KAAK;AACtD,QAAM,CAAC,OAAO,QAAQ,IAAI,MAAM,SAAuB,IAAI;AAC3D,QAAM,aACJ,qBAAqB,qBAAqB,cACtC,qBAAqB,SACrB,qBAAqB;AAC3B,QAAM,OAAO,UAAU;AAEvB,QAAM,eAAe,MAAM;AAAA,IACzB,OAAO,YAAiC;AACtC,UAAI,qBAAqB,qBAAqB,aAAa;AACzD,iBAAS,MAAM,mDAAmD,CAAC;AACnE,eAAO;AAAA,MACT;AAEA,UAAI,YAAiC;AAErC,UAAI,OAAO,YAAY,UAAU;AAC/B,cAAM,UAAU,IAAI,YAAY;AAChC,kBAAU,QAAQ,OAAO,OAAO;AAAA,MAClC;AAEA,UAAI,qBAAqB,oBAAoB,GAAG;AAC9C,oBAAY,MAAM,qBAAqB,YAAY,OAAO;AAAA,MAC5D,OAAO;AACL,iBAAS,MAAM,oDAAoD,CAAC;AACpE,gBAAQ,MAAM,oDAAoD;AAAA,MACpE;AACA,aAAO,kBAAkB,SAAS;AAAA,IACpC;AAAA,IACA,CAAC,UAAU;AAAA,EACb;AAEA,QAAM,gBAAgB,MAAM;AAAA,IAC1B,OAAO,kBAA0B;AAC/B,UAAI,qBAAqB,qBAAqB,aAAa;AACzD,iBAAS,MAAM,mDAAmD,CAAC;AACnE,eAAO;AAAA,MACT;AAKA,YAAM,UAA0B;AAAA,QAC9B,sBAAsB;AAAA,QACtB,KAAK;AAAA,MACP;AACA,YAAM,UAAU,qBAAqB;AAErC,YAAM,SAAS;AAAA,QACb,YAAY,MAAuB;AACjC,iBAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,oBAAQ,OAAO;AAAA,UACjB,CAAC;AAAA,QACH;AAAA,QACA,aAAa,OAAO,YAAkD;AACpE,iBAAO,aAAa,OAAO;AAAA,QAC7B;AAAA,MACF;AAEA,YAAM,SAAS,MAAM,KAAK,WAAW,EAAE,SAAS,OAAO,CAAC;AACxD,UAAI,CAAC,QAAQ;AACX,cAAM;AAAA,UACJ;AAAA,QACF;AAAA,MACF;AAEA,YAAM,eACJ,MAAM,OAAO,cAAc,gBAAgB,aAAa;AAE1D,YAAM,OAAO,SAAS,MAAM,CAAC,aAAa,CAAC;AAE3C,aAAO,aAAa,MAAM,MAAM,GAAG,EAAE,CAAC;AAAA,IACxC;AAAA,IACA,CAAC,MAAM,YAAY;AAAA,EACrB;AAEA,QAAM,wBAAwB,MAAM;AAAA,IAClC,OACE,gBACA,cACA,kBAC0D;AAC1D,UAAI,qBAAqB,qBAAqB,aAAa;AACzD,iBAAS,MAAM,mDAAmD,CAAC;AACnE;AAAA,MACF;AACA,mBAAa,IAAI;AACjB,UAAI;AACF,cAAM,oBAAoB,MAAM,cAAc,aAAa;AAC3D,YAAI,CAAC;AACH,gBAAM,MAAM,sCAAsC;AAEpD,cAAM,UAAU,qBAAqB;AACrC,cAAM,QAAQ,MAAM,oBAAoB;AAExC,cAAM,UAAU,WAAW,SAAS,eAAe,KAAK;AAGxD,cAAM,YAAY,MAAM,aAAa,OAAO;AAE5C,YAAI,CAAC;AACH,gBAAM,MAAM,8CAA8C;AAE5D,cAAM,UAAU;AAAA,UACd;AAAA,UACA;AAAA,UACA;AAAA,UACA,kBAAkB;AAAA,UAClB,gBAAgB;AAAA,UAChB;AAAA,QACF;AACA,cAAM,2BAA2B,OAAO;AACxC,cAAM,qBACJ,MAAM,eAAe,yBAAyB;AAAA,UAC5C,OAAO;AAAA,YACL;AAAA,YACA,WAAW;AAAA,YACX;AAAA,UACF;AAAA,QACF,CAAC;AAEH,eAAO,mBAAmB,yBAAyB;AAAA,MACrD,SAAS,GAAG;AACV,gBAAQ,MAAM,oCAAoC,CAAC;AACnD;AAAA,UACE,aAAa,QACT;AAAA,YACE,GAAG;AAAA,YACH,SAAS,qCAAqC,EAAE;AAAA,UAClD,IACA,MAAM,mDAAmD;AAAA,QAC/D;AACA;AAAA,MACF,UAAE;AACA,qBAAa,KAAK;AAAA,MACpB;AAAA,IACF;AAAA,IACA,CAAC,aAAa;AAAA,EAChB;AACA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;ADxHI;AAxBJ,IAAM,4BACJC,OAAM,cAA6C;AAAA,EACjD,WAAW;AAAA,EACX,OAAO;AAAA,EACP,uBAAuB,YAAY;AACjC,YAAQ;AAAA,MACN;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF,CAAC;AAMI,IAAM,oCAET,CAAC,EAAE,UAAU,qBAAqB,MAAM;AAC1C,QAAM,eAA8C,QAAQ;AAAA,IAC1D;AAAA,EACF,CAAC;AAED,SACE,oBAAC,0BAA0B,UAA1B,EAAmC,OAAO,cACxC,UACH;AAEJ;AAEO,IAAM,yBAAyB,MACpCA,OAAM,WAAW,yBAAyB;;;AIpD5C;AAAA,EAEE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;ACRP;AAAA,EAKE;AAAA,EACA;AAAA,EACA;AAAA,OACK;AA8CH,gBAAAC,YAAA;AArBJ,IAAM,qBAAqB,cAAsC;AAAA,EAC/D,eAAe,EAAE,WAAW,MAAM;AAAA,EAClC,kBAAkB,MAAM;AAAA,EACxB,aAAa;AAAA,EACb,gBAAgB,MAAM;AAAA,EACtB,YAAY;AAAA,EACZ,eAAe,MAAM;AACvB,CAAC;AAEM,IAAM,6BAAoD,CAAC;AAAA,EAChE;AACF,MAAM;AACJ,QAAM,CAAC,eAAe,gBAAgB,IAAI,SAAwB;AAAA,IAChE,WAAW;AAAA,EACb,CAAC;AAED,QAAM,CAAC,aAAa,cAAc,IAAI,SAA6B,IAAI;AAEvE,QAAM,CAAC,YAAY,aAAa,IAAI,SAA4B,IAAI;AAEpE,SACE,gBAAAA;AAAA,IAAC,mBAAmB;AAAA,IAAnB;AAAA,MACC,OAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;;;ADnBgB,gBAAAC,YAAA;AA7BT,IAAM,8CAET,CAAC,EAAE,UAAU,GAAG,OAAO,MAAM;AAC/B,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACL,IAAI;AACJ,QAAM,eAAe,QAAQ;AAAA,IAC3B;AAAA,EACF,CAAC;AACD,SACE,gBAAAA,KAAC,uCAAqC,GAAG,QACvC,0BAAAA;AAAA,IAAC;AAAA;AAAA,MACC,QAAQ,OAAO;AAAA,MACf,QAAQ,OAAO;AAAA,MAEf,0BAAAA;AAAA,QAAC;AAAA;AAAA,UACC,0BAA0B,OAAO;AAAA,UACjC,QAAQ,EAAE,cAAc,aAAa;AAAA,UAErC,0BAAAA,KAAC,8BACC,0BAAAA;AAAA,YAAC;AAAA;AAAA,cACC,0BAA0B,OAAO;AAAA,cACjC,kBAAkB,OAAO;AAAA,cAEzB,0BAAAA,KAAC,oCACC,0BAAAA,KAAC,8BACE,UACH,GACF;AAAA;AAAA,UACF,GACF;AAAA;AAAA,MACF;AAAA;AAAA,EACF,GACF;AAEJ;","names":["React","React","jsx","jsx"]}