Skip to content

Commit 924f7f4

Browse files
committed
test(payment-processor, smart-contracts): enhance payment encoding tests and event assertions
- Added comprehensive tests for encoding functions in `erc20-commerce-escrow-wrapper` to verify function selectors and parameter inclusion. - Improved event assertions in `ERC20CommerceEscrowWrapper` tests to check emitted events with exact values for payment authorization, capture, voiding, charging, and reclaiming payments. - Validated function signatures and parameter types across various payment functions to ensure expected behavior.
1 parent be390cc commit 924f7f4

File tree

2 files changed

+321
-17
lines changed

2 files changed

+321
-17
lines changed

packages/payment-processor/test/payment/erc20-commerce-escrow-wrapper.test.ts

Lines changed: 247 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,26 @@ describe('erc20-commerce-escrow-wrapper', () => {
307307

308308
expect(typeof encodedData).toBe('string');
309309
expect(encodedData).toMatch(/^0x[a-fA-F0-9]+$/); // Should be valid hex string
310+
311+
// Verify it starts with the correct function selector for authorizePayment
312+
// Function signature: authorizePayment(bytes8,address,address,address,address,uint256,uint256,uint256,uint256,uint256,address,bytes)
313+
expect(encodedData.substring(0, 10)).toBe('0x5532a547'); // Actual function selector
314+
315+
// Verify the encoded data contains our test parameters
316+
expect(encodedData.length).toBeGreaterThan(10); // More than just function selector
317+
expect(encodedData).toContain(mockAuthorizeParams.paymentReference.substring(2)); // Remove 0x prefix
318+
expect(encodedData.toLowerCase()).toContain(
319+
mockAuthorizeParams.payer.substring(2).toLowerCase(),
320+
);
321+
expect(encodedData.toLowerCase()).toContain(
322+
mockAuthorizeParams.merchant.substring(2).toLowerCase(),
323+
);
324+
expect(encodedData.toLowerCase()).toContain(
325+
mockAuthorizeParams.operator.substring(2).toLowerCase(),
326+
);
327+
expect(encodedData.toLowerCase()).toContain(
328+
mockAuthorizeParams.token.substring(2).toLowerCase(),
329+
);
310330
});
311331

