Skip to content

Task 1-2: SmartAccountClient Caching

Phase: 1 Priority: Medium Module: biconomy Depends on: Không có Reference: docs/bountyhunter-blockchain-p2/details/feature-evm-integration/SPEC.md

Background

Hiện tại createSmartAccountClient() được gọi mới hoàn toàn trong mỗi job tại handleBiconomySendGaslessNfthandleBiconomySendGaslessToken. Đây là thao tác khởi tạo SDK tốn kém — bao gồm thiết lập Bundler client, Paymaster client và sign session. Với traffic cao, mỗi job đều phải thực hiện lại toàn bộ quá trình này dù cùng private key và chainId, gây lãng phí tài nguyên và tăng độ trễ xử lý.

Tasks

Note: Cache SmartAccountClient là instance-level state trên BiconomyProcessor (singleton trong NestJS DI). Sử dụng Map<string, SmartAccountClient> là đủ vì processor là singleton. Tuyệt đối không dùng private key làm cache key trực tiếp — phải hash trước. Import crypto từ Node.js built-in.

  • [ ] Khai báo cache map ở class level trong BiconomyProcessor:
    private readonly clientCache = new Map<string, SmartAccountClient>();
    
  • [ ] Implement helper getOrCreateSmartAccountClient(privateKey: string, chainId: number):
    private async getOrCreateSmartAccountClient(
      privateKey: string,
      chainId: number,
    ): Promise<SmartAccountClient> {
      const keyHash = crypto
        .createHash('sha256')
        .update(privateKey)
        .digest('hex');
      const cacheKey = `${keyHash}:${chainId}`;
    
      if (this.clientCache.has(cacheKey)) {
        return this.clientCache.get(cacheKey)!;
      }
    
      const client = await createSmartAccountClient({ privateKey, chainId });
      this.clientCache.set(cacheKey, client);
      return client;
    }
    
  • [ ] Thay thế toàn bộ lời gọi createSmartAccountClient(...) trực tiếp trong handleBiconomySendGaslessNfthandleBiconomySendGaslessToken bằng getOrCreateSmartAccountClient(...)
  • [ ] Thêm TTL eviction để tránh memory leak — dùng setTimeout xóa entry sau N phút:
    setTimeout(() => this.clientCache.delete(cacheKey), 30 * 60 * 1000); // 30 phút
    
  • [ ] Log khi cache hit vs cache miss (dùng this.logger.debug(...) — xem task-1-1)

Verification / Acceptance Criteria

  • [ ] 2 jobs liên tiếp với cùng privateKey + chainIdcreateSmartAccountClient SDK chỉ được gọi 1 lần (cache hit lần 2)
  • [ ] 2 jobs với privateKey khác nhau → 2 client khác nhau được tạo
  • [ ] Private key không xuất hiện trong cache key hoặc log
  • [ ] Sau TTL 30 phút → entry bị xóa khỏi cache; job tiếp theo tạo lại client bình thường
  • [ ] TypeScript compile không có lỗi

Files to Modify

  • src/biconomy/biconomy.processor.ts