Skip to content

Task 3-2: Integration Test - Solana Marketplace & Rental

Phase: 3 Priority: Medium Module: solana Depends on: task-1-1 Reference: docs/bountyhunter-blockchain-p2/details/feature-solana-integration/SPEC.md

Background

Solana Marketplace (list, buy) và Rental (create, rent) sử dụng Anchor programs với IDL (MARKETPLACE_IDL, RENTAL_IDL). Đây là Solana-native smart contracts với PDA (Program Derived Address) — cần mock @project-serum/anchor Program để test mà không cần local validator. Chưa có test coverage cho các luồng này dù là core business operations.

Tasks

Note: Mock @project-serum/anchor Program trong DI test module — inject mock thay vì real program. Escrow PDA được tính bởi PublicKey.findProgramAddressSync — cần mock hoặc dùng deterministic test address. AnchorProvider cần được setup với mock Wallet và mock Connection. Import Program, AnchorProvider, web3 từ @project-serum/anchor.

  • [ ] Setup mock Anchor Program trong test module:
    const mockMarketplaceProgram = {
      methods: {
        listNft: jest.fn().mockReturnValue({
          accounts: jest.fn().mockReturnThis(),
          signers: jest.fn().mockReturnThis(),
          rpc: jest.fn().mockResolvedValue('list-tx-signature'),
        }),
        buyNft: jest.fn().mockReturnValue({ /* similar chain */ }),
      },
    };
    
    TestingModule = await Test.createTestingModule({
      providers: [
        { provide: 'MARKETPLACE_PROGRAM', useValue: mockMarketplaceProgram },
        // ...
      ],
    }).compile();
    
  • [ ] Test case 1 — List NFT (Solana Marketplace):
    it('POST /solana/list-nft → Anchor listNft instruction executed → Escrow PDA created → webhook', async () => {
      const res = await request(app.getHttpServer())
        .post('/solana/list-nft')
        .send({ mint: 'NFT...mint', price: 1_000_000, webhookUrl: '...' });
    
      expect(res.status).toBe(201);
      await waitForJobCompletion();
      expect(mockMarketplaceProgram.methods.listNft).toHaveBeenCalled();
      expect(mockWebhook).toHaveBeenCalledWith(
        expect.any(String),
        expect.objectContaining({ status: 'SUCCESS', txHash: 'list-tx-signature' })
      );
    });
    
  • [ ] Test case 2 — Buy NFT (on-chain purchase):
    it('POST /solana/buy-nft → purchase on-chain → NFT transferred to buyer → webhook', async () => {
      mockMarketplaceProgram.methods.buyNft.mockReturnValue({
        accounts: jest.fn().mockReturnThis(),
        rpc: jest.fn().mockResolvedValue('buy-tx-signature'),
      });
      // ...verify flow
      expect(mockWebhook).toHaveBeenCalledWith(
        expect.any(String),
        expect.objectContaining({ status: 'SUCCESS', txHash: 'buy-tx-signature' })
      );
    });
    
  • [ ] Test case 3 — Create Rental (Rental PDA):
    it('POST /solana/create-rental → Rental PDA created via Anchor → webhook', async () => {
      const mockRentalPda = PublicKey.default; // deterministic test PDA
      mockRentalProgram.methods.createRental.mockReturnValue({
        accounts: jest.fn().mockReturnThis(),
        rpc: jest.fn().mockResolvedValue('rental-create-sig'),
      });
      // ...verify PDA in response
    });
    
  • [ ] Test case 4 — Rent NFT (rental started):
    it('POST /solana/rent-nft → rental started on-chain → webhook', async () => {
      // ...mock rentNft Anchor method
      // verify webhook called with rental details
    });
    
  • [ ] Test case 5 — Retry on BlockhashNotFound trong Anchor call:
  • Mock rpc() throws BlockhashNotFound first time → retry → success

Verification / Acceptance Criteria

  • [ ] List NFT: program.methods.listNft được gọi với đúng mintprice
  • [ ] Buy NFT: program.methods.buyNft được gọi; webhook success với txHash
  • [ ] Create Rental: program.methods.createRental được gọi; Rental PDA address trong response
  • [ ] Rent NFT: program.methods.rentNft được gọi với đúng duration
  • [ ] Retry: BlockhashNotFound trong Anchor RPC call → sendWithRetry handles retry
  • [ ] Test pass khi chạy npm run test

Files to Modify

  • src/solana/tests/solana-marketplace.integration.spec.ts (tạo mới)
  • src/solana/tests/solana-rental.integration.spec.ts (tạo mới)