312332
it('should encode capturePayment function data', () => {
@@ -318,17 +338,44 @@ describe('erc20-commerce-escrow-wrapper', () => {
318338

319339
expect(typeof encodedData).toBe('string');
320340
expect(encodedData).toMatch(/^0x[a-fA-F0-9]+$/); // Should be valid hex string
341+
342+
// Verify it starts with the correct function selector for capturePayment
343+
expect(encodedData.substring(0, 10)).toBe('0xa2615767');
344+
345+
// Verify the encoded data contains our test parameters
346+
expect(encodedData).toContain(mockCaptureParams.paymentReference.substring(2));
347+
expect(encodedData.toLowerCase()).toContain(
348+
mockCaptureParams.feeReceiver.substring(2).toLowerCase(),
349+
);
350+
351+
// Verify encoded amounts (as hex)
352+
const captureAmountHex = parseInt(mockCaptureParams.captureAmount.toString())
353+
.toString(16)
354+
.padStart(64, '0');
355+
const feeBpsHex = mockCaptureParams.feeBps.toString(16).padStart(64, '0');
356+
expect(encodedData.toLowerCase()).toContain(captureAmountHex);
357+
expect(encodedData.toLowerCase()).toContain(feeBpsHex);
321358
});
322359

323360
it('should encode voidPayment function data', () => {
361+
const testPaymentRef = '0x0123456789abcdef';
324362
const encodedData = encodeVoidPayment({
325-
paymentReference: '0x0123456789abcdef',
363+
paymentReference: testPaymentRef,
326364
network,
327365
provider,
328366
});
329367

330368
expect(typeof encodedData).toBe('string');
331369
expect(encodedData).toMatch(/^0x[a-fA-F0-9]+$/); // Should be valid hex string
370+
371+
// Verify it starts with the correct function selector for voidPayment
372+
expect(encodedData.substring(0, 10)).toBe('0x4eff2760');
373+
374+
// Verify the encoded data contains the payment reference
375+
expect(encodedData).toContain(testPaymentRef.substring(2));
376+
377+
// Void payment should be relatively short (just function selector + payment reference)
378+
expect(encodedData.length).toBe(74); // 10 chars for selector + 64 chars for padded bytes8
332379
});
333380

334381
it('should encode chargePayment function data', () => {
@@ -340,17 +387,55 @@ describe('erc20-commerce-escrow-wrapper', () => {
340387

341388
expect(typeof encodedData).toBe('string');
342389
expect(encodedData).toMatch(/^0x[a-fA-F0-9]+$/); // Should be valid hex string
390+
391+
// Verify it starts with the correct function selector for chargePayment
392+
expect(encodedData.substring(0, 10)).toBe('0x739802a3');
393+
394+
// Verify the encoded data contains our test parameters
395+
expect(encodedData).toContain(mockChargeParams.paymentReference.substring(2));
396+
expect(encodedData.toLowerCase()).toContain(
397+
mockChargeParams.payer.substring(2).toLowerCase(),
398+
);
399+
expect(encodedData.toLowerCase()).toContain(
400+
mockChargeParams.merchant.substring(2).toLowerCase(),
401+
);
402+
expect(encodedData.toLowerCase()).toContain(
403+
mockChargeParams.operator.substring(2).toLowerCase(),
404+
);
405+
expect(encodedData.toLowerCase()).toContain(
406+
mockChargeParams.token.substring(2).toLowerCase(),
407+
);
408+
expect(encodedData.toLowerCase()).toContain(
409+
mockChargeParams.feeReceiver.substring(2).toLowerCase(),
410+
);
411+
expect(encodedData.toLowerCase()).toContain(
412+
mockChargeParams.tokenCollector.substring(2).toLowerCase(),
413+
);
414+
415+
// Verify encoded fee basis points
416+
const feeBpsHex = mockChargeParams.feeBps.toString(16).padStart(64, '0');
417+
expect(encodedData.toLowerCase()).toContain(feeBpsHex);
343418
});
344419

345420
it('should encode reclaimPayment function data', () => {
421+
const testPaymentRef = '0x0123456789abcdef';
346422
const encodedData = encodeReclaimPayment({
347-
paymentReference: '0x0123456789abcdef',
423+
paymentReference: testPaymentRef,
348424
network,
349425
provider,
350426
});
351427

352428
expect(typeof encodedData).toBe('string');
353429
expect(encodedData).toMatch(/^0x[a-fA-F0-9]+$/); // Should be valid hex string
430+
431+
// Verify it starts with the correct function selector for reclaimPayment
432+
expect(encodedData.substring(0, 10)).toBe('0xafda9d20');
433+
434+
// Verify the encoded data contains the payment reference
435+
expect(encodedData).toContain(testPaymentRef.substring(2));
436+
437+
// Reclaim payment should be relatively short (just function selector + payment reference)
438+
expect(encodedData.length).toBe(74); // 10 chars for selector + 64 chars for padded bytes8
354439
});
355440

356441
it('should encode refundPayment function data', () => {
@@ -362,6 +447,24 @@ describe('erc20-commerce-escrow-wrapper', () => {
362447

363448
expect(typeof encodedData).toBe('string');
364449
expect(encodedData).toMatch(/^0x[a-fA-F0-9]+$/); // Should be valid hex string
450+
451+
// Verify it starts with the correct function selector for refundPayment
452+
expect(encodedData.substring(0, 10)).toBe('0xf9b777ea');
453+
454+
// Verify the encoded data contains our test parameters
455+
expect(encodedData).toContain(mockRefundParams.paymentReference.substring(2));
456+
expect(encodedData.toLowerCase()).toContain(
457+
mockRefundParams.tokenCollector.substring(2).toLowerCase(),
458+
);
459+
460+
// Verify encoded refund amount (as hex)
461+
const refundAmountHex = parseInt(mockRefundParams.refundAmount.toString())
462+
.toString(16)
463+
.padStart(64, '0');
464+
expect(encodedData.toLowerCase()).toContain(refundAmountHex);
465+
466+
// Verify collector data is included
467+
expect(encodedData).toContain(mockRefundParams.collectorData.substring(2));
365468
});
366469

367470
it('should throw for encodeAuthorizePayment when wrapper not found on mainnet', () => {
@@ -807,12 +910,17 @@ describe('erc20-commerce-escrow-wrapper', () => {
807910

808911
describe('query functions', () => {
809912
// These tests demonstrate the expected behavior but require actual contract deployment
810-
// For now, we'll test that the functions exist and have the right signatures
811-
it('should have the correct function signatures', () => {
913+
it('should have the correct function signatures and expected behavior', () => {
812914
expect(typeof getPaymentData).toBe('function');
813915
expect(typeof getPaymentState).toBe('function');
814916
expect(typeof canCapture).toBe('function');
815917
expect(typeof canVoid).toBe('function');
918+
919+
// Verify function arity (number of parameters)
920+
expect(getPaymentData.length).toBe(1); // Takes one parameter object
921+
expect(getPaymentState.length).toBe(1); // Takes one parameter object
922+
expect(canCapture.length).toBe(1); // Takes one parameter object
923+
expect(canVoid.length).toBe(1); // Takes one parameter object
816924
});
817925

818926
it('should throw for getPaymentData when wrapper not found on mainnet', async () => {
@@ -835,14 +943,36 @@ describe('ERC20 Commerce Escrow Wrapper Integration', () => {
835943
// 3. Capture payment
836944
// 4. Check payment state
837945

838-
// For now, we just test that the functions exist and have the right signatures
946+
// Test that functions exist and validate their expected behavior
839947
expect(typeof encodeSetCommerceEscrowAllowance).toBe('function');
840948
expect(typeof encodeAuthorizePayment).toBe('function');
841949
expect(typeof encodeCapturePayment).toBe('function');
842950
expect(typeof authorizePayment).toBe('function');
843951
expect(typeof capturePayment).toBe('function');
844952
expect(typeof getPaymentData).toBe('function');
845953
expect(typeof getPaymentState).toBe('function');
954+
955+
// Verify function parameters and return types
956+
expect(encodeSetCommerceEscrowAllowance.length).toBe(1); // Takes parameter object
957+
expect(encodeAuthorizePayment.length).toBe(1); // Takes parameter object
958+
expect(encodeCapturePayment.length).toBe(1); // Takes parameter object
959+
expect(authorizePayment.length).toBe(1); // Takes parameter object
960+
expect(capturePayment.length).toBe(1); // Takes parameter object
961+
962+
// Test that encode functions return valid transaction data
963+
const allowanceTxs = encodeSetCommerceEscrowAllowance({
964+
tokenAddress: erc20ContractAddress,
965+
amount: '1000000000000000000',
966+
provider,
967+
network,
968+
});
969+
expect(Array.isArray(allowanceTxs)).toBe(true);
970+
expect(allowanceTxs.length).toBeGreaterThan(0);
971+
expect(allowanceTxs[0]).toHaveProperty('to');
972+
expect(allowanceTxs[0]).toHaveProperty('data');
973+
expect(allowanceTxs[0]).toHaveProperty('value');
974+
expect(allowanceTxs[0].to).toBe(erc20ContractAddress);
975+
expect(allowanceTxs[0].value).toBe(0);
846976
});
847977

848978
it('should handle void payment flow when contracts are available', async () => {
@@ -854,6 +984,20 @@ describe('ERC20 Commerce Escrow Wrapper Integration', () => {
854984
expect(typeof encodeVoidPayment).toBe('function');
855985
expect(typeof voidPayment).toBe('function');
856986
expect(typeof canVoid).toBe('function');
987+
988+
// Verify function arity
989+
expect(encodeVoidPayment.length).toBe(1);
990+
expect(voidPayment.length).toBe(1);
991+
expect(canVoid.length).toBe(1);
992+
993+
// Test void encoding returns valid data
994+
const voidData = encodeVoidPayment({
995+
paymentReference: '0x0123456789abcdef',
996+
network,
997+
provider,
998+
});
999+
expect(voidData).toMatch(/^0x[a-fA-F0-9]+$/);
1000+
expect(voidData.substring(0, 10)).toBe('0x4eff2760'); // voidPayment selector
8571001
});
8581002

8591003
it('should handle charge payment flow when contracts are available', async () => {
@@ -863,6 +1007,20 @@ describe('ERC20 Commerce Escrow Wrapper Integration', () => {
8631007

8641008
expect(typeof encodeChargePayment).toBe('function');
8651009
expect(typeof chargePayment).toBe('function');
1010+
1011+
// Verify function arity
1012+
expect(encodeChargePayment.length).toBe(1);
1013+
expect(chargePayment.length).toBe(1);
1014+
1015+
// Test charge encoding returns valid data with correct selector
1016+
const chargeData = encodeChargePayment({
1017+
params: mockChargeParams,
1018+
network,
1019+
provider,
1020+
});
1021+
expect(chargeData).toMatch(/^0x[a-fA-F0-9]+$/);
1022+
expect(chargeData.substring(0, 10)).toBe('0x739802a3'); // chargePayment selector
1023+
expect(chargeData.length).toBeGreaterThan(100); // Should be long due to many parameters
8661024
});
8671025

8681026
it('should handle reclaim payment flow when contracts are available', async () => {
@@ -874,6 +1032,20 @@ describe('ERC20 Commerce Escrow Wrapper Integration', () => {
8741032

8751033
expect(typeof encodeReclaimPayment).toBe('function');
8761034
expect(typeof reclaimPayment).toBe('function');
1035+
1036+
// Verify function arity
1037+
expect(encodeReclaimPayment.length).toBe(1);
1038+
expect(reclaimPayment.length).toBe(1);
1039+
1040+
// Test reclaim encoding returns valid data
1041+
const reclaimData = encodeReclaimPayment({
1042+
paymentReference: '0x0123456789abcdef',
1043+
network,
1044+
provider,
1045+
});
1046+
expect(reclaimData).toMatch(/^0x[a-fA-F0-9]+$/);
1047+
expect(reclaimData.substring(0, 10)).toBe('0xafda9d20'); // reclaimPayment selector
1048+
expect(reclaimData.length).toBe(74); // Short function with just payment reference
8771049
});
8781050

8791051
it('should handle refund payment flow when contracts are available', async () => {
@@ -885,20 +1057,58 @@ describe('ERC20 Commerce Escrow Wrapper Integration', () => {
8851057

8861058
expect(typeof encodeRefundPayment).toBe('function');
8871059
expect(typeof refundPayment).toBe('function');
1060+
1061+
// Verify function arity
1062+
expect(encodeRefundPayment.length).toBe(1);
1063+
expect(refundPayment.length).toBe(1);
1064+
1065+
// Test refund encoding returns valid data
1066+
const refundData = encodeRefundPayment({
1067+
params: mockRefundParams,
1068+
network,
1069+
provider,
1070+
});
1071+
expect(refundData).toMatch(/^0x[a-fA-F0-9]+$/);
1072+
expect(refundData.substring(0, 10)).toBe('0xf9b777ea'); // refundPayment selector
1073+
expect(refundData.length).toBeGreaterThan(74); // Longer than simple functions due to multiple parameters
8881074
});
8891075

8901076
it('should validate payment parameters', () => {
891-
// Test parameter validation
892-
const invalidParams = {
893-
...mockAuthorizeParams,
894-
paymentReference: '', // Invalid empty reference
895-
};
896-
897-
// The actual validation would happen in the contract
898-
// Here we just test that the parameters are properly typed
1077+
// Test parameter validation and ensure all expected values are present
8991078
expect(mockAuthorizeParams.paymentReference).toBe('0x0123456789abcdef');
1079+
expect(mockAuthorizeParams.payer).toBe(wallet.address);
1080+
expect(mockAuthorizeParams.merchant).toBe('0x3234567890123456789012345678901234567890');
1081+
expect(mockAuthorizeParams.operator).toBe('0x4234567890123456789012345678901234567890');
1082+
expect(mockAuthorizeParams.token).toBe(erc20ContractAddress);
9001083
expect(mockAuthorizeParams.amount).toBe('1000000000000000000');
1084+
expect(mockAuthorizeParams.maxAmount).toBe('1100000000000000000');
1085+
expect(mockAuthorizeParams.tokenCollector).toBe('0x5234567890123456789012345678901234567890');
1086+
expect(mockAuthorizeParams.collectorData).toBe('0x1234');
1087+
1088+
// Validate capture parameters
1089+
expect(mockCaptureParams.paymentReference).toBe('0x0123456789abcdef');
1090+
expect(mockCaptureParams.captureAmount).toBe('1000000000000000000');
9011091
expect(mockCaptureParams.feeBps).toBe(250);
1092+
expect(mockCaptureParams.feeReceiver).toBe('0x6234567890123456789012345678901234567890');
1093+
1094+
// Validate charge parameters (should include all authorize params plus fee info)
1095+
expect(mockChargeParams.feeBps).toBe(250);
1096+
expect(mockChargeParams.feeReceiver).toBe('0x6234567890123456789012345678901234567890');
1097+
1098+
// Validate refund parameters
1099+
expect(mockRefundParams.paymentReference).toBe('0x0123456789abcdef');
1100+
expect(mockRefundParams.refundAmount).toBe('500000000000000000');
1101+
expect(mockRefundParams.tokenCollector).toBe('0x7234567890123456789012345678901234567890');
1102+
expect(mockRefundParams.collectorData).toBe('0x5678');
1103+
1104+
// Validate timestamp parameters are reasonable
1105+
expect(mockAuthorizeParams.preApprovalExpiry).toBeGreaterThan(Math.floor(Date.now() / 1000));
1106+
expect(mockAuthorizeParams.authorizationExpiry).toBeGreaterThan(
1107+
mockAuthorizeParams.preApprovalExpiry,
1108+
);
1109+
expect(mockAuthorizeParams.refundExpiry).toBeGreaterThan(
1110+
mockAuthorizeParams.authorizationExpiry,
1111+
);
9021112
});
9031113

9041114
it('should handle different token types', () => {
@@ -915,6 +1125,18 @@ describe('ERC20 Commerce Escrow Wrapper Integration', () => {
9151125

9161126
expect(usdtTransactions).toHaveLength(2); // Reset to 0, then approve amount
9171127

1128+
// Validate first transaction (reset to 0)
1129+
expect(usdtTransactions[0].to).toBe(usdtAddress);
1130+
expect(usdtTransactions[0].value).toBe(0);
1131+
expect(usdtTransactions[0].data).toMatch(/^0x[a-fA-F0-9]+$/);
1132+
expect(usdtTransactions[0].data.substring(0, 10)).toBe('0x095ea7b3'); // approve function selector
1133+
1134+
// Validate second transaction (approve amount)
1135+
expect(usdtTransactions[1].to).toBe(usdtAddress);
1136+
expect(usdtTransactions[1].value).toBe(0);
1137+
expect(usdtTransactions[1].data).toMatch(/^0x[a-fA-F0-9]+$/);
1138+
expect(usdtTransactions[1].data.substring(0, 10)).toBe('0x095ea7b3'); // approve function selector
1139+
9181140
const regularTransactions = encodeSetCommerceEscrowAllowance({
9191141
tokenAddress: erc20ContractAddress,
9201142
amount: '1000000000000000000',
@@ -924,6 +1146,18 @@ describe('ERC20 Commerce Escrow Wrapper Integration', () => {
9241146
});
9251147

9261148
expect(regularTransactions).toHaveLength(1); // Just approve amount
1149+
1150+
// Validate regular transaction
1151+
expect(regularTransactions[0].to).toBe(erc20ContractAddress);
1152+
expect(regularTransactions[0].value).toBe(0);
1153+
expect(regularTransactions[0].data).toMatch(/^0x[a-fA-F0-9]+$/);
1154+
expect(regularTransactions[0].data.substring(0, 10)).toBe('0x095ea7b3'); // approve function selector
1155+
1156+
// Verify the wrapper address is encoded in the transaction data
1157+
const wrapperAddress = getCommerceEscrowWrapperAddress(network);
1158+
expect(regularTransactions[0].data.toLowerCase()).toContain(
1159+
wrapperAddress.substring(2).toLowerCase(),
1160+
);
9271161
});
9281162

9291163
describe('comprehensive edge case scenarios', () => {

0 commit comments

Comments
 (0)