Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/services/__tests__/providerService.security.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,18 +94,21 @@ describe('ProviderService Security Tests', () => {
name: 'Test Wallet',
type: 'mnemonic',
addressFormat: 'p2wpkh',
isTestOnly: false,
addresses: []
}]),
getActiveWallet: vi.fn().mockResolvedValue({
id: 'wallet1',
name: 'Test Wallet',
type: 'mnemonic',
addressFormat: 'p2wpkh',
isTestOnly: false,
addresses: []
}),
getActiveAddress: vi.fn().mockResolvedValue({
id: 'addr1',
address: 'bc1qtest123',
pubKey: '038ca117a13f9d5671e5d98e7f4e522bce3ca6d207e771080e0b70ce0ba11e2ec4',
label: 'Test Address',
walletId: 'wallet1',
walletName: 'Test Wallet',
Expand Down Expand Up @@ -493,7 +496,7 @@ describe('ProviderService Security Tests', () => {
expect(accounts).toHaveLength(1);
expect(accounts[0]).toBe('bc1qtest123');
});

it('should hide accounts when wallet is locked', async () => {
vi.mocked(walletManager.getSettings).mockReturnValue({
...DEFAULT_SETTINGS,
Expand All @@ -517,4 +520,4 @@ describe('ProviderService Security Tests', () => {
expect(accounts).toEqual([]);
});
});
});
});
18 changes: 17 additions & 1 deletion src/services/__tests__/providerService.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -173,13 +173,15 @@ describe('ProviderService', () => {
name: 'Test Wallet',
type: 'mnemonic',
addressFormat: 'p2wpkh',
isTestOnly: false,
addresses: []
}]),
getActiveWallet: vi.fn().mockResolvedValue({
id: 'wallet1',
name: 'Test Wallet',
type: 'mnemonic',
addressFormat: 'p2wpkh',
isTestOnly: false,
addresses: []
}),
setActiveWallet: vi.fn().mockResolvedValue(undefined),
Expand Down Expand Up @@ -208,6 +210,7 @@ describe('ProviderService', () => {
getActiveAddress: vi.fn().mockResolvedValue({
id: 'addr1',
address: 'bc1qtest123',
pubKey: '038ca117a13f9d5671e5d98e7f4e522bce3ca6d207e771080e0b70ce0ba11e2ec4',
label: 'Test Address',
walletId: 'wallet1',
walletName: 'Test Wallet',
Expand Down Expand Up @@ -316,6 +319,17 @@ describe('ProviderService', () => {
) as any;

expect(result.accounts).toEqual(['bc1qtest123']);
expect(result.account).toEqual({
address: 'bc1qtest123',
publicKey: '038ca117a13f9d5671e5d98e7f4e522bce3ca6d207e771080e0b70ce0ba11e2ec4',
xOnlyPublicKey: '8ca117a13f9d5671e5d98e7f4e522bce3ca6d207e771080e0b70ce0ba11e2ec4',
addressType: 'p2wpkh',
network: 'mainnet',
walletType: 'software',
});
expect(result.account).not.toHaveProperty('path');
expect(result.account).not.toHaveProperty('xpub');
expect(result.account).not.toHaveProperty('privateKey');
expect(result.proof).toBeDefined();
});

Expand All @@ -341,6 +355,8 @@ describe('ProviderService', () => {

// Should return accounts with proof
expect((result as any).accounts).toEqual(['bc1qtest123']);
expect((result as any).account.publicKey).toBe('038ca117a13f9d5671e5d98e7f4e522bce3ca6d207e771080e0b70ce0ba11e2ec4');
expect((result as any).account.xOnlyPublicKey).toBe('8ca117a13f9d5671e5d98e7f4e522bce3ca6d207e771080e0b70ce0ba11e2ec4');
expect((result as any).proof).toBeDefined();
});

Expand Down Expand Up @@ -761,4 +777,4 @@ describe('ProviderService', () => {
});

});
});
});
41 changes: 39 additions & 2 deletions src/services/providerService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,15 @@ export type ProviderRequestParams = unknown[];
export type ProviderMetadata = Record<string, unknown>;
export type ProviderResponse = unknown;

interface ProviderAccountInfo {
address: string;
publicKey: string | null;
xOnlyPublicKey: string | null;
addressType: string;
network: 'mainnet';
walletType: 'software' | 'hardware' | 'test';
}

export interface ProviderService {
/**
* Handle provider requests from dApps
Expand Down Expand Up @@ -183,10 +192,38 @@ export function createProviderService(): ProviderService {
return isConnected ? [activeAddress.address] : [];
}

async function getAccountInfo(accounts: string[]): Promise<ProviderAccountInfo | null> {
if (accounts.length === 0) return null;

const walletService = getWalletService();
const activeAddress = await walletService.getActiveAddress();
const activeWallet = await walletService.getActiveWallet();
if (!activeAddress || !activeWallet) return null;

const publicKey = activeAddress.pubKey || null;
const xOnlyPublicKey = publicKey ? toXOnlyPublicKey(publicKey) : null;

return {
address: activeAddress.address,
publicKey,
xOnlyPublicKey,
addressType: activeWallet.addressFormat,
network: 'mainnet',
walletType: activeWallet.isTestOnly ? 'test' : activeWallet.type === 'hardware' ? 'hardware' : 'software',
};
}

function toXOnlyPublicKey(publicKey: string): string | null {
if (/^[0-9a-fA-F]{64}$/.test(publicKey)) return publicKey.toLowerCase();
if (/^(02|03)[0-9a-fA-F]{64}$/.test(publicKey)) return publicKey.slice(2).toLowerCase();
return null;
}

/** Build the standard response for xcp_requestAccounts with proof. */
async function buildConnectResponse(origin: string, accounts: string[]) {
const account = await getAccountInfo(accounts);
const proof = accounts.length > 0 ? await generateConnectionProof(origin) : null;
return { accounts, proof };
return { accounts, account, proof };
}

/**
Expand Down Expand Up @@ -959,4 +996,4 @@ export function createProviderService(): ProviderService {
export const [registerProviderService, getProviderService] = defineProxyService(
'ProviderService',
createProviderService
);
);