@magiceden/magiceden-sdk
Version:
A TypeScript SDK for interacting with Magic Eden's API across multiple chains.
339 lines (338 loc) • 16.2 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const solana_1 = require("../../../services/nft/solana");
const solana_2 = require("../../../mappers/nft/solana");
const solana_3 = require("../../../adapters/transactions/solana");
const v2_1 = require("../../../api/clients/v2");
const types_1 = require("../../../types");
// Mock dependencies
jest.mock('../../../mappers/nft/solana');
jest.mock('../../../adapters/transactions/solana');
jest.mock('../../../api/clients/v2');
describe('SolanaNftService V2', () => {
let service;
let mockWallet;
let mockV2ApiClient;
let mockTransaction;
let mockApiResponse;
beforeEach(() => {
// Reset mocks
jest.clearAllMocks();
// Create mock transaction
mockTransaction = {
/* mock transaction object */
serialize: jest.fn().mockReturnValue(new Uint8Array([1, 2, 3])),
};
// Create mock API response
mockApiResponse = {
v0: {
txSigned: {
type: 'Buffer',
data: [1, 2, 3],
},
},
};
// Create mock wallet
mockWallet = {
getAddress: jest.fn().mockReturnValue('mock-address'),
signAndSendTransaction: jest.fn().mockResolvedValue('mock-signature'),
waitForTransactionConfirmation: jest.fn().mockResolvedValue({
txId: 'mock-signature',
status: 'confirmed',
}),
};
// Create service instance
service = new solana_1.SolanaNftService({
chain: types_1.ChainType.SOLANA,
apiKey: 'test-api-key',
wallet: mockWallet,
});
// Get mock API client instance
mockV2ApiClient = v2_1.V2ApiClient.mock
.instances[0];
// Setup default mock implementations
solana_3.SolanaTransactionAdapters.fromInstructionsResponse.mockReturnValue([
mockTransaction,
]);
});
describe('list', () => {
it('should map parameters, call API, and sign transaction', async () => {
// Setup mocks
const mockParams = {
token: 'mockTokenMint',
price: '1000000000',
seller: 'mockSeller',
auctionHouseAddress: 'mockAuctionHouse',
tokenAccount: 'mockTokenAccount',
expiry: 1234567890,
};
const mockApiRequest = { tokenMint: 'mockTokenMint' /* other fields */ };
// Setup mock implementations
solana_2.SolanaApiMappers.v2.listRequest.mockReturnValue(mockApiRequest);
mockV2ApiClient.list.mockResolvedValue(mockApiResponse);
// Call the method
const result = await service.list(mockParams);
// Verify the flow
expect(solana_2.SolanaApiMappers.v2.listRequest).toHaveBeenCalledWith(mockParams);
expect(mockV2ApiClient.list).toHaveBeenCalledWith(mockApiRequest);
expect(solana_3.SolanaTransactionAdapters.fromInstructionsResponse).toHaveBeenCalledWith(mockApiResponse);
expect(mockWallet.signAndSendTransaction).toHaveBeenCalledWith(mockTransaction);
expect(result).toEqual([{ txId: 'mock-signature', status: 'confirmed' }]);
});
it('should handle API errors', async () => {
// Setup mocks
const mockParams = {
token: 'mockTokenMint',
price: '1000000000',
seller: 'mockSeller',
auctionHouseAddress: 'mockAuctionHouse',
tokenAccount: 'mockTokenAccount',
expiry: 1234567890,
};
// Setup mock to throw error
mockV2ApiClient.list.mockRejectedValue(new Error('API error'));
// Call the method and expect it to throw
await expect(service.list(mockParams)).rejects.toThrow('API error');
});
it('should handle wallet errors', async () => {
// Setup mocks
const mockParams = {
token: 'mockTokenMint',
price: '1000000000',
seller: 'mockSeller',
auctionHouseAddress: 'mockAuctionHouse',
tokenAccount: 'mockTokenAccount',
expiry: 1234567890,
};
// Setup wallet to throw error
mockWallet.signAndSendTransaction.mockRejectedValue(new Error('Wallet error'));
// Call the method and expect it to throw
await expect(service.list(mockParams)).rejects.toThrow('Wallet error');
});
});
describe('cancelListing', () => {
it('should map parameters, call API, and sign transaction', async () => {
// Setup mocks
const mockParams = {
token: 'mockTokenMint',
price: '1000000000',
seller: 'mockSeller',
auctionHouseAddress: 'mockAuctionHouse',
tokenAccount: 'mockTokenAccount',
expiry: 1234567890,
};
const mockApiRequest = { tokenMint: 'mockTokenMint' /* other fields */ };
// Setup mock implementations
solana_2.SolanaApiMappers.v2.cancelListingRequest.mockReturnValue(mockApiRequest);
mockV2ApiClient.cancelListing.mockResolvedValue(mockApiResponse);
// Call the method
const result = await service.cancelListing(mockParams);
// Verify the flow
expect(solana_2.SolanaApiMappers.v2.cancelListingRequest).toHaveBeenCalledWith(mockParams);
expect(mockV2ApiClient.cancelListing).toHaveBeenCalledWith(mockApiRequest);
expect(solana_3.SolanaTransactionAdapters.fromInstructionsResponse).toHaveBeenCalledWith(mockApiResponse);
expect(mockWallet.signAndSendTransaction).toHaveBeenCalledWith(mockTransaction);
expect(result).toEqual([{ txId: 'mock-signature', status: 'confirmed' }]);
});
});
describe('makeItemOffer', () => {
it('should map parameters, call API, and sign transaction', async () => {
// Setup mocks
const mockParams = {
token: 'mockTokenMint',
price: '1000000000',
buyer: 'mockBuyer',
auctionHouseAddress: 'mockAuctionHouse',
expiry: 1234567890,
};
const mockApiRequest = { tokenMint: 'mockTokenMint' /* other fields */ };
// Setup mock implementations
solana_2.SolanaApiMappers.v2.makeItemOfferRequest.mockReturnValue(mockApiRequest);
mockV2ApiClient.makeItemOffer.mockResolvedValue(mockApiResponse);
// Call the method
const result = await service.makeItemOffer(mockParams);
// Verify the flow
expect(solana_2.SolanaApiMappers.v2.makeItemOfferRequest).toHaveBeenCalledWith(mockParams);
expect(mockV2ApiClient.makeItemOffer).toHaveBeenCalledWith(mockApiRequest);
expect(solana_3.SolanaTransactionAdapters.fromInstructionsResponse).toHaveBeenCalledWith(mockApiResponse);
expect(mockWallet.signAndSendTransaction).toHaveBeenCalledWith(mockTransaction);
expect(result).toEqual([{ txId: 'mock-signature', status: 'confirmed' }]);
});
});
describe('cancelItemOffer', () => {
it('should map parameters, call API, and sign transaction', async () => {
// Setup mocks
const mockParams = {
token: 'mockTokenMint',
price: '1000000000',
buyer: 'mockBuyer',
auctionHouseAddress: 'mockAuctionHouse',
expiry: 1234567890,
};
const mockApiRequest = { tokenMint: 'mockTokenMint' /* other fields */ };
// Setup mock implementations
solana_2.SolanaApiMappers.v2.cancelItemOfferRequest.mockReturnValue(mockApiRequest);
mockV2ApiClient.cancelItemOffer.mockResolvedValue(mockApiResponse);
// Call the method
const result = await service.cancelItemOffer(mockParams);
// Verify the flow
expect(solana_2.SolanaApiMappers.v2.cancelItemOfferRequest).toHaveBeenCalledWith(mockParams);
expect(mockV2ApiClient.cancelItemOffer).toHaveBeenCalledWith(mockApiRequest);
expect(solana_3.SolanaTransactionAdapters.fromInstructionsResponse).toHaveBeenCalledWith(mockApiResponse);
expect(mockWallet.signAndSendTransaction).toHaveBeenCalledWith(mockTransaction);
expect(result).toEqual([{ txId: 'mock-signature', status: 'confirmed' }]);
});
});
describe('takeItemOffer', () => {
it('should map parameters, call API, and sign transaction', async () => {
// Setup mocks
const mockParams = {
token: 'mockTokenMint',
buyer: 'mockBuyer',
seller: 'mockSeller',
auctionHouseAddress: 'mockAuctionHouse',
tokenATA: 'mockTokenATA',
price: '1000000000',
newPrice: '1100000000',
buyerExpiry: 1234567890,
sellerExpiry: 1234567891,
};
const mockApiRequest = { tokenMint: 'mockTokenMint' /* other fields */ };
// Setup mock implementations
solana_2.SolanaApiMappers.v2.takeItemOfferRequest.mockReturnValue(mockApiRequest);
mockV2ApiClient.takeItemOffer.mockResolvedValue(mockApiResponse);
// Call the method
const result = await service.takeItemOffer(mockParams);
// Verify the flow
expect(solana_2.SolanaApiMappers.v2.takeItemOfferRequest).toHaveBeenCalledWith(mockParams);
expect(mockV2ApiClient.takeItemOffer).toHaveBeenCalledWith(mockApiRequest);
expect(solana_3.SolanaTransactionAdapters.fromInstructionsResponse).toHaveBeenCalledWith(mockApiResponse);
expect(mockWallet.signAndSendTransaction).toHaveBeenCalledWith(mockTransaction);
expect(result).toEqual([{ txId: 'mock-signature', status: 'confirmed' }]);
});
});
describe('buy', () => {
it('should map parameters, call API, and sign transaction', async () => {
// Setup mocks
const mockParams = {
token: 'mockTokenMint',
buyer: 'mockBuyer',
seller: 'mockSeller',
auctionHouseAddress: 'mockAuctionHouse',
tokenATA: 'mockTokenATA',
price: '1000000000',
sellerExpiry: 1234567891,
};
const mockApiRequest = { tokenMint: 'mockTokenMint' /* other fields */ };
// Setup mock implementations
solana_2.SolanaApiMappers.v2.buyRequest.mockReturnValue(mockApiRequest);
mockV2ApiClient.buy.mockResolvedValue(mockApiResponse);
// Call the method
const result = await service.buy(mockParams);
// Verify the flow
expect(solana_2.SolanaApiMappers.v2.buyRequest).toHaveBeenCalledWith(mockParams);
expect(mockV2ApiClient.buy).toHaveBeenCalledWith(mockApiRequest);
expect(solana_3.SolanaTransactionAdapters.fromInstructionsResponse).toHaveBeenCalledWith(mockApiResponse);
expect(mockWallet.signAndSendTransaction).toHaveBeenCalledWith(mockTransaction);
expect(result).toEqual([{ txId: 'mock-signature', status: 'confirmed' }]);
});
});
describe('transfer', () => {
it('should map parameters, call API, and sign transaction', async () => {
// Setup mocks
const mockParams = {
token: 'mockTokenMint',
from: 'mockFrom',
to: 'mockTo',
};
const mockApiRequest = { mint: 'mockTokenMint' /* other fields */ };
// Setup mock implementations
solana_2.SolanaApiMappers.v2.transferRequest.mockReturnValue(mockApiRequest);
mockV2ApiClient.transfer.mockResolvedValue(mockApiResponse);
// Call the method
const result = await service.transfer(mockParams);
// Verify the flow
expect(solana_2.SolanaApiMappers.v2.transferRequest).toHaveBeenCalledWith(mockParams);
expect(mockV2ApiClient.transfer).toHaveBeenCalledWith(mockApiRequest);
expect(solana_3.SolanaTransactionAdapters.fromInstructionsResponse).toHaveBeenCalledWith(mockApiResponse);
expect(mockWallet.signAndSendTransaction).toHaveBeenCalledWith(mockTransaction);
expect(result).toEqual([{ txId: 'mock-signature', status: 'confirmed' }]);
});
});
describe('error handling', () => {
it('should handle adapter errors', async () => {
// Setup mocks
const mockParams = {
token: 'mockTokenMint',
price: '1000000000',
seller: 'mockSeller',
auctionHouseAddress: 'mockAuctionHouse',
tokenAccount: 'mockTokenAccount',
expiry: 1234567890,
};
// Setup adapter to throw error
solana_3.SolanaTransactionAdapters.fromInstructionsResponse.mockImplementation(() => {
throw new Error('Adapter error');
});
// Call the method and expect it to throw
await expect(service.list(mockParams)).rejects.toThrow('Adapter error');
});
it('should handle mapper errors', async () => {
// Setup mocks
const mockParams = {
token: 'mockTokenMint',
price: '1000000000',
seller: 'mockSeller',
auctionHouseAddress: 'mockAuctionHouse',
tokenAccount: 'mockTokenAccount',
expiry: 1234567890,
};
// Setup mapper to throw error
solana_2.SolanaApiMappers.v2.listRequest.mockImplementation(() => {
throw new Error('Invalid transaction response format');
});
// Call the method and expect it to throw
await expect(service.list(mockParams)).rejects.toThrow('Invalid transaction response format');
});
});
describe('edge cases', () => {
it('should handle empty transaction response', async () => {
// Setup mocks
const mockParams = {
token: 'mockTokenMint',
price: '1000000000',
seller: 'mockSeller',
auctionHouseAddress: 'mockAuctionHouse',
tokenAccount: 'mockTokenAccount',
expiry: 1234567890,
};
// Setup API to return empty response
mockV2ApiClient.list.mockResolvedValue({});
// Setup adapter to throw for empty response
solana_3.SolanaTransactionAdapters.fromInstructionsResponse.mockImplementation(() => {
throw new Error('Invalid transaction response format');
});
// Call the method and expect it to throw
await expect(service.list(mockParams)).rejects.toThrow('Invalid transaction response format');
});
it('should handle null wallet', async () => {
// Create service with null wallet
service = new solana_1.SolanaNftService({
chain: types_1.ChainType.SOLANA,
apiKey: 'test-api-key',
wallet: null,
});
// Setup mocks
const mockParams = {
token: 'mockTokenMint',
price: '1000000000',
seller: 'mockSeller',
auctionHouseAddress: 'mockAuctionHouse',
tokenAccount: 'mockTokenAccount',
expiry: 1234567890,
};
// Call the method and expect it to throw
await expect(service.list(mockParams)).rejects.toThrow();
});
});
});