diff --git a/README.md b/README.md index 32ded7c4..9896d4fb 100644 --- a/README.md +++ b/README.md @@ -430,24 +430,26 @@ const sig = getFunctionSelector( "transfer(address, uint256)" ) const permissions = [ - { - target: , // address of the target contract - valueLimit: 0, // max value the session key can use in tx - sig, // The function selector of the function that can be called on the target contract - operation: Operation.Call, // The kind of call session key can make CALL/DELEGATECALL - rules: [ // Parameter rules - { - condition: ParamCondition.LESS_THAN_OR_EQUAL, // The condition to check - offset: 32, // The offset where the param is in the calldata - param: pad(toHex(10000), { size: 32 }), // The value to check in condition - }, - { - condition: ParamCondition.EQUAL, - offset: 0, - param: pad(, { size: 32 }), - }, - ], - } + getPermissionFromABI({ + target: , // address of the target contract, + valueLimit: 0n, // max value the session key can use in tx -- (Default: 0) + operation: Operation.Call, // The kind of call session key can make CALL/DELEGATECALL (Default: Operation.Call) + abi: TEST_ERC20Abi, // Abi of the target contract + functionName: "transfer", // The function that can be called on the target contract + args: [, 10000n], // The value to check in condition + conditions: [ + ParamCondition.EQUAL, + ParamCondition.LESS_THAN_OR_EQUAL, + ], // The condition to check + + // To allows specific params to not have any condition pass `null` in the param position in the `args` and `conditions` like below: + + // args: [, null], // The value to check in condition + // conditions: [ + // ParamCondition.EQUAL, + // null + // ], // The condition to check + }) ] const sessionKeyProvider = await SessionKeyProvider.init({ @@ -455,10 +457,10 @@ const sessionKeyProvider = await SessionKeyProvider.init({ defaultProvider: ecdsaProvider, // Pass the ECDSAProvider as default provider sessionKey, // Session Key Signer sessionKeyData: { - validAfter: 0, - validUntil: 0, + validAfter: 0, // (Default: 0) + validUntil: 0, // (Default: 0) permissions, - paymaster, // Paymaster Address : zeroAddress means accept userOp without paymaster, oneAddress means reject userOp without paymaster, other address means accept userOp with paymaster with the address + paymaster, // Paymaster Address : zeroAddress means accept userOp without paymaster, oneAddress means reject userOp without paymaster, other address means accept userOp with paymaster with the address // (Default: zeroAddress) } }); @@ -481,15 +483,12 @@ import { constants, MultiSendAbi } from "@zerodev/sdk"; // Permission object to pass in the `sessionKeyData.permissions` array const permissions = [ ..., - { - target: constants.MULTISEND_ADDR, - valueLimit: 0n, - sig: getFunctionSelector( - getAbiItem({ abi: MultiSendAbi, name: "multiSend" }) - ), - operation: Operation.DelegateCall, - rules: [], - } + getPermissionFromABI({ + target: MULTISEND_ADDR, + abi: MultiSendAbi, + functionName: "multiSend", + operation: Operation.DelegateCall + }), ] ``` @@ -525,178 +524,11 @@ const sessionKeyProvider = await SessionKeyProvider.fromSessionKeyParams({ #### Creating Session Key on the client and approving on the server -```ts -// On the server -// 1. Create an EmptyAccountSigner from the session key address sent from the client and pass to the provider -const sessionKey = new EmptyAccountSigner(); - -const sessionKeyProvider = await SessionKeyProvider.init({ - projectId, //ZeroDevProject - defaultProvider: ecdsaProvider, - sessionKey, - sessionKeyData: { - validAfter: 0, - validUntil: 0, - permissions, - paymaster, // Paymaster Address : zeroAddress means accept userOp without paymaster, oneAddress means reject userOp without paymaster, other address means accept userOp with paymaster with the address - } -}); - -// 2. Serialize the session key params and send it to the client -const serializedSessionKeyParams = await sessionKeyProvider.serializeSessionKeyParams(); - -// On client side -// 3. Deserialize the session key params and pass the session private key to the object -const sessionKeyParams = { - ...SessionKeyProvider.deserializeSessionKeyParams(serializedSessionKeyParams) - sessionPrivateKey -} - -// 4. Initialize the SessionKey Provider from the session key params -const sessionKeyProvider = await SessionKeyProvider.fromSessionKeyParams({ - projectId, //ZeroDevProject - sessionKeyParams - }); -``` +[Please check out the session key docs here.](https://docs.zerodev.app/use-wallets/use-session-keys) ### Recovery Key Validator -#### Enable the recovery plugin - -```ts -// 1. Get the default ecdsa validator provider -const ecdsaProvider = await ECDSAProvider.init({ - projectId, // zeroDev projectId - owner, -}); - -// 2. Initialize the Recovery Provider -const recoveryData = { - guardians: { - // Guardian addresses with their weights - [guardianAddress]: 1, - [guardian2Address]: 1, - [guardian3Address]: 1, - }, - threshold: 3, - delaySeconds: 0, -}; - -const recoveryProvider = await RecoveryProvider.init({ - projectId, - defaultProvider: ecdsaProvider, - opts: { - validatorConfig: { - ...recoveryData, - }, - }, -}); - -// 3. Enable the recovery plugin -const result = await recoveryProvider.enableRecovery(); -await recoveryProvider.waitForUserOperationTransaction(result.hash as Hex); -``` - -#### Initiate the recovery and retrieve the recoveryId - -```ts -// 1. Initialize the Recovery Provider -const recoveryProvider = await RecoveryProvider.init({ - projectId, - opts: { - accountConfig: { - accountAddress - } - } -}); - -// 2. Initiate the recovery -const recoveryId = await recoveryProvider.initiateRecovery(); -``` - -#### Share recoveryId with the guardians to sign recoveryHash - -```ts -// 1. Intialize the Recovery Provider for guardian -const guardian = - LocalAccountSigner.privateKeyToAccountSigner(); -const recoveryProvider = await RecoveryProvider.init({ - projectId, - recoveryId, - opts: { - validatorConfig: { - accountSigner: guardian, - }, - }, -}); - -// 2. Sign the recovery hash -await recoveryProvider.signRecovery(); -``` - -#### Submit the recovery request - -| Anybody can submit the recovery request if they have the recoveryId - -```ts -// 1. Initialize the recovery provider -const account = privateKeyToAccount(); -const recoveryProvider = await RecoveryProvider.init({ - projectId, - recoveryId, -}); - -// 2. Submit the recovery request -const result = await recoveryProvider.submitRecovery(); -await recoveryProvider.waitForUserOperationTransaction( - result.hash as Hex -); -``` - -#### Cancel the recovery request - -| Owner of the account can cancel the recovery request - -```ts -// 1. Get the default ecdsa validator provider -const ecdsaProvider = await ECDSAProvider.init({ - projectId, // zeroDev projectId - owner, -}); - -// 2. Initialize the Recovery Provider -const recoveryProvider = await RecoveryProvider.init({ - projectId, - defaultProvider: ecdsaProvider, - recoveryId, -}); - -// 3. Cancel the recovery -const result = await recoveryProvider.cancelRecovery(); -await recoveryProvider.waitForUserOperationTransaction(result.hash as Hex); -``` - -#### Disable the recovery plugin - -| To re-enable Recovery plugin with new recovery data (e.g. guardians, weights, threshold, delaySeconds), the existing enabled recovery plugin needs to be disabled first. - -```ts -// 1. Get the default ecdsa validator provider -const ecdsaProvider = await ECDSAProvider.init({ - projectId, // zeroDev projectId - owner, -}); - -// 2. Initialize the Recovery Provider -const recoveryProvider = await RecoveryProvider.init({ - projectId, - defaultProvider: ecdsaProvider, -}); - -// 3. Delete the recovery data -const result = await recoveryProvider.deleteRecoveryData(); -await recoveryProvider.waitForUserOperationTransaction(result.hash as Hex); -``` +[Please check out the recovery docs here.](https://docs.zerodev.app/use-wallets/recovery) ## Components diff --git a/packages/accounts/package.json b/packages/accounts/package.json index 1d98ac55..68fc0a56 100644 --- a/packages/accounts/package.json +++ b/packages/accounts/package.json @@ -1,6 +1,6 @@ { "name": "@zerodev/sdk", - "version": "4.0.29", + "version": "4.0.31", "description": "A collection of ERC-4337 compliant smart contract account interfaces", "author": "ZeroDev", "license": "MIT", @@ -36,8 +36,8 @@ }, "scripts": { "build": "yarn clean && yarn build:cjs && yarn build:esm && yarn build:types", - "build:cjs": "tsc --project tsconfig.build.json --module commonjs --outDir ./dist/cjs --removeComments --verbatimModuleSyntax false && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'", - "build:esm": "tsc --project tsconfig.build.json --module es2020 --outDir ./dist/esm --removeComments && echo > ./dist/esm/package.json '{\"type\":\"module\"}'", + "build:cjs": "tsc --project tsconfig.build-cjs.json && echo > ./dist/cjs/package.json '{\"type\":\"commonjs\"}'", + "build:esm": "tsc --project tsconfig.build.json && echo > ./dist/esm/package.json '{\"type\":\"module\"}'", "build:types": "tsc --project tsconfig.build.json --module esnext --declarationDir ./dist/types --emitDeclarationOnly --declaration --declarationMap", "clean": "rm -rf ./dist", "test": "vitest", diff --git a/packages/accounts/src/index.ts b/packages/accounts/src/index.ts index 081f75a2..b12f858f 100644 --- a/packages/accounts/src/index.ts +++ b/packages/accounts/src/index.ts @@ -12,7 +12,11 @@ export { export * from "./kernel-zerodev/validator/index.js"; export type * from "./kernel-zerodev/validator/types.js"; export type { KernelBaseValidatorParams } from "./kernel-zerodev/validator/base.js"; -export { ParamCondition } from "./kernel-zerodev/validator/session-key-validator.js"; +export { + ParamCondition, + getAbiItem, + getPermissionFromABI, +} from "./kernel-zerodev/validator/session-key-validator.js"; // Validator Provider exports export { ValidatorProvider } from "./kernel-zerodev/validator-provider/base.js"; diff --git a/packages/accounts/src/kernel-zerodev/__tests__/kernel-session-key-provider.test.ts b/packages/accounts/src/kernel-zerodev/__tests__/kernel-session-key-provider.test.ts index 65ff140c..2592cd0f 100644 --- a/packages/accounts/src/kernel-zerodev/__tests__/kernel-session-key-provider.test.ts +++ b/packages/accounts/src/kernel-zerodev/__tests__/kernel-session-key-provider.test.ts @@ -4,11 +4,8 @@ import { type Hex, getFunctionSelector, encodeFunctionData, - toHex, - pad, zeroAddress, type Hash, - getAbiItem, } from "viem"; import { polygonMumbai } from "viem/chains"; import { generatePrivateKey } from "viem/accounts"; @@ -28,6 +25,7 @@ import { } from "@alchemy/aa-core"; import { ParamCondition, + getPermissionFromABI, type Permission, } from "../validator/session-key-validator.js"; import { Operation } from "../provider.js"; @@ -53,9 +51,6 @@ describe("Kernel SessionKey Provider Test", async () => { chain: polygonMumbai, transport: http(CHAIN_ID_TO_NODE[polygonMumbai.id]), }); - const erc20TransferSelector = getFunctionSelector( - "transfer(address, uint256)" - ); const transfer20ActionSelector = getFunctionSelector( "transfer20Action(address, uint256, address)" ); @@ -204,42 +199,17 @@ describe("Kernel SessionKey Provider Test", async () => { executeSelector, amountToMint, [ - { + getPermissionFromABI({ target: Test_ERC20Address, valueLimit: 0n, - sig: erc20TransferSelector, - operation: Operation.Call, - rules: [ - { - condition: ParamCondition.LESS_THAN_OR_EQUAL, - offset: 32, - param: pad(toHex(10000), { size: 32 }), - }, - { - condition: ParamCondition.EQUAL, - offset: 0, - param: pad(await secondOwner.getAddress(), { size: 32 }), - }, - ], - }, - { - target: Test_ERC20Address, - valueLimit: 1n, - sig: erc20TransferSelector, - operation: Operation.Call, - rules: [ - { - condition: ParamCondition.LESS_THAN_OR_EQUAL, - offset: 32, - param: pad(toHex(10000), { size: 32 }), - }, - { - condition: ParamCondition.EQUAL, - offset: 0, - param: pad(await owner.getAddress(), { size: 32 }), - }, + abi: TEST_ERC20Abi, + functionName: "transfer", + args: [await secondOwner.getAddress(), 10000n], + conditions: [ + ParamCondition.EQUAL, + ParamCondition.LESS_THAN_OR_EQUAL, ], - }, + }), ] ); await sessionKeyProvider.sendUserOperation({ @@ -271,24 +241,16 @@ describe("Kernel SessionKey Provider Test", async () => { executeSelector, amountToMint, [ - { + getPermissionFromABI({ target: Test_ERC20Address, - valueLimit: 0n, - sig: erc20TransferSelector, - operation: Operation.Call, - rules: [ - // { - // condition: ParamCondition.LESS_THAN_OR_EQUAL, - // offset: 32, - // param: pad(toHex(10000), { size: 32 }), - // }, - // { - // condition: ParamCondition.EQUAL, - // offset: 0, - // param: pad(await secondOwner.getAddress(), { size: 32 }), - // }, + abi: TEST_ERC20Abi, + functionName: "transfer", + args: [await secondOwner.getAddress(), 10000n], + conditions: [ + ParamCondition.EQUAL, + ParamCondition.LESS_THAN_OR_EQUAL, ], - }, + }), ] ); @@ -346,22 +308,17 @@ describe("Kernel SessionKey Provider Test", async () => { executeSelector, amountToMint, [ - { + getPermissionFromABI({ target: Test_ERC20Address, - valueLimit: 0n, - sig: erc20TransferSelector, - operation: Operation.Call, - rules: [], - }, - { + abi: TEST_ERC20Abi, + functionName: "transfer", + }), + getPermissionFromABI({ target: MULTISEND_ADDR, - valueLimit: 0n, - sig: getFunctionSelector( - getAbiItem({ abi: MultiSendAbi, name: "multiSend" }) - ), + abi: MultiSendAbi, + functionName: "multiSend", operation: Operation.DelegateCall, - rules: [], - }, + }), ], zeroAddress, true, @@ -481,24 +438,16 @@ describe("Kernel SessionKey Provider Test", async () => { executeSelector, amountToMint, [ - { + getPermissionFromABI({ target: Test_ERC20Address, - valueLimit: 0n, - sig: erc20TransferSelector, - operation: Operation.Call, - rules: [ - { - condition: ParamCondition.LESS_THAN_OR_EQUAL, - offset: 32, - param: pad(toHex(10000), { size: 32 }), - }, - { - condition: ParamCondition.EQUAL, - offset: 0, - param: pad(await secondOwner.getAddress(), { size: 32 }), - }, + abi: TEST_ERC20Abi, + functionName: "transfer", + args: [await secondOwner.getAddress(), 10000n], + conditions: [ + ParamCondition.EQUAL, + ParamCondition.LESS_THAN_OR_EQUAL, ], - }, + }), ] ); @@ -539,24 +488,16 @@ describe("Kernel SessionKey Provider Test", async () => { executeSelector, amountToMint, [ - { + getPermissionFromABI({ target: Test_ERC20Address, - valueLimit: 0n, - sig: erc20TransferSelector, - operation: Operation.Call, - rules: [ - { - condition: ParamCondition.LESS_THAN_OR_EQUAL, - offset: 32, - param: pad(toHex(10000), { size: 32 }), - }, - { - condition: ParamCondition.EQUAL, - offset: 0, - param: pad(await randomOwner.getAddress(), { size: 32 }), - }, + abi: TEST_ERC20Abi, + functionName: "transfer", + args: [await randomOwner.getAddress(), 10000n], + conditions: [ + ParamCondition.EQUAL, + ParamCondition.LESS_THAN_OR_EQUAL, ], - }, + }), ], oneAddress, false @@ -592,13 +533,12 @@ describe("Kernel SessionKey Provider Test", async () => { executeSelector, 0n, [ - { + getPermissionFromABI({ target: Test_ERC20Address, + abi: TEST_ERC20Abi, + functionName: "transfer", valueLimit: bigInt, - sig: erc20TransferSelector, - operation: Operation.Call, - rules: [], - }, + }), ], oneAddress, false diff --git a/packages/accounts/src/kernel-zerodev/abis/ERC20Abi.ts b/packages/accounts/src/kernel-zerodev/abis/ERC20Abi.ts index 17520b89..c496d49f 100644 --- a/packages/accounts/src/kernel-zerodev/abis/ERC20Abi.ts +++ b/packages/accounts/src/kernel-zerodev/abis/ERC20Abi.ts @@ -150,4 +150,4 @@ export const ERC20Abi = [ stateMutability: "nonpayable", type: "function", }, -]; +] as const; diff --git a/packages/accounts/src/kernel-zerodev/validator/session-key-validator.ts b/packages/accounts/src/kernel-zerodev/validator/session-key-validator.ts index bbaf0de4..06e92fa2 100644 --- a/packages/accounts/src/kernel-zerodev/validator/session-key-validator.ts +++ b/packages/accounts/src/kernel-zerodev/validator/session-key-validator.ts @@ -6,6 +6,7 @@ import { type UserOperationRequest, getChain, type SignTypedDataParams, + type Abi, } from "@alchemy/aa-core"; import { KernelBaseValidator, @@ -26,14 +27,18 @@ import { decodeFunctionData, isHex, getFunctionSelector, + type GetAbiItemParameters, } from "viem"; +import { formatAbiItem } from "viem/utils"; import { SessionKeyValidatorAbi } from "../abis/SessionKeyValidatorAbi.js"; import { DUMMY_ECDSA_SIG } from "../constants.js"; import { KernelAccountAbi } from "../abis/KernelAccountAbi.js"; import { MerkleTree } from "merkletreejs"; -import type { Operation } from "../provider.js"; +import { Operation } from "../provider.js"; import { getChainId } from "../api/index.js"; import { fixSignedData } from "../utils.js"; +import type { GetAbiItemReturnType } from "viem/dist/types/utils/abi/getAbiItem.js"; +import type { GeneratePermissionFromArgsParameters } from "./types.js"; // We need to be able to serialize bigint to transmit session key over // the network. @@ -72,13 +77,13 @@ export interface ParamRules { param: Hex; } -export interface Permission { +export type Permission = { target: Address; - valueLimit: bigint; sig: Hex; rules: ParamRules[]; - operation: Operation; -} + valueLimit?: bigint; + operation?: Operation; +}; export interface SessionKeyData { validUntil: number; @@ -87,6 +92,93 @@ export interface SessionKeyData { permissions?: Permission[]; } +export function getAbiItem< + TAbi extends Abi | readonly unknown[], + TItemName extends string +>({ + abi, + args = [], + name, +}: GetAbiItemParameters): GetAbiItemReturnType< + TAbi, + TItemName +> { + const abiItems = (abi as Abi).filter((x) => "name" in x && x.name === name); + if (abiItems.length === 0) return undefined as any; + if (abiItems.length === 1) return abiItems[0] as any; + const abiItemsParamFiltered = []; + for (const abiItem of abiItems) { + if (!("inputs" in abiItem)) continue; + if (!args || args.length === 0) { + if (!abiItem.inputs || abiItem.inputs.length === 0) return abiItem as any; + continue; + } + if (!abiItem.inputs) continue; + if (abiItem.inputs.length === 0) continue; + if (abiItem.inputs.length !== args.length) continue; + abiItemsParamFiltered.push(abiItem); + } + if (abiItemsParamFiltered.length === 0) return abiItems[0] as any; + else if (abiItemsParamFiltered.length === 1) + return abiItemsParamFiltered[0] as any; + else + throw Error( + `Couldn't parse funtion signature using params, set appropriate one from below:\n${abiItemsParamFiltered + .map((item) => formatAbiItem(item)) + .reduce((a, c) => `${a}\n${c}`)}` + ); +} + +export function getPermissionFromABI< + TAbi extends Abi | readonly unknown[], + TFunctionName extends string | undefined = string +>({ + abi, + target, + args, + conditions, + functionName, + operation, + valueLimit, +}: GeneratePermissionFromArgsParameters): Permission { + const abiItem = getAbiItem({ + abi, + args, + name: functionName, + } as GetAbiItemParameters); + if (abiItem.type !== "function") { + throw Error(`${functionName} not found in abi`); + } + const functionSelector = getFunctionSelector(abiItem); + let paramRules: ParamRules[] = []; + if ( + args && + Array.isArray(args) && + conditions && + Array.isArray(conditions) && + args.length === conditions.length + ) { + paramRules = args + .map( + (arg, i) => + arg && + conditions && { + param: pad(isHex(arg) ? arg : toHex(arg), { size: 32 }), + offset: i * 32, + condition: conditions[i], + } + ) + .filter((rule) => rule); + } + return { + sig: functionSelector, + rules: paramRules, + target, + operation: operation ?? Operation.Call, + valueLimit: valueLimit ?? 0n, + }; +} + export class SessionKeyValidator extends KernelBaseValidator { protected sessionKey: SmartAccountSigner; sessionKeyData: SessionKeyData; @@ -97,8 +189,17 @@ export class SessionKeyValidator extends KernelBaseValidator { this.sessionKey = params.sessionKey; this.sessionKeyData = { ...params.sessionKeyData, + validAfter: params.sessionKeyData.validAfter ?? 0, + validUntil: params.sessionKeyData.validUntil ?? 0, paymaster: params.sessionKeyData.paymaster ?? zeroAddress, }; + this.sessionKeyData.permissions = this.sessionKeyData.permissions?.map( + (perm) => ({ + ...perm, + operation: perm.operation ?? Operation.Call, + valueLimit: perm.valueLimit ?? 0n, + }) + ); this.merkleTree = this.getMerkleTree(); if (this.shouldDelegateViaFallback()) { throw Error("Session key permissions not set"); @@ -168,15 +269,15 @@ export class SessionKeyValidator extends KernelBaseValidator { ); const valueLimitPermissions = signaturePermissions.filter( - (permission) => permission.valueLimit >= args[1] + (permission) => (permission.valueLimit ?? 0n) >= args[1] ); if (!valueLimitPermissions.length) return undefined; const sortedPermissions = valueLimitPermissions.sort((a, b) => { - if (b.valueLimit > a.valueLimit) { + if ((b.valueLimit ?? 0n) > (a.valueLimit ?? 0n)) { return 1; - } else if (b.valueLimit < a.valueLimit) { + } else if ((b.valueLimit ?? 0n) < (a.valueLimit ?? 0n)) { return -1; } else { return 0; @@ -194,7 +295,8 @@ export class SessionKeyValidator extends KernelBaseValidator { operation: Operation ): Permission[] { return permissions.filter( - (permission) => permission.operation === operation + (permission) => + permission.operation === operation || Operation.Call === operation ); } diff --git a/packages/accounts/src/kernel-zerodev/validator/types.ts b/packages/accounts/src/kernel-zerodev/validator/types.ts index 89093a25..9dabb3bb 100644 --- a/packages/accounts/src/kernel-zerodev/validator/types.ts +++ b/packages/accounts/src/kernel-zerodev/validator/types.ts @@ -1,3 +1,11 @@ +import { + type AbiParameter, + type AbiParameterKind, + type AbiParameterToPrimitiveType, + type AbiFunction, + type ExtractAbiFunction, +} from "abitype"; +import { type Pretty } from "abitype/src/types.js"; import type { ECDSAValidator, ECDSAValidatorParams, @@ -22,7 +30,9 @@ import type { Permission, SessionKeyData, SessionKeyParams, + ParamCondition, } from "./session-key-validator.js"; +import type { Abi, InferFunctionName, Narrow } from "viem"; export type SupportedValidators = | "ECDSA" @@ -56,3 +66,57 @@ export type ValidatorMap = { export type EthereumProvider = { request(...args: any): Promise }; export type { ParamRules, Permission, SessionKeyData, SessionKeyParams }; + +// Session Key types +export type AbiParametersToPrimitiveTypes< + TAbiParameters extends readonly AbiParameter[], + TAbiParameterKind extends AbiParameterKind = AbiParameterKind +> = Pretty<{ + [K in keyof TAbiParameters]: AbiParameterToPrimitiveType< + TAbiParameters[K], + TAbiParameterKind + > | null; +}>; + +export type AbiParametersToConditons< + TAbiParameters extends readonly AbiParameter[] +> = Pretty<{ + [K in keyof TAbiParameters]: ParamCondition | null; +}>; + +export type GetFunctionArgs< + TAbi extends Abi | readonly unknown[], + TFunctionName extends string, + TAbiFunction extends AbiFunction = TAbi extends Abi + ? ExtractAbiFunction + : AbiFunction, + TArgs = AbiParametersToPrimitiveTypes, + TConditions = AbiParametersToConditons, + FailedToParseArgs = + | ([TArgs] extends [never] ? true : false) + | (readonly unknown[] extends TArgs ? true : false) +> = true extends FailedToParseArgs + ? { + args?: readonly unknown[]; + conditions?: readonly unknown[]; + } + : TArgs extends readonly [] + ? { args?: never; conditions?: never } + : { + args?: TArgs; + conditions?: TConditions; + }; + +export type GeneratePermissionFromArgsParameters< + TAbi extends Abi | readonly unknown[], + TFunctionName extends string | undefined = string, + _FunctionName = TAbi extends Abi + ? InferFunctionName + : never +> = Pick & { + functionName?: _FunctionName; +} & (TFunctionName extends string + ? { abi: Narrow } & GetFunctionArgs + : _FunctionName extends string + ? { abi: [Narrow] } & GetFunctionArgs + : never); diff --git a/packages/accounts/tsconfig.build-cjs.json b/packages/accounts/tsconfig.build-cjs.json new file mode 100644 index 00000000..f3ea6c4c --- /dev/null +++ b/packages/accounts/tsconfig.build-cjs.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.build.json", + "compilerOptions": { + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "module": "CommonJS", + "outDir": "./dist/cjs", + "verbatimModuleSyntax": false + } +} diff --git a/packages/accounts/tsconfig.build.json b/packages/accounts/tsconfig.build.json index 345f8f3f..8b4d5ac9 100644 --- a/packages/accounts/tsconfig.build.json +++ b/packages/accounts/tsconfig.build.json @@ -3,6 +3,11 @@ "exclude": ["node_modules", "**/*/__tests__", "vitest.config.ts"], "include": ["src"], "compilerOptions": { - "sourceMap": true + "sourceMap": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "module": "ES2020", + "outDir": "./dist/esm", + "removeComments": true } }