alchemy 0.69.1 → 0.70.1
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/bin/alchemy.js +3883 -3906
- package/bin/alchemy.ts +2 -0
- package/bin/commands/telemetry.ts +33 -0
- package/bin/services/execute-alchemy.ts +7 -0
- package/bin/trpc.ts +4 -9
- package/lib/alchemy.d.ts +7 -3
- package/lib/alchemy.d.ts.map +1 -1
- package/lib/alchemy.js +3 -15
- package/lib/alchemy.js.map +1 -1
- package/lib/apply.js +24 -9
- package/lib/apply.js.map +1 -1
- package/lib/aws/utils.d.ts +2 -1
- package/lib/aws/utils.d.ts.map +1 -1
- package/lib/aws/utils.js.map +1 -1
- package/lib/clickhouse/api/client.gen.d.ts +13 -0
- package/lib/clickhouse/api/client.gen.d.ts.map +1 -0
- package/lib/clickhouse/api/client.gen.js +7 -0
- package/lib/clickhouse/api/client.gen.js.map +1 -0
- package/lib/clickhouse/api/sdk.gen.d.ts +322 -0
- package/lib/clickhouse/api/sdk.gen.d.ts.map +1 -0
- package/lib/clickhouse/api/sdk.gen.js +683 -0
- package/lib/clickhouse/api/sdk.gen.js.map +1 -0
- package/lib/clickhouse/api/types.gen.d.ts +5030 -0
- package/lib/clickhouse/api/types.gen.d.ts.map +1 -0
- package/lib/clickhouse/api/types.gen.js +2 -0
- package/lib/clickhouse/api/types.gen.js.map +1 -0
- package/lib/clickhouse/api-key.d.ts +29 -0
- package/lib/clickhouse/api-key.d.ts.map +1 -0
- package/lib/clickhouse/api-key.js +83 -0
- package/lib/clickhouse/api-key.js.map +1 -0
- package/lib/clickhouse/api.d.ts +36 -0
- package/lib/clickhouse/api.d.ts.map +1 -0
- package/lib/clickhouse/api.js +48 -0
- package/lib/clickhouse/api.js.map +1 -0
- package/lib/clickhouse/index.d.ts +4 -0
- package/lib/clickhouse/index.d.ts.map +1 -0
- package/lib/clickhouse/index.js +4 -0
- package/lib/clickhouse/index.js.map +1 -0
- package/lib/clickhouse/organization.d.ts +16 -0
- package/lib/clickhouse/organization.d.ts.map +1 -0
- package/lib/clickhouse/organization.js +21 -0
- package/lib/clickhouse/organization.js.map +1 -0
- package/lib/clickhouse/service.d.ts +275 -0
- package/lib/clickhouse/service.d.ts.map +1 -0
- package/lib/clickhouse/service.js +274 -0
- package/lib/clickhouse/service.js.map +1 -0
- package/lib/cloudflare/account-api-token.d.ts.map +1 -1
- package/lib/cloudflare/account-api-token.js +1 -1
- package/lib/cloudflare/account-api-token.js.map +1 -1
- package/lib/cloudflare/api.d.ts.map +1 -1
- package/lib/cloudflare/api.js +2 -0
- package/lib/cloudflare/api.js.map +1 -1
- package/lib/cloudflare/bun-spa/bun-spa.d.ts +13 -0
- package/lib/cloudflare/bun-spa/bun-spa.d.ts.map +1 -0
- package/lib/cloudflare/bun-spa/bun-spa.js +95 -0
- package/lib/cloudflare/bun-spa/bun-spa.js.map +1 -0
- package/lib/cloudflare/compatibility-date.gen.d.ts +1 -1
- package/lib/cloudflare/compatibility-date.gen.js +1 -1
- package/lib/cloudflare/container.d.ts +11 -1
- package/lib/cloudflare/container.d.ts.map +1 -1
- package/lib/cloudflare/container.js.map +1 -1
- package/lib/cloudflare/index.d.ts +1 -0
- package/lib/cloudflare/index.d.ts.map +1 -1
- package/lib/cloudflare/index.js +1 -0
- package/lib/cloudflare/index.js.map +1 -1
- package/lib/cloudflare/miniflare/build-worker-options.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/build-worker-options.js +33 -6
- package/lib/cloudflare/miniflare/build-worker-options.js.map +1 -1
- package/lib/cloudflare/miniflare/miniflare-controller.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/miniflare-controller.js +2 -0
- package/lib/cloudflare/miniflare/miniflare-controller.js.map +1 -1
- package/lib/cloudflare/miniflare/miniflare-worker-proxy.d.ts +1 -1
- package/lib/cloudflare/miniflare/miniflare-worker-proxy.d.ts.map +1 -1
- package/lib/cloudflare/miniflare/miniflare-worker-proxy.js +36 -49
- package/lib/cloudflare/miniflare/miniflare-worker-proxy.js.map +1 -1
- package/lib/cloudflare/permission-groups.d.ts +2 -3
- package/lib/cloudflare/permission-groups.d.ts.map +1 -1
- package/lib/cloudflare/permission-groups.js +10 -15
- package/lib/cloudflare/permission-groups.js.map +1 -1
- package/lib/cloudflare/redwood/redwood.d.ts +1 -1
- package/lib/cloudflare/redwood/redwood.js +1 -1
- package/lib/cloudflare/util/filter-env-bindings.d.ts +62 -0
- package/lib/cloudflare/util/filter-env-bindings.d.ts.map +1 -0
- package/lib/cloudflare/util/filter-env-bindings.js +81 -0
- package/lib/cloudflare/util/filter-env-bindings.js.map +1 -0
- package/lib/cloudflare/website.d.ts +2 -2
- package/lib/cloudflare/website.d.ts.map +1 -1
- package/lib/cloudflare/website.js +6 -18
- package/lib/cloudflare/website.js.map +1 -1
- package/lib/cloudflare/worker-metadata.d.ts +1 -0
- package/lib/cloudflare/worker-metadata.d.ts.map +1 -1
- package/lib/cloudflare/worker-metadata.js +1 -0
- package/lib/cloudflare/worker-metadata.js.map +1 -1
- package/lib/cloudflare/worker.d.ts +11 -1
- package/lib/cloudflare/worker.d.ts.map +1 -1
- package/lib/cloudflare/worker.js.map +1 -1
- package/lib/cloudflare/wrangler.json.d.ts +8 -0
- package/lib/cloudflare/wrangler.json.d.ts.map +1 -1
- package/lib/cloudflare/wrangler.json.js +3 -4
- package/lib/cloudflare/wrangler.json.js.map +1 -1
- package/lib/coinbase/client.d.ts +54 -0
- package/lib/coinbase/client.d.ts.map +1 -0
- package/lib/coinbase/client.js +89 -0
- package/lib/coinbase/client.js.map +1 -0
- package/lib/coinbase/evm-account.d.ts +118 -0
- package/lib/coinbase/evm-account.d.ts.map +1 -0
- package/lib/coinbase/evm-account.js +198 -0
- package/lib/coinbase/evm-account.js.map +1 -0
- package/lib/coinbase/evm-smart-account.d.ts +122 -0
- package/lib/coinbase/evm-smart-account.d.ts.map +1 -0
- package/lib/coinbase/evm-smart-account.js +213 -0
- package/lib/coinbase/evm-smart-account.js.map +1 -0
- package/lib/coinbase/faucet.d.ts +11 -0
- package/lib/coinbase/faucet.d.ts.map +1 -0
- package/lib/coinbase/faucet.js +146 -0
- package/lib/coinbase/faucet.js.map +1 -0
- package/lib/coinbase/index.d.ts +4 -0
- package/lib/coinbase/index.d.ts.map +1 -0
- package/lib/coinbase/index.js +4 -0
- package/lib/coinbase/index.js.map +1 -0
- package/lib/coinbase/types.d.ts +28 -0
- package/lib/coinbase/types.d.ts.map +1 -0
- package/lib/coinbase/types.js +4 -0
- package/lib/{util/telemetry → coinbase}/types.js.map +1 -1
- package/lib/coinbase/utils.d.ts +13 -0
- package/lib/coinbase/utils.d.ts.map +1 -0
- package/lib/coinbase/utils.js +17 -0
- package/lib/coinbase/utils.js.map +1 -0
- package/lib/neon/api/types.gen.d.ts +7 -2
- package/lib/neon/api/types.gen.d.ts.map +1 -1
- package/lib/planetscale/api/types.gen.d.ts +20 -4
- package/lib/planetscale/api/types.gen.d.ts.map +1 -1
- package/lib/planetscale/api.d.ts.map +1 -1
- package/lib/planetscale/api.js +1 -0
- package/lib/planetscale/api.js.map +1 -1
- package/lib/planetscale/password.d.ts.map +1 -1
- package/lib/planetscale/password.js +1 -13
- package/lib/planetscale/password.js.map +1 -1
- package/lib/resource.d.ts.map +1 -1
- package/lib/resource.js +7 -3
- package/lib/resource.js.map +1 -1
- package/lib/scope.d.ts +9 -9
- package/lib/scope.d.ts.map +1 -1
- package/lib/scope.js +18 -37
- package/lib/scope.js.map +1 -1
- package/lib/state/instrumented-state-store.d.ts +1 -3
- package/lib/state/instrumented-state-store.d.ts.map +1 -1
- package/lib/state/instrumented-state-store.js +19 -21
- package/lib/state/instrumented-state-store.js.map +1 -1
- package/lib/test/bun.d.ts.map +1 -1
- package/lib/test/bun.js +1 -2
- package/lib/test/bun.js.map +1 -1
- package/lib/test/vitest.d.ts.map +1 -1
- package/lib/test/vitest.js +1 -2
- package/lib/test/vitest.js.map +1 -1
- package/lib/util/diff.d.ts +5 -0
- package/lib/util/diff.d.ts.map +1 -0
- package/lib/util/diff.js +14 -0
- package/lib/util/diff.js.map +1 -0
- package/lib/util/idempotent-spawn.js +1 -1
- package/lib/util/idempotent-spawn.js.map +1 -1
- package/lib/util/telemetry.d.ts +53 -0
- package/lib/util/telemetry.d.ts.map +1 -0
- package/lib/util/telemetry.js +215 -0
- package/lib/util/telemetry.js.map +1 -0
- package/package.json +19 -1
- package/src/alchemy.ts +10 -20
- package/src/apply.ts +29 -12
- package/src/aws/utils.ts +2 -1
- package/src/clickhouse/api/client.gen.ts +28 -0
- package/src/clickhouse/api/sdk.gen.ts +1286 -0
- package/src/clickhouse/api/types.gen.ts +5898 -0
- package/src/clickhouse/api-key.ts +136 -0
- package/src/clickhouse/api.ts +84 -0
- package/src/clickhouse/index.ts +3 -0
- package/src/clickhouse/organization.ts +31 -0
- package/src/clickhouse/service.ts +668 -0
- package/src/cloudflare/account-api-token.ts +1 -4
- package/src/cloudflare/api.ts +2 -0
- package/src/cloudflare/bun-spa/bun-spa.ts +136 -0
- package/src/cloudflare/compatibility-date.gen.ts +1 -1
- package/src/cloudflare/container.ts +20 -1
- package/src/cloudflare/index.ts +1 -0
- package/src/cloudflare/miniflare/build-worker-options.ts +38 -8
- package/src/cloudflare/miniflare/miniflare-controller.ts +2 -0
- package/src/cloudflare/miniflare/miniflare-worker-proxy.ts +41 -58
- package/src/cloudflare/permission-groups.ts +21 -49
- package/src/cloudflare/redwood/redwood.ts +1 -1
- package/src/cloudflare/util/filter-env-bindings.ts +96 -0
- package/src/cloudflare/website.ts +11 -24
- package/src/cloudflare/worker-metadata.ts +2 -0
- package/src/cloudflare/worker.ts +12 -1
- package/src/cloudflare/wrangler.json.ts +12 -8
- package/src/coinbase/client.ts +146 -0
- package/src/coinbase/evm-account.ts +317 -0
- package/src/coinbase/evm-smart-account.ts +339 -0
- package/src/coinbase/faucet.ts +173 -0
- package/src/coinbase/index.ts +3 -0
- package/src/coinbase/types.ts +33 -0
- package/src/coinbase/utils.ts +19 -0
- package/src/neon/api/types.gen.ts +13 -1
- package/src/planetscale/api/types.gen.ts +22 -2
- package/src/planetscale/api.ts +1 -0
- package/src/planetscale/password.ts +1 -14
- package/src/resource.ts +11 -4
- package/src/scope.ts +29 -45
- package/src/state/instrumented-state-store.ts +27 -26
- package/src/test/bun.ts +1 -2
- package/src/test/vitest.ts +1 -2
- package/src/util/diff.ts +14 -0
- package/src/util/idempotent-spawn.ts +1 -1
- package/src/util/telemetry.ts +328 -0
- package/templates/tanstack-start/package.json +2 -2
- package/workers/tunnel-proxy.js +1 -1
- package/lib/util/telemetry/client.d.ts +0 -31
- package/lib/util/telemetry/client.d.ts.map +0 -1
- package/lib/util/telemetry/client.js +0 -121
- package/lib/util/telemetry/client.js.map +0 -1
- package/lib/util/telemetry/constants.d.ts +0 -5
- package/lib/util/telemetry/constants.d.ts.map +0 -1
- package/lib/util/telemetry/constants.js +0 -8
- package/lib/util/telemetry/constants.js.map +0 -1
- package/lib/util/telemetry/context.d.ts +0 -15
- package/lib/util/telemetry/context.d.ts.map +0 -1
- package/lib/util/telemetry/context.js +0 -128
- package/lib/util/telemetry/context.js.map +0 -1
- package/lib/util/telemetry/index.d.ts +0 -3
- package/lib/util/telemetry/index.d.ts.map +0 -1
- package/lib/util/telemetry/index.js +0 -3
- package/lib/util/telemetry/index.js.map +0 -1
- package/lib/util/telemetry/types.d.ts +0 -68
- package/lib/util/telemetry/types.d.ts.map +0 -1
- package/lib/util/telemetry/types.js +0 -1
- package/src/util/telemetry/client.ts +0 -156
- package/src/util/telemetry/constants.ts +0 -13
- package/src/util/telemetry/context.ts +0 -154
- package/src/util/telemetry/index.ts +0 -2
- package/src/util/telemetry/types.ts +0 -105
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import type { Context } from "../context.ts";
|
|
2
|
+
import type { Secret } from "../index.ts";
|
|
3
|
+
import { Resource } from "../resource.ts";
|
|
4
|
+
import { type CoinbaseClientOptions } from "./client.ts";
|
|
5
|
+
import type { Address, FaucetConfig, PrivateKey } from "./types.ts";
|
|
6
|
+
export type { FaucetConfig, FaucetNetwork, FaucetToken } from "./types.ts";
|
|
7
|
+
export interface EvmAccountProps extends CoinbaseClientOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Name for the account.
|
|
10
|
+
* Used for identification in CDP.
|
|
11
|
+
* Must contain only letters, numbers, and hyphens.
|
|
12
|
+
*/
|
|
13
|
+
name: string;
|
|
14
|
+
/**
|
|
15
|
+
* Optional private key to import an existing account.
|
|
16
|
+
* Must be a hex string (starting with 0x) encrypted using alchemy.secret().
|
|
17
|
+
* If not provided, a new account will be created or existing one will be used.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* privateKey: alchemy.secret(process.env.PRIVATE_KEY)
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
privateKey?: Secret<PrivateKey>;
|
|
25
|
+
/**
|
|
26
|
+
* Whether to adopt an existing account with the same name if it already exists.
|
|
27
|
+
* Without adoption, creation will fail if an account with the same name exists.
|
|
28
|
+
* With adoption, the existing account will be used.
|
|
29
|
+
* @default false
|
|
30
|
+
*/
|
|
31
|
+
adopt?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Faucet configuration for development funding.
|
|
34
|
+
* Declares which tokens this account should have.
|
|
35
|
+
* Used by external funding scripts - not processed by the resource.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```ts
|
|
39
|
+
* faucet: {
|
|
40
|
+
* "base-sepolia": ["eth", "usdc"],
|
|
41
|
+
* "ethereum-sepolia": ["eth"]
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
faucet?: FaucetConfig;
|
|
46
|
+
}
|
|
47
|
+
export interface EvmAccount extends Resource<"coinbase::evm-account"> {
|
|
48
|
+
/**
|
|
49
|
+
* The account name in CDP
|
|
50
|
+
*/
|
|
51
|
+
name: string;
|
|
52
|
+
/**
|
|
53
|
+
* The EVM address (same across all EVM networks)
|
|
54
|
+
*/
|
|
55
|
+
address: Address;
|
|
56
|
+
/**
|
|
57
|
+
* Faucet configuration (passed through from props)
|
|
58
|
+
*/
|
|
59
|
+
faucet?: FaucetConfig;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Manages EVM EOA (Externally Owned Accounts) on Coinbase Developer Platform.
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ## Create a new EVM account
|
|
66
|
+
*
|
|
67
|
+
* ```ts
|
|
68
|
+
* const account = await EvmAccount("my-account", {
|
|
69
|
+
* name: "my-account"
|
|
70
|
+
* });
|
|
71
|
+
*
|
|
72
|
+
* console.log("Account address:", account.address);
|
|
73
|
+
* ```
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ## Create account with funding metadata
|
|
77
|
+
*
|
|
78
|
+
* Declare what tokens this account needs for development
|
|
79
|
+
*
|
|
80
|
+
* ```ts
|
|
81
|
+
* const account = await EvmAccount("test-account", {
|
|
82
|
+
* name: "test-account",
|
|
83
|
+
* faucet: {
|
|
84
|
+
* "base-sepolia": ["eth", "usdc"],
|
|
85
|
+
* "ethereum-sepolia": ["eth"]
|
|
86
|
+
* }
|
|
87
|
+
* });
|
|
88
|
+
*
|
|
89
|
+
* // Account automatically requests tokens on creation
|
|
90
|
+
* // The faucet script can be used for bulk funding operations
|
|
91
|
+
* ```
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* ## Import an existing account
|
|
95
|
+
*
|
|
96
|
+
* Import an existing EVM account using a private key
|
|
97
|
+
*
|
|
98
|
+
* ```ts
|
|
99
|
+
* const account = await EvmAccount("imported-account", {
|
|
100
|
+
* name: "imported-account",
|
|
101
|
+
* privateKey: alchemy.secret(process.env.COINBASE_PRIVATE_KEY)
|
|
102
|
+
* });
|
|
103
|
+
* ```
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ## Adopt an existing account
|
|
107
|
+
*
|
|
108
|
+
* Use an existing account with the same name if it exists
|
|
109
|
+
*
|
|
110
|
+
* ```ts
|
|
111
|
+
* const account = await EvmAccount("my-account", {
|
|
112
|
+
* name: "existing-account",
|
|
113
|
+
* adopt: true // Uses existing account if it exists
|
|
114
|
+
* });
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
export declare const EvmAccount: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<EvmAccount>, _id: string, props: EvmAccountProps) => Promise<EvmAccount>);
|
|
118
|
+
//# sourceMappingURL=evm-account.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evm-account.d.ts","sourceRoot":"","sources":["../../src/coinbase/evm-account.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAmB,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,KAAK,EACV,OAAO,EACP,YAAY,EAGZ,UAAU,EACX,MAAM,YAAY,CAAC;AAIpB,YAAY,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE3E,MAAM,WAAW,eAAgB,SAAQ,qBAAqB;IAC5D;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;;;;;;;;OASG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAChC;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,MAAM,WAAW,UAAW,SAAQ,QAAQ,CAAC,uBAAuB,CAAC;IACnE;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB;;OAEG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,eAAO,MAAM,UAAU,yFAGb,OAAO,CAAC,UAAU,CAAC,OACpB,MAAM,SACJ,eAAe,KACrB,OAAO,CAAC,UAAU,CAAC,CAsLvB,CAAC"}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
import { Resource } from "../resource.js";
|
|
2
|
+
import { createCdpClient } from "./client.js";
|
|
3
|
+
import { validateAccountName } from "./utils.js";
|
|
4
|
+
/**
|
|
5
|
+
* Manages EVM EOA (Externally Owned Accounts) on Coinbase Developer Platform.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ## Create a new EVM account
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* const account = await EvmAccount("my-account", {
|
|
12
|
+
* name: "my-account"
|
|
13
|
+
* });
|
|
14
|
+
*
|
|
15
|
+
* console.log("Account address:", account.address);
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ## Create account with funding metadata
|
|
20
|
+
*
|
|
21
|
+
* Declare what tokens this account needs for development
|
|
22
|
+
*
|
|
23
|
+
* ```ts
|
|
24
|
+
* const account = await EvmAccount("test-account", {
|
|
25
|
+
* name: "test-account",
|
|
26
|
+
* faucet: {
|
|
27
|
+
* "base-sepolia": ["eth", "usdc"],
|
|
28
|
+
* "ethereum-sepolia": ["eth"]
|
|
29
|
+
* }
|
|
30
|
+
* });
|
|
31
|
+
*
|
|
32
|
+
* // Account automatically requests tokens on creation
|
|
33
|
+
* // The faucet script can be used for bulk funding operations
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* @example
|
|
37
|
+
* ## Import an existing account
|
|
38
|
+
*
|
|
39
|
+
* Import an existing EVM account using a private key
|
|
40
|
+
*
|
|
41
|
+
* ```ts
|
|
42
|
+
* const account = await EvmAccount("imported-account", {
|
|
43
|
+
* name: "imported-account",
|
|
44
|
+
* privateKey: alchemy.secret(process.env.COINBASE_PRIVATE_KEY)
|
|
45
|
+
* });
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ## Adopt an existing account
|
|
50
|
+
*
|
|
51
|
+
* Use an existing account with the same name if it exists
|
|
52
|
+
*
|
|
53
|
+
* ```ts
|
|
54
|
+
* const account = await EvmAccount("my-account", {
|
|
55
|
+
* name: "existing-account",
|
|
56
|
+
* adopt: true // Uses existing account if it exists
|
|
57
|
+
* });
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export const EvmAccount = Resource("coinbase::evm-account", async function (_id, props) {
|
|
61
|
+
// Validate account name format
|
|
62
|
+
validateAccountName(props.name);
|
|
63
|
+
// Initialize CDP client with credentials from props or environment
|
|
64
|
+
const cdp = await createCdpClient({
|
|
65
|
+
apiKeyId: props.apiKeyId,
|
|
66
|
+
apiKeySecret: props.apiKeySecret,
|
|
67
|
+
walletSecret: props.walletSecret,
|
|
68
|
+
});
|
|
69
|
+
// Handle update phase
|
|
70
|
+
if (this.phase === "update" && this.output) {
|
|
71
|
+
// Only name can be updated
|
|
72
|
+
if (props.name !== this.output.name) {
|
|
73
|
+
// CDP SDK supports updating account names via updateAccount
|
|
74
|
+
await cdp.evm.updateAccount({
|
|
75
|
+
address: this.output.address,
|
|
76
|
+
update: {
|
|
77
|
+
name: props.name,
|
|
78
|
+
},
|
|
79
|
+
});
|
|
80
|
+
return {
|
|
81
|
+
...this.output,
|
|
82
|
+
name: props.name, // Use the requested name
|
|
83
|
+
faucet: props.faucet,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
// Update faucet configuration if changed
|
|
87
|
+
if (JSON.stringify(props.faucet) !== JSON.stringify(this.output.faucet)) {
|
|
88
|
+
// Only fund NEW combinations that weren't in the previous config
|
|
89
|
+
try {
|
|
90
|
+
// Get all old combinations
|
|
91
|
+
const oldCombinations = new Set(Object.entries(this.output.faucet ?? {}).flatMap(([network, tokens]) => tokens.map((token) => `${network}:${token}`)));
|
|
92
|
+
// Get all new combinations
|
|
93
|
+
const newCombinations = Object.entries(props.faucet ?? {}).flatMap(([network, tokens]) => tokens.map((token) => ({
|
|
94
|
+
network: network,
|
|
95
|
+
token: token,
|
|
96
|
+
key: `${network}:${token}`,
|
|
97
|
+
})));
|
|
98
|
+
// Filter to only combinations that are actually new
|
|
99
|
+
const toFund = newCombinations.filter(({ key }) => !oldCombinations.has(key));
|
|
100
|
+
if (toFund.length > 0) {
|
|
101
|
+
await Promise.all(toFund.map(({ network, token }) => cdp.evm
|
|
102
|
+
.requestFaucet({
|
|
103
|
+
address: this.output.address,
|
|
104
|
+
network,
|
|
105
|
+
token,
|
|
106
|
+
})
|
|
107
|
+
.catch((err) => {
|
|
108
|
+
console.warn(`⚠️ Failed to request ${token} on ${network} for ${this.output.address}: ${err.message}`);
|
|
109
|
+
return null;
|
|
110
|
+
})));
|
|
111
|
+
console.log(`💧 Requested ${toFund.length} new faucet fund${toFund.length === 1 ? "" : "s"} for ${this.output.address}`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
console.warn(`⚠️ Failed to request additional faucet funds for ${this.output.address}: ${error.message}`);
|
|
116
|
+
// Continue - don't break the update
|
|
117
|
+
}
|
|
118
|
+
return {
|
|
119
|
+
...this.output,
|
|
120
|
+
faucet: props.faucet,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return this.output;
|
|
124
|
+
}
|
|
125
|
+
// Handle delete phase
|
|
126
|
+
if (this.phase === "delete") {
|
|
127
|
+
// CDP SDK doesn't support deleting accounts
|
|
128
|
+
// Accounts remain in CDP but are no longer tracked by Alchemy
|
|
129
|
+
console.log(`🗑️ Untracking EVM Account: ${this.output.address}`);
|
|
130
|
+
return this.destroy();
|
|
131
|
+
}
|
|
132
|
+
let account;
|
|
133
|
+
// Handle account creation/retrieval
|
|
134
|
+
if (props.privateKey) {
|
|
135
|
+
// Import account with private key
|
|
136
|
+
// This is idempotent in CDP
|
|
137
|
+
account = await cdp.evm.importAccount({
|
|
138
|
+
privateKey: props.privateKey.unencrypted,
|
|
139
|
+
name: props.name,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
// Check for adoption or use getOrCreate pattern
|
|
144
|
+
const adopt = props.adopt ?? this.scope.adopt;
|
|
145
|
+
if (adopt) {
|
|
146
|
+
// With adoption, use getOrCreate which returns existing if it exists
|
|
147
|
+
account = await cdp.evm.getOrCreateAccount({
|
|
148
|
+
name: props.name,
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
// Without adoption, we can attempt to create it.
|
|
153
|
+
// It will throw if already exist
|
|
154
|
+
try {
|
|
155
|
+
account = await cdp.evm.createAccount({ name: props.name });
|
|
156
|
+
}
|
|
157
|
+
catch (error) {
|
|
158
|
+
// Provide helpful error message if account already exists
|
|
159
|
+
if (error.errorType === "already_exists") {
|
|
160
|
+
throw new Error(`Account with name '${props.name}' already exists. Use adopt: true to use the existing account.`);
|
|
161
|
+
}
|
|
162
|
+
// Rethrow other errors unchanged
|
|
163
|
+
throw error;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// Fund the account if faucet configuration is provided
|
|
168
|
+
if (props.faucet) {
|
|
169
|
+
try {
|
|
170
|
+
const combinations = Object.entries(props.faucet).flatMap(([network, tokens]) => tokens.map((token) => ({
|
|
171
|
+
network: network,
|
|
172
|
+
token: token,
|
|
173
|
+
})));
|
|
174
|
+
await Promise.all(combinations.map(({ network, token }) => cdp.evm
|
|
175
|
+
.requestFaucet({
|
|
176
|
+
address: account.address,
|
|
177
|
+
network,
|
|
178
|
+
token,
|
|
179
|
+
})
|
|
180
|
+
.catch((err) => {
|
|
181
|
+
console.warn(`⚠️ Failed to request ${token} on ${network} for ${account.address}: ${err.message}`);
|
|
182
|
+
return null;
|
|
183
|
+
})));
|
|
184
|
+
console.log(`💧 Requested faucet funds for ${account.address}`);
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
console.warn(`⚠️ Failed to request faucet funds for ${account.address}: ${error.message}`);
|
|
188
|
+
// Continue - don't break account creation
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Return account details
|
|
192
|
+
return {
|
|
193
|
+
name: props.name, // Always use the name from props for consistency
|
|
194
|
+
address: account.address,
|
|
195
|
+
faucet: props.faucet,
|
|
196
|
+
};
|
|
197
|
+
});
|
|
198
|
+
//# sourceMappingURL=evm-account.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evm-account.js","sourceRoot":"","sources":["../../src/coinbase/evm-account.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { Context } from "../context.ts";
|
|
2
|
+
import { Resource } from "../resource.ts";
|
|
3
|
+
import { type CoinbaseClientOptions } from "./client.ts";
|
|
4
|
+
import type { EvmAccount } from "./evm-account.ts";
|
|
5
|
+
import type { Address, FaucetConfig } from "./types.ts";
|
|
6
|
+
export interface EvmSmartAccountProps extends CoinbaseClientOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Name for the smart account.
|
|
9
|
+
* If not provided, inherits the name from the owner account.
|
|
10
|
+
* This allows EOA and Smart Account to have matching names in CDP.
|
|
11
|
+
* Used for identification in CDP.
|
|
12
|
+
* Must contain only letters, numbers, and hyphens.
|
|
13
|
+
* @default Inherits from owner account name
|
|
14
|
+
*/
|
|
15
|
+
name?: string;
|
|
16
|
+
/**
|
|
17
|
+
* The owner account that controls this smart account.
|
|
18
|
+
* Can be either an EvmAccount resource or an owner address.
|
|
19
|
+
*/
|
|
20
|
+
owner: EvmAccount | Address;
|
|
21
|
+
/**
|
|
22
|
+
* Whether to adopt an existing smart account with the same name if it already exists.
|
|
23
|
+
* Without adoption, creation will fail if a smart account with the same name exists.
|
|
24
|
+
* With adoption, the existing smart account will be used.
|
|
25
|
+
* @default false
|
|
26
|
+
*/
|
|
27
|
+
adopt?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Faucet configuration for development funding.
|
|
30
|
+
* Declares which tokens this smart account should have.
|
|
31
|
+
* Used by external funding scripts - not processed by the resource.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* faucet: {
|
|
36
|
+
* "base-sepolia": ["eth", "usdc"],
|
|
37
|
+
* "ethereum-sepolia": ["eth"]
|
|
38
|
+
* }
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
faucet?: FaucetConfig;
|
|
42
|
+
}
|
|
43
|
+
export interface EvmSmartAccount extends Resource<"coinbase::evm-smart-account"> {
|
|
44
|
+
/**
|
|
45
|
+
* The smart account name in CDP
|
|
46
|
+
*/
|
|
47
|
+
name: string;
|
|
48
|
+
/**
|
|
49
|
+
* The smart account address (same across all EVM networks)
|
|
50
|
+
*/
|
|
51
|
+
address: Address;
|
|
52
|
+
/**
|
|
53
|
+
* The owner account address
|
|
54
|
+
*/
|
|
55
|
+
ownerAddress: Address;
|
|
56
|
+
/**
|
|
57
|
+
* Faucet configuration (passed through from props)
|
|
58
|
+
*/
|
|
59
|
+
faucet?: FaucetConfig;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Manages ERC-4337 smart accounts on Coinbase Developer Platform.
|
|
63
|
+
* Smart accounts enable gasless transactions and advanced features like batch operations.
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ## Create a smart account with an EVM account owner
|
|
67
|
+
*
|
|
68
|
+
* ```ts
|
|
69
|
+
* const owner = await EvmAccount("owner", {
|
|
70
|
+
* name: "owner-account"
|
|
71
|
+
* });
|
|
72
|
+
*
|
|
73
|
+
* const smartAccount = await EvmSmartAccount("my-smart-account", {
|
|
74
|
+
* name: "my-smart-account",
|
|
75
|
+
* owner: owner
|
|
76
|
+
* });
|
|
77
|
+
*
|
|
78
|
+
* console.log("Smart account address:", smartAccount.address);
|
|
79
|
+
* ```
|
|
80
|
+
*
|
|
81
|
+
* @example
|
|
82
|
+
* ## Create a smart account with existing owner
|
|
83
|
+
*
|
|
84
|
+
* ```ts
|
|
85
|
+
* const smartAccount = await EvmSmartAccount("my-smart-account", {
|
|
86
|
+
* name: "my-smart-account",
|
|
87
|
+
* owner: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb" // Owner address
|
|
88
|
+
* });
|
|
89
|
+
* ```
|
|
90
|
+
*
|
|
91
|
+
* @example
|
|
92
|
+
* ## Smart account with inherited name
|
|
93
|
+
*
|
|
94
|
+
* When name is omitted, the smart account inherits the owner's name
|
|
95
|
+
*
|
|
96
|
+
* ```ts
|
|
97
|
+
* const owner = await EvmAccount("owner", {
|
|
98
|
+
* name: "my-app-wallet"
|
|
99
|
+
* });
|
|
100
|
+
*
|
|
101
|
+
* // Smart account will also be named "my-app-wallet" in CDP
|
|
102
|
+
* const smartAccount = await EvmSmartAccount("smart", {
|
|
103
|
+
* owner: owner
|
|
104
|
+
* // name is omitted, inherits "my-app-wallet" from owner
|
|
105
|
+
* });
|
|
106
|
+
*
|
|
107
|
+
* console.log(smartAccount.name); // "my-app-wallet"
|
|
108
|
+
* ```
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* ## Adopt an existing smart account
|
|
112
|
+
*
|
|
113
|
+
* ```ts
|
|
114
|
+
* const smartAccount = await EvmSmartAccount("my-smart-account", {
|
|
115
|
+
* name: "existing-smart-account",
|
|
116
|
+
* owner: ownerAccount, // or "0x..." address
|
|
117
|
+
* adopt: true // Uses existing smart account if it exists
|
|
118
|
+
* });
|
|
119
|
+
* ```
|
|
120
|
+
*/
|
|
121
|
+
export declare const EvmSmartAccount: (((this: any, id: string, props?: {}) => never) & (new (_: never) => never)) | ((this: Context<EvmSmartAccount>, _id: string, props: EvmSmartAccountProps) => Promise<EvmSmartAccount>);
|
|
122
|
+
//# sourceMappingURL=evm-smart-account.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evm-smart-account.d.ts","sourceRoot":"","sources":["../../src/coinbase/evm-smart-account.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAmB,KAAK,qBAAqB,EAAE,MAAM,aAAa,CAAC;AAC1E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EACV,OAAO,EACP,YAAY,EAGb,MAAM,YAAY,CAAC;AAGpB,MAAM,WAAW,oBAAqB,SAAQ,qBAAqB;IACjE;;;;;;;OAOG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC;IAC5B;;;;;OAKG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED,MAAM,WAAW,eACf,SAAQ,QAAQ,CAAC,6BAA6B,CAAC;IAC/C;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,OAAO,EAAE,OAAO,CAAC;IACjB;;OAEG;IACH,YAAY,EAAE,OAAO,CAAC;IACtB;;OAEG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AACH,eAAO,MAAM,eAAe,yFAGlB,OAAO,CAAC,eAAe,CAAC,OACzB,MAAM,SACJ,oBAAoB,KAC1B,OAAO,CAAC,eAAe,CAAC,CA0M5B,CAAC"}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { Resource } from "../resource.js";
|
|
2
|
+
import { createCdpClient } from "./client.js";
|
|
3
|
+
import { validateAccountName } from "./utils.js";
|
|
4
|
+
/**
|
|
5
|
+
* Manages ERC-4337 smart accounts on Coinbase Developer Platform.
|
|
6
|
+
* Smart accounts enable gasless transactions and advanced features like batch operations.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ## Create a smart account with an EVM account owner
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* const owner = await EvmAccount("owner", {
|
|
13
|
+
* name: "owner-account"
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* const smartAccount = await EvmSmartAccount("my-smart-account", {
|
|
17
|
+
* name: "my-smart-account",
|
|
18
|
+
* owner: owner
|
|
19
|
+
* });
|
|
20
|
+
*
|
|
21
|
+
* console.log("Smart account address:", smartAccount.address);
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ## Create a smart account with existing owner
|
|
26
|
+
*
|
|
27
|
+
* ```ts
|
|
28
|
+
* const smartAccount = await EvmSmartAccount("my-smart-account", {
|
|
29
|
+
* name: "my-smart-account",
|
|
30
|
+
* owner: "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb" // Owner address
|
|
31
|
+
* });
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ## Smart account with inherited name
|
|
36
|
+
*
|
|
37
|
+
* When name is omitted, the smart account inherits the owner's name
|
|
38
|
+
*
|
|
39
|
+
* ```ts
|
|
40
|
+
* const owner = await EvmAccount("owner", {
|
|
41
|
+
* name: "my-app-wallet"
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* // Smart account will also be named "my-app-wallet" in CDP
|
|
45
|
+
* const smartAccount = await EvmSmartAccount("smart", {
|
|
46
|
+
* owner: owner
|
|
47
|
+
* // name is omitted, inherits "my-app-wallet" from owner
|
|
48
|
+
* });
|
|
49
|
+
*
|
|
50
|
+
* console.log(smartAccount.name); // "my-app-wallet"
|
|
51
|
+
* ```
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ## Adopt an existing smart account
|
|
55
|
+
*
|
|
56
|
+
* ```ts
|
|
57
|
+
* const smartAccount = await EvmSmartAccount("my-smart-account", {
|
|
58
|
+
* name: "existing-smart-account",
|
|
59
|
+
* owner: ownerAccount, // or "0x..." address
|
|
60
|
+
* adopt: true // Uses existing smart account if it exists
|
|
61
|
+
* });
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export const EvmSmartAccount = Resource("coinbase::evm-smart-account", async function (_id, props) {
|
|
65
|
+
// Initialize CDP client with credentials from props or environment
|
|
66
|
+
const cdp = await createCdpClient({
|
|
67
|
+
apiKeyId: props.apiKeyId,
|
|
68
|
+
apiKeySecret: props.apiKeySecret,
|
|
69
|
+
walletSecret: props.walletSecret,
|
|
70
|
+
});
|
|
71
|
+
// Get owner address
|
|
72
|
+
const ownerAddress = typeof props.owner === "string" ? props.owner : props.owner.address;
|
|
73
|
+
// Get owner account for CDP operations
|
|
74
|
+
// When owner is an address string, we use it to get the account
|
|
75
|
+
const ownerAccount = typeof props.owner === "string"
|
|
76
|
+
? await cdp.evm.getAccount({ address: props.owner })
|
|
77
|
+
: await cdp.evm.getAccount({ address: props.owner.address });
|
|
78
|
+
// If no name provided, inherit from owner
|
|
79
|
+
// this mean that if you pass only { owner } the created smartAccount will be same name as the EOA owner
|
|
80
|
+
// this to support https://github.com/base/account-sdk/blob/master/packages/account-sdk/src/interface/payment/charge.ts#L120
|
|
81
|
+
let accountName = props.name ? props.name : ownerAccount.name;
|
|
82
|
+
if (!accountName) {
|
|
83
|
+
throw new Error(`Smart account requires a name. Either provide 'name' in props or ensure the owner account has a name. Owner address: ${ownerAddress}`);
|
|
84
|
+
}
|
|
85
|
+
// Validate account name format
|
|
86
|
+
validateAccountName(accountName);
|
|
87
|
+
// Handle update phase
|
|
88
|
+
if (this.phase === "update" && this.output) {
|
|
89
|
+
// Check if owner changed (which would require replacement)
|
|
90
|
+
if (ownerAddress !== this.output.ownerAddress) {
|
|
91
|
+
this.replace();
|
|
92
|
+
}
|
|
93
|
+
// Check if name changed
|
|
94
|
+
if (accountName !== this.output.name) {
|
|
95
|
+
await cdp.evm.updateSmartAccount({
|
|
96
|
+
address: this.output.address,
|
|
97
|
+
owner: ownerAccount,
|
|
98
|
+
update: {
|
|
99
|
+
name: accountName,
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
return {
|
|
103
|
+
...this.output,
|
|
104
|
+
name: accountName,
|
|
105
|
+
// faucet: props.faucet, not sure we need this?
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
// Update faucet configuration if changed
|
|
109
|
+
if (JSON.stringify(props.faucet) !== JSON.stringify(this.output.faucet)) {
|
|
110
|
+
// Only fund NEW combinations that weren't in the previous config
|
|
111
|
+
try {
|
|
112
|
+
// Get all old combinations
|
|
113
|
+
const oldCombinations = new Set(Object.entries(this.output.faucet ?? {}).flatMap(([network, tokens]) => tokens.map((token) => `${network}:${token}`)));
|
|
114
|
+
// Get all new combinations
|
|
115
|
+
const newCombinations = Object.entries(props.faucet ?? {}).flatMap(([network, tokens]) => tokens.map((token) => ({
|
|
116
|
+
network: network,
|
|
117
|
+
token: token,
|
|
118
|
+
key: `${network}:${token}`,
|
|
119
|
+
})));
|
|
120
|
+
// Filter to only combinations that are actually new
|
|
121
|
+
const toFund = newCombinations.filter(({ key }) => !oldCombinations.has(key));
|
|
122
|
+
if (toFund.length > 0) {
|
|
123
|
+
await Promise.all(toFund.map(({ network, token }) => cdp.evm
|
|
124
|
+
.requestFaucet({
|
|
125
|
+
address: this.output.address,
|
|
126
|
+
network,
|
|
127
|
+
token,
|
|
128
|
+
})
|
|
129
|
+
.catch((err) => {
|
|
130
|
+
console.warn(`⚠️ Failed to request ${token} on ${network} for smart account ${this.output.address}: ${err.message}`);
|
|
131
|
+
return null;
|
|
132
|
+
})));
|
|
133
|
+
console.log(`💧 Requested ${toFund.length} new faucet fund${toFund.length === 1 ? "" : "s"} for smart account ${this.output.address}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
console.warn(`⚠️ Failed to request additional faucet funds for smart account ${this.output.address}: ${error.message}`);
|
|
138
|
+
// Continue - don't break the update
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
...this.output,
|
|
142
|
+
faucet: props.faucet,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
return this.output;
|
|
146
|
+
}
|
|
147
|
+
// Handle delete phase
|
|
148
|
+
if (this.phase === "delete") {
|
|
149
|
+
// CDP SDK doesn't support deleting accounts
|
|
150
|
+
// Accounts remain in CDP but are no longer tracked by Alchemy
|
|
151
|
+
console.log(`🗑️ Untracking Smart Account: ${this.output?.address}`);
|
|
152
|
+
return this.destroy();
|
|
153
|
+
}
|
|
154
|
+
let smartAccount;
|
|
155
|
+
// Check for adoption or use getOrCreate pattern
|
|
156
|
+
const adopt = props.adopt ?? this.scope.adopt;
|
|
157
|
+
if (adopt) {
|
|
158
|
+
// With adoption, use getOrCreateSmartAccount which returns existing if it exists
|
|
159
|
+
smartAccount = await cdp.evm.getOrCreateSmartAccount({
|
|
160
|
+
name: accountName,
|
|
161
|
+
owner: ownerAccount,
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
// Without adoption, create a new smart account
|
|
166
|
+
try {
|
|
167
|
+
smartAccount = await cdp.evm.createSmartAccount({
|
|
168
|
+
name: accountName,
|
|
169
|
+
owner: ownerAccount,
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
// Provide helpful error message if smart account already exists
|
|
174
|
+
if (error.errorType === "already_exists") {
|
|
175
|
+
throw new Error(`Smart account with name '${accountName}' already exists. Use adopt: true to use the existing smart account.`);
|
|
176
|
+
}
|
|
177
|
+
// Rethrow other errors unchanged
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// Fund the smart account if faucet configuration is provided
|
|
182
|
+
if (props.faucet) {
|
|
183
|
+
try {
|
|
184
|
+
const combinations = Object.entries(props.faucet).flatMap(([network, tokens]) => tokens.map((token) => ({
|
|
185
|
+
network: network,
|
|
186
|
+
token: token,
|
|
187
|
+
})));
|
|
188
|
+
await Promise.all(combinations.map(({ network, token }) => cdp.evm
|
|
189
|
+
.requestFaucet({
|
|
190
|
+
address: smartAccount.address,
|
|
191
|
+
network,
|
|
192
|
+
token,
|
|
193
|
+
})
|
|
194
|
+
.catch((err) => {
|
|
195
|
+
console.warn(`⚠️ Failed to request ${token} on ${network} for smart account ${smartAccount.address}: ${err.message}`);
|
|
196
|
+
return null;
|
|
197
|
+
})));
|
|
198
|
+
console.log(`💧 Requested faucet funds for smart account ${smartAccount.address}`);
|
|
199
|
+
}
|
|
200
|
+
catch (error) {
|
|
201
|
+
console.warn(`⚠️ Failed to request faucet funds for smart account ${smartAccount.address}: ${error.message}`);
|
|
202
|
+
// Continue - don't break account creation
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
// Return smart account details
|
|
206
|
+
return {
|
|
207
|
+
name: accountName,
|
|
208
|
+
address: smartAccount.address,
|
|
209
|
+
ownerAddress,
|
|
210
|
+
faucet: props.faucet,
|
|
211
|
+
};
|
|
212
|
+
});
|
|
213
|
+
//# sourceMappingURL=evm-smart-account.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evm-smart-account.js","sourceRoot":"","sources":["../../src/coinbase/evm-smart-account.ts"],"names":[],"mappings":"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"}
|