@namera-ai/cli 0.1.4 → 1.0.0
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 +91 -221
- package/dist/index.js +1660 -0
- package/dist/index.js.map +1 -0
- package/package.json +57 -50
- package/LICENSE +0 -201
- package/dist/commands/index.mjs +0 -21
- package/dist/commands/index.mjs.map +0 -1
- package/dist/commands/keystore/create.mjs +0 -74
- package/dist/commands/keystore/create.mjs.map +0 -1
- package/dist/commands/keystore/decrypt.mjs +0 -71
- package/dist/commands/keystore/decrypt.mjs.map +0 -1
- package/dist/commands/keystore/import.mjs +0 -84
- package/dist/commands/keystore/import.mjs.map +0 -1
- package/dist/commands/keystore/index.mjs +0 -28
- package/dist/commands/keystore/index.mjs.map +0 -1
- package/dist/commands/keystore/info.mjs +0 -62
- package/dist/commands/keystore/info.mjs.map +0 -1
- package/dist/commands/keystore/list.mjs +0 -46
- package/dist/commands/keystore/list.mjs.map +0 -1
- package/dist/commands/keystore/remove.mjs +0 -51
- package/dist/commands/keystore/remove.mjs.map +0 -1
- package/dist/commands/mcp/index.mjs +0 -13
- package/dist/commands/mcp/index.mjs.map +0 -1
- package/dist/commands/mcp/start.mjs +0 -82
- package/dist/commands/mcp/start.mjs.map +0 -1
- package/dist/commands/schema/index.mjs +0 -53
- package/dist/commands/schema/index.mjs.map +0 -1
- package/dist/commands/session-key/create/index.mjs +0 -87
- package/dist/commands/session-key/create/index.mjs.map +0 -1
- package/dist/commands/session-key/create/prompts/base.mjs +0 -52
- package/dist/commands/session-key/create/prompts/base.mjs.map +0 -1
- package/dist/commands/session-key/create/prompts/call.mjs +0 -85
- package/dist/commands/session-key/create/prompts/call.mjs.map +0 -1
- package/dist/commands/session-key/create/prompts/common.mjs +0 -27
- package/dist/commands/session-key/create/prompts/common.mjs.map +0 -1
- package/dist/commands/session-key/create/prompts/gas.mjs +0 -19
- package/dist/commands/session-key/create/prompts/gas.mjs.map +0 -1
- package/dist/commands/session-key/create/prompts/index.mjs +0 -44
- package/dist/commands/session-key/create/prompts/index.mjs.map +0 -1
- package/dist/commands/session-key/create/prompts/rate-limit.mjs +0 -40
- package/dist/commands/session-key/create/prompts/rate-limit.mjs.map +0 -1
- package/dist/commands/session-key/create/prompts/signature-caller.mjs +0 -26
- package/dist/commands/session-key/create/prompts/signature-caller.mjs.map +0 -1
- package/dist/commands/session-key/create/prompts/timestamp.mjs +0 -32
- package/dist/commands/session-key/create/prompts/timestamp.mjs.map +0 -1
- package/dist/commands/session-key/index.mjs +0 -26
- package/dist/commands/session-key/index.mjs.map +0 -1
- package/dist/commands/session-key/info.mjs +0 -64
- package/dist/commands/session-key/info.mjs.map +0 -1
- package/dist/commands/session-key/list.mjs +0 -54
- package/dist/commands/session-key/list.mjs.map +0 -1
- package/dist/commands/session-key/remove.mjs +0 -51
- package/dist/commands/session-key/remove.mjs.map +0 -1
- package/dist/commands/session-key/status.mjs +0 -64
- package/dist/commands/session-key/status.mjs.map +0 -1
- package/dist/commands/smart-account/create.mjs +0 -94
- package/dist/commands/smart-account/create.mjs.map +0 -1
- package/dist/commands/smart-account/import.mjs +0 -45
- package/dist/commands/smart-account/import.mjs.map +0 -1
- package/dist/commands/smart-account/index.mjs +0 -30
- package/dist/commands/smart-account/index.mjs.map +0 -1
- package/dist/commands/smart-account/info.mjs +0 -66
- package/dist/commands/smart-account/info.mjs.map +0 -1
- package/dist/commands/smart-account/list.mjs +0 -48
- package/dist/commands/smart-account/list.mjs.map +0 -1
- package/dist/commands/smart-account/remove.mjs +0 -54
- package/dist/commands/smart-account/remove.mjs.map +0 -1
- package/dist/commands/smart-account/status.mjs +0 -63
- package/dist/commands/smart-account/status.mjs.map +0 -1
- package/dist/dto/index.mjs +0 -6
- package/dist/dto/keystore.mjs +0 -44
- package/dist/dto/keystore.mjs.map +0 -1
- package/dist/dto/mcp.mjs +0 -13
- package/dist/dto/mcp.mjs.map +0 -1
- package/dist/dto/session-key.mjs +0 -54
- package/dist/dto/session-key.mjs.map +0 -1
- package/dist/dto/smart-account.mjs +0 -45
- package/dist/dto/smart-account.mjs.map +0 -1
- package/dist/flags/global.mjs +0 -29
- package/dist/flags/global.mjs.map +0 -1
- package/dist/flags/shared.mjs +0 -11
- package/dist/flags/shared.mjs.map +0 -1
- package/dist/helpers/humanize.mjs +0 -153
- package/dist/helpers/humanize.mjs.map +0 -1
- package/dist/helpers/paths.mjs +0 -31
- package/dist/helpers/paths.mjs.map +0 -1
- package/dist/helpers/policy.mjs +0 -89
- package/dist/helpers/policy.mjs.map +0 -1
- package/dist/helpers/pretty.mjs +0 -71
- package/dist/helpers/pretty.mjs.map +0 -1
- package/dist/index.d.mts +0 -2
- package/dist/index.mjs +0 -36
- package/dist/index.mjs.map +0 -1
- package/dist/layers/config.mjs +0 -124
- package/dist/layers/config.mjs.map +0 -1
- package/dist/layers/index.mjs +0 -11
- package/dist/layers/keystore.mjs +0 -225
- package/dist/layers/keystore.mjs.map +0 -1
- package/dist/layers/mcp-context.mjs +0 -8
- package/dist/layers/mcp-context.mjs.map +0 -1
- package/dist/layers/mcp.mjs +0 -31
- package/dist/layers/mcp.mjs.map +0 -1
- package/dist/layers/output.mjs +0 -21
- package/dist/layers/output.mjs.map +0 -1
- package/dist/layers/prompt.mjs +0 -78
- package/dist/layers/prompt.mjs.map +0 -1
- package/dist/layers/session-key.mjs +0 -218
- package/dist/layers/session-key.mjs.map +0 -1
- package/dist/layers/smart-account.mjs +0 -175
- package/dist/layers/smart-account.mjs.map +0 -1
- package/dist/layers/web3.mjs +0 -83
- package/dist/layers/web3.mjs.map +0 -1
- package/dist/mcp/helpers/common.mjs +0 -9
- package/dist/mcp/helpers/common.mjs.map +0 -1
- package/dist/mcp/helpers/index.mjs +0 -4
- package/dist/mcp/helpers/session-key.mjs +0 -129
- package/dist/mcp/helpers/session-key.mjs.map +0 -1
- package/dist/mcp/index.mjs +0 -43
- package/dist/mcp/index.mjs.map +0 -1
- package/dist/mcp/mcp.mjs +0 -15
- package/dist/mcp/mcp.mjs.map +0 -1
- package/dist/mcp/tools/account/address.mjs +0 -20
- package/dist/mcp/tools/account/address.mjs.map +0 -1
- package/dist/mcp/tools/account/get-balance.mjs +0 -54
- package/dist/mcp/tools/account/get-balance.mjs.map +0 -1
- package/dist/mcp/tools/account/index.mjs +0 -15
- package/dist/mcp/tools/account/index.mjs.map +0 -1
- package/dist/mcp/tools/read/index.mjs +0 -11
- package/dist/mcp/tools/read/index.mjs.map +0 -1
- package/dist/mcp/tools/read/read-contract.mjs +0 -49
- package/dist/mcp/tools/read/read-contract.mjs.map +0 -1
- package/dist/mcp/tools/transaction/execute-transaction.mjs +0 -38
- package/dist/mcp/tools/transaction/execute-transaction.mjs.map +0 -1
- package/dist/mcp/tools/transaction/index.mjs +0 -15
- package/dist/mcp/tools/transaction/index.mjs.map +0 -1
- package/dist/mcp/tools/transaction/native-transfer.mjs +0 -59
- package/dist/mcp/tools/transaction/native-transfer.mjs.map +0 -1
- package/dist/schema/chain.mjs +0 -124
- package/dist/schema/chain.mjs.map +0 -1
- package/dist/schema/common.mjs +0 -29
- package/dist/schema/common.mjs.map +0 -1
- package/dist/schema/index.mjs +0 -5
- package/dist/schema/policy.mjs +0 -114
- package/dist/schema/policy.mjs.map +0 -1
- package/dist/schema/tx.mjs +0 -19
- package/dist/schema/tx.mjs.map +0 -1
- package/dist/types/index.mjs +0 -11
- package/dist/types/index.mjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"session-key.mjs","names":["createSessionKey","createNameraSessionKey"],"sources":["../../src/layers/session-key.ts"],"sourcesContent":["import { Wallet } from \"@ethereumjs/wallet\";\nimport {\n createSessionKey as createNameraSessionKey,\n isSessionKeyInstalled,\n} from \"@namera-ai/sdk/session-key\";\nimport { Context, Data, Effect, Layer, type Redacted, Schema } from \"effect\";\nimport type { QuitError } from \"effect/Terminal\";\nimport type { Prompt } from \"effect/unstable/cli\";\nimport { hexToBytes, toHex } from \"viem\";\nimport {\n generatePrivateKey,\n type LocalAccount,\n privateKeyToAccount,\n} from \"viem/accounts\";\n\nimport {\n type CreateSessionKeyParams,\n type Keystore,\n SessionKey,\n type SessionKeyData,\n} from \"@/dto\";\nimport { policyParamsToPolicies } from \"@/helpers/policy\";\nimport { chainIdToChainName } from \"@/schema\";\n\nimport type {\n GetSessionKeyParams,\n GetSessionKeyStatusParams,\n ListSessionKeysParams,\n RemoveSessionKeyParams,\n} from \"../dto/session-key\";\nimport { ConfigManager, type ConfigManagerError } from \"./config\";\nimport { KeystoreManager, type KeystoreManagerError } from \"./keystore\";\nimport { PromptManager } from \"./prompt\";\nimport { SmartAccountManager } from \"./smart-account\";\nimport { Web3Service } from \"./web3\";\n\nexport type SessionKeyManager = {\n createSessionKey: (\n params: CreateSessionKeyParams,\n ) => Effect.Effect<\n SessionKeyData,\n SessionKeyManagerError | ConfigManagerError | KeystoreManagerError\n >;\n getSessionKey: (\n params: GetSessionKeyParams,\n ) => Effect.Effect<\n SessionKeyData,\n SessionKeyManagerError | ConfigManagerError\n >;\n listSessionKeys: (\n params: ListSessionKeysParams,\n ) => Effect.Effect<\n SessionKeyData[],\n ConfigManagerError | SessionKeyManagerError\n >;\n selectSessionKey: (params: {\n message: string;\n }) => Effect.Effect<\n SessionKeyData,\n ConfigManagerError | SessionKeyManagerError | QuitError,\n Prompt.Environment\n >;\n getSessionKeyStatus: (\n params: GetSessionKeyStatusParams,\n ) => Effect.Effect<\n boolean,\n ConfigManagerError | SessionKeyManagerError,\n never\n >;\n multiSelectSessionKeys: (params: {\n message: string;\n smartAccount?: string;\n }) => Effect.Effect<\n SessionKeyData[],\n ConfigManagerError | SessionKeyManagerError | QuitError,\n Prompt.Environment\n >;\n getSessionKeyPassword: (params: {\n alias: string;\n message: string;\n }) => Effect.Effect<\n Redacted.Redacted<string>,\n SessionKeyManagerError | ConfigManagerError | QuitError,\n Prompt.Environment\n >;\n getSessionKeySigner: (params: {\n alias: string;\n password: string;\n }) => Effect.Effect<\n SessionKeyData & { signer: LocalAccount },\n SessionKeyManagerError | ConfigManagerError | QuitError,\n never\n >;\n removeSessionKey: (params: {\n readonly alias: string;\n }) => Effect.Effect<void, SessionKeyManagerError | ConfigManagerError, never>;\n};\nexport const SessionKeyManager = Context.Service<SessionKeyManager>(\n \"@namera-ai/cli/SessionKeyManager\",\n);\n\nexport class SessionKeyManagerError extends Data.TaggedError(\n \"@namera-ai/cli/SessionKeyManagerError\",\n)<{\n code:\n | \"EncryptionError\"\n | \"SessionKeyAlreadyExists\"\n | \"SessionKeyParseError\"\n | \"DecryptError\";\n message: string;\n}> {}\n\nexport const layer = Layer.effect(\n SessionKeyManager,\n Effect.gen(function* () {\n const configManager = yield* ConfigManager;\n const promptManager = yield* PromptManager;\n const keystoreManager = yield* KeystoreManager;\n const smartAccountManager = yield* SmartAccountManager;\n const web3Service = yield* Web3Service;\n\n const createSessionKey = (params: CreateSessionKeyParams) =>\n Effect.gen(function* () {\n const exists = yield* configManager.checkEntityExists({\n alias: params.alias,\n type: \"session-key\",\n });\n\n if (exists) {\n return yield* Effect.fail(\n new SessionKeyManagerError({\n code: \"SessionKeyAlreadyExists\",\n message: `Session key for alias ${params.alias} already exists`,\n }),\n );\n }\n\n const entityPath = yield* configManager.getEntityPath({\n alias: params.alias,\n type: \"session-key\",\n });\n\n const sa = yield* smartAccountManager.getSmartAccount({\n alias: params.smartAccountAlias,\n });\n\n const ownerSigner = yield* keystoreManager.getSigner({\n alias: sa.data.ownerAlias,\n password: params.ownerKeystorePassword,\n });\n const policies = policyParamsToPolicies(params.policyParams);\n\n const clients = yield* Effect.all(\n params.chains.map((chain) => web3Service.getPublicClient({ chain })),\n { concurrency: \"unbounded\" },\n );\n\n const sessionPrivateKey = generatePrivateKey();\n const sessionKeyAccount = privateKeyToAccount(sessionPrivateKey);\n\n const res = yield* Effect.promise(() =>\n createNameraSessionKey({\n type: \"ecdsa\",\n accountType: \"ecdsa\",\n sessionPrivateKey,\n clients,\n entrypointVersion: sa.data.entryPointVersion,\n kernelVersion: sa.data.kernelVersion,\n index: sa.data.index,\n signer: ownerSigner,\n policies,\n }),\n );\n\n // Encrypt Session Key\n const encData = (yield* Effect.tryPromise({\n try: () =>\n Wallet.fromPrivateKey(hexToBytes(sessionPrivateKey)).toV3(\n params.sessionKeyPassword,\n ),\n catch: () =>\n new SessionKeyManagerError({\n code: \"EncryptionError\",\n message: \"Failed to encrypt session key\",\n }),\n })) as Keystore;\n\n const data: SessionKey = {\n sessionKeyType: \"ecdsa\",\n serializedAccounts: res.serializedAccounts.map((a) => ({\n chain: chainIdToChainName(a.chainId),\n serializedAccount: a.serializedAccount,\n })),\n sessionKeyAddress: sessionKeyAccount.address,\n smartAccountAlias: sa.alias,\n ...encData,\n };\n\n yield* configManager.storeEntity({\n alias: params.alias,\n content: JSON.stringify(data),\n path: entityPath,\n type: \"session-key\",\n });\n\n return {\n alias: params.alias,\n data,\n path: entityPath,\n } satisfies SessionKeyData;\n });\n\n const getSessionKey = (params: GetSessionKeyParams) =>\n Effect.gen(function* () {\n const res = yield* configManager.getEntity({\n alias: params.alias,\n type: \"session-key\",\n });\n\n const parsed = Schema.decodeUnknownOption(\n Schema.fromJsonString(SessionKey),\n )(res.content);\n\n if (parsed._tag === \"None\") {\n return yield* Effect.fail(\n new SessionKeyManagerError({\n code: \"SessionKeyParseError\",\n message: \"Unable to parse session key\",\n }),\n );\n }\n\n const data: SessionKeyData = {\n alias: res.alias,\n data: parsed.value,\n path: res.path,\n };\n\n return data;\n });\n\n const listSessionKeys = (params: ListSessionKeysParams) =>\n Effect.gen(function* () {\n const res = yield* configManager.getEntitiesForType(\"session-key\");\n\n const effects = res.map((entity) =>\n Effect.gen(function* () {\n const parsed = Schema.decodeUnknownOption(\n Schema.fromJsonString(SessionKey),\n )(entity.content);\n\n if (parsed._tag === \"None\") {\n return yield* Effect.fail(\n new SessionKeyManagerError({\n code: \"SessionKeyParseError\",\n message: \"Unable to parse session key\",\n }),\n );\n }\n\n const data: SessionKeyData = {\n alias: entity.alias,\n data: parsed.value,\n path: entity.path,\n };\n\n return data;\n }),\n );\n\n const allKeys = yield* Effect.all(effects, {\n concurrency: \"unbounded\",\n });\n // .map((d) => (d._op === \"Success\" ? d.success : undefined))\n // .filter(Boolean) as SessionKeyData[];\n\n if (params.smartAccount) {\n return allKeys.filter(\n (k) => k.data.smartAccountAlias === params.smartAccount,\n );\n }\n\n return allKeys;\n });\n\n const selectSessionKey = (params: { message: string }) =>\n Effect.gen(function* () {\n const sessionKeys = yield* listSessionKeys({});\n\n const res = yield* promptManager.selectPrompt({\n message: params.message,\n choices: sessionKeys.map((sk) => ({\n title: sk.alias,\n value: sk,\n description: `${sk.data.sessionKeyType === \"ecdsa\" ? sk.data.sessionKeyAddress : sk.data.passKeyName} (${sk.data.smartAccountAlias})`,\n })) satisfies Prompt.SelectChoice<SessionKeyData>[],\n });\n\n return res;\n });\n\n const getSessionKeyStatus = (params: GetSessionKeyStatusParams) =>\n Effect.gen(function* () {\n const sessionKey = yield* getSessionKey({ alias: params.alias });\n const sa = yield* smartAccountManager.getSmartAccount({\n alias: sessionKey.data.smartAccountAlias,\n });\n\n const publicClient = yield* web3Service.getPublicClient({\n chain: params.chain,\n rpcUrl: params.rpcUrl,\n });\n\n if (sessionKey.data.sessionKeyType !== \"ecdsa\") {\n return yield* Effect.fail(\n new SessionKeyManagerError({\n code: \"SessionKeyParseError\",\n message: \"Only ECDSA session keys have an on-chain status\",\n }),\n );\n }\n const sessionKeyAddress = sessionKey.data.sessionKeyAddress;\n\n const res = yield* Effect.tryPromise({\n try: () =>\n isSessionKeyInstalled(publicClient, {\n accountAddress: sa.data.smartAccountAddress,\n sessionKeyAddress,\n }),\n catch: () => false,\n }).pipe(Effect.catch(() => Effect.succeed(false)));\n\n return res;\n });\n\n const multiSelectSessionKeys = (params: {\n message: string;\n smartAccount?: string;\n }) =>\n Effect.gen(function* () {\n const allKeys = yield* listSessionKeys({\n smartAccount: params.smartAccount,\n });\n\n const res = yield* promptManager.multiSelectPrompt({\n message: params.message,\n choices: allKeys.map((k) => ({\n title: k.alias,\n value: k,\n description: `${k.data.sessionKeyType === \"ecdsa\" ? k.data.sessionKeyAddress : k.data.passKeyName} (${k.data.smartAccountAlias})`,\n })) satisfies Prompt.SelectChoice<SessionKeyData>[],\n min: 1,\n });\n\n return res;\n });\n\n const getSessionKeyPassword = (params: {\n alias: string;\n message: string;\n }) =>\n Effect.gen(function* () {\n const key = yield* getSessionKey({ alias: params.alias });\n\n const password = yield* promptManager.passwordPrompt({\n message: params.message,\n validate: (v) =>\n Effect.gen(function* () {\n if (v.trim() === \"\") {\n return yield* Effect.fail(\"Password cannot be empty\");\n }\n\n yield* Effect.tryPromise({\n try: () => Wallet.fromV3(key.data, v),\n catch: () =>\n new SessionKeyManagerError({\n code: \"DecryptError\",\n message: `Invalid password for session key ${params.alias}`,\n }),\n }).pipe(Effect.catch(() => Effect.fail(\"Invalid password\")));\n\n return v;\n }),\n });\n\n return password;\n });\n\n const getSessionKeySigner = (params: { alias: string; password: string }) =>\n Effect.gen(function* () {\n const key = yield* getSessionKey({ alias: params.alias });\n\n const signer = yield* Effect.tryPromise({\n try: async () => {\n const wallet = await Wallet.fromV3(key.data, params.password);\n return privateKeyToAccount(\n toHex(wallet.getPrivateKey()),\n ) as LocalAccount;\n },\n catch: () =>\n new SessionKeyManagerError({\n code: \"DecryptError\",\n message: `Invalid password for session key ${params.alias}`,\n }),\n });\n\n return { ...key, signer };\n });\n\n const removeSessionKey = (params: RemoveSessionKeyParams) =>\n Effect.gen(function* () {\n const key = yield* getSessionKey({ alias: params.alias });\n\n return yield* configManager.removeEntity({\n alias: key.alias,\n type: \"session-key\",\n });\n });\n\n return SessionKeyManager.of({\n createSessionKey,\n getSessionKey,\n listSessionKeys,\n selectSessionKey,\n getSessionKeyStatus,\n multiSelectSessionKeys,\n getSessionKeyPassword,\n getSessionKeySigner,\n removeSessionKey,\n });\n }),\n);\n"],"mappings":"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"}
|
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { LocalSmartAccount } from "../dto/smart-account.mjs";
|
|
3
|
-
import "../dto/index.mjs";
|
|
4
|
-
import { ConfigManager } from "./config.mjs";
|
|
5
|
-
import { PromptManager } from "./prompt.mjs";
|
|
6
|
-
import { KeystoreManager } from "./keystore.mjs";
|
|
7
|
-
import { Web3Service } from "./web3.mjs";
|
|
8
|
-
import { Context, Data, Effect, Layer, Schema } from "effect";
|
|
9
|
-
import { mainnet } from "viem/chains";
|
|
10
|
-
import { createPublicClient, http } from "viem";
|
|
11
|
-
import { createAccountClient } from "@namera-ai/sdk/account";
|
|
12
|
-
//#region src/layers/smart-account.ts
|
|
13
|
-
/**
|
|
14
|
-
* Service tag for resolving {@link SmartAccountManager} from the Effect context.
|
|
15
|
-
*/
|
|
16
|
-
const SmartAccountManager = Context.Service("@namera-ai/cli/SmartAccountManager");
|
|
17
|
-
/**
|
|
18
|
-
* Domain error for smart account lifecycle operations.
|
|
19
|
-
*/
|
|
20
|
-
var SmartAccountManagerError = class extends Data.TaggedError("@namera-ai/cli/SmartAccountManagerError") {};
|
|
21
|
-
/**
|
|
22
|
-
* Live layer that manages smart account storage and derivation.
|
|
23
|
-
*/
|
|
24
|
-
const layer = Layer.effect(SmartAccountManager, Effect.gen(function* () {
|
|
25
|
-
const configManager = yield* ConfigManager;
|
|
26
|
-
const keystoreManager = yield* KeystoreManager;
|
|
27
|
-
const promptManager = yield* PromptManager;
|
|
28
|
-
const web3Service = yield* Web3Service;
|
|
29
|
-
const getSmartAccount = (params) => Effect.gen(function* () {
|
|
30
|
-
const res = yield* configManager.getEntity({
|
|
31
|
-
alias: params.alias,
|
|
32
|
-
type: "smart-account"
|
|
33
|
-
});
|
|
34
|
-
const parsedSmartAccount = Schema.decodeUnknownSync(Schema.fromJsonString(LocalSmartAccount))(res.content);
|
|
35
|
-
return {
|
|
36
|
-
alias: res.alias,
|
|
37
|
-
data: parsedSmartAccount,
|
|
38
|
-
path: res.path
|
|
39
|
-
};
|
|
40
|
-
});
|
|
41
|
-
const listSmartAccounts = () => Effect.gen(function* () {
|
|
42
|
-
const effects = (yield* configManager.getEntitiesForType("smart-account")).map((entity) => Effect.gen(function* () {
|
|
43
|
-
const parsedSmartAccount = Schema.decodeUnknownSync(Schema.fromJsonString(LocalSmartAccount))(entity.content);
|
|
44
|
-
return {
|
|
45
|
-
alias: entity.alias,
|
|
46
|
-
data: parsedSmartAccount,
|
|
47
|
-
path: entity.path
|
|
48
|
-
};
|
|
49
|
-
}));
|
|
50
|
-
return yield* Effect.all(effects, { concurrency: "unbounded" });
|
|
51
|
-
});
|
|
52
|
-
const createSmartAccount = (params) => Effect.gen(function* () {
|
|
53
|
-
const existingAccounts = yield* listSmartAccounts();
|
|
54
|
-
const entityPath = yield* configManager.getEntityPath({
|
|
55
|
-
alias: params.alias,
|
|
56
|
-
type: "smart-account"
|
|
57
|
-
});
|
|
58
|
-
const ownerKeystore = yield* keystoreManager.getKeystore({ alias: params.ownerAlias });
|
|
59
|
-
const ownerSigner = yield* keystoreManager.getSigner({
|
|
60
|
-
alias: params.ownerAlias,
|
|
61
|
-
password: params.ownerPassword
|
|
62
|
-
});
|
|
63
|
-
const publicClient = createPublicClient({
|
|
64
|
-
chain: mainnet,
|
|
65
|
-
transport: http()
|
|
66
|
-
});
|
|
67
|
-
const entryPointVersion = "0.7";
|
|
68
|
-
const kernelVersion = "0.3.2";
|
|
69
|
-
const index = BigInt(params.index ?? 0);
|
|
70
|
-
const ownerType = "ecdsa";
|
|
71
|
-
const saAddress = (yield* Effect.tryPromise({
|
|
72
|
-
try: () => createAccountClient({
|
|
73
|
-
type: "ecdsa",
|
|
74
|
-
bundlerTransport: http(),
|
|
75
|
-
chain: mainnet,
|
|
76
|
-
client: publicClient,
|
|
77
|
-
entrypointVersion: entryPointVersion,
|
|
78
|
-
kernelVersion,
|
|
79
|
-
signer: ownerSigner
|
|
80
|
-
}),
|
|
81
|
-
catch: () => new SmartAccountManagerError({
|
|
82
|
-
code: "KernelAddressGenerationError",
|
|
83
|
-
message: `Unable to compute smart account address for Address: ${ownerKeystore.data.address} and Index: ${params.index}`
|
|
84
|
-
})
|
|
85
|
-
})).account.address;
|
|
86
|
-
if (existingAccounts.find((d) => d.data.smartAccountAddress === saAddress)) return yield* Effect.fail(new SmartAccountManagerError({
|
|
87
|
-
code: "SmartAccountAlreadyExists",
|
|
88
|
-
message: `Smart account for owner: ${ownerKeystore.alias} and index: ${params.index} already exists`
|
|
89
|
-
}));
|
|
90
|
-
const saData = {
|
|
91
|
-
entryPointVersion,
|
|
92
|
-
kernelVersion,
|
|
93
|
-
ownerAlias: ownerKeystore.alias,
|
|
94
|
-
ownerType,
|
|
95
|
-
smartAccountAddress: saAddress,
|
|
96
|
-
index
|
|
97
|
-
};
|
|
98
|
-
const data = {
|
|
99
|
-
data: saData,
|
|
100
|
-
path: entityPath,
|
|
101
|
-
alias: params.alias
|
|
102
|
-
};
|
|
103
|
-
const encoded = Schema.encodeSync(LocalSmartAccount)(saData);
|
|
104
|
-
yield* configManager.storeEntity({
|
|
105
|
-
alias: params.alias,
|
|
106
|
-
content: JSON.stringify(encoded),
|
|
107
|
-
path: entityPath,
|
|
108
|
-
type: "smart-account"
|
|
109
|
-
});
|
|
110
|
-
return data;
|
|
111
|
-
});
|
|
112
|
-
const selectSmartAccount = (params) => Effect.gen(function* () {
|
|
113
|
-
const smartAccounts = yield* listSmartAccounts();
|
|
114
|
-
return yield* promptManager.selectPrompt({
|
|
115
|
-
message: params.message,
|
|
116
|
-
choices: smartAccounts.map((a) => ({
|
|
117
|
-
title: a.alias,
|
|
118
|
-
value: a,
|
|
119
|
-
description: a.data.smartAccountAddress
|
|
120
|
-
}))
|
|
121
|
-
});
|
|
122
|
-
});
|
|
123
|
-
const removeSmartAccount = (params) => Effect.gen(function* () {
|
|
124
|
-
const sa = yield* getSmartAccount({ alias: params.alias });
|
|
125
|
-
return yield* configManager.removeEntity({
|
|
126
|
-
alias: sa.alias,
|
|
127
|
-
type: "smart-account"
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
const getSmartAccountStatus = (params) => Effect.gen(function* () {
|
|
131
|
-
const sa = yield* getSmartAccount({ alias: params.alias });
|
|
132
|
-
const publicClient = yield* web3Service.getPublicClient({
|
|
133
|
-
chain: params.chain,
|
|
134
|
-
rpcUrl: params.rpcUrl
|
|
135
|
-
});
|
|
136
|
-
const code = yield* Effect.promise(() => publicClient.getCode({ address: sa.data.smartAccountAddress }));
|
|
137
|
-
return Boolean(code);
|
|
138
|
-
});
|
|
139
|
-
const importSmartAccount = (params) => Effect.gen(function* () {
|
|
140
|
-
const { alias, ...rest } = params;
|
|
141
|
-
const entityPath = yield* configManager.getEntityPath({
|
|
142
|
-
alias: params.alias,
|
|
143
|
-
type: "smart-account"
|
|
144
|
-
});
|
|
145
|
-
const ownerKeystore = yield* keystoreManager.getKeystore({ alias: params.ownerAlias });
|
|
146
|
-
if ((yield* listSmartAccounts()).find((d) => d.data.smartAccountAddress === rest.smartAccountAddress)) return yield* Effect.fail(new SmartAccountManagerError({
|
|
147
|
-
code: "SmartAccountAlreadyExists",
|
|
148
|
-
message: `Smart account for owner: ${ownerKeystore.alias} and address: ${rest.smartAccountAddress} already exists`
|
|
149
|
-
}));
|
|
150
|
-
yield* configManager.storeEntity({
|
|
151
|
-
alias: params.alias,
|
|
152
|
-
content: JSON.stringify(Schema.encodeSync(LocalSmartAccount)(rest)),
|
|
153
|
-
path: entityPath,
|
|
154
|
-
type: "smart-account"
|
|
155
|
-
});
|
|
156
|
-
return {
|
|
157
|
-
alias: params.alias,
|
|
158
|
-
data: rest,
|
|
159
|
-
path: entityPath
|
|
160
|
-
};
|
|
161
|
-
});
|
|
162
|
-
return SmartAccountManager.of({
|
|
163
|
-
createSmartAccount,
|
|
164
|
-
getSmartAccount,
|
|
165
|
-
listSmartAccounts,
|
|
166
|
-
selectSmartAccount,
|
|
167
|
-
removeSmartAccount,
|
|
168
|
-
getSmartAccountStatus,
|
|
169
|
-
importSmartAccount
|
|
170
|
-
});
|
|
171
|
-
}));
|
|
172
|
-
//#endregion
|
|
173
|
-
export { SmartAccountManager, SmartAccountManagerError, layer };
|
|
174
|
-
|
|
175
|
-
//# sourceMappingURL=smart-account.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"smart-account.mjs","names":[],"sources":["../../src/layers/smart-account.ts"],"sourcesContent":["import { createAccountClient } from \"@namera-ai/sdk/account\";\nimport { Context, Data, Effect, Layer, Schema } from \"effect\";\nimport type { QuitError } from \"effect/Terminal\";\nimport type { Prompt } from \"effect/unstable/cli\";\nimport type { Environment } from \"effect/unstable/cli/Prompt\";\nimport { createPublicClient, http, type PublicClient } from \"viem\";\nimport { mainnet } from \"viem/chains\";\n\nimport {\n type CreateSmartAccountParams,\n type GetSmartAccountParams,\n type GetSmartAccountStatusParams,\n type ImportSmartAccountParams,\n LocalSmartAccount,\n type LocalSmartAccountData,\n type RemoveSmartAccountParams,\n} from \"@/dto\";\n\nimport { ConfigManager, type ConfigManagerError } from \"./config\";\nimport { KeystoreManager, type KeystoreManagerError } from \"./keystore\";\nimport { PromptManager } from \"./prompt\";\nimport { Web3Service } from \"./web3\";\n\nexport type SmartAccountManager = {\n /**\n * Loads a smart account by alias and parses the stored JSON payload.\n *\n * @param params Alias of the smart account to load.\n * @returns The parsed smart account data.\n */\n getSmartAccount: (\n params: GetSmartAccountParams,\n ) => Effect.Effect<LocalSmartAccountData, ConfigManagerError, never>;\n /**\n * Lists all locally stored smart accounts.\n *\n * @returns The list of smart account data.\n */\n listSmartAccounts: () => Effect.Effect<\n LocalSmartAccountData[],\n ConfigManagerError,\n never\n >;\n /**\n * Prompts the user to select a smart account from local storage.\n *\n * @param params - Prompt message to display.\n * @returns The selected smart account data.\n */\n selectSmartAccount: (params: {\n message: string;\n }) => Effect.Effect<\n LocalSmartAccountData,\n ConfigManagerError | KeystoreManagerError | QuitError,\n Environment\n >;\n /**\n * Creates a new smart account derived from a local keystore and index.\n *\n * @param params - Alias, owner alias, and optional index for derivation.\n * @returns The created smart account data.\n */\n createSmartAccount: (\n params: CreateSmartAccountParams,\n ) => Effect.Effect<\n LocalSmartAccountData,\n SmartAccountManagerError | ConfigManagerError | KeystoreManagerError,\n never\n >;\n /**\n * Removes a locally stored smart account by alias.\n *\n * @param params - Alias of the smart account to remove.\n */\n removeSmartAccount: (\n params: RemoveSmartAccountParams,\n ) => Effect.Effect<\n void,\n ConfigManagerError | SmartAccountManagerError,\n never\n >;\n /**\n * Checks if a smart account is deployed on the specified chain.\n *\n * @param params - Alias plus chain and optional RPC URL.\n * @returns Whether the smart account is deployed.\n */\n getSmartAccountStatus: (\n params: GetSmartAccountStatusParams,\n ) => Effect.Effect<boolean, ConfigManagerError, never>;\n /**\n * Imports a smart account with precomputed metadata and address.\n *\n * @param params - Smart account metadata and alias to store.\n * @returns The imported smart account data.\n */\n importSmartAccount: (\n params: ImportSmartAccountParams,\n ) => Effect.Effect<\n LocalSmartAccountData,\n SmartAccountManagerError | ConfigManagerError | KeystoreManagerError,\n never\n >;\n};\n\n/**\n * Service tag for resolving {@link SmartAccountManager} from the Effect context.\n */\nexport const SmartAccountManager = Context.Service<SmartAccountManager>(\n \"@namera-ai/cli/SmartAccountManager\",\n);\n\n/**\n * Domain error for smart account lifecycle operations.\n */\nexport class SmartAccountManagerError extends Data.TaggedError(\n \"@namera-ai/cli/SmartAccountManagerError\",\n)<{\n code:\n | \"KernelAddressGenerationError\"\n | \"SmartAccountAlreadyExists\"\n | \"SmartAccountNotFound\"\n | \"SmartAccountImportError\";\n message: string;\n}> {}\n\n/**\n * Live layer that manages smart account storage and derivation.\n */\nexport const layer = Layer.effect(\n SmartAccountManager,\n Effect.gen(function* () {\n const configManager = yield* ConfigManager;\n const keystoreManager = yield* KeystoreManager;\n const promptManager = yield* PromptManager;\n const web3Service = yield* Web3Service;\n\n const getSmartAccount = (params: GetSmartAccountParams) =>\n Effect.gen(function* () {\n const res = yield* configManager.getEntity({\n alias: params.alias,\n type: \"smart-account\",\n });\n\n const parsedSmartAccount = Schema.decodeUnknownSync(\n Schema.fromJsonString(LocalSmartAccount),\n )(res.content);\n\n return {\n alias: res.alias,\n data: parsedSmartAccount,\n path: res.path,\n } satisfies LocalSmartAccountData;\n });\n\n const listSmartAccounts = () =>\n Effect.gen(function* () {\n const res = yield* configManager.getEntitiesForType(\"smart-account\");\n\n const effects = res.map((entity) =>\n Effect.gen(function* () {\n const parsedSmartAccount = Schema.decodeUnknownSync(\n Schema.fromJsonString(LocalSmartAccount),\n )(entity.content);\n\n return {\n alias: entity.alias,\n data: parsedSmartAccount,\n path: entity.path,\n } satisfies LocalSmartAccountData;\n }),\n );\n\n return yield* Effect.all(effects, { concurrency: \"unbounded\" });\n });\n\n const createSmartAccount = (params: CreateSmartAccountParams) =>\n Effect.gen(function* () {\n const existingAccounts = yield* listSmartAccounts();\n\n const entityPath = yield* configManager.getEntityPath({\n alias: params.alias,\n type: \"smart-account\",\n });\n\n const ownerKeystore = yield* keystoreManager.getKeystore({\n alias: params.ownerAlias,\n });\n\n const ownerSigner = yield* keystoreManager.getSigner({\n alias: params.ownerAlias,\n password: params.ownerPassword,\n });\n\n // Doesn't matter because public client is only needed for 0.6 entrypoints\n const publicClient = createPublicClient({\n chain: mainnet,\n transport: http(),\n });\n\n const entryPointVersion = \"0.7\";\n const kernelVersion = \"0.3.2\";\n const index = BigInt(params.index ?? 0);\n const ownerType = \"ecdsa\";\n\n const res = yield* Effect.tryPromise({\n try: () =>\n createAccountClient({\n type: \"ecdsa\",\n bundlerTransport: http(),\n chain: mainnet,\n client: publicClient,\n entrypointVersion: entryPointVersion,\n kernelVersion,\n signer: ownerSigner,\n }),\n catch: () =>\n new SmartAccountManagerError({\n code: \"KernelAddressGenerationError\",\n message: `Unable to compute smart account address for Address: ${ownerKeystore.data.address} and Index: ${params.index}`,\n }),\n });\n\n const saAddress = res.account.address;\n\n const exists = existingAccounts.find(\n (d) => d.data.smartAccountAddress === saAddress,\n );\n\n if (exists) {\n return yield* Effect.fail(\n new SmartAccountManagerError({\n code: \"SmartAccountAlreadyExists\",\n message: `Smart account for owner: ${ownerKeystore.alias} and index: ${params.index} already exists`,\n }),\n );\n }\n\n const saData: LocalSmartAccount = {\n entryPointVersion,\n kernelVersion,\n ownerAlias: ownerKeystore.alias,\n ownerType,\n smartAccountAddress: saAddress,\n index,\n };\n\n const data: LocalSmartAccountData = {\n data: saData,\n path: entityPath,\n alias: params.alias,\n };\n\n const encoded = Schema.encodeSync(LocalSmartAccount)(saData);\n\n yield* configManager.storeEntity({\n alias: params.alias,\n content: JSON.stringify(encoded),\n path: entityPath,\n type: \"smart-account\",\n });\n\n return data;\n });\n\n const selectSmartAccount = (params: { message: string }) =>\n Effect.gen(function* () {\n const smartAccounts = yield* listSmartAccounts();\n\n const res = yield* promptManager.selectPrompt({\n message: params.message,\n choices: smartAccounts.map((a) => ({\n title: a.alias,\n value: a,\n description: a.data.smartAccountAddress,\n })) satisfies Prompt.SelectChoice<LocalSmartAccountData>[],\n });\n\n return res;\n });\n\n const removeSmartAccount = (params: RemoveSmartAccountParams) =>\n Effect.gen(function* () {\n const sa = yield* getSmartAccount({ alias: params.alias });\n\n return yield* configManager.removeEntity({\n alias: sa.alias,\n type: \"smart-account\",\n });\n });\n\n const getSmartAccountStatus = (params: GetSmartAccountStatusParams) =>\n Effect.gen(function* () {\n const sa = yield* getSmartAccount({ alias: params.alias });\n\n const publicClient = (yield* web3Service.getPublicClient({\n chain: params.chain,\n rpcUrl: params.rpcUrl,\n })) as PublicClient;\n\n const code = yield* Effect.promise(() =>\n publicClient.getCode({\n address: sa.data.smartAccountAddress,\n }),\n );\n\n return Boolean(code);\n });\n\n const importSmartAccount = (params: ImportSmartAccountParams) =>\n Effect.gen(function* () {\n const { alias, ...rest } = params;\n const entityPath = yield* configManager.getEntityPath({\n alias: params.alias,\n type: \"smart-account\",\n });\n\n const ownerKeystore = yield* keystoreManager.getKeystore({\n alias: params.ownerAlias,\n });\n\n const allAccounts = yield* listSmartAccounts();\n\n const exists = allAccounts.find(\n (d) => d.data.smartAccountAddress === rest.smartAccountAddress,\n );\n\n if (exists) {\n return yield* Effect.fail(\n new SmartAccountManagerError({\n code: \"SmartAccountAlreadyExists\",\n message: `Smart account for owner: ${ownerKeystore.alias} and address: ${rest.smartAccountAddress} already exists`,\n }),\n );\n }\n\n yield* configManager.storeEntity({\n alias: params.alias,\n content: JSON.stringify(Schema.encodeSync(LocalSmartAccount)(rest)),\n path: entityPath,\n type: \"smart-account\",\n });\n\n return {\n alias: params.alias,\n data: rest,\n path: entityPath,\n };\n });\n\n return SmartAccountManager.of({\n createSmartAccount,\n getSmartAccount,\n listSmartAccounts,\n selectSmartAccount,\n removeSmartAccount,\n getSmartAccountStatus,\n importSmartAccount,\n });\n }),\n);\n"],"mappings":"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"}
|
package/dist/layers/web3.mjs
DELETED
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { getChain, supportedChains } from "../schema/chain.mjs";
|
|
3
|
-
import "../schema/index.mjs";
|
|
4
|
-
import { PromptManager } from "./prompt.mjs";
|
|
5
|
-
import { Config, Context, Effect, Layer, Redacted } from "effect";
|
|
6
|
-
import { createPublicClient, http } from "viem";
|
|
7
|
-
//#region src/layers/web3.ts
|
|
8
|
-
/**
|
|
9
|
-
* Service tag for resolving {@link Web3Service} from the Effect context.
|
|
10
|
-
*/
|
|
11
|
-
const Web3Service = Context.Service("@namera-ai/cli/Web3Service");
|
|
12
|
-
/**
|
|
13
|
-
* Live layer that wires web3 clients and chain selection prompts.
|
|
14
|
-
*/
|
|
15
|
-
const layer = Layer.effect(Web3Service, Effect.gen(function* () {
|
|
16
|
-
const promptManager = yield* PromptManager;
|
|
17
|
-
const chainNameToEnvVar = (chain, suffix) => {
|
|
18
|
-
return `${chain.replaceAll("-", "_").toUpperCase()}_${suffix}`;
|
|
19
|
-
};
|
|
20
|
-
const getRpcUrl = (params) => Effect.gen(function* () {
|
|
21
|
-
let rpcUrl;
|
|
22
|
-
if (params.rpcUrl) rpcUrl = params.rpcUrl;
|
|
23
|
-
else {
|
|
24
|
-
const envVarName = chainNameToEnvVar(params.chain, "RPC_URL");
|
|
25
|
-
const envRpcUrl = yield* Config.option(Config.redacted(envVarName));
|
|
26
|
-
if (envRpcUrl._tag === "Some") rpcUrl = Redacted.value(envRpcUrl.value);
|
|
27
|
-
else rpcUrl = void 0;
|
|
28
|
-
}
|
|
29
|
-
return rpcUrl;
|
|
30
|
-
}).pipe(Effect.orDie);
|
|
31
|
-
const getBundlerUrl = (params) => Effect.gen(function* () {
|
|
32
|
-
let bundlerUrl;
|
|
33
|
-
if (params.bundlerUrl) bundlerUrl = params.bundlerUrl;
|
|
34
|
-
else {
|
|
35
|
-
const envVarName = chainNameToEnvVar(params.chain, "BUNDLER_URL");
|
|
36
|
-
const envRpcUrl = yield* Config.option(Config.redacted(envVarName));
|
|
37
|
-
if (envRpcUrl._tag === "Some") bundlerUrl = Redacted.value(envRpcUrl.value);
|
|
38
|
-
else bundlerUrl = `https://public.pimlico.io/v2/${getChain(params.chain).id}/rpc`;
|
|
39
|
-
}
|
|
40
|
-
return bundlerUrl;
|
|
41
|
-
}).pipe(Effect.orDie);
|
|
42
|
-
const getPublicClient = (params) => Effect.gen(function* () {
|
|
43
|
-
const rpcUrl = yield* getRpcUrl(params);
|
|
44
|
-
return createPublicClient({
|
|
45
|
-
chain: getChain(params.chain),
|
|
46
|
-
transport: http(rpcUrl)
|
|
47
|
-
});
|
|
48
|
-
});
|
|
49
|
-
const getBundlerTransport = (params) => Effect.gen(function* () {
|
|
50
|
-
return http(yield* getBundlerUrl(params));
|
|
51
|
-
});
|
|
52
|
-
const selectChain = (params) => Effect.gen(function* () {
|
|
53
|
-
const chains = Object.values(supportedChains);
|
|
54
|
-
return yield* promptManager.selectPrompt({
|
|
55
|
-
message: params.message,
|
|
56
|
-
choices: chains.map((c) => ({
|
|
57
|
-
title: c.name,
|
|
58
|
-
value: c.key
|
|
59
|
-
}))
|
|
60
|
-
});
|
|
61
|
-
});
|
|
62
|
-
const multiSelectChain = (params) => Effect.gen(function* () {
|
|
63
|
-
const chains = Object.values(supportedChains);
|
|
64
|
-
return yield* promptManager.multiSelectPrompt({
|
|
65
|
-
message: params.message,
|
|
66
|
-
choices: chains.map((c) => ({
|
|
67
|
-
title: c.name,
|
|
68
|
-
value: c.key
|
|
69
|
-
})),
|
|
70
|
-
min: 1
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
return Web3Service.of({
|
|
74
|
-
getPublicClient,
|
|
75
|
-
selectChain,
|
|
76
|
-
multiSelectChain,
|
|
77
|
-
getBundlerTransport
|
|
78
|
-
});
|
|
79
|
-
}));
|
|
80
|
-
//#endregion
|
|
81
|
-
export { Web3Service, layer };
|
|
82
|
-
|
|
83
|
-
//# sourceMappingURL=web3.mjs.map
|
package/dist/layers/web3.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"web3.mjs","names":[],"sources":["../../src/layers/web3.ts"],"sourcesContent":["import { Config, Context, Effect, Layer, Redacted } from \"effect\";\nimport type { QuitError } from \"effect/Terminal\";\nimport type { Prompt } from \"effect/unstable/cli\";\nimport {\n type Chain,\n type Client,\n createPublicClient,\n type HttpTransport,\n http,\n} from \"viem\";\n\nimport {\n type ChainWithMetadata,\n getChain,\n type SupportedChain,\n supportedChains,\n} from \"@/schema\";\n\nimport { PromptManager } from \"./prompt\";\n\nexport type Web3Service = {\n /**\n * Creates a viem public client for the requested chain.\n *\n * Falls back to an environment-derived RPC URL when not explicitly provided.\n *\n * @param params - Chain key and optional RPC URL override.\n */\n getPublicClient: (\n params: GetPublicClientParams,\n ) => Effect.Effect<Client<HttpTransport, Chain, undefined>>;\n /**\n * Prompts the user to select a single supported chain.\n *\n * @param params - Prompt message to display.\n */\n selectChain: (params: {\n message: string;\n }) => Effect.Effect<SupportedChain, QuitError, Prompt.Environment>;\n /**\n * Prompts the user to select one or more supported chains.\n *\n * @param params - Prompt message to display.\n */\n multiSelectChain: (params: {\n message: string;\n }) => Effect.Effect<SupportedChain[], QuitError, Prompt.Environment>;\n /**\n * Creates a viem bundler transport for the requested chain.\n *\n * Falls back to an environment-derived RPC URL when not explicitly provided.\n *\n * @param params - Chain key and optional RPC URL override.\n */\n getBundlerTransport: (\n params: GetBundlerClientParams,\n ) => Effect.Effect<HttpTransport<undefined, false>, never, never>;\n};\n\n/**\n * Parameters for constructing a public client.\n */\ntype GetPublicClientParams = {\n /**\n * Target chain identifier key.\n */\n chain: SupportedChain;\n /**\n * Optional RPC URL override for the chain.\n */\n rpcUrl?: string;\n};\n\nexport type GetBundlerClientParams = {\n /**\n * Target chain identifier key.\n */\n chain: SupportedChain;\n /**\n * Optional RPC URL override for the chain.\n *\n */\n bundlerUrl?: string;\n};\n\n/**\n * Service tag for resolving {@link Web3Service} from the Effect context.\n */\nexport const Web3Service = Context.Service<Web3Service>(\n \"@namera-ai/cli/Web3Service\",\n);\n\n/**\n * Live layer that wires web3 clients and chain selection prompts.\n */\nexport const layer = Layer.effect(\n Web3Service,\n Effect.gen(function* () {\n const promptManager = yield* PromptManager;\n\n const chainNameToEnvVar = (chain: SupportedChain, suffix: string) => {\n return `${chain.replaceAll(\"-\", \"_\").toUpperCase()}_${suffix}`;\n };\n\n const getRpcUrl = (params: GetPublicClientParams) =>\n Effect.gen(function* () {\n let rpcUrl: string | undefined;\n\n if (params.rpcUrl) {\n rpcUrl = params.rpcUrl;\n } else {\n // check env\n const envVarName = chainNameToEnvVar(params.chain, \"RPC_URL\");\n const envRpcUrl = yield* Config.option(Config.redacted(envVarName));\n\n if (envRpcUrl._tag === \"Some\") {\n rpcUrl = Redacted.value(envRpcUrl.value);\n } else {\n rpcUrl = undefined;\n }\n }\n\n return rpcUrl;\n }).pipe(Effect.orDie);\n\n const getBundlerUrl = (params: GetBundlerClientParams) =>\n Effect.gen(function* () {\n let bundlerUrl: string | undefined;\n\n if (params.bundlerUrl) {\n bundlerUrl = params.bundlerUrl;\n } else {\n // check env\n const envVarName = chainNameToEnvVar(params.chain, \"BUNDLER_URL\");\n const envRpcUrl = yield* Config.option(Config.redacted(envVarName));\n\n if (envRpcUrl._tag === \"Some\") {\n bundlerUrl = Redacted.value(envRpcUrl.value);\n } else {\n const chain = getChain(params.chain);\n // Defaults to Pimlico Public RPC\n bundlerUrl = `https://public.pimlico.io/v2/${chain.id}/rpc`;\n }\n }\n\n return bundlerUrl;\n }).pipe(Effect.orDie);\n\n const getPublicClient = (params: GetPublicClientParams) =>\n Effect.gen(function* () {\n const rpcUrl = yield* getRpcUrl(params);\n const chain = getChain(params.chain);\n const client = createPublicClient({\n chain,\n transport: http(rpcUrl),\n });\n\n return client;\n });\n\n const getBundlerTransport = (params: GetBundlerClientParams) =>\n Effect.gen(function* () {\n const bundlerUrl = yield* getBundlerUrl(params);\n return http(bundlerUrl);\n });\n\n const selectChain = (params: { message: string }) =>\n Effect.gen(function* () {\n const chains = Object.values(supportedChains) as ChainWithMetadata[];\n\n const res = yield* promptManager.selectPrompt({\n message: params.message,\n choices: chains.map((c) => ({\n title: c.name,\n value: c.key as SupportedChain,\n })) satisfies Prompt.SelectChoice<SupportedChain>[],\n });\n\n return res;\n });\n\n const multiSelectChain = (params: { message: string }) =>\n Effect.gen(function* () {\n const chains = Object.values(supportedChains) as ChainWithMetadata[];\n\n const res = yield* promptManager.multiSelectPrompt({\n message: params.message,\n choices: chains.map((c) => ({\n title: c.name,\n value: c.key as SupportedChain,\n })) satisfies Prompt.SelectChoice<SupportedChain>[],\n min: 1,\n });\n\n return res;\n });\n\n return Web3Service.of({\n getPublicClient,\n selectChain,\n multiSelectChain,\n getBundlerTransport,\n });\n }),\n);\n"],"mappings":";;;;;;;;;;AAwFA,MAAa,cAAc,QAAQ,QACjC,6BACD;;;;AAKD,MAAa,QAAQ,MAAM,OACzB,aACA,OAAO,IAAI,aAAa;CACtB,MAAM,gBAAgB,OAAO;CAE7B,MAAM,qBAAqB,OAAuB,WAAmB;AACnE,SAAO,GAAG,MAAM,WAAW,KAAK,IAAI,CAAC,aAAa,CAAC,GAAG;;CAGxD,MAAM,aAAa,WACjB,OAAO,IAAI,aAAa;EACtB,IAAI;AAEJ,MAAI,OAAO,OACT,UAAS,OAAO;OACX;GAEL,MAAM,aAAa,kBAAkB,OAAO,OAAO,UAAU;GAC7D,MAAM,YAAY,OAAO,OAAO,OAAO,OAAO,SAAS,WAAW,CAAC;AAEnE,OAAI,UAAU,SAAS,OACrB,UAAS,SAAS,MAAM,UAAU,MAAM;OAExC,UAAS;;AAIb,SAAO;GACP,CAAC,KAAK,OAAO,MAAM;CAEvB,MAAM,iBAAiB,WACrB,OAAO,IAAI,aAAa;EACtB,IAAI;AAEJ,MAAI,OAAO,WACT,cAAa,OAAO;OACf;GAEL,MAAM,aAAa,kBAAkB,OAAO,OAAO,cAAc;GACjE,MAAM,YAAY,OAAO,OAAO,OAAO,OAAO,SAAS,WAAW,CAAC;AAEnE,OAAI,UAAU,SAAS,OACrB,cAAa,SAAS,MAAM,UAAU,MAAM;OAI5C,cAAa,gCAFC,SAAS,OAAO,MAEe,CAAM,GAAG;;AAI1D,SAAO;GACP,CAAC,KAAK,OAAO,MAAM;CAEvB,MAAM,mBAAmB,WACvB,OAAO,IAAI,aAAa;EACtB,MAAM,SAAS,OAAO,UAAU,OAAO;AAOvC,SALe,mBAAmB;GAChC,OAFY,SAAS,OAAO,MAE5B;GACA,WAAW,KAAK,OAAO;GACxB,CAEM;GACP;CAEJ,MAAM,uBAAuB,WAC3B,OAAO,IAAI,aAAa;AAEtB,SAAO,KAAK,OADc,cAAc,OAAO,CACxB;GACvB;CAEJ,MAAM,eAAe,WACnB,OAAO,IAAI,aAAa;EACtB,MAAM,SAAS,OAAO,OAAO,gBAAgB;AAU7C,SAAO,OARY,cAAc,aAAa;GAC5C,SAAS,OAAO;GAChB,SAAS,OAAO,KAAK,OAAO;IAC1B,OAAO,EAAE;IACT,OAAO,EAAE;IACV,EAAE;GACJ,CAAC;GAGF;CAEJ,MAAM,oBAAoB,WACxB,OAAO,IAAI,aAAa;EACtB,MAAM,SAAS,OAAO,OAAO,gBAAgB;AAW7C,SAAO,OATY,cAAc,kBAAkB;GACjD,SAAS,OAAO;GAChB,SAAS,OAAO,KAAK,OAAO;IAC1B,OAAO,EAAE;IACT,OAAO,EAAE;IACV,EAAE;GACH,KAAK;GACN,CAAC;GAGF;AAEJ,QAAO,YAAY,GAAG;EACpB;EACA;EACA;EACA;EACD,CAAC;EACF,CACH"}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { Schema } from "effect";
|
|
3
|
-
//#region src/mcp/helpers/common.ts
|
|
4
|
-
const EmptyArgs = Schema.Record(Schema.String, Schema.Unknown);
|
|
5
|
-
var InsufficientPermissions = class extends Schema.TaggedErrorClass()("InsufficientPermissions", {}) {};
|
|
6
|
-
//#endregion
|
|
7
|
-
export { EmptyArgs, InsufficientPermissions };
|
|
8
|
-
|
|
9
|
-
//# sourceMappingURL=common.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"common.mjs","names":[],"sources":["../../../src/mcp/helpers/common.ts"],"sourcesContent":["import { Schema } from \"effect\";\n\nexport const EmptyArgs = Schema.Record(Schema.String, Schema.Unknown);\n\nexport class InsufficientPermissions extends Schema.TaggedErrorClass<InsufficientPermissions>()(\n \"InsufficientPermissions\",\n {},\n) {}\n"],"mappings":";;;AAEA,MAAa,YAAY,OAAO,OAAO,OAAO,QAAQ,OAAO,QAAQ;AAErE,IAAa,0BAAb,cAA6C,OAAO,kBAA2C,CAC7F,2BACA,EAAE,CACH,CAAC"}
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { chainIdToChainName, getChain } from "../../schema/chain.mjs";
|
|
3
|
-
import "../../schema/index.mjs";
|
|
4
|
-
import { McpContext } from "../../layers/mcp-context.mjs";
|
|
5
|
-
import { InsufficientPermissions } from "./common.mjs";
|
|
6
|
-
import { Web3Service } from "../../layers/web3.mjs";
|
|
7
|
-
import "../../layers/index.mjs";
|
|
8
|
-
import { Effect } from "effect";
|
|
9
|
-
import { createSessionKeyClient, deserializePermissionAccountParams } from "@namera-ai/sdk/session-key";
|
|
10
|
-
//#region src/mcp/helpers/session-key.ts
|
|
11
|
-
const toPolicyMap = (policies) => {
|
|
12
|
-
const map = {};
|
|
13
|
-
for (const p of policies) {
|
|
14
|
-
if (p.type === "timestamp") {
|
|
15
|
-
if (map.timestamp) return null;
|
|
16
|
-
map.timestamp = p;
|
|
17
|
-
}
|
|
18
|
-
if (p.type === "call") {
|
|
19
|
-
if (map.call) return null;
|
|
20
|
-
map.call = p;
|
|
21
|
-
}
|
|
22
|
-
if (p.type === "signature-caller") {
|
|
23
|
-
if (map.signatureCaller) return null;
|
|
24
|
-
map.signatureCaller = p;
|
|
25
|
-
}
|
|
26
|
-
if (p.type === "gas") {
|
|
27
|
-
if (map.gas) return null;
|
|
28
|
-
map.gas = p;
|
|
29
|
-
}
|
|
30
|
-
if (p.type === "rate-limit") {
|
|
31
|
-
if (map.rateLimit) return null;
|
|
32
|
-
map.rateLimit = p;
|
|
33
|
-
}
|
|
34
|
-
if (p.type === "sudo") {
|
|
35
|
-
if (map.sudo) return null;
|
|
36
|
-
map.sudo = p;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return map;
|
|
40
|
-
};
|
|
41
|
-
function evaluateTimestamp(policy, _chainIds, _operation) {
|
|
42
|
-
const now = Date.now();
|
|
43
|
-
if (policy.validAfter !== void 0 && now < policy.validAfter * 1e3) return false;
|
|
44
|
-
if (policy.validUntil !== void 0 && now >= policy.validUntil * 1e3) return false;
|
|
45
|
-
return true;
|
|
46
|
-
}
|
|
47
|
-
function evaluateSignature(policy, chainIds, operation) {
|
|
48
|
-
const callers = operation.allowedCallers;
|
|
49
|
-
if (!callers || callers.length === 0) return false;
|
|
50
|
-
if (!chainIds.includes(operation.chainId)) return false;
|
|
51
|
-
return callers.every((caller) => policy.allowedCallers.includes(caller));
|
|
52
|
-
}
|
|
53
|
-
function evaluateCall(policy, chainIds, operation) {
|
|
54
|
-
const permissions = policy.permissions ?? [];
|
|
55
|
-
if (permissions.length === 0) return false;
|
|
56
|
-
const { batches } = operation;
|
|
57
|
-
if (batches.length === 0) return false;
|
|
58
|
-
return batches.every((batch) => {
|
|
59
|
-
const { calls, chainId } = batch;
|
|
60
|
-
return calls.every((call) => {
|
|
61
|
-
const { to, value = 0n, data } = call;
|
|
62
|
-
if (!chainIds.includes(chainId)) return false;
|
|
63
|
-
return permissions.some((p) => {
|
|
64
|
-
if (p.target !== to) return false;
|
|
65
|
-
if (value > (p.valueLimit ?? 0n)) return false;
|
|
66
|
-
const isContractCall = data.length >= 10;
|
|
67
|
-
if ("functionName" in p) {
|
|
68
|
-
if (!isContractCall) return false;
|
|
69
|
-
if (!p.selector) return false;
|
|
70
|
-
if (data.slice(0, 10) !== p.selector) return false;
|
|
71
|
-
return true;
|
|
72
|
-
}
|
|
73
|
-
return true;
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
const evaluateSessionKey = (sessionKey, operation) => {
|
|
79
|
-
if (operation.intent === "read") return true;
|
|
80
|
-
const accountParams = deserializePermissionAccountParams(sessionKey.data.serializedAccounts[0]?.serializedAccount ?? "");
|
|
81
|
-
const chainIds = sessionKey.data.serializedAccounts.map((a) => getChain(a.chain).id);
|
|
82
|
-
const p = toPolicyMap((accountParams.permissionParams.policies ?? []).map((x) => x.policyParams));
|
|
83
|
-
if (!p) return false;
|
|
84
|
-
const hasSudo = Boolean(p.sudo);
|
|
85
|
-
if (hasSudo && (p.call || p.signatureCaller)) return false;
|
|
86
|
-
if (p.timestamp && !evaluateTimestamp(p.timestamp, chainIds, operation)) return false;
|
|
87
|
-
if (!hasSudo) {
|
|
88
|
-
if (operation.intent === "transaction") {
|
|
89
|
-
if (!p.call) return false;
|
|
90
|
-
if (!evaluateCall(p.call, chainIds, operation)) return false;
|
|
91
|
-
}
|
|
92
|
-
if (operation.intent === "sign") {
|
|
93
|
-
if (!p.signatureCaller) return false;
|
|
94
|
-
if (!evaluateSignature(p.signatureCaller, chainIds, operation)) return false;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return true;
|
|
98
|
-
};
|
|
99
|
-
const getSessionKeyClient = (params) => Effect.gen(function* () {
|
|
100
|
-
const { sessionKeys, smartAccount } = yield* McpContext;
|
|
101
|
-
const key = sessionKeys.filter((sk) => {
|
|
102
|
-
return evaluateSessionKey(sk, params.operation);
|
|
103
|
-
})[0];
|
|
104
|
-
if (!key) return yield* Effect.fail(new InsufficientPermissions());
|
|
105
|
-
const web3Service = yield* Web3Service;
|
|
106
|
-
let chainId;
|
|
107
|
-
if (params.operation.intent === "read") chainId = params.operation.chainId;
|
|
108
|
-
else if (params.operation.intent === "sign") chainId = params.operation.chainId;
|
|
109
|
-
else chainId = params.operation.batches[0]?.chainId ?? 1;
|
|
110
|
-
const chainName = chainIdToChainName(chainId);
|
|
111
|
-
const chain = getChain(chainName);
|
|
112
|
-
const publicClient = yield* web3Service.getPublicClient({ chain: chainName });
|
|
113
|
-
const bundlerTransport = yield* web3Service.getBundlerTransport({ chain: chainName });
|
|
114
|
-
const serializedAccount = key.data.serializedAccounts.find((a) => a.chain === chainName)?.serializedAccount ?? "";
|
|
115
|
-
return yield* Effect.promise(() => createSessionKeyClient({
|
|
116
|
-
type: "ecdsa",
|
|
117
|
-
bundlerTransport,
|
|
118
|
-
chain,
|
|
119
|
-
client: publicClient,
|
|
120
|
-
entrypointVersion: smartAccount.entryPointVersion,
|
|
121
|
-
kernelVersion: smartAccount.kernelVersion,
|
|
122
|
-
serializedAccount,
|
|
123
|
-
signer: key.signer
|
|
124
|
-
}));
|
|
125
|
-
});
|
|
126
|
-
//#endregion
|
|
127
|
-
export { evaluateCall, evaluateSignature, evaluateTimestamp, getSessionKeyClient };
|
|
128
|
-
|
|
129
|
-
//# sourceMappingURL=session-key.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"session-key.mjs","names":["McpContext.McpContext","Web3Service.Web3Service"],"sources":["../../../src/mcp/helpers/session-key.ts"],"sourcesContent":["/** biome-ignore-all lint/complexity/noExcessiveCognitiveComplexity: safe */\nimport type {\n CallPolicyParams,\n Policy,\n SignatureCallerPolicyParams,\n TimestampPolicyParams,\n} from \"@namera-ai/sdk/policy\";\nimport {\n createSessionKeyClient,\n deserializePermissionAccountParams,\n} from \"@namera-ai/sdk/session-key\";\nimport { Effect } from \"effect\";\n\nimport type { SessionKeyData } from \"@/dto\";\nimport { McpContext, Web3Service } from \"@/layers\";\nimport { getChain } from \"@/schema\";\n\nimport { chainIdToChainName } from \"../../schema/chain\";\nimport type { AnyOperation, PolicyMap } from \"../types\";\nimport { InsufficientPermissions } from \"./common\";\n\ntype PolicyParams = Policy[\"policyParams\"];\n\nconst toPolicyMap = (policies: PolicyParams[]): PolicyMap | null => {\n const map: PolicyMap = {};\n\n for (const p of policies) {\n if (p.type === \"timestamp\") {\n if (map.timestamp) return null; // Gracefully invalidate this key\n map.timestamp = p;\n }\n if (p.type === \"call\") {\n if (map.call) return null;\n map.call = p;\n }\n if (p.type === \"signature-caller\") {\n if (map.signatureCaller) return null;\n map.signatureCaller = p;\n }\n if (p.type === \"gas\") {\n if (map.gas) return null;\n map.gas = p;\n }\n if (p.type === \"rate-limit\") {\n if (map.rateLimit) return null;\n map.rateLimit = p;\n }\n if (p.type === \"sudo\") {\n if (map.sudo) return null;\n map.sudo = p;\n }\n }\n\n return map;\n};\n\nexport function evaluateTimestamp(\n policy: TimestampPolicyParams,\n _chainIds: number[],\n _operation: AnyOperation,\n): boolean {\n // validAfter: the time after which the signer becomes valid.\n // If not specified (or 0), the signer is immediately valid.\n //\n // validUntil: the time before which the signer is valid.\n // If not specified, the signer never expires.\n const now = Date.now(); // ms\n\n if (policy.validAfter !== undefined && now < policy.validAfter * 1000) {\n return false;\n }\n\n if (policy.validUntil !== undefined && now >= policy.validUntil * 1000) {\n return false;\n }\n\n return true;\n}\n\nexport function evaluateSignature(\n policy: SignatureCallerPolicyParams,\n chainIds: number[],\n operation: Extract<AnyOperation, { intent: \"sign\" }>,\n): boolean {\n const callers = operation.allowedCallers;\n\n if (!callers || callers.length === 0) return false;\n if (!chainIds.includes(operation.chainId)) return false;\n\n // every caller must be allowed\n return callers.every((caller) => policy.allowedCallers.includes(caller));\n}\n\nexport function evaluateCall(\n policy: CallPolicyParams,\n chainIds: number[],\n operation: Extract<AnyOperation, { intent: \"transaction\" }>,\n): boolean {\n const permissions = policy.permissions ?? [];\n if (permissions.length === 0) return false;\n\n const { batches } = operation;\n\n if (batches.length === 0) return false;\n\n return batches.every((batch) => {\n const { calls, chainId } = batch;\n\n return calls.every((call) => {\n const { to, value = 0n, data } = call;\n if (!chainIds.includes(chainId)) return false;\n\n return permissions.some((p) => {\n if (p.target !== to) return false;\n const valueLimit = p.valueLimit ?? 0n;\n if (value > valueLimit) return false;\n\n const isContractCall = data.length >= 10;\n\n if (\"functionName\" in p) {\n if (!isContractCall) return false;\n if (!p.selector) return false;\n\n const selector = data.slice(0, 10);\n if (selector !== p.selector) return false;\n\n // TODO: param rules\n return true;\n }\n\n // EOA\n return true;\n });\n });\n });\n}\n\nconst evaluateSessionKey = (\n sessionKey: SessionKeyData,\n operation: AnyOperation,\n) => {\n // Read is always allowed\n if (operation.intent === \"read\") return true;\n\n const accountParams = deserializePermissionAccountParams(\n sessionKey.data.serializedAccounts[0]?.serializedAccount ?? \"\",\n );\n\n const chainIds = sessionKey.data.serializedAccounts.map(\n (a) => getChain(a.chain).id,\n );\n\n const policies = (accountParams.permissionParams.policies ?? []).map(\n (x) => x.policyParams,\n );\n\n const p = toPolicyMap(policies);\n\n if (!p) return false;\n\n const hasSudo = Boolean(p.sudo);\n\n // A valid sudo key should not have call or signature policies attached\n if (hasSudo && (p.call || p.signatureCaller)) {\n return false;\n }\n\n if (p.timestamp && !evaluateTimestamp(p.timestamp, chainIds, operation))\n return false;\n\n // TODO: Do gas and rate limits\n\n if (!hasSudo) {\n if (operation.intent === \"transaction\") {\n if (!p.call) return false;\n if (!evaluateCall(p.call, chainIds, operation)) return false;\n }\n\n if (operation.intent === \"sign\") {\n if (!p.signatureCaller) return false;\n if (!evaluateSignature(p.signatureCaller, chainIds, operation))\n return false;\n }\n }\n\n return true;\n};\n\nexport type GetValidSessionKeysParams = {\n operation: AnyOperation;\n};\n\nexport const getValidSessionKeys = (params: GetValidSessionKeysParams) =>\n Effect.gen(function* () {\n const context = yield* McpContext.McpContext;\n const { sessionKeys } = context;\n\n const validKeys = sessionKeys.filter((sk) => {\n return evaluateSessionKey(sk, params.operation);\n });\n\n return validKeys;\n });\n\nexport const getSessionKeyClient = (params: GetValidSessionKeysParams) =>\n Effect.gen(function* () {\n const context = yield* McpContext.McpContext;\n const { sessionKeys, smartAccount } = context;\n\n const validKeys = sessionKeys.filter((sk) => {\n return evaluateSessionKey(sk, params.operation);\n });\n\n const key = validKeys[0];\n\n if (!key) return yield* Effect.fail(new InsufficientPermissions());\n\n const web3Service = yield* Web3Service.Web3Service;\n\n let chainId: number;\n\n if (params.operation.intent === \"read\") {\n chainId = params.operation.chainId;\n } else if (params.operation.intent === \"sign\") {\n chainId = params.operation.chainId;\n } else {\n chainId = params.operation.batches[0]?.chainId ?? 1;\n }\n\n const chainName = chainIdToChainName(chainId);\n const chain = getChain(chainName);\n const publicClient = yield* web3Service.getPublicClient({\n chain: chainName,\n });\n const bundlerTransport = yield* web3Service.getBundlerTransport({\n chain: chainName,\n });\n const serializedAccount =\n key.data.serializedAccounts.find((a) => a.chain === chainName)\n ?.serializedAccount ?? \"\";\n\n const accountClient = yield* Effect.promise(() =>\n createSessionKeyClient({\n type: \"ecdsa\",\n bundlerTransport,\n chain,\n client: publicClient,\n entrypointVersion: smartAccount.entryPointVersion,\n kernelVersion: smartAccount.kernelVersion,\n serializedAccount,\n signer: key.signer,\n }),\n );\n\n return accountClient;\n });\n"],"mappings":"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"}
|
package/dist/mcp/index.mjs
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { McpLive } from "./mcp.mjs";
|
|
3
|
-
import { NodeHttpServer, NodeStdio } from "@effect/platform-node";
|
|
4
|
-
import { Layer, Logger } from "effect";
|
|
5
|
-
import { createServer } from "node:http";
|
|
6
|
-
import { McpServer } from "effect/unstable/ai";
|
|
7
|
-
import { HttpRouter } from "effect/unstable/http";
|
|
8
|
-
//#region src/mcp/index.ts
|
|
9
|
-
const MCP_SERVER_NAME = "Namera MCP Server";
|
|
10
|
-
const MCP_SERVER_VERSION = "0.0.1";
|
|
11
|
-
const McpRouter = McpLive.pipe(Layer.provideMerge(McpServer.layerHttp({
|
|
12
|
-
name: MCP_SERVER_NAME,
|
|
13
|
-
path: "/mcp",
|
|
14
|
-
version: MCP_SERVER_VERSION
|
|
15
|
-
})), Layer.provideMerge(HttpRouter.cors({
|
|
16
|
-
allowedHeaders: [
|
|
17
|
-
"Content-Type",
|
|
18
|
-
"Authorization",
|
|
19
|
-
"mcp-session-id",
|
|
20
|
-
"mcp-protocol-version"
|
|
21
|
-
],
|
|
22
|
-
allowedMethods: [
|
|
23
|
-
"GET",
|
|
24
|
-
"POST",
|
|
25
|
-
"PUT",
|
|
26
|
-
"DELETE",
|
|
27
|
-
"PATCH",
|
|
28
|
-
"OPTIONS"
|
|
29
|
-
],
|
|
30
|
-
allowedOrigins: ["*"],
|
|
31
|
-
credentials: false,
|
|
32
|
-
exposedHeaders: ["mcp-session-id", "mcp-protocol-version"]
|
|
33
|
-
})));
|
|
34
|
-
const McpStdio = McpLive.pipe(Layer.provideMerge(McpServer.layerStdio({
|
|
35
|
-
name: MCP_SERVER_NAME,
|
|
36
|
-
version: MCP_SERVER_VERSION
|
|
37
|
-
})), Layer.provide(NodeStdio.layer), Layer.provide(Layer.succeed(Logger.LogToStderr)(true)));
|
|
38
|
-
const startMcpHttpServer = (port) => Layer.launch(HttpRouter.serve(McpRouter).pipe(Layer.provideMerge(NodeHttpServer.layer(createServer, { port }))));
|
|
39
|
-
const startMcpStdioServer = () => Layer.launch(McpStdio);
|
|
40
|
-
//#endregion
|
|
41
|
-
export { startMcpHttpServer, startMcpStdioServer };
|
|
42
|
-
|
|
43
|
-
//# sourceMappingURL=index.mjs.map
|
package/dist/mcp/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/mcp/index.ts"],"sourcesContent":["import { createServer } from \"node:http\";\n\nimport { NodeHttpServer, NodeStdio } from \"@effect/platform-node\";\nimport { Layer, Logger } from \"effect\";\nimport { McpServer } from \"effect/unstable/ai\";\nimport { HttpRouter } from \"effect/unstable/http\";\n\nimport { McpLive } from \"./mcp\";\n\nconst MCP_SERVER_NAME = \"Namera MCP Server\";\nconst MCP_SERVER_VERSION = \"0.0.1\";\n\nconst McpRouter = McpLive.pipe(\n Layer.provideMerge(\n McpServer.layerHttp({\n name: MCP_SERVER_NAME,\n path: \"/mcp\",\n version: MCP_SERVER_VERSION,\n }),\n ),\n Layer.provideMerge(\n HttpRouter.cors({\n allowedHeaders: [\n \"Content-Type\",\n \"Authorization\",\n \"mcp-session-id\",\n \"mcp-protocol-version\",\n ],\n allowedMethods: [\"GET\", \"POST\", \"PUT\", \"DELETE\", \"PATCH\", \"OPTIONS\"],\n allowedOrigins: [\"*\"],\n credentials: false,\n exposedHeaders: [\"mcp-session-id\", \"mcp-protocol-version\"],\n }),\n ),\n);\n\nconst McpStdio = McpLive.pipe(\n Layer.provideMerge(\n McpServer.layerStdio({\n name: MCP_SERVER_NAME,\n version: MCP_SERVER_VERSION,\n }),\n ),\n Layer.provide(NodeStdio.layer),\n Layer.provide(Layer.succeed(Logger.LogToStderr)(true)),\n);\n\nexport const startMcpHttpServer = (port: number) =>\n Layer.launch(\n HttpRouter.serve(McpRouter).pipe(\n Layer.provideMerge(NodeHttpServer.layer(createServer, { port })),\n ),\n );\n\nexport const startMcpStdioServer = () => Layer.launch(McpStdio);\n"],"mappings":";;;;;;;;AASA,MAAM,kBAAkB;AACxB,MAAM,qBAAqB;AAE3B,MAAM,YAAY,QAAQ,KACxB,MAAM,aACJ,UAAU,UAAU;CAClB,MAAM;CACN,MAAM;CACN,SAAS;CACV,CAAC,CACH,EACD,MAAM,aACJ,WAAW,KAAK;CACd,gBAAgB;EACd;EACA;EACA;EACA;EACD;CACD,gBAAgB;EAAC;EAAO;EAAQ;EAAO;EAAU;EAAS;EAAU;CACpE,gBAAgB,CAAC,IAAI;CACrB,aAAa;CACb,gBAAgB,CAAC,kBAAkB,uBAAuB;CAC3D,CAAC,CACH,CACF;AAED,MAAM,WAAW,QAAQ,KACvB,MAAM,aACJ,UAAU,WAAW;CACnB,MAAM;CACN,SAAS;CACV,CAAC,CACH,EACD,MAAM,QAAQ,UAAU,MAAM,EAC9B,MAAM,QAAQ,MAAM,QAAQ,OAAO,YAAY,CAAC,KAAK,CAAC,CACvD;AAED,MAAa,sBAAsB,SACjC,MAAM,OACJ,WAAW,MAAM,UAAU,CAAC,KAC1B,MAAM,aAAa,eAAe,MAAM,cAAc,EAAE,MAAM,CAAC,CAAC,CACjE,CACF;AAEH,MAAa,4BAA4B,MAAM,OAAO,SAAS"}
|
package/dist/mcp/mcp.mjs
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { AccountTools, AccountToolsHandlers } from "./tools/account/index.mjs";
|
|
3
|
-
import { ReadTools, ReadToolsHandlers } from "./tools/read/index.mjs";
|
|
4
|
-
import { TransactionTools, TransactionToolsHandlers } from "./tools/transaction/index.mjs";
|
|
5
|
-
import { Layer } from "effect";
|
|
6
|
-
import { McpServer } from "effect/unstable/ai";
|
|
7
|
-
//#region src/mcp/mcp.ts
|
|
8
|
-
const Account = Layer.effectDiscard(McpServer.registerToolkit(AccountTools)).pipe(Layer.provideMerge(AccountToolsHandlers));
|
|
9
|
-
const Transfer = Layer.effectDiscard(McpServer.registerToolkit(TransactionTools)).pipe(Layer.provideMerge(TransactionToolsHandlers));
|
|
10
|
-
const Read = Layer.effectDiscard(McpServer.registerToolkit(ReadTools)).pipe(Layer.provideMerge(ReadToolsHandlers));
|
|
11
|
-
const McpLive = Layer.mergeAll(Account, Transfer, Read);
|
|
12
|
-
//#endregion
|
|
13
|
-
export { McpLive };
|
|
14
|
-
|
|
15
|
-
//# sourceMappingURL=mcp.mjs.map
|
package/dist/mcp/mcp.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mcp.mjs","names":[],"sources":["../../src/mcp/mcp.ts"],"sourcesContent":["import { Layer } from \"effect\";\nimport { McpServer } from \"effect/unstable/ai\";\n\nimport { AccountTools, AccountToolsHandlers } from \"./tools/account\";\nimport { ReadTools, ReadToolsHandlers } from \"./tools/read\";\nimport {\n TransactionTools,\n TransactionToolsHandlers,\n} from \"./tools/transaction\";\n\nconst Account = Layer.effectDiscard(\n McpServer.registerToolkit(AccountTools),\n).pipe(Layer.provideMerge(AccountToolsHandlers));\n\nconst Transfer = Layer.effectDiscard(\n McpServer.registerToolkit(TransactionTools),\n).pipe(Layer.provideMerge(TransactionToolsHandlers));\n\nconst Read = Layer.effectDiscard(McpServer.registerToolkit(ReadTools)).pipe(\n Layer.provideMerge(ReadToolsHandlers),\n);\n\nexport const McpLive = Layer.mergeAll(Account, Transfer, Read);\n"],"mappings":";;;;;;;AAUA,MAAM,UAAU,MAAM,cACpB,UAAU,gBAAgB,aAAa,CACxC,CAAC,KAAK,MAAM,aAAa,qBAAqB,CAAC;AAEhD,MAAM,WAAW,MAAM,cACrB,UAAU,gBAAgB,iBAAiB,CAC5C,CAAC,KAAK,MAAM,aAAa,yBAAyB,CAAC;AAEpD,MAAM,OAAO,MAAM,cAAc,UAAU,gBAAgB,UAAU,CAAC,CAAC,KACrE,MAAM,aAAa,kBAAkB,CACtC;AAED,MAAa,UAAU,MAAM,SAAS,SAAS,UAAU,KAAK"}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import { McpContext } from "../../../layers/mcp-context.mjs";
|
|
3
|
-
import { EmptyArgs } from "../../helpers/common.mjs";
|
|
4
|
-
import { Effect, Schema } from "effect";
|
|
5
|
-
import { Tool } from "effect/unstable/ai";
|
|
6
|
-
//#region src/mcp/tools/account/address.ts
|
|
7
|
-
const GetAddressTool = Tool.make("get_wallet_address", {
|
|
8
|
-
dependencies: [McpContext],
|
|
9
|
-
description: "Get the address of the wallet",
|
|
10
|
-
failure: Schema.Never,
|
|
11
|
-
parameters: EmptyArgs,
|
|
12
|
-
success: Schema.String
|
|
13
|
-
});
|
|
14
|
-
const getAddressToolHandler = () => Effect.gen(function* () {
|
|
15
|
-
return (yield* McpContext).smartAccount.smartAccountAddress;
|
|
16
|
-
});
|
|
17
|
-
//#endregion
|
|
18
|
-
export { GetAddressTool, getAddressToolHandler };
|
|
19
|
-
|
|
20
|
-
//# sourceMappingURL=address.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"address.mjs","names":[],"sources":["../../../../src/mcp/tools/account/address.ts"],"sourcesContent":["import { Effect, Schema } from \"effect\";\nimport { Tool } from \"effect/unstable/ai\";\n\nimport { McpContext } from \"@/layers/mcp-context\";\nimport { EmptyArgs } from \"@/mcp/helpers/common\";\n\nexport const GetAddressTool = Tool.make(\"get_wallet_address\", {\n dependencies: [McpContext],\n description: \"Get the address of the wallet\",\n failure: Schema.Never,\n parameters: EmptyArgs,\n success: Schema.String,\n});\n\nexport const getAddressToolHandler = () =>\n Effect.gen(function* () {\n const context = yield* McpContext;\n\n return context.smartAccount.smartAccountAddress;\n });\n"],"mappings":";;;;;;AAMA,MAAa,iBAAiB,KAAK,KAAK,sBAAsB;CAC5D,cAAc,CAAC,WAAW;CAC1B,aAAa;CACb,SAAS,OAAO;CAChB,YAAY;CACZ,SAAS,OAAO;CACjB,CAAC;AAEF,MAAa,8BACX,OAAO,IAAI,aAAa;AAGtB,SAAO,OAFgB,YAER,aAAa;EAC5B"}
|