Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
58f68ee
chore: update release workflows (#2314)
dschlabach Apr 29, 2025
e6c7613
fix: fix root build command (#2320)
dschlabach Apr 29, 2025
e9cd45d
fix: fix build command in workflow (#2321)
dschlabach Apr 29, 2025
ce14bc4
fix: narrow filtering for release workflow (#2322)
dschlabach Apr 29, 2025
4bf7a34
chore: version packages v0.38.9 🌊 (#2323)
github-actions[bot] Apr 29, 2025
4d20133
fix: support an insecure fallback for session id to allow for testing…
xtbase Apr 29, 2025
6e7a23f
chore: Make create-onchain library public (#2324)
dgca Apr 30, 2025
16c90fb
chore: Don't ask to generate manifest during app creation in create-o…
dgca May 1, 2025
9b557ef
fix: Basenames bidirectional validation (#2329)
dgca May 1, 2025
0ac58ad
chore: version packages v0.38.10 🌊 (#2330)
github-actions[bot] May 1, 2025
51d248c
fix: getSocials (#2333)
dgca May 2, 2025
24af8e5
docs: fix broken link (#2331)
GarmashAlex May 2, 2025
41a2ca5
feat: Make sign up button optional (#2332)
dgca May 6, 2025
84b09b3
chore: Release changesets (#2342)
dgca May 6, 2025
a8e0e61
Chore: workflow improvement for vscode/cursor users (#2334)
xtbase May 6, 2025
f8ac25a
chore: version packages 🚀 (#2343)
github-actions[bot] May 7, 2025
9645a3c
chore: enable paymaster for wallet advanced Send (#2335)
abcrane123 May 7, 2025
e099e59
fix: MiniKit frames connector (#2347)
dgca May 7, 2025
623fbb1
chore: version packages 🚀 (#2348)
github-actions[bot] May 7, 2025
a2336bb
fix: Update wagmi config if connectors change (#2350)
dgca May 7, 2025
02c1e93
chore: version packages 🚀 (#2352)
github-actions[bot] May 7, 2025
46903c4
chore(deps-dev): bump vite from 6.2.3 to 6.2.7 (#2327)
dependabot[bot] May 8, 2025
377c47e
Merge branch 'main' into onchainkit-v1
xtbase May 12, 2025
60fbf29
update test to fix coverage
xtbase May 12, 2025
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
2 changes: 1 addition & 1 deletion packages/miniapp-manifest-generator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
"tailwindcss": "^4.1.4",
"typescript": "~5.7.2",
"typescript-eslint": "^8.24.1",
"vite": "^6.2.0",
"vite": "^5.4.19",
"vitest": "^3.0.5"
},
"packageManager": "pnpm@10.6.3"
Expand Down
7 changes: 7 additions & 0 deletions packages/onchainkit/.vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"recommendations": [
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"bradlc.vscode-tailwindcss"
]
}
5 changes: 5 additions & 0 deletions packages/onchainkit/.vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"files.associations": {
"*.css": "tailwindcss"
}
}
21 changes: 21 additions & 0 deletions packages/onchainkit/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
# Changelog

## 0.38.13

### Patch Changes

- **fix**: Update wagmi config if connectors change. By @dgca #2350

## 0.38.12

### Patch Changes

- **fix**: MiniKit frames connector. By @dgca #2347

## 0.38.11

### Patch Changes

- **feat**: Make "Sign Up" button optional in `<WalletModal/>`. By @dgca #2332
- **fix**: Use mainnet to resolve ENS social media accounts. By @dgca #2333
- **feat**: Configure Coinbase wallet preference via `<OnchainKitProvider/>`. By @dgca #2332
- **fix**: Broken link in CHANGELOG. By @GarmashAlex #2331

## 0.38.10

### Patch Changes
Expand Down
4 changes: 2 additions & 2 deletions packages/onchainkit/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@coinbase/onchainkit",
"version": "0.38.10",
"version": "0.38.13",
"type": "module",
"repository": "https://github.com/coinbase/onchainkit.git",
"license": "MIT",
Expand Down Expand Up @@ -75,7 +75,7 @@
"tailwindcss-animate": "^1.0.7",
"tscpaths": "^0.0.9",
"tsup": "^8.3.5",
"vite": "^5.3.3",
"vite": "^5.4.19",
"vite-plugin-dts": "^4.5.3",
"vite-plugin-externalize-deps": "^0.9.0",
"vitest": "^3.0.5"
Expand Down
107 changes: 103 additions & 4 deletions packages/onchainkit/src/DefaultOnchainKitProviders.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,24 @@ import { QueryClient } from '@tanstack/react-query';
import { render, screen } from '@testing-library/react';
import { type Mock, beforeEach, describe, expect, it, vi } from 'vitest';
import { http, createConfig } from 'wagmi';
import type { CreateConnectorFn } from 'wagmi';
import { DefaultOnchainKitProviders } from './DefaultOnchainKitProviders';
import { useProviderDependencies } from './internal/hooks/useProviderDependencies';
import { useOnchainKit } from './useOnchainKit';
import type { CreateWagmiConfigParams } from './core/types';

// Mock the coinbase wallet connector
const mockCoinbaseWallet = vi.fn();

// Mock for the createWagmiConfig
const mockCreateWagmiConfig = vi.fn();
vi.mock('./core/createWagmiConfig', () => ({
createWagmiConfig: (params: CreateWagmiConfigParams) => {
mockCreateWagmiConfig(params);
return { mock: 'config', params };
},
}));

const queryClient = new QueryClient();
const wagmiConfig = createConfig({
chains: [
Expand All @@ -27,8 +38,10 @@ vi.mock('wagmi', async (importOriginal) => {
const actual = await importOriginal<typeof import('wagmi')>();
return {
...actual,
WagmiProvider: vi.fn(({ children }) => (
<div data-testid="wagmi-provider">{children}</div>
WagmiProvider: vi.fn(({ children, config }) => (
<div data-testid="wagmi-provider" data-config={JSON.stringify(config)}>
{children}
</div>
)),
};
});
Expand Down Expand Up @@ -65,6 +78,30 @@ vi.mock('./useOnchainKit', () => ({
})),
}));

// Create mock connector function that satisfies the CreateConnectorFn interface
const createMockConnector = (id: string): CreateConnectorFn => {
return () => ({
id,
name: `Mock ${id}`,
type: 'mock',
icon: undefined,
rdns: undefined,
supportsSimulation: false,
connect: async () => ({
accounts: [],
chainId: 1,
}),
disconnect: async () => {},
getAccounts: async () => [],
getChainId: async () => 1,
getProvider: async () => ({}),
isAuthorized: async () => false,
onAccountsChanged: () => {},
onChainChanged: () => {},
onDisconnect: () => {},
});
};

// Mock wagmi/connectors
vi.mock('wagmi/connectors', () => {
return {
Expand All @@ -74,8 +111,8 @@ vi.mock('wagmi/connectors', () => {
appLogoUrl?: string;
}) => {
mockCoinbaseWallet(params);
// Return a connector function that Wagmi expects
return () => ({ id: 'coinbaseWalletSDK' });
// Return a connector function that satisfies the CreateConnectorFn interface
return createMockConnector('coinbaseWalletSDK');
},
};
});
Expand Down Expand Up @@ -283,4 +320,66 @@ describe('DefaultOnchainKitProviders', () => {
}),
);
});

it('should update the Wagmi config when connectors change', async () => {
const { rerender } = render(
<DefaultOnchainKitProviders>
<div>Test Child</div>
</DefaultOnchainKitProviders>,
);

// Initial config creation
expect(mockCreateWagmiConfig).toHaveBeenCalledTimes(1);

// First call parameters
const firstCallParams = mockCreateWagmiConfig.mock.calls[0][0];
expect(firstCallParams.connectors).toBeDefined();

// Clear mocks to check rerender behavior
mockCreateWagmiConfig.mockClear();

// Create a different connector
const newConnector = createMockConnector('newConnector');

// Re-render with new connectors
rerender(
<DefaultOnchainKitProviders connectors={[newConnector]}>
<div>Test Child</div>
</DefaultOnchainKitProviders>,
);

// Should create a new config with the new connectors
expect(mockCreateWagmiConfig).toHaveBeenCalledTimes(1);

// Second call parameters
const secondCallParams = mockCreateWagmiConfig.mock.calls[0][0];
expect(secondCallParams.connectors).toEqual([newConnector]);
});

it('should not update the Wagmi config when the same connectors are passed', async () => {
// Create an initial connector
const initialConnectors = [createMockConnector('initialConnector')];

const { rerender } = render(
<DefaultOnchainKitProviders connectors={initialConnectors}>
<div>Test Child</div>
</DefaultOnchainKitProviders>,
);

// Initial config creation
expect(mockCreateWagmiConfig).toHaveBeenCalledTimes(1);

// Clear mocks to check rerender behavior
mockCreateWagmiConfig.mockClear();

// Re-render with the same connectors
rerender(
<DefaultOnchainKitProviders connectors={initialConnectors}>
<div>Test Child</div>
</DefaultOnchainKitProviders>,
);

// Should not create a new config
expect(mockCreateWagmiConfig).not.toHaveBeenCalled();
});
});
44 changes: 39 additions & 5 deletions packages/onchainkit/src/DefaultOnchainKitProviders.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,32 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { type PropsWithChildren, useMemo, useState } from 'react';
import {
type PropsWithChildren,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import { Config, WagmiProvider } from 'wagmi';
import { coinbaseWallet } from 'wagmi/connectors';
import { createWagmiConfig } from './core/createWagmiConfig';
import { useProviderDependencies } from './internal/hooks/useProviderDependencies';
import { useOnchainKit } from './useOnchainKit';
import type { CreateWagmiConfigParams } from './core/types';

export function DefaultOnchainKitProviders({ children }: PropsWithChildren) {
export function DefaultOnchainKitProviders({
children,
connectors,
}: PropsWithChildren<{ connectors?: CreateWagmiConfigParams['connectors'] }>) {
// Check the React context for WagmiProvider and QueryClientProvider
const { providedWagmiConfig, providedQueryClient } =
useProviderDependencies();

return (
<WagmiProviderWithDefault providedWagmiConfig={providedWagmiConfig}>
<WagmiProviderWithDefault
providedWagmiConfig={providedWagmiConfig}
connectors={connectors}
>
<QueryClientProviderWithDefault providedQueryClient={providedQueryClient}>
{children}
</QueryClientProviderWithDefault>
Expand All @@ -23,12 +37,16 @@ export function DefaultOnchainKitProviders({ children }: PropsWithChildren) {
function WagmiProviderWithDefault({
children,
providedWagmiConfig,
connectors,
}: PropsWithChildren<{
providedWagmiConfig: Config | null;
connectors?: CreateWagmiConfigParams['connectors'];
}>) {
const onchainKitConfig = useOnchainKit();
const prevConnectorsRef =
useRef<CreateWagmiConfigParams['connectors']>(connectors);

const [config] = useState(() => {
const getWagmiConfig = useCallback(() => {
if (providedWagmiConfig) return providedWagmiConfig;

const appName = onchainKitConfig.config?.appearance?.name ?? undefined;
Expand All @@ -38,16 +56,32 @@ function WagmiProviderWithDefault({
apiKey: onchainKitConfig.apiKey ?? undefined,
appName,
appLogoUrl,
connectors: [
connectors: connectors ?? [
coinbaseWallet({
appName,
appLogoUrl,
preference: onchainKitConfig.config?.wallet?.preference,
}),
],
});
}, [
onchainKitConfig.apiKey,
onchainKitConfig.config,
connectors,
providedWagmiConfig,
]);

const [config, setConfig] = useState(() => {
return getWagmiConfig();
});

useEffect(() => {
if (prevConnectorsRef.current !== connectors) {
setConfig(getWagmiConfig());
prevConnectorsRef.current = connectors;
}
}, [connectors, getWagmiConfig]);

if (providedWagmiConfig) {
return children;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { render, screen } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { Connected } from '../components/Connected';
import { Connected } from '../';
import { useAccount } from 'wagmi';

vi.mock('wagmi', () => ({
Expand Down
7 changes: 1 addition & 6 deletions packages/onchainkit/src/minikit/MiniKitProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,7 @@ export function MiniKitProvider({

return (
<MiniKitContext.Provider value={value}>
<DefaultOnchainKitProviders
apiKey={onchainKitProps.apiKey}
appName={onchainKitProps.config?.appearance?.name ?? undefined}
appLogoUrl={onchainKitProps.config?.appearance?.logo ?? undefined}
connectors={connectors}
>
<DefaultOnchainKitProviders connectors={connectors}>
<OnchainKitProvider {...onchainKitProps}>
<div
style={{
Expand Down
3 changes: 2 additions & 1 deletion packages/onchainkit/src/wallet/components/Wallet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export function Wallet({
className,
draggable,
draggableStartingPosition,
isSponsored,
}: WalletReact) {
const componentTheme = useTheme();

Expand All @@ -35,7 +36,7 @@ export function Wallet({
}

return (
<WalletProvider>
<WalletProvider isSponsored={isSponsored}>
<WalletContent
className={cn(componentTheme, className)}
{...getWalletDraggableProps({ draggable, draggableStartingPosition })}
Expand Down
8 changes: 7 additions & 1 deletion packages/onchainkit/src/wallet/components/WalletIsland.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,17 @@ import { WalletDropdown } from './WalletDropdown';

export function WalletIsland({
startingPosition = getDefaultDraggableStartingPosition(),
isSponsored,
}: {
startingPosition?: { x: number; y: number };
isSponsored?: boolean;
}) {
return (
<Wallet draggable={true} draggableStartingPosition={startingPosition}>
<Wallet
draggable={true}
draggableStartingPosition={startingPosition}
isSponsored={isSponsored}
>
<ConnectWallet
className="!rounded-full m-0 flex h-14 w-14 min-w-14 flex-col items-center justify-center p-0"
disconnectedLabel={<div className="h-5 w-5">{portfolioSvg}</div>}
Expand Down
6 changes: 5 additions & 1 deletion packages/onchainkit/src/wallet/components/WalletProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@ const WalletContext = createContext<WalletContextType>(emptyContext);

export type WalletProviderReact = {
children: ReactNode;
/** Whether to sponsor transactions for Send feature of advanced wallet implementation */
isSponsored?: boolean;
};

export function WalletProvider({ children }: WalletProviderReact) {
export function WalletProvider({ children, isSponsored }: WalletProviderReact) {
const { chain } = useOnchainKit();
const [isConnectModalOpen, setIsConnectModalOpen] = useState(false);
const [isSubComponentOpen, setIsSubComponentOpen] = useState(false);
Expand Down Expand Up @@ -81,6 +83,7 @@ export function WalletProvider({ children }: WalletProviderReact) {
isActiveFeatureClosing,
setIsActiveFeatureClosing,
animations,
isSponsored,
};
}, [
address,
Expand All @@ -95,6 +98,7 @@ export function WalletProvider({ children }: WalletProviderReact) {
activeFeature,
isActiveFeatureClosing,
animations,
isSponsored,
]);

return (
Expand Down
Loading