diff --git a/packages/sdk/src/core/__mocks__/mock-social-wallet-provider.ts b/packages/sdk/src/core/__mocks__/mock-social-wallet-provider.ts new file mode 100644 index 0000000..109723b --- /dev/null +++ b/packages/sdk/src/core/__mocks__/mock-social-wallet-provider.ts @@ -0,0 +1,55 @@ +import { GnoSocialWalletProvider } from '../../providers'; +import { WalletResponseSuccessType } from '../types'; +import { GetSocialUserProfileResponse } from '../types/methods/get-social-user-profile.types'; +import { makeResponseMessage } from '../utils'; + +export const defineMockSocialWalletProvider = () => { + jest.mock('../../providers', () => ({ + GnoSOcialWalletProvider: jest.fn(() => mockSocialWalletProvider), + })); +}; + +// Mock social user profile response +export const getSocialUserProfileSuccessMock: GetSocialUserProfileResponse = { + email: 'test@example.com', + name: 'Test User', + profileImage: 'https://example.com/profile.jpg', + verifier: 'test-verifier', + verifierId: 'test-verifier-id', + typeOfLogin: 'google', + aggregateVerifier: 'test-aggregate-verifier', + idToken: 'test-id-token', + oAuthIdToken: 'test-oauth-id-token', + oAuthAccessToken: 'test-oauth-access-token', +}; + +// Create mock instance +const mockSocialWalletProvider = Object.create(GnoSocialWalletProvider.prototype); + +// Add mock implementations +Object.assign(mockSocialWalletProvider, { + isConnected: jest.fn().mockResolvedValue(makeResponseMessage(WalletResponseSuccessType.CONNECTION_SUCCESS)), + addEstablish: jest.fn().mockResolvedValue(makeResponseMessage(WalletResponseSuccessType.CONNECTION_SUCCESS)), + getAccount: jest.fn().mockResolvedValue(makeResponseMessage(WalletResponseSuccessType.GET_ACCOUNT_SUCCESS)), + getNetwork: jest.fn().mockResolvedValue(makeResponseMessage(WalletResponseSuccessType.GET_NETWORK_SUCCESS)), + switchNetwork: jest.fn().mockResolvedValue(makeResponseMessage(WalletResponseSuccessType.SWITCH_NETWORK_SUCCESS)), + addNetwork: jest.fn().mockResolvedValue(makeResponseMessage(WalletResponseSuccessType.ADD_NETWORK_SUCCESS)), + signTransaction: jest.fn().mockResolvedValue(makeResponseMessage(WalletResponseSuccessType.SIGN_SUCCESS)), + broadcastTransaction: jest.fn().mockResolvedValue(makeResponseMessage(WalletResponseSuccessType.TRANSACTION_SUCCESS)), + onChangeAccount: jest.fn().mockImplementation(() => { + return; + }), + onChangeNetwork: jest.fn().mockImplementation(() => { + return; + }), + connect: jest.fn().mockResolvedValue(true), + disconnect: jest.fn().mockResolvedValue(true), + getWallet: jest.fn().mockReturnValue(null), + setNetworks: jest.fn(), + getSocialUserProfile: jest.fn().mockResolvedValue(getSocialUserProfileSuccessMock), +}); + +export { mockSocialWalletProvider }; + +export const getSocialUserProfileFailureMock = new Error('Failed to get social user profile'); +export const getSocialUserProfileNotInitializedMock = new Error('Not initialized web3 provider.'); diff --git a/packages/sdk/src/core/__tests__/methods/get-social-user-profile.test.ts b/packages/sdk/src/core/__tests__/methods/get-social-user-profile.test.ts new file mode 100644 index 0000000..6f46efb --- /dev/null +++ b/packages/sdk/src/core/__tests__/methods/get-social-user-profile.test.ts @@ -0,0 +1,33 @@ +import { getSocialUserProfileSuccessMock, mockSocialWalletProvider } from '../../__mocks__/mock-social-wallet-provider'; +import { mockWalletProvider } from '../../__mocks__/mock-wallet-provider'; +import { getSocialUserProfile } from '../../methods/get-social-user-profile'; +import { GetSocialUserProfileResponse } from '../../types/methods/get-social-user-profile.types'; + +describe('getSocialUserProfile', () => { + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should throw error if wallet provider is not GnoSocialWalletProvider', async () => { + await expect(getSocialUserProfile(mockWalletProvider)).rejects.toThrow( + 'Wallet provider is not a GnoSocialWalletProvider' + ); + }); + + it('should call getSocialUserProfile and return the response', async () => { + const mockResponse: GetSocialUserProfileResponse = getSocialUserProfileSuccessMock; + + mockSocialWalletProvider.getSocialUserProfile.mockResolvedValue(mockResponse); + + const response = await getSocialUserProfile(mockSocialWalletProvider); + + expect(mockSocialWalletProvider.getSocialUserProfile).toHaveBeenCalled(); + expect(response).toEqual(mockResponse); + }); + + it('should throw an error if getSocialUserProfile fails', async () => { + mockSocialWalletProvider.getSocialUserProfile.mockRejectedValue(new Error('Failed to get social user profile')); + + await expect(getSocialUserProfile(mockSocialWalletProvider)).rejects.toThrow('Failed to get social user profile'); + }); +}); diff --git a/packages/sdk/src/core/methods/get-social-user-profile.ts b/packages/sdk/src/core/methods/get-social-user-profile.ts new file mode 100644 index 0000000..4a5f38e --- /dev/null +++ b/packages/sdk/src/core/methods/get-social-user-profile.ts @@ -0,0 +1,11 @@ +import { WalletProvider } from '../providers'; +import { GetSocialUserProfileResponse } from '../types/methods/get-social-user-profile.types'; +import { isGnoSocialWalletProvider } from '../utils/provider.utils'; + +export const getSocialUserProfile = async (walletProvider: WalletProvider): Promise => { + if (!isGnoSocialWalletProvider(walletProvider)) { + throw new Error('Wallet provider is not a GnoSocialWalletProvider'); + } + + return await walletProvider.getSocialUserProfile(); +}; diff --git a/packages/sdk/src/core/providers/tm2-wallet.ts b/packages/sdk/src/core/providers/tm2-wallet.ts index 3a41ee4..8edabac 100644 --- a/packages/sdk/src/core/providers/tm2-wallet.ts +++ b/packages/sdk/src/core/providers/tm2-wallet.ts @@ -1,6 +1,7 @@ import { Wallet as TM2Wallet } from '@gnolang/tm2-js-client'; import { WalletProvider } from './wallet'; import { GetNetworkResponse } from '../types/methods'; +import { GetSocialUserProfileResponse } from '../types/methods/get-social-user-profile.types'; export interface TM2WalletProvider extends WalletProvider { connect(): Promise; @@ -10,4 +11,6 @@ export interface TM2WalletProvider extends WalletProvider { getWallet(): TM2Wallet | null; getNetwork(): Promise; + + getSocialUserProfile(): Promise; } diff --git a/packages/sdk/src/core/sdk/adena-sdk.ts b/packages/sdk/src/core/sdk/adena-sdk.ts index 70cc0ab..8dca558 100644 --- a/packages/sdk/src/core/sdk/adena-sdk.ts +++ b/packages/sdk/src/core/sdk/adena-sdk.ts @@ -41,6 +41,7 @@ import { SwitchNetworkOptions, SwitchNetworkResponse, } from '../types/methods'; +import { getSocialUserProfile } from '../methods/get-social-user-profile'; const DEFAULT_ADENA_URL = 'https://www.adena.app'; @@ -193,6 +194,14 @@ export class AdenaSDK { return onChangeNetwork(this.walletProvider, options); } + /** + * For social accounts, get the profile information for the social account. + * @returns A promise that resolves to the profile information for the social account. + */ + getSocialUserProfile() { + return getSocialUserProfile(this.walletProvider); + } + public static createAdenaWallet(config?: SDKConfigure): AdenaSDK { return new AdenaSDK(new AdenaWalletProvider(), config); } diff --git a/packages/sdk/src/core/types/config.types.ts b/packages/sdk/src/core/types/config.types.ts index 54a9013..ad19625 100644 --- a/packages/sdk/src/core/types/config.types.ts +++ b/packages/sdk/src/core/types/config.types.ts @@ -13,6 +13,7 @@ interface SocialBaseConfigure { network: 'mainnet' | 'testnet'; clientId: string; addressPrefix?: string; + storageKey?: 'session' | 'local'; } export interface SocialGoogleConfigure extends SocialBaseConfigure { diff --git a/packages/sdk/src/core/types/methods/get-social-user-profile.types.ts b/packages/sdk/src/core/types/methods/get-social-user-profile.types.ts new file mode 100644 index 0000000..4d6aed1 --- /dev/null +++ b/packages/sdk/src/core/types/methods/get-social-user-profile.types.ts @@ -0,0 +1,56 @@ +export declare const LOGIN_PROVIDER: { + readonly GOOGLE: 'google'; + readonly FACEBOOK: 'facebook'; + readonly REDDIT: 'reddit'; + readonly DISCORD: 'discord'; + readonly TWITCH: 'twitch'; + readonly APPLE: 'apple'; + readonly LINE: 'line'; + readonly GITHUB: 'github'; + readonly KAKAO: 'kakao'; + readonly LINKEDIN: 'linkedin'; + readonly TWITTER: 'twitter'; + readonly WEIBO: 'weibo'; + readonly WECHAT: 'wechat'; + readonly FARCASTER: 'farcaster'; + readonly EMAIL_PASSWORDLESS: 'email_passwordless'; + readonly SMS_PASSWORDLESS: 'sms_passwordless'; + readonly WEBAUTHN: 'webauthn'; + readonly JWT: 'jwt'; +}; + +export type LOGIN_PROVIDER_TYPE = (typeof LOGIN_PROVIDER)[keyof typeof LOGIN_PROVIDER]; + +export type CUSTOM_LOGIN_PROVIDER_TYPE = string & { + toString?: (radix?: number) => string; +}; + +export interface SocialUserInfo { + email?: string; + name?: string; + profileImage?: string; + aggregateVerifier?: string; + verifier?: string; + verifierId?: string; + typeOfLogin?: LOGIN_PROVIDER_TYPE | CUSTOM_LOGIN_PROVIDER_TYPE; + dappShare?: string; + /** + * Token issued by Web3Auth. + */ + idToken?: string; + /** + * Token issued by OAuth provider. Will be available only if you are using + * custom verifiers. + */ + oAuthIdToken?: string; + /** + * Access Token issued by OAuth provider. Will be available only if you are using + * custom verifiers. + */ + oAuthAccessToken?: string; + appState?: string; + touchIDPreference?: string; + isMfaEnabled?: boolean; +} + +export type GetSocialUserProfileResponse = SocialUserInfo; diff --git a/packages/sdk/src/core/utils/provider.utils.ts b/packages/sdk/src/core/utils/provider.utils.ts index a8ba524..7333875 100644 --- a/packages/sdk/src/core/utils/provider.utils.ts +++ b/packages/sdk/src/core/utils/provider.utils.ts @@ -4,3 +4,7 @@ import { TM2WalletProvider, WalletProvider } from '../providers'; export function isTM2WalletProvider(wallet: WalletProvider): wallet is TM2WalletProvider { return wallet instanceof GnoWalletProvider || wallet instanceof GnoSocialWalletProvider; } + +export function isGnoSocialWalletProvider(wallet: WalletProvider): wallet is GnoSocialWalletProvider { + return wallet instanceof GnoSocialWalletProvider; +} diff --git a/packages/sdk/src/providers/gno-wallet/gno-social-wallet.ts b/packages/sdk/src/providers/gno-wallet/gno-social-wallet.ts index 2f6b529..b819c17 100644 --- a/packages/sdk/src/providers/gno-wallet/gno-social-wallet.ts +++ b/packages/sdk/src/providers/gno-wallet/gno-social-wallet.ts @@ -14,6 +14,7 @@ import { import { GNO_ADDRESS_PREFIX } from '../../core/constants/chains.constant'; import { hexToUint8Array } from '../../core/utils/encode.utils'; import { GnoWalletProvider } from './gno-wallet'; +import { GetSocialUserProfileResponse } from '../../core/types/methods/get-social-user-profile.types'; export class GnoSocialWalletProvider extends GnoWalletProvider { private web3auth: Web3AuthNoModal; @@ -124,6 +125,7 @@ export class GnoSocialWalletProvider extends GnoWalletProvider { const openloginAdapter = new OpenloginAdapter({ privateKeyProvider: privateKeyProvider, adapterSettings: { + storageKey: config.storageKey || 'local', clientId: config.clientId, uxMode: 'popup', loginConfig: { @@ -172,6 +174,7 @@ export class GnoSocialWalletProvider extends GnoWalletProvider { const openloginAdapter = new OpenloginAdapter({ privateKeyProvider: privateKeyProvider, adapterSettings: { + storageKey: config.storageKey || 'local', uxMode: 'popup', loginConfig: { [socialType]: { @@ -224,6 +227,7 @@ export class GnoSocialWalletProvider extends GnoWalletProvider { const openloginAdapter = new OpenloginAdapter({ privateKeyProvider: privateKeyProvider, adapterSettings: { + storageKey: config.storageKey || 'local', uxMode: 'popup', loginConfig: { [socialType]: { @@ -243,4 +247,12 @@ export class GnoSocialWalletProvider extends GnoWalletProvider { web3auth.configureAdapter(openloginAdapter); return new GnoSocialWalletProvider(web3auth, socialType, [networkConfig]); } + + public async getSocialUserProfile(): Promise { + if (!this.web3auth) { + throw new Error('Not initialized web3 provider.'); + } + + return await this.web3auth.getUserInfo(); + } } diff --git a/packages/sdk/src/providers/gno-wallet/gno-wallet.ts b/packages/sdk/src/providers/gno-wallet/gno-wallet.ts index 6b351dd..83df825 100644 --- a/packages/sdk/src/providers/gno-wallet/gno-wallet.ts +++ b/packages/sdk/src/providers/gno-wallet/gno-wallet.ts @@ -30,6 +30,7 @@ import { encodeTransaction } from '../../core/utils/encode.utils'; import { makeResponseMessage } from '../../core/utils/message.utils'; import { DEFAULT_RPC_URL, GNO_ADDRESS_PREFIX } from '../../core/constants/chains.constant'; import { normalizeRpcUrl, validateNetworkInput } from '../../core/utils/network.utils'; +import { GetSocialUserProfileResponse } from '../../core/types/methods/get-social-user-profile.types'; export class GnoWalletProvider implements TM2WalletProvider { protected wallet: TM2Wallet | null; @@ -252,4 +253,8 @@ export class GnoWalletProvider implements TM2WalletProvider { (network) => network.chainId === chainId || normalizeRpcUrl(network.rpcUrl) === normalizedRpcUrl ); } + + async getSocialUserProfile(): Promise { + throw new Error('Social user profile is not supported in GnoWalletProvider. Use GnoSocialWalletProvider instead.'); + } }