// tests/transfer-action.test.ts import { describe, it, expect, beforeEach, vi } from 'vitest'; import { createServerGeneratedSecret, DistributeAction } from './distribute'; import { PrexClient } from '../prex-client'; import { PrexSigner } from '../core/sign'; import { PrexApiService } from '../api'; import { PrexUser } from '../types'; import { PrexStorage } from '../storage/PrexStorage'; import { Address, zeroAddress, zeroHash } from 'viem'; // graphのモジュールをモック化 vi.mock('../graph/distributions', () => ({ queryTokenDistributeRequests: vi.fn(), })); import { queryTokenDistributeRequests } from '../graph/distributions'; import { TokenDistributeRequestEntity } from '../types'; import { hexToBase64 } from '../utils/base64'; import { serializeDistributionSecret } from '../utils/distribution-secrets'; const TOKEN_ADDRESS = '0x0000000000000000000000000000000000000001' as Address; const USER_ADDRESS = '0x0000000000000000000000000000000000000002' as Address; const COORDINATE = zeroHash; describe('DistributeAction', () => { let distributeAction: DistributeAction; let mockClient: PrexClient; let mockSigner: PrexSigner; let mockApiService: PrexApiService; let mockUser: PrexUser; let mockStorage: PrexStorage; beforeEach(() => { mockClient = { updatePermit2Nonce: vi.fn(() => 1n), getPermit2Nonce: vi.fn(() => 1n), fetchBalance: vi.fn(), evmChainClient: { estimateGas: vi.fn(() => 1000000n), readContract: vi.fn(() => [0n, 0n, 0n, 0n, TOKEN_ADDRESS, 0n, 0n, 0n]), }, logger: { debug: vi.fn(), }, } as unknown as PrexClient; mockSigner = { chainId: 1337, signTypedData: vi.fn(), } as unknown as PrexSigner; mockApiService = { chainId: 1337, distributeSubmit: vi.fn(), distributeDeposit: vi.fn(), distributeWithdraw: vi.fn(), confirmLinkTransfer: vi.fn(), } as unknown as PrexApiService; mockUser = { id: 'user-id', name: 'Test User', address: USER_ADDRESS, walletId: 'wallet-id', } as unknown as PrexUser; mockStorage = { getItem: vi.fn(), setItem: vi.fn(), getItemFromSessionStorage: vi.fn(), setItemToSessionStorage: vi.fn(), removeItemFromSessionStorage: vi.fn(), } as unknown as PrexStorage; distributeAction = new DistributeAction( mockClient, mockApiService, mockStorage, mockUser, mockSigner ); }); it('succeed to submit', async () => { vi.mocked(mockSigner.signTypedData).mockResolvedValue('0x00'); vi.mocked(mockApiService.distributeSubmit).mockResolvedValue({ hash: '0x00', }); await distributeAction.submit({ token: TOKEN_ADDRESS, amount: 1n, amountPerWithdrawal: 1n, maxAmountPerAddress: 1n, expiry: 1n, coolTime: 1n, name: 'test', coordinate: COORDINATE, }); expect(mockSigner.signTypedData).toHaveBeenCalled(); expect(mockApiService.distributeSubmit).toHaveBeenCalled(); }); it('succeed to deposit', async () => { vi.mocked(mockSigner.signTypedData).mockResolvedValue('0x00'); vi.mocked(mockApiService.distributeDeposit).mockResolvedValue({ hash: '0x00', }); await distributeAction.deposit({ amount: 1n, requestId: COORDINATE, }); expect(mockSigner.signTypedData).toHaveBeenCalled(); expect(mockApiService.distributeDeposit).toHaveBeenCalled(); }); it('succeed to get request', async () => { const REQUEST_ID = zeroHash; const SECRET = '0x0000000000000000000000000000000000000000000000000000000000800003'; const request = await distributeAction.getRequest(REQUEST_ID, { secret: SECRET, }); expect(request).toMatchObject({ amount: 0n, }); }); it('succeed to prepare withdraw', async () => { const REQUEST_ID = zeroHash; const SECRET = '0x0000000000000000000000000000000000000000000000000000000000800003'; vi.mocked(mockStorage.getItemFromSessionStorage).mockResolvedValue(SECRET); const result = await distributeAction.prepareReceive({ requestId: REQUEST_ID, secret: hexToBase64(SECRET), }); expect(result).toMatchObject({ id: REQUEST_ID, }); }); it('succeed to prepare withdraw with server generated secret', async () => { const REQUEST_ID = zeroHash; const SECRET = '0x0000000000000000000000000000000000000000000000000000000000800003'; const secret = await createServerGeneratedSecret( serializeDistributionSecret({ type: 'secret', secret: SECRET, }), { distributionId: REQUEST_ID, recipient: USER_ADDRESS, coordinate: zeroHash, deadline: '1', shortCode: 'myshortcode', } ); const result = await distributeAction.prepareReceive({ requestId: REQUEST_ID, secret: secret, }); expect(result).toMatchObject({ id: REQUEST_ID, }); }); it('succeed to distribute', async () => { const REQUEST_ID = zeroHash; vi.mocked(mockStorage.getItemFromSessionStorage).mockResolvedValue({ sig: '0x00', nonce: '1', deadline: '1', recipient: USER_ADDRESS, subPublicKey: zeroAddress, subSig: '0x', }); vi.mocked(mockApiService.distributeWithdraw).mockResolvedValue({ hash: '0x00', }); await distributeAction.receive({ requestId: REQUEST_ID, }); expect(mockApiService.distributeWithdraw).toHaveBeenCalledWith({ requestId: REQUEST_ID, recipient: USER_ADDRESS, sig: expect.any(String), nonce: expect.any(String), deadline: expect.any(String), subPublicKey: zeroAddress, subSig: '0x', }); }); describe('queryRequests', () => { it('succeed to query requests', async () => { const mockRequests = [ { id: '0x01', amount: 100n, token: TOKEN_ADDRESS, createdAt: 1, status: 'PENDING', name: 'test', maxAmountPerAddress: 1n, expiry: 1, sender: USER_ADDRESS, coordinate: COORDINATE, amountPerWithdrawal: 1n, txHash: zeroHash, cooltime: 1, }, ] as TokenDistributeRequestEntity[]; vi.mocked(queryTokenDistributeRequests).mockResolvedValue(mockRequests); const requests = await distributeAction.queryRequests(undefined, { offset: 0, limit: 10, }); expect(requests).toEqual(mockRequests); expect(queryTokenDistributeRequests).toHaveBeenCalledWith( mockApiService, { user: USER_ADDRESS }, 0, 10 ); }); }); });