Claim price impact

This commit is contained in:
2025-06-05 22:13:24 +07:00
parent 9680329e10
commit aac28adebe
2 changed files with 82 additions and 143 deletions

View File

@@ -167,12 +167,7 @@ const claimFundingFeesSchema = z.object({
// Schema for claim price impact request // Schema for claim price impact request
const claimPriceImpactSchema = z.object({ const claimPriceImpactSchema = z.object({
account: z.string().nonempty(), account: z.string().nonempty()
claimablePositionPriceImpactFees: z.array(z.object({
marketAddress: z.string().nonempty(),
tokenAddress: z.string().nonempty(),
timeKey: z.number().positive()
}))
}); });
// Schema for get price impact rebates request // Schema for get price impact rebates request
@@ -1316,35 +1311,19 @@ export async function claimGmxFundingFees(
} }
} }
/**
* Interface for claimable position price impact fee
*/
interface ClaimablePositionPriceImpactFee {
marketAddress: string;
tokenAddress: string;
timeKey: number;
}
/**
* Interface for price impact rebate parameters
*/
interface ClaimPriceImpactRebateParams {
account: string;
claimablePositionPriceImpactFees: ClaimablePositionPriceImpactFee[];
}
/** /**
* Implementation function to claim price impact rebates * Implementation function to claim price impact rebates
* @param sdk The GMX SDK client * @param sdk The GMX SDK client
* @param claimablePositionPriceImpactFees Array of claimable position price impact fees
* @returns Transaction hash * @returns Transaction hash
*/ */
export const claimGmxPriceImpactImpl = async ( export const claimGmxPriceImpactImpl = async (
sdk: GmxSdk, sdk: GmxSdk
claimablePositionPriceImpactFees: ClaimablePositionPriceImpactFee[]
): Promise<string> => { ): Promise<string> => {
try { try {
if (!claimablePositionPriceImpactFees || claimablePositionPriceImpactFees.length === 0) { // First, get the claimable position price impact fees using our GraphQL method
const rebatesInfo = await getGmxPriceImpactRebatesImpl(sdk);
if (!rebatesInfo.claimablePositionPriceImpactFees || rebatesInfo.claimablePositionPriceImpactFees.length === 0) {
throw new Error("No price impact fees available to claim"); throw new Error("No price impact fees available to claim");
} }
@@ -1356,7 +1335,7 @@ export const claimGmxPriceImpactImpl = async (
const tokens: string[] = []; const tokens: string[] = [];
const timeKeys: number[] = []; const timeKeys: number[] = [];
claimablePositionPriceImpactFees.forEach((fee) => { rebatesInfo.claimablePositionPriceImpactFees.forEach((fee) => {
markets.push(fee.marketAddress); markets.push(fee.marketAddress);
tokens.push(fee.tokenAddress); tokens.push(fee.tokenAddress);
timeKeys.push(fee.timeKey); timeKeys.push(fee.timeKey);
@@ -1387,24 +1366,22 @@ export const claimGmxPriceImpactImpl = async (
* @param this The FastifyRequest instance * @param this The FastifyRequest instance
* @param reply The FastifyReply instance * @param reply The FastifyReply instance
* @param account The wallet address of the user * @param account The wallet address of the user
* @param claimablePositionPriceImpactFees Array of claimable position price impact fees
* @returns The response object with success status and transaction hash * @returns The response object with success status and transaction hash
*/ */
export async function claimGmxPriceImpact( export async function claimGmxPriceImpact(
this: FastifyRequest, this: FastifyRequest,
reply: FastifyReply, reply: FastifyReply,
account: string, account: string
claimablePositionPriceImpactFees: ClaimablePositionPriceImpactFee[]
) { ) {
try { try {
// Validate the request parameters // Validate the request parameters
claimPriceImpactSchema.parse({ account, claimablePositionPriceImpactFees }); claimPriceImpactSchema.parse({ account });
// Get client for the address // Get client for the address
const sdk = await this.getClientForAddress(account); const sdk = await this.getClientForAddress(account);
// Call the implementation function // Call the implementation function
const hash = await claimGmxPriceImpactImpl(sdk, claimablePositionPriceImpactFees); const hash = await claimGmxPriceImpactImpl(sdk);
return { return {
success: true, success: true,

View File

@@ -5,153 +5,115 @@ import {claimGmxPriceImpactImpl, getClientForAddress} from '../../src/plugins/cu
test('GMX Claim Price Impact', async (t) => { test('GMX Claim Price Impact', async (t) => {
const testAccount = '0xbBA4eaA534cbD0EcAed5E2fD6036Aec2E7eE309f'; const testAccount = '0xbBA4eaA534cbD0EcAed5E2fD6036Aec2E7eE309f';
await t.test('should claim price impact for valid account with fees', async () => { await t.test('should claim price impact rebates for valid account with claimable fees', async () => {
try { try {
const sdk = await getClientForAddress(testAccount); const sdk = await getClientForAddress(testAccount);
const result = await claimGmxPriceImpactImpl(sdk);
// Mock claimable position price impact fees
const mockClaimableFees = [
{
marketAddress: '0x47c031236e19d024b42f8AE6780E44A573170703',
tokenAddress: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
timeKey: 1640995200
},
{
marketAddress: '0x70d95587d40A2caf56bd97485aB3Eec10Bee6336',
tokenAddress: '0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8',
timeKey: 1640995300
}
];
const result = await claimGmxPriceImpactImpl(sdk, mockClaimableFees);
console.log('Claim price impact result:', result); console.log('Claim price impact result:', result);
// Should return a success indicator
assert.ok(typeof result === 'string', 'Result should be a string'); assert.ok(typeof result === 'string', 'Result should be a string');
assert.ok(result.length > 0, 'Result should not be empty');
assert.equal(result, 'price_impact_claimed', 'Should return success indicator'); assert.equal(result, 'price_impact_claimed', 'Should return success indicator');
} catch (error) { } catch (error) {
console.warn('Expected error in test environment:', error.message); console.warn('Expected error in test environment:', error.message);
// Expected behavior - may fail in test environment
assert.ok(error instanceof Error, 'Should throw an Error instance'); assert.ok(error instanceof Error, 'Should throw an Error instance');
// Check for expected error messages // Should be a meaningful error message
const errorMessage = error.message; assert.ok(
const expectedErrors = [ error.message.includes('No price impact fees available to claim') ||
'Failed to claim price impact rebates', error.message.includes('Failed to claim price impact rebates') ||
'No price impact fees available to claim' error.message.includes('Error claiming price impact rebates'),
]; 'Error message should be meaningful'
const hasExpectedError = expectedErrors.some(expectedError =>
errorMessage.includes(expectedError)
); );
if (!hasExpectedError) {
// Log unexpected errors for debugging
console.warn('Unexpected error in claimGmxPriceImpactImpl:', errorMessage);
}
// Still assert it's an error for test completeness
assert.ok(true, 'Expected error occurred');
} }
}); });
await t.test('should handle empty claimable fees array', async () => { await t.test('should handle SDK client creation for claim', async () => {
try {
const sdk = await getClientForAddress(testAccount);
const emptyFees = [];
await claimGmxPriceImpactImpl(sdk, emptyFees);
// Should not reach here
assert.fail('Should have thrown an error for empty fees array');
} catch (error) {
// Expected behavior for empty array
assert.ok(error instanceof Error, 'Should throw an Error instance');
assert.ok(error.message.includes('No price impact fees available to claim'), 'Should have specific error message');
console.log('Correctly handled empty fees array');
}
});
await t.test('should handle null claimable fees', async () => {
try {
const sdk = await getClientForAddress(testAccount);
const nullFees = null as any;
await claimGmxPriceImpactImpl(sdk, nullFees);
// Should not reach here
assert.fail('Should have thrown an error for null fees');
} catch (error) {
// Expected behavior for null input
assert.ok(error instanceof Error, 'Should throw an Error instance');
assert.ok(error.message.includes('No price impact fees available to claim'), 'Should have specific error message');
console.log('Correctly handled null fees');
}
});
await t.test('should handle SDK client creation for price impact claiming', async () => {
try { try {
const sdk = await getClientForAddress(testAccount); const sdk = await getClientForAddress(testAccount);
// Validate SDK properties before attempting to claim // Validate SDK properties
assert.ok(typeof sdk === 'object', 'SDK should be an object'); assert.ok(typeof sdk === 'object', 'SDK should be an object');
assert.ok(sdk.account === testAccount, 'SDK account should match test account'); assert.ok(sdk.account === testAccount, 'SDK account should match test account');
assert.ok(typeof sdk.chainId === 'number', 'Chain ID should be a number'); assert.ok(typeof sdk.chainId === 'number', 'Chain ID should be a number');
console.log('SDK validation passed for price impact claiming'); console.log('SDK validation passed for claim');
} catch (error) { } catch (error) {
console.warn('Expected error in test environment:', error.message); console.warn('Expected error in test environment:', error.message);
assert.ok(error instanceof Error, 'Should throw an Error instance'); assert.ok(error instanceof Error, 'Should throw an Error instance');
} }
}); });
await t.test('should validate claim process with multiple fees', async () => { await t.test('should automatically fetch claimable fees before claiming', async () => {
try { try {
const sdk = await getClientForAddress(testAccount); const sdk = await getClientForAddress(testAccount);
// Test with multiple different fees // The method should now automatically fetch claimable fees using GraphQL
const multipleFees = [ // This test verifies that the method integrates with getGmxPriceImpactRebatesImpl
{ const result = await claimGmxPriceImpactImpl(sdk);
marketAddress: '0x47c031236e19d024b42f8AE6780E44A573170703',
tokenAddress: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
timeKey: 1640995200
},
{
marketAddress: '0x70d95587d40A2caf56bd97485aB3Eec10Bee6336',
tokenAddress: '0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8',
timeKey: 1640995300
},
{
marketAddress: '0x09400D9DB990D5ed3f35D7be61DfAEB900Af03C9',
tokenAddress: '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f',
timeKey: 1640995400
}
];
const result = await claimGmxPriceImpactImpl(sdk, multipleFees); console.log('Auto-fetch and claim result:', result);
console.log('Multiple fees claim result:', result); // If successful, should return the success indicator
assert.ok(typeof result === 'string', 'Should return transaction hash or success indicator'); assert.equal(result, 'price_impact_claimed', 'Should return success indicator');
} catch (error) { } catch (error) {
// Expected errors during the claiming process console.warn('Expected error in test environment:', error.message);
const errorMessage = error.message; assert.ok(error instanceof Error, 'Should throw an Error instance');
const validClaimErrors = [
'Failed to claim price impact rebates',
'No price impact fees available to claim'
];
const isValidError = validClaimErrors.some(validError => // Should handle the case where no claimable fees are found
errorMessage.includes(validError) if (error.message.includes('No price impact fees available to claim')) {
); console.log('No claimable fees found - this is expected for test account');
assert.ok(true, 'Correctly handled no claimable fees case');
if (isValidError) {
console.log('Multiple fees claim handled expected error:', errorMessage);
assert.ok(true, 'Expected error in claim process');
} else { } else {
console.warn('Unexpected error in multiple fees claim:', errorMessage); assert.ok(
assert.ok(error instanceof Error, 'Should still be an Error instance'); error.message.includes('Failed to claim price impact rebates') ||
error.message.includes('Error claiming price impact rebates'),
'Should be a meaningful claim error'
);
} }
} }
}); });
await t.test('should handle chain ID validation for claim', async () => {
try {
const sdk = await getClientForAddress(testAccount);
// Should only work for Arbitrum (chainId 42161)
assert.equal(sdk.chainId, 42161, 'Should be using Arbitrum chain ID');
console.log('Chain ID validation passed for claim');
} catch (error) {
console.warn('Expected error in test environment:', error.message);
assert.ok(error instanceof Error, 'Should throw an Error instance');
}
});
await t.test('should validate contract addresses for claim', async () => {
try {
const sdk = await getClientForAddress(testAccount);
// The method should validate that proper contract addresses are available
// This tests the ExchangeRouter contract address retrieval
await claimGmxPriceImpactImpl(sdk);
console.log('Contract validation passed');
} catch (error) {
console.warn('Expected error in test environment:', error.message);
assert.ok(error instanceof Error, 'Should throw an Error instance');
// Validate error messages are meaningful
assert.ok(
error.message.includes('No price impact fees available to claim') ||
error.message.includes('Failed to claim price impact rebates') ||
error.message.includes('Unsupported chain ID') ||
error.message.includes('Error claiming price impact rebates'),
'Should provide meaningful error messages'
);
}
});
}); });