-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
556 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,4 +3,4 @@ | |
zkeys/ | ||
proofs/ | ||
tally.json | ||
|
||
session-keys.json |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/** | ||
* Generate the RPCUrl for Pimlico based on the chain we need to interact with | ||
* @param network - the network we want to interact with | ||
* @returns the RPCUrl for the network | ||
*/ | ||
export const genPimlicoRPCUrl = (network: string): string => { | ||
const pimlicoAPIKey = process.env.PIMLICO_API_KEY; | ||
|
||
if (!pimlicoAPIKey) { | ||
throw new Error("PIMLICO_API_KEY is not set"); | ||
} | ||
|
||
return `https://api.pimlico.io/v2/${network}/rpc?apikey=${pimlicoAPIKey}`; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
40 changes: 40 additions & 0 deletions
40
packages/coordinator/ts/sessionKeys/__tests__/sessionKeys.service.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import dotenv from "dotenv"; | ||
import { ZeroAddress } from "ethers"; | ||
|
||
import { CryptoService } from "../../crypto/crypto.service"; | ||
import { FileService } from "../../file/file.service"; | ||
import { SessionKeysService } from "../sessionKeys.service"; | ||
|
||
dotenv.config(); | ||
|
||
describe("DeployerService", () => { | ||
afterEach(() => { | ||
jest.clearAllMocks(); | ||
}); | ||
|
||
const cryptoService = new CryptoService(); | ||
const fileService = new FileService(); | ||
const sessionKeysService = new SessionKeysService(cryptoService, fileService); | ||
|
||
test("should generate and store a session key", () => { | ||
const sessionKeyAddress = sessionKeysService.generateSessionKey(); | ||
expect(sessionKeyAddress).toBeDefined(); | ||
expect(sessionKeyAddress).not.toEqual(ZeroAddress); | ||
|
||
const sessionKey = fileService.getSessionKey(sessionKeyAddress.sessionKeyAddress); | ||
expect(sessionKey).toBeDefined(); | ||
}); | ||
|
||
test("should delete a session key", () => { | ||
const sessionKeyAddress = sessionKeysService.generateSessionKey(); | ||
expect(sessionKeyAddress).toBeDefined(); | ||
expect(sessionKeyAddress).not.toEqual(ZeroAddress); | ||
|
||
const sessionKey = fileService.getSessionKey(sessionKeyAddress.sessionKeyAddress); | ||
expect(sessionKey).toBeDefined(); | ||
|
||
sessionKeysService.deactivateSessionKey(sessionKeyAddress.sessionKeyAddress); | ||
const sessionKeyDeleted = fileService.getSessionKey(sessionKeyAddress.sessionKeyAddress); | ||
expect(sessionKeyDeleted).toBeUndefined(); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import { signerToEcdsaValidator } from "@zerodev/ecdsa-validator"; | ||
import { type Policy, serializePermissionAccount, toPermissionValidator } from "@zerodev/permissions"; | ||
import { toTimestampPolicy } from "@zerodev/permissions/policies"; | ||
import { toECDSASigner } from "@zerodev/permissions/signers"; | ||
import { addressToEmptyAccount, createKernelAccount } from "@zerodev/sdk"; | ||
import { KERNEL_V3_1 } from "@zerodev/sdk/constants"; | ||
import { ENTRYPOINT_ADDRESS_V07 } from "permissionless"; | ||
import { createPublicClient, http } from "viem"; | ||
import { generatePrivateKey, privateKeyToAccount } from "viem/accounts"; | ||
import { localhost } from "viem/chains"; | ||
|
||
// use the latest kernel version | ||
const kernelVersion = KERNEL_V3_1; | ||
// we use the most recent entrypoint | ||
const entryPoint = ENTRYPOINT_ADDRESS_V07; | ||
|
||
/** | ||
* Generate a timestamp policy | ||
* @param endTime - The end time of the policy | ||
* @param start - The start time of the policy | ||
* @returns The timestamp policy | ||
*/ | ||
export const generateTimestampPolicy = (endTime: number, start?: number): Policy => | ||
toTimestampPolicy({ | ||
validAfter: start, | ||
validUntil: endTime, | ||
}); | ||
|
||
/** | ||
* Mock a session key approval | ||
* @dev This will fail in hardhat with: | ||
* "InvalidEntryPointError: The entry point address | ||
* (`entryPoint` = 0x0000000071727De22E5E9d8BAf0edAc6f37da032) | ||
* is not a valid entry point. getSenderAddress did not revert with | ||
* a SenderAddressResult error." | ||
* | ||
* @param sessionKeyAddress - The address of the session key | ||
* @returns The approval string | ||
*/ | ||
export const mockSessionKeyApproval = async (sessionKeyAddress: `0x${string}`): Promise<string> => { | ||
const policies = [generateTimestampPolicy(Math.floor(Date.now() / 1000) + 1000)]; | ||
|
||
const publicClient = createPublicClient({ | ||
chain: localhost, | ||
transport: http(), | ||
}); | ||
|
||
const sessionPrivateKey = generatePrivateKey(); | ||
|
||
const signer = privateKeyToAccount(sessionPrivateKey); | ||
|
||
const ecdsaValidator = await signerToEcdsaValidator(publicClient, { | ||
signer, | ||
entryPoint, | ||
kernelVersion, | ||
}); | ||
|
||
// Create an "empty account" as the signer -- you only need the public | ||
// key (address) to do this. | ||
const emptyAccount = addressToEmptyAccount(sessionKeyAddress); | ||
const emptySessionKeySigner = toECDSASigner({ signer: emptyAccount }); | ||
|
||
const permissionPlugin = await toPermissionValidator(publicClient, { | ||
entryPoint, | ||
kernelVersion, | ||
signer: emptySessionKeySigner, | ||
policies, | ||
}); | ||
|
||
const sessionKeyAccount = await createKernelAccount(publicClient, { | ||
entryPoint, | ||
kernelVersion, | ||
plugins: { | ||
sudo: ecdsaValidator, | ||
regular: permissionPlugin, | ||
}, | ||
}); | ||
|
||
const approval = await serializePermissionAccount(sessionKeyAccount); | ||
|
||
return approval; | ||
}; |
50 changes: 50 additions & 0 deletions
50
packages/coordinator/ts/sessionKeys/sessionKeys.controller.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
/* eslint-disable @typescript-eslint/no-shadow */ | ||
import { Controller, Delete, Get, HttpStatus, Param, UseGuards } from "@nestjs/common"; | ||
import { ApiBearerAuth, ApiResponse, ApiTags } from "@nestjs/swagger"; | ||
|
||
import type { IGenerateSessionKeyReturn } from "./types"; | ||
|
||
import { AccountSignatureGuard } from "../auth/AccountSignatureGuard.service"; | ||
|
||
import { SessionKeysService } from "./sessionKeys.service"; | ||
|
||
@ApiTags("v1/session-keys") | ||
@ApiBearerAuth() | ||
@Controller("v1/session-keys") | ||
@UseGuards(AccountSignatureGuard) | ||
export class SessionKeysController { | ||
/** | ||
* Initialize SessionKeysController | ||
* | ||
* @param sessionKeysService - session keys service | ||
*/ | ||
constructor(private readonly sessionKeysService: SessionKeysService) {} | ||
|
||
/** | ||
* Generate a session key api method | ||
* | ||
* @param args - generate session key dto | ||
* @returns generated session key address | ||
*/ | ||
@ApiResponse({ status: HttpStatus.CREATED, description: "The session key was successfully generated" }) | ||
@ApiResponse({ status: HttpStatus.FORBIDDEN, description: "Forbidden" }) | ||
@ApiResponse({ status: HttpStatus.BAD_REQUEST, description: "BadRequest" }) | ||
@Get("generate") | ||
generateSessionKey(): IGenerateSessionKeyReturn { | ||
return this.sessionKeysService.generateSessionKey(); | ||
} | ||
|
||
/** | ||
* Delete a session key api method | ||
* | ||
* @param args - delete session key dto | ||
* @returns deleted session key address | ||
*/ | ||
@ApiResponse({ status: HttpStatus.CREATED, description: "The session key was successfully deactivated" }) | ||
@ApiResponse({ status: HttpStatus.FORBIDDEN, description: "Forbidden" }) | ||
@ApiResponse({ status: HttpStatus.BAD_REQUEST, description: "BadRequest" }) | ||
@Delete(":sessionKeyAddress") | ||
deactivateSessionKey(@Param("sessionKeyAddress") sessionKeyAddress: `0x${string}`): void { | ||
this.sessionKeysService.deactivateSessionKey(sessionKeyAddress); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { Module } from "@nestjs/common"; | ||
|
||
import { CryptoModule } from "../crypto/crypto.module"; | ||
import { FileModule } from "../file/file.module"; | ||
|
||
import { SessionKeysController } from "./sessionKeys.controller"; | ||
import { SessionKeysService } from "./sessionKeys.service"; | ||
|
||
@Module({ | ||
imports: [FileModule, CryptoModule], | ||
controllers: [SessionKeysController], | ||
providers: [SessionKeysService], | ||
}) | ||
export class SessionKeysModule {} |
Oops, something went wrong.