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
const claimPriceImpactSchema = z.object({
account: z.string().nonempty(),
claimablePositionPriceImpactFees: z.array(z.object({
marketAddress: z.string().nonempty(),
tokenAddress: z.string().nonempty(),
timeKey: z.number().positive()
}))
account: z.string().nonempty()
});
// 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
* @param sdk The GMX SDK client
* @param claimablePositionPriceImpactFees Array of claimable position price impact fees
* @returns Transaction hash
*/
export const claimGmxPriceImpactImpl = async (
sdk: GmxSdk,
claimablePositionPriceImpactFees: ClaimablePositionPriceImpactFee[]
sdk: GmxSdk
): Promise<string> => {
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");
}
@@ -1356,7 +1335,7 @@ export const claimGmxPriceImpactImpl = async (
const tokens: string[] = [];
const timeKeys: number[] = [];
claimablePositionPriceImpactFees.forEach((fee) => {
rebatesInfo.claimablePositionPriceImpactFees.forEach((fee) => {
markets.push(fee.marketAddress);
tokens.push(fee.tokenAddress);
timeKeys.push(fee.timeKey);
@@ -1387,24 +1366,22 @@ export const claimGmxPriceImpactImpl = async (
* @param this The FastifyRequest instance
* @param reply The FastifyReply instance
* @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
*/
export async function claimGmxPriceImpact(
this: FastifyRequest,
reply: FastifyReply,
account: string,
claimablePositionPriceImpactFees: ClaimablePositionPriceImpactFee[]
account: string
) {
try {
// Validate the request parameters
claimPriceImpactSchema.parse({ account, claimablePositionPriceImpactFees });
claimPriceImpactSchema.parse({ account });
// Get client for the address
const sdk = await this.getClientForAddress(account);
// Call the implementation function
const hash = await claimGmxPriceImpactImpl(sdk, claimablePositionPriceImpactFees);
const hash = await claimGmxPriceImpactImpl(sdk);
return {
success: true,

View File

@@ -5,153 +5,115 @@ import {claimGmxPriceImpactImpl, getClientForAddress} from '../../src/plugins/cu
test('GMX Claim Price Impact', async (t) => {
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 {
const sdk = await getClientForAddress(testAccount);
// 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);
const result = await claimGmxPriceImpactImpl(sdk);
console.log('Claim price impact result:', result);
// Should return a success indicator
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');
} catch (error) {
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');
// Check for expected error messages
const errorMessage = error.message;
const expectedErrors = [
'Failed to claim price impact rebates',
'No price impact fees available to claim'
];
const hasExpectedError = expectedErrors.some(expectedError =>
errorMessage.includes(expectedError)
// Should be a meaningful error message
assert.ok(
error.message.includes('No price impact fees available to claim') ||
error.message.includes('Failed to claim price impact rebates') ||
error.message.includes('Error claiming price impact rebates'),
'Error message should be meaningful'
);
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 () => {
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 () => {
await t.test('should handle SDK client creation for claim', async () => {
try {
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(sdk.account === testAccount, 'SDK account should match test account');
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) {
console.warn('Expected error in test environment:', error.message);
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 {
const sdk = await getClientForAddress(testAccount);
// Test with multiple different fees
const multipleFees = [
{
marketAddress: '0x47c031236e19d024b42f8AE6780E44A573170703',
tokenAddress: '0x82aF49447D8a07e3bd95BD0d56f35241523fBab1',
timeKey: 1640995200
},
{
marketAddress: '0x70d95587d40A2caf56bd97485aB3Eec10Bee6336',
tokenAddress: '0xFF970A61A04b1cA14834A43f5dE4533eBDDB5CC8',
timeKey: 1640995300
},
{
marketAddress: '0x09400D9DB990D5ed3f35D7be61DfAEB900Af03C9',
tokenAddress: '0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f',
timeKey: 1640995400
}
];
// The method should now automatically fetch claimable fees using GraphQL
// This test verifies that the method integrates with getGmxPriceImpactRebatesImpl
const result = await claimGmxPriceImpactImpl(sdk);
const result = await claimGmxPriceImpactImpl(sdk, multipleFees);
console.log('Auto-fetch and claim result:', result);
console.log('Multiple fees claim result:', result);
assert.ok(typeof result === 'string', 'Should return transaction hash or success indicator');
// If successful, should return the success indicator
assert.equal(result, 'price_impact_claimed', 'Should return success indicator');
} catch (error) {
// Expected errors during the claiming process
const errorMessage = error.message;
const validClaimErrors = [
'Failed to claim price impact rebates',
'No price impact fees available to claim'
];
console.warn('Expected error in test environment:', error.message);
assert.ok(error instanceof Error, 'Should throw an Error instance');
const isValidError = validClaimErrors.some(validError =>
errorMessage.includes(validError)
);
if (isValidError) {
console.log('Multiple fees claim handled expected error:', errorMessage);
assert.ok(true, 'Expected error in claim process');
// Should handle the case where no claimable fees are found
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');
} else {
console.warn('Unexpected error in multiple fees claim:', errorMessage);
assert.ok(error instanceof Error, 'Should still be an Error instance');
assert.ok(
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'
);
}
});
});