Skip to content

Commit

Permalink
#fix appName can be empty string (#1244)
Browse files Browse the repository at this point in the history
* merged commits

* test
  • Loading branch information
fan-zhang-sv authored Apr 30, 2024
1 parent ac1990c commit 1b3c781
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 125 deletions.
150 changes: 48 additions & 102 deletions packages/wallet-sdk/src/CoinbaseWalletSDK.test.ts
Original file line number Diff line number Diff line change
@@ -1,122 +1,68 @@
import { CoinbaseWalletProvider } from './CoinbaseWalletProvider';
import { CoinbaseWalletSDK } from './CoinbaseWalletSDK';
import { ProviderInterface } from ':core/provider/interface';
import { getFavicon } from ':core/type/util';
import { getCoinbaseInjectedProvider } from ':util/provider';

const window = globalThis as any;
jest.mock(':core/type/util');
jest.mock(':util/provider');
jest.mock('./CoinbaseWalletProvider');

describe('CoinbaseWalletSDK', () => {
describe('public methods', () => {
let coinbaseWalletSDK2: CoinbaseWalletSDK;
beforeEach(() => {
coinbaseWalletSDK2 = new CoinbaseWalletSDK({
appName: 'Test',
appLogoUrl: 'http://coinbase.com/wallet-logo.png',
});
});

describe('sdk', () => {
test('@makeWeb3Provider', () => {
expect(coinbaseWalletSDK2.makeWeb3Provider()).toBeInstanceOf(CoinbaseWalletProvider);
});

test('@getCoinbaseWalletLogo', () => {
let svgUri;

svgUri = coinbaseWalletSDK2.getCoinbaseWalletLogo('standard');
expect(svgUri).toContain("viewBox='0 0 1024 1024'");

svgUri = coinbaseWalletSDK2.getCoinbaseWalletLogo('circle');
expect(svgUri).toContain("viewBox='0 0 999.81 999.81'");

svgUri = coinbaseWalletSDK2.getCoinbaseWalletLogo('text');
expect(svgUri).toContain("viewBox='0 0 528.15 53.64'");
expect(svgUri).toContain('fill:%230052ff');

svgUri = coinbaseWalletSDK2.getCoinbaseWalletLogo('textWithLogo');
expect(svgUri).toContain("viewBox='0 0 308.44 77.61'");
expect(svgUri).toContain('fill:%230052ff');

svgUri = coinbaseWalletSDK2.getCoinbaseWalletLogo('textLight');
expect(svgUri).toContain("viewBox='0 0 528.15 53.64'");
expect(svgUri).toContain('fill:%23fefefe');
test('@makeWeb3Provider - return Coinbase Injected Provider', () => {
const injectedProvider = {} as unknown as ProviderInterface;
(getCoinbaseInjectedProvider as jest.Mock).mockReturnValue(injectedProvider);

svgUri = coinbaseWalletSDK2.getCoinbaseWalletLogo('textWithLogoLight');
expect(svgUri).toContain("viewBox='0 0 308.44 77.61'");
expect(svgUri).toContain('fill:%23fefefe');
});
const SDK = new CoinbaseWalletSDK({
appName: 'Test',
appLogoUrl: 'http://coinbase.com/wallet-logo.png',
});

describe('extension', () => {
const mockProvider = { close: jest.fn() } as unknown as ProviderInterface;

beforeAll(() => {
window.coinbaseWalletExtension = mockProvider;
});

afterAll(() => {
window.coinbaseWalletExtension = undefined;
});

test('@makeWeb3Provider - only walletExtension injected', () => {
// Returns extension provider
expect(coinbaseWalletSDK2.makeWeb3Provider()).toEqual(mockProvider);
});

test('@makeWeb3Provider - walletExtension.shouldUseSigner is true', () => {
// Returns extension provider
const mockProvider2 = {
close: jest.fn(),
shouldUseSigner: true,
} as unknown as ProviderInterface;
window.coinbaseWalletExtension = mockProvider2;
expect(SDK.makeWeb3Provider()).toBe(injectedProvider);
});

const provider = coinbaseWalletSDK2.makeWeb3Provider();
expect(provider).not.toEqual(mockProvider2);
});
test('@makeWeb3Provider - return new CoinbaseWalletProvider', () => {
(getCoinbaseInjectedProvider as jest.Mock).mockReturnValue(undefined);

test('@makeWeb3Provider, but with smartWalletOnly as true', () => {
const sdk = new CoinbaseWalletSDK({
appName: 'Test',
appLogoUrl: 'http://coinbase.com/wallet-logo.png',
});
// Returns extension provider
const provider = sdk.makeWeb3Provider({
options: 'smartWalletOnly',
});
expect(provider).toBeTruthy();
expect(provider).not.toEqual(mockProvider);
});
const SDK = new CoinbaseWalletSDK({
appName: 'Test',
appLogoUrl: 'http://coinbase.com/wallet-logo.png',
});

describe('cipher provider', () => {
class MockCipherProviderClass {
public isCoinbaseBrowser = true;
}
SDK.makeWeb3Provider();

const mockCipherProvider = new MockCipherProviderClass() as unknown as ProviderInterface;
beforeAll(() => {
window.ethereum = mockCipherProvider;
});
expect(CoinbaseWalletProvider).toHaveBeenCalledWith({
metadata: {
appName: 'Test',
appLogoUrl: 'http://coinbase.com/wallet-logo.png',
appChainIds: [],
},
preference: {
options: 'all',
},
});
});

afterAll(() => {
window.ethereum = undefined;
});
test('@makeWeb3Provider - default values for metadata', () => {
(getFavicon as jest.Mock).mockReturnValue('https://dapp.xyz/pic.png');
(getCoinbaseInjectedProvider as jest.Mock).mockReturnValue(undefined);

test('@makeWeb3Provider', () => {
expect(coinbaseWalletSDK2.makeWeb3Provider()).toEqual(mockCipherProvider);
});
const SDK = new CoinbaseWalletSDK({
appName: '',
appLogoUrl: '',
});

test('@makeWeb3Provider, it should ignore smartWalletOnly true', () => {
const sdk = new CoinbaseWalletSDK({
appName: 'Test',
appLogoUrl: 'http://coinbase.com/wallet-logo.png',
});
expect(
sdk.makeWeb3Provider({
options: 'smartWalletOnly',
})
).toEqual(mockCipherProvider);
});
SDK.makeWeb3Provider();

expect(CoinbaseWalletProvider).toHaveBeenCalledWith({
metadata: {
appName: 'Dapp',
appLogoUrl: 'https://dapp.xyz/pic.png',
appChainIds: [],
},
preference: {
options: 'all',
},
});
});
});
27 changes: 8 additions & 19 deletions packages/wallet-sdk/src/CoinbaseWalletSDK.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,31 +12,20 @@ import { getCoinbaseInjectedProvider } from ':util/provider';
type CoinbaseWalletSDKOptions = Partial<AppMetadata>;

export class CoinbaseWalletSDK {
private metadata: CoinbaseWalletSDKOptions;
private metadata: AppMetadata;

constructor(metadata: Readonly<CoinbaseWalletSDKOptions>) {
this.metadata = metadata;
this.metadata = {
appName: metadata.appName || 'Dapp',
appLogoUrl: metadata.appLogoUrl || getFavicon(),
appChainIds: metadata.appChainIds || [],
};
this.storeLatestVersion();
}

public makeWeb3Provider(preference: Preference = { options: 'all' }): ProviderInterface {
const { appName = 'Dapp', appLogoUrl = getFavicon(), appChainIds = [] } = this.metadata;

const provider = getCoinbaseInjectedProvider(preference);
if (provider) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(provider as any).setAppInfo?.(appName, appLogoUrl, appChainIds);
return provider;
}

return new CoinbaseWalletProvider({
metadata: {
appName,
appLogoUrl,
appChainIds,
},
preference,
});
const params = { metadata: this.metadata, preference };
return getCoinbaseInjectedProvider(params) ?? new CoinbaseWalletProvider(params);
}

/**
Expand Down
132 changes: 130 additions & 2 deletions packages/wallet-sdk/src/util/provider.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { checkErrorForInvalidRequestArgs } from './provider';
import { checkErrorForInvalidRequestArgs, getCoinbaseInjectedProvider } from './provider';
import { standardErrors } from ':core/error';
import { ProviderInterface } from ':core/provider/interface';

const window = globalThis as {
top: Window;
ethereum?: ProviderInterface;
coinbaseWalletExtension?: ProviderInterface;
};

// @ts-expect-error-next-line
const invalidArgsError = (args) =>
Expand All @@ -20,7 +27,128 @@ const invalidParamsError = (args) =>
data: args,
});

describe('eip1193Utils', () => {
describe('Utils', () => {
describe('getCoinbaseInjectedProvider', () => {
describe('Extension Provider', () => {
afterEach(() => {
window.coinbaseWalletExtension = undefined;
});

it('should return extension provider', () => {
const mockSetAppInfo = jest.fn();
const extensionProvider = {
shouldUseSigner: false,
setAppInfo: mockSetAppInfo,
} as unknown as ProviderInterface;

window.coinbaseWalletExtension = extensionProvider;

expect(
getCoinbaseInjectedProvider({
metadata: {
appName: 'Dapp',
appChainIds: [],
appLogoUrl: null,
},
preference: {
options: 'all',
},
})
).toBe(extensionProvider);

expect(mockSetAppInfo).toHaveBeenCalledWith('Dapp', null, []);
});

it('shouldUseSigner as true - should return undefined', () => {
const extensionProvider = {
shouldUseSigner: true,
} as unknown as ProviderInterface;

window.coinbaseWalletExtension = extensionProvider;

expect(
getCoinbaseInjectedProvider({
metadata: {
appName: 'Dapp',
appChainIds: [],
appLogoUrl: null,
},
preference: {
options: 'all',
},
})
).toBe(undefined);
});

it('smartWalletOnly - should return undefined', () => {
const extensionProvider = {
shouldUseSigner: false,
setAppInfo: jest.fn(),
} as unknown as ProviderInterface;

window.coinbaseWalletExtension = extensionProvider;

expect(
getCoinbaseInjectedProvider({
metadata: {
appName: 'Dapp',
appChainIds: [],
appLogoUrl: null,
},
preference: {
options: 'smartWalletOnly',
},
})
).toBe(undefined);
});
});
describe('Browser Provider', () => {
class MockCipherProviderClass {
public isCoinbaseBrowser = true;
}

const mockCipherProvider = new MockCipherProviderClass() as unknown as ProviderInterface;

beforeAll(() => {
window.ethereum = mockCipherProvider;
});

afterAll(() => {
window.ethereum = undefined;
});

it('Should return injected browser provider', () => {
expect(
getCoinbaseInjectedProvider({
metadata: {
appName: 'Dapp',
appChainIds: [],
appLogoUrl: null,
},
preference: {
options: 'all',
},
})
).toBe(mockCipherProvider);
});

it('smartWalletOnly - Should still return injected browser provider', () => {
expect(
getCoinbaseInjectedProvider({
metadata: {
appName: 'Dapp',
appChainIds: [],
appLogoUrl: null,
},
preference: {
options: 'smartWalletOnly',
},
})
).toBe(mockCipherProvider);
});
});
});

describe('getErrorForInvalidRequestArgs', () => {
it('should throw if args is not an object', () => {
const args = 'not an object';
Expand Down
10 changes: 8 additions & 2 deletions packages/wallet-sdk/src/util/provider.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { LIB_VERSION } from '../version';
import { standardErrors } from ':core/error';
import { Preference, ProviderInterface, RequestArguments } from ':core/provider/interface';
import { ConstructorOptions, ProviderInterface, RequestArguments } from ':core/provider/interface';
import { Chain } from ':core/type';

export async function fetchRPCRequest(request: RequestArguments, chain: Chain) {
Expand All @@ -27,12 +27,18 @@ interface Window {
coinbaseWalletExtension?: ProviderInterface;
}

export function getCoinbaseInjectedProvider(preference: Preference): ProviderInterface | undefined {
export function getCoinbaseInjectedProvider({
metadata,
preference,
}: Readonly<ConstructorOptions>): ProviderInterface | undefined {
const window = globalThis as Window;

if (preference.options !== 'smartWalletOnly') {
const extension = window.coinbaseWalletExtension;
if (extension && !('shouldUseSigner' in extension && extension.shouldUseSigner)) {
const { appName, appLogoUrl, appChainIds } = metadata;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(extension as any).setAppInfo?.(appName, appLogoUrl, appChainIds);
return extension;
}
}
Expand Down

0 comments on commit 1b3c781

Please sign in to comment.