diff --git a/.changeset/solana-wallet-name.md b/.changeset/solana-wallet-name.md new file mode 100644 index 0000000..a665909 --- /dev/null +++ b/.changeset/solana-wallet-name.md @@ -0,0 +1,6 @@ +--- +"@alien-id/sso-solana": minor +"@alien-id/sso-solana-react": minor +--- + +Add optional `walletName` argument to `generateDeeplink`. When provided, it is sent as `wallet_name` in `POST /solana/link` and embedded in the signed deeplink so the Alien app can display the source wallet (e.g. phantom, solflare). Backward compatible — omitting it behaves as before. diff --git a/packages/solanaCore/jest.config.ts b/packages/solanaCore/jest.config.ts index fa68be1..669c177 100644 --- a/packages/solanaCore/jest.config.ts +++ b/packages/solanaCore/jest.config.ts @@ -9,6 +9,9 @@ const config: Config.InitialOptions = { globals: { 'ts-jest': { useESM: true, + // ES2020 keeps native BigInt ** (ES2015 downlevels it to Math.pow, + // which breaks @noble/curves when transformed here). + tsconfig: { target: 'ES2020' }, }, }, transform: { diff --git a/packages/solanaCore/src/client.ts b/packages/solanaCore/src/client.ts index 3f19557..9aa4259 100644 --- a/packages/solanaCore/src/client.ts +++ b/packages/solanaCore/src/client.ts @@ -119,9 +119,13 @@ export class AlienSolanaSsoClient { ); } - async generateDeeplink(solanaAddress: string): Promise { + async generateDeeplink( + solanaAddress: string, + walletName?: string + ): Promise { const linkPayload: SolanaLinkRequest = { solana_address: solanaAddress, + ...(walletName ? { wallet_name: walletName } : {}), }; SolanaLinkRequestSchema.parse(linkPayload); diff --git a/packages/solanaCore/src/schema.ts b/packages/solanaCore/src/schema.ts index 2f46423..3dcd603 100644 --- a/packages/solanaCore/src/schema.ts +++ b/packages/solanaCore/src/schema.ts @@ -5,6 +5,7 @@ import { z } from 'zod/v4-mini'; */ export const SolanaLinkRequestSchema = z.object({ solana_address: z.string(), + wallet_name: z.optional(z.string()), }); export type SolanaLinkRequest = z.infer; diff --git a/packages/solanaCore/tests/generateDeeplink.test.ts b/packages/solanaCore/tests/generateDeeplink.test.ts new file mode 100644 index 0000000..2ddece4 --- /dev/null +++ b/packages/solanaCore/tests/generateDeeplink.test.ts @@ -0,0 +1,47 @@ +import { AlienSolanaSsoClient } from '../src/client'; + +describe('generateDeeplink — wallet_name', () => { + const config = { + ssoBaseUrl: 'https://sso.develop.alien-api.com', + providerAddress: '00000001040000000000000100000000', + }; + + const linkResponse = { + deep_link: 'https://s.alien-api.com/abc', + polling_code: 'poll-code', + expired_at: 1780000000, + }; + + let fetchMock: jest.Mock; + + beforeEach(() => { + fetchMock = jest.fn().mockResolvedValue({ + ok: true, + json: async () => linkResponse, + }); + global.fetch = fetchMock as unknown as typeof fetch; + }); + + const getBody = () => JSON.parse(fetchMock.mock.calls[0][1].body); + + it('includes wallet_name when provided', async () => { + const client = new AlienSolanaSsoClient(config); + await client.generateDeeplink('7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU', 'phantom'); + + expect(getBody()).toEqual({ + solana_address: '7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU', + wallet_name: 'phantom', + }); + }); + + it('omits wallet_name when not provided', async () => { + const client = new AlienSolanaSsoClient(config); + await client.generateDeeplink('7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU'); + + const body = getBody(); + expect(body).toEqual({ + solana_address: '7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU', + }); + expect(body).not.toHaveProperty('wallet_name'); + }); +}); diff --git a/packages/solanaReact/lib/providers/AlienSolanaSsoProvider.tsx b/packages/solanaReact/lib/providers/AlienSolanaSsoProvider.tsx index e380515..de44986 100644 --- a/packages/solanaReact/lib/providers/AlienSolanaSsoProvider.tsx +++ b/packages/solanaReact/lib/providers/AlienSolanaSsoProvider.tsx @@ -65,7 +65,8 @@ type SolanaSsoContextValue = { connectionAdapter: SolanaConnectionAdapter; queryClient: QueryClient; generateDeeplink: ( - solanaAddress: string + solanaAddress: string, + walletName?: string ) => Promise; pollAuth: (pollingCode: string) => Promise; verifyAttestation: (solanaAddress: string) => Promise; @@ -114,8 +115,8 @@ export function AlienSolanaSsoProvider({ }); const generateDeeplink = useCallback( - async (solanaAddress: string) => { - return await client.generateDeeplink(solanaAddress); + async (solanaAddress: string, walletName?: string) => { + return await client.generateDeeplink(solanaAddress, walletName); }, [client] );