@coinbase/cdp-wagmi 0.0.0 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,221 @@
1
+ This package provides an embedded wallet connector for [Wagmi](https://wagmi.sh), which
2
+ is a commonly used React Hooks library for Ethereum.
3
+
4
+ Developers who use Wagmi in their application should be able to use the provided
5
+ {@link createCDPEmbeddedWalletConnector} out of the box to integrate CDP embedded wallets
6
+ into their existing environment.
7
+
8
+ ## Quickstart
9
+
10
+ This guide will help you get started with `@coinbase/cdp-wagmi`. You'll learn how to install the package, set up the provider, and render your first component.
11
+
12
+ ### Installation
13
+
14
+ First, add the package to your project using your preferred package manager.
15
+
16
+ ```bash
17
+ # With pnpm
18
+ pnpm add @coinbase/cdp-wagmi @coinbase/cdp-core @tanstack/react-query viem wagmi
19
+
20
+ # With yarn
21
+ yarn add @coinbase/cdp-wagmi @coinbase/cdp-core @tanstack/react-query viem wagmi
22
+
23
+ # With npm
24
+ npm install @coinbase/cdp-wagmi @coinbase/cdp-core @tanstack/react-query viem wagmi
25
+ ```
26
+
27
+ ### Gather your CDP Project information
28
+
29
+ 1. Sign in or create an account on the [CDP Portal](https://portal.cdp.coinbase.com)
30
+ 2. On your dashboard, select a project from the dropdown at the at the top, and copy the Project ID
31
+
32
+ ### Setup Provider
33
+
34
+ Next, you must configure your WagmiProvider with the `CDPEmbeddedWalletConnector`.
35
+
36
+ `CDPEmbeddedWalletConnector` provides the necessary context Wagmi to work correctly with
37
+ the CDP Frontend SDK. The `providerConfig` must be provided and is responsible for
38
+ configuring the EIP-1193 provider's transports which are used to broadcast non-Base
39
+ transactions.
40
+
41
+ ```tsx
42
+ import React from 'react';
43
+ import ReactDOM from 'react-dom/client';
44
+ import { App } from './App'; // Your main App component
45
+ import { Config }from '@coinbase/cdp-core';
46
+ import { createCDPEmbeddedWalletConector } from '@coinbase/cdp-wagmi';
47
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
48
+ import { http }from "viem";
49
+ import { baseSepolia, base } from 'viem/chains';
50
+ import { WagmiProvider, createConfig, http } from 'wagmi';
51
+
52
+ // Your CDP config
53
+ const cdpConfig: Config = {
54
+ projectId: "your-project-id", // Copy your Project ID here.
55
+ }
56
+
57
+ const connector = createCDPEmbeddedWalletConnector({
58
+ cdpConfig: cdpConfig,
59
+ providerConfig:{
60
+ chains: [base, baseSepolia],
61
+ transports: {
62
+ [base.id]: http(),
63
+ [baseSepolia.id]: http()
64
+ }
65
+ }
66
+ });
67
+
68
+ const wagmiConfig = createConfig({
69
+ connectors: [connector],
70
+ chains: [base, baseSepolia],
71
+ transports: {
72
+ [base.id]: http(),
73
+ [baseSepolia.id]: http(),
74
+ },
75
+ });
76
+
77
+ const queryClient = new QueryClient(); // For use with react-query
78
+
79
+ ReactDOM.createRoot(document.getElementById('root')!).render(
80
+ <React.StrictMode>
81
+ <WagmiProvider config={wagmiConfig} >
82
+ <QueryClientProvider client={ queryClient }>
83
+ <App />
84
+ </QueryClientProvider>
85
+ </WagmiProvider>
86
+ </React.StrictMode>,
87
+ );
88
+ ```
89
+
90
+ ### Call Wagmi Hooks
91
+
92
+ Now, your application should be able to successfully call Wagmi hooks. For example:
93
+
94
+ ```tsx
95
+ import { useState } from "react";
96
+ import { parseEther } from "viem";
97
+ import { useAccount, useSendTransaction, useWaitForTransactionReceipt } from "wagmi";
98
+
99
+ /**
100
+ * The burn address (0x0000000000000000000000000000000000000000)
101
+ */
102
+ const BURN_ADDRESS = "0x0000000000000000000000000000000000000000" as const;
103
+
104
+ /**
105
+ * The amount to send in ETH (0.00001 ETH)
106
+ */
107
+ const AMOUNT_TO_SEND = "0.00001";
108
+
109
+ /**
110
+ * A component that demonstrates wagmi's useSendTransaction hook
111
+ * by sending 0.00001 ETH to the burn address.
112
+ *
113
+ * @returns A component that allows the user to send a transaction using wagmi.
114
+ */
115
+ export default function WagmiTransaction() {
116
+ const { address } = useAccount();
117
+ const [isLoading, setIsLoading] = useState(false);
118
+
119
+ const { data: hash, sendTransaction, isPending, error } = useSendTransaction();
120
+
121
+ const { isLoading: isConfirming, isSuccess } = useWaitForTransactionReceipt({
122
+ hash,
123
+ });
124
+
125
+ const handleSendTransaction = async () => {
126
+ if (!address) return;
127
+
128
+ setIsLoading(true);
129
+
130
+ try {
131
+ sendTransaction({
132
+ to: BURN_ADDRESS,
133
+ value: parseEther(AMOUNT_TO_SEND),
134
+ });
135
+ } catch (error) {
136
+ console.error("Failed to send transaction:", error);
137
+ } finally {
138
+ setIsLoading(false);
139
+ }
140
+ };
141
+
142
+ const handleReset = () => {
143
+ // Reset by refreshing the page or clearing state
144
+ window.location.reload();
145
+ };
146
+
147
+ return (
148
+ <div>
149
+ <div>
150
+ <p>
151
+ ⚠️ Warning: This will send {AMOUNT_TO_SEND} ETH to the burn address (0x0000...0000).
152
+ This transaction cannot be reversed and the ETH will be permanently lost.
153
+ </p>
154
+ </div>
155
+
156
+ <div>
157
+ <div>
158
+ <div>Amount: {AMOUNT_TO_SEND} ETH</div>
159
+ <div>To (Burn Address): {BURN_ADDRESS.slice(0, 6)}...{BURN_ADDRESS.slice(-4)}</div>
160
+ <div>From: {address?.slice(0, 6)}...{address?.slice(-4)}</div>
161
+ </div>
162
+ </div>
163
+
164
+ {error && (
165
+ <div>
166
+ <strong>Error:</strong> {error.message}
167
+ </div>
168
+ )}
169
+
170
+ {!hash && !isPending && !isLoading && (
171
+ <button disabled={!address} onClick={handleSendTransaction}>
172
+ Send {AMOUNT_TO_SEND} ETH to Burn Address
173
+ </button>
174
+ )}
175
+
176
+ {(isPending || isConfirming) && (
177
+ <div>
178
+ <div>Sending transaction...</div>
179
+ {hash && (
180
+ <div>
181
+ Hash: {hash.slice(0, 10)}...{hash.slice(-8)}
182
+ </div>
183
+ )}
184
+ </div>
185
+ )}
186
+
187
+ {isSuccess && hash && (
188
+ <div>
189
+ <div>
190
+ <div>✅</div>
191
+ </div>
192
+
193
+ <div>
194
+ <div>Transaction Confirmed!</div>
195
+ <div>Your transaction has been successfully sent to the burn address</div>
196
+ </div>
197
+
198
+ <div>
199
+ <div>Amount: {AMOUNT_TO_SEND} ETH</div>
200
+ <div>To: {BURN_ADDRESS.slice(0, 6)}...{BURN_ADDRESS.slice(-4)}</div>
201
+ <div>
202
+ Block Explorer:{" "}
203
+ <a
204
+ href={`https://sepolia.basescan.org/tx/${hash}`}
205
+ target="_blank"
206
+ rel="noopener noreferrer"
207
+ >
208
+ {hash.slice(0, 10)}...{hash.slice(-8)}
209
+ </a>
210
+ </div>
211
+ </div>
212
+
213
+ <button onClick={handleReset}>
214
+ Send Another Transaction →
215
+ </button>
216
+ </div>
217
+ )}
218
+ </div>
219
+ );
220
+ }
221
+ ```
@@ -0,0 +1,4 @@
1
+ import { createCDPEmbeddedWalletConnector as r } from "./index2.js";
2
+ export {
3
+ r as createCDPEmbeddedWalletConnector
4
+ };
@@ -0,0 +1,173 @@
1
+ import { createCDPEmbeddedWallet as w, STANDARD_ERROR_CODES as g, EIP1193ProviderError as I, initialize as p } from "@coinbase/cdp-core";
2
+ import { SwitchChainError as y, numberToHex as b, getAddress as f } from "viem";
3
+ import { createConnector as D } from "wagmi";
4
+ function Z(d) {
5
+ return D((a) => {
6
+ const v = d.providerConfig?.chains ?? a.chains ?? [];
7
+ let h, i, r, u, c, m;
8
+ async function C() {
9
+ m || (m = p(d.cdpConfig)), await m;
10
+ }
11
+ return {
12
+ /**
13
+ * Sets up the connector by binding the 1193's internal events to the connector's methods,
14
+ * is called as soon as app mounts.
15
+ *
16
+ * Core sdk must be initialised before 1193 provider is created,
17
+ * this.getProvider internally awaits the stored initPromise
18
+ */
19
+ async setup() {
20
+ const e = await this.getProvider();
21
+ r || (r = this.onDisconnect.bind(this), e.on("disconnect", r)), c || (c = this.onAccountsChanged.bind(this), e.on("accountsChanged", c)), i || (i = this.onChainChanged.bind(this), e.on("chainChanged", i)), u || (u = this.onConnect.bind(this), e.on("connect", u));
22
+ },
23
+ /**
24
+ * Connector function called when the user connects their wallet.
25
+ * On app mount, if the user was previously connected, this will be called
26
+ * with `isReconnecting` set to true.
27
+ *
28
+ * @param args - connect args
29
+ * @param args.chainId - {string} - the target chain id to connect to
30
+ * @param args.isReconnecting - {boolean} - whether the user was previously connected
31
+ * @returns The accounts and chain id of the now-connected user
32
+ */
33
+ async connect({
34
+ chainId: e,
35
+ isReconnecting: t
36
+ } = {}) {
37
+ let o = [];
38
+ t && (o = await this.getAccounts());
39
+ try {
40
+ if (!o?.length && !t && (o = await (await this.getProvider()).request({ method: "eth_requestAccounts" }), o.length === 0))
41
+ throw new Error("User has no evm addresses available or is not authenticated");
42
+ let n = await this.getChainId();
43
+ return e && n !== e && (n = (await this.switchChain({ chainId: e }).catch(
44
+ (l) => {
45
+ if (l.code === g.provider.userRejectedRequest) throw l;
46
+ return { id: n };
47
+ }
48
+ ))?.id ?? n), { accounts: o, chainId: n };
49
+ } catch (n) {
50
+ const s = n;
51
+ throw s.code === g.provider.userRejectedRequest ? new I(
52
+ g.provider.userRejectedRequest,
53
+ s.message
54
+ ) : s;
55
+ }
56
+ },
57
+ /**
58
+ * Disconnects the user, cleans up the connector's event listeners and calls
59
+ * the embedded wallet's destroy method
60
+ */
61
+ async disconnect() {
62
+ const e = await this.getProvider();
63
+ await e.request({ method: "wallet_disconnect" }), r && (e.removeListener("disconnect", r), r = void 0), c && (e.removeListener("accountsChanged", c), c = void 0), i && (e.removeListener("chainChanged", i), i = void 0);
64
+ },
65
+ /**
66
+ * Get the accounts of the user
67
+ *
68
+ * @returns {Address[]} The accounts of the user
69
+ */
70
+ async getAccounts() {
71
+ return await (await this.getProvider()).request({
72
+ method: "eth_accounts"
73
+ });
74
+ },
75
+ /**
76
+ * Get the chain id of the user
77
+ *
78
+ * @returns {number} The chain id of the user
79
+ */
80
+ async getChainId() {
81
+ const e = await this.getProvider();
82
+ return Number(await e.request({ method: "eth_chainId" }));
83
+ },
84
+ /**
85
+ * Get the provider, which internally is sensitive to the signed in user
86
+ *
87
+ * @returns {EIP1193Provider} The 1193 provider
88
+ */
89
+ async getProvider() {
90
+ return await C(), h || (h = w({
91
+ chains: v,
92
+ transports: d.providerConfig.transports
93
+ })), h.provider;
94
+ },
95
+ /**
96
+ * Checks if the user is authorized
97
+ *
98
+ * @returns {boolean} Whether the user is authorized
99
+ */
100
+ async isAuthorized() {
101
+ try {
102
+ return !!(await this.getAccounts()).length;
103
+ } catch {
104
+ return !1;
105
+ }
106
+ },
107
+ /**
108
+ * Below we have thin internal methods that ensure we emit the events to wagmi's
109
+ * internal event emitter, which it uses to update the wagmi store.
110
+ *
111
+ * We bind these to the EIP1193 provider's event emission in `setup()`
112
+ */
113
+ /**
114
+ * Handle accounts changed events ensuring we emit the events to wagmi
115
+ *
116
+ * @param accounts - {readonly string[]} - The accounts of the user (wagmi expects readonly string, not 0xstring)
117
+ */
118
+ onAccountsChanged(e) {
119
+ a.emitter.emit("change", {
120
+ accounts: e.map((t) => f(t))
121
+ });
122
+ },
123
+ /**
124
+ * Handle chain changed events ensuring we emit the events to wagmi
125
+ *
126
+ * @param chain - {string} - The chain of the user
127
+ */
128
+ onChainChanged(e) {
129
+ const t = Number(e);
130
+ a.emitter.emit("change", { chainId: t });
131
+ },
132
+ /**
133
+ * Handle connect events ensuring we emit the events to wagmi
134
+ *
135
+ * @param args - The connect info
136
+ * @param args.chainId - {string} - The chain id to connect to
137
+ */
138
+ async onConnect({ chainId: e }) {
139
+ const t = await this.getAccounts();
140
+ t.length !== 0 && a.emitter.emit("connect", { accounts: t, chainId: Number(e) });
141
+ },
142
+ /**
143
+ * Handle disconnect events ensuring we emit the events to wagmi
144
+ */
145
+ async onDisconnect() {
146
+ a.emitter.emit("disconnect");
147
+ },
148
+ /**
149
+ * Switches the user to the specified chain
150
+ *
151
+ * @param args - The switch chain args
152
+ * @param args.chainId - {number} - The chain id to switch to
153
+ * @returns {Promise<Chain>} The chain that was switched to
154
+ */
155
+ async switchChain({ chainId: e }) {
156
+ const t = v.find((n) => n.id === e);
157
+ if (!t) throw new y(new Error("Chain not configured"));
158
+ return await (await this.getProvider()).request({
159
+ method: "wallet_switchEthereumChain",
160
+ params: [{ chainId: b(e) }]
161
+ }), t;
162
+ },
163
+ // Below are temporary values while we dev
164
+ icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZD0iTTEyIDJMMiA3VjE3TDEyIDIyTDIyIDE3VjdMMTIgMloiIHN0cm9rZT0iY3VycmVudENvbG9yIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPgo8L3N2Zz4K",
165
+ id: "cdp",
166
+ name: "CDP",
167
+ type: "injected"
168
+ };
169
+ });
170
+ }
171
+ export {
172
+ Z as createCDPEmbeddedWalletConnector
173
+ };
@@ -0,0 +1,10 @@
1
+ import { CDPEmbeddedWalletConfig } from '@coinbase/cdp-core';
2
+ import { Config } from '@coinbase/cdp-core';
3
+ import { createConnector } from 'wagmi';
4
+
5
+ export declare function createCDPEmbeddedWalletConnector(parameters: {
6
+ cdpConfig: Config;
7
+ providerConfig: CDPEmbeddedWalletConfig;
8
+ }): ReturnType<typeof createConnector>;
9
+
10
+ export { }
package/package.json CHANGED
@@ -1,8 +1,64 @@
1
1
  {
2
2
  "name": "@coinbase/cdp-wagmi",
3
- "version": "0.0.0",
4
- "description": "Placeholder package",
5
- "main": "index.js",
6
- "author": "Coinbase Inc.",
7
- "license": "Apache-2.0"
8
- }
3
+ "version": "0.0.5",
4
+ "type": "module",
5
+ "files": [
6
+ "dist/**",
7
+ "!dist/**/*.tsbuildinfo"
8
+ ],
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/types/index.d.ts",
12
+ "default": "./dist/esm/index.js"
13
+ }
14
+ },
15
+ "dependencies": {},
16
+ "peerDependencies": {
17
+ "@tanstack/react-query": "^5.0.0",
18
+ "react": ">=18.2.0",
19
+ "viem": "^2.33.0",
20
+ "wagmi": "^2.16.0",
21
+ "@coinbase/cdp-core": "^0.0.5"
22
+ },
23
+ "devDependencies": {
24
+ "@tanstack/react-query": "^5.0.0",
25
+ "@testing-library/jest-dom": "^6.6.3",
26
+ "@testing-library/react": "^16.3.0",
27
+ "@types/react": "^19.1.0",
28
+ "@types/react-dom": "^19.1.0",
29
+ "jsdom": "^24.0.0",
30
+ "react": "^19.1.0",
31
+ "react-dom": "^19.1.0",
32
+ "vitest": "^3.2.2",
33
+ "@size-limit/preset-big-lib": "^11.2.0",
34
+ "@size-limit/webpack": "^11.2.0",
35
+ "@size-limit/webpack-why": "^11.2.0",
36
+ "size-limit": "^11.2.0",
37
+ "@coinbase/cdp-core": "^0.0.5"
38
+ },
39
+ "size-limit": [
40
+ {
41
+ "name": "full-package",
42
+ "path": "./dist/esm/index.js",
43
+ "import": "*",
44
+ "limit": "70 KB"
45
+ },
46
+ {
47
+ "name": "connector-only",
48
+ "path": "./dist/esm/index.js",
49
+ "import": "{ createCDPEmbeddedWalletConnector }",
50
+ "limit": "70 KB"
51
+ }
52
+ ],
53
+ "scripts": {
54
+ "build": "pnpm run clean && pnpm run check:types && vite build --config ../../vite.config.base.ts",
55
+ "build:watch": "vite build --config ../../vite.config.base.ts --watch",
56
+ "check:types": "tsc --noEmit",
57
+ "clean": "rm -rf dist",
58
+ "clean:all": "pnpm clean && rm -rf node_modules",
59
+ "size-limit": "size-limit",
60
+ "size-limit:why": "size-limit --why",
61
+ "test": "vitest",
62
+ "test:run": "vitest --run"
63
+ }
64
+ }
package/index.js DELETED
@@ -1 +0,0 @@
1
- console.log("Temporary package");