@@ -370,36 +370,53 @@ abstract contract PythTestUtils is Test, WormholeTestUtils, RandTestUtils {
370370}
371371
372372contract PythUtilsTest is Test , WormholeTestUtils , PythTestUtils , IPythEvents {
373- function successTest (int64 price1 , int32 expo1 , int64 price2 , int32 expo2 , int64 expectedPrice , int32 expectedExpo ) internal {
374- (int64 price , int32 expo ) = PythUtils.deriveCrossRate (price1, expo1, price2, expo2);
373+ function assertCrossRateEquals (
374+ int64 price1 ,
375+ int32 expo1 ,
376+ int64 price2 ,
377+ int32 expo2 ,
378+ int32 targetExpo ,
379+
380+ int64 expectedPrice ,
381+ int32 expectedExpo
382+ ) internal {
383+ (int64 price , int32 expo ) = PythUtils.deriveCrossRate (price1, expo1, price2, expo2, targetExpo);
375384 assertEq (price, expectedPrice);
376385 assertEq (expo, expectedExpo);
377386 }
378387
379- function revertTest (int64 price1 , int32 expo1 , int64 price2 , int32 expo2 ) internal {
380- vm.expectRevert ();
381- PythUtils.deriveCrossRate (price1, expo1, price2, expo2);
388+ function assertCrossRateReverts (
389+ int64 price1 ,
390+ int32 expo1 ,
391+ int64 price2 ,
392+ int32 expo2 ,
393+ int32 targetExpo ,
394+ bytes4 expectedError
395+ ) internal {
396+ vm.expectRevert (expectedError);
397+ PythUtils.deriveCrossRate (price1, expo1, price2, expo2, targetExpo);
382398 }
383399
384400 function testConvertToUnit () public {
385401 // Price can't be negative
386- vm.expectRevert ();
402+ vm.expectRevert (PythErrors.NegativeInputPrice. selector );
387403 PythUtils.convertToUint (- 100 , - 5 , 18 );
388404
389- // Exponent can't be positive
390- vm.expectRevert ();
391- PythUtils.convertToUint (100 , 5 , 18 );
405+ // Exponent can't be less than -255
406+ vm.expectRevert (PythErrors.InvalidInputExpo. selector );
407+ PythUtils.convertToUint (100 , - 256 , 18 );
392408
409+ // Negative Exponent Tests
393410 // Price with 18 decimals and exponent -5
394411 assertEq (
395412 PythUtils.convertToUint (100 , - 5 , 18 ),
396- 1000000000000000 // 100 * 10^13
413+ 100_0_000_000_000_000 // 100 * 10^13
397414 );
398415
399416 // Price with 9 decimals and exponent -2
400417 assertEq (
401418 PythUtils.convertToUint (100 , - 2 , 9 ),
402- 1000000000 // 100 * 10^7
419+ 100_0_000_000 // 100 * 10^7
403420 );
404421
405422 // Price with 4 decimals and exponent -5
@@ -409,45 +426,66 @@ contract PythUtilsTest is Test, WormholeTestUtils, PythTestUtils, IPythEvents {
409426 // @note: We will lose precision here as price is
410427 // 0.00001 and we are targetDecimals is 2.
411428 assertEq (PythUtils.convertToUint (100 , - 5 , 2 ), 0 );
429+
430+ assertEq (PythUtils.convertToUint (123 , - 8 , 5 ), 0 );
431+
432+ // Positive Exponent Tests
433+ // Price with 18 decimals and exponent 5
434+ assertEq (PythUtils.convertToUint (100 , 5 , 18 ), 100_00_000_000_000_000_000_000_000 ); // 100 with23 zeros
435+
436+ // Price with 9 decimals and exponent 2
437+ assertEq (PythUtils.convertToUint (100 , 2 , 9 ), 100_00_000_000_000 ); // 100 with 11 zeros
438+
439+ // Price with 4 decimals and exponent 5
440+ assertEq (PythUtils.convertToUint (100 , 1 , 2 ), 100_000 ); // 100 with 3 zeros
412441 }
413442
414443 function testCombinePrices () public {
415444
416445 // Basic Tests
417- successTest ( 100 , - 2 , 100 , - 2 , 100 , - 2 );
418- successTest ( 10000 , - 2 , 100 , - 2 , 10000 , - 2 );
419- successTest ( 1_000_000 , - 2 , 10_000 , - 2 , 10_000 , - 2 );
446+ assertCrossRateEquals ( 500 , - 8 , 500 , - 8 , - 5 , 100000 , - 5 );
447+ assertCrossRateEquals ( 10_000 , - 8 , 100 , - 2 , - 5 , 10 , - 5 );
448+ assertCrossRateEquals ( 10_000 , - 2 , 100 , - 8 , - 4 , 1_000_000_000_000 , - 4 );
420449
421450 // Negative Price Tests
422- revertTest (- 100 , - 2 , 100 , - 2 );
423- revertTest (100 , - 2 , - 100 , - 2 );
424- revertTest (- 100 , - 2 , - 100 , - 2 );
451+ assertCrossRateReverts (- 100 , - 2 , 100 , - 2 , - 5 , PythErrors.NegativeInputPrice. selector );
452+ assertCrossRateReverts (100 , - 2 , - 100 , - 2 , - 5 , PythErrors.NegativeInputPrice. selector );
453+ assertCrossRateReverts (- 100 , - 2 , - 100 , - 2 , - 5 , PythErrors.NegativeInputPrice. selector );
425454
426455 // Positive Exponent Tests
427- revertTest (100 , 2 , 100 , - 2 );
428- revertTest (100 , - 2 , 100 , 2 );
429- revertTest (100 , 2 , 100 , 2 );
456+ assertCrossRateReverts (100 , 2 , 100 , - 2 , - 5 , PythErrors.InvalidInputExpo.selector );
457+ assertCrossRateReverts (100 , - 2 , 100 , 2 , - 5 , PythErrors.InvalidInputExpo.selector );
458+ assertCrossRateReverts (100 , 2 , 100 , 2 , - 5 , PythErrors.InvalidInputExpo.selector );
459+
460+ // Invalid Target Exponent Tests
461+ assertCrossRateReverts (100 , - 2 , 100 , - 2 , 1 , PythErrors.InvalidTargetExpo.selector );
430462
431463 // Different Exponent Tests
432- successTest (10_000 , - 2 , 100 , - 4 , 100_000_000 , - 4 );
433- successTest (10_000 , - 2 , 10_000 , 0 , 1 , - 2 );
434- successTest (10_000 , 0 , 10_000 , 0 , 1 , 0 );
435-
436- // End Range Tests
437- successTest (int64 (type (int64 ).max), 0 , int64 (type (int64 ).max), 0 , 1 , 0 );
438- successTest (int64 (type (int64 ).max), 0 , 1 , 0 , int64 (type (int64 ).max), 0 );
439- successTest (1 , 0 , int64 (type (int64 ).max), 0 , 1 / int64 (type (int64 ).max), 0 );
440- revertTest (10_000 , - 2 , 10_000 , - 256 );
464+ assertCrossRateEquals (10_000 , - 2 , 100 , - 4 , - 4 , 100_000_000 , - 4 );
465+ assertCrossRateEquals (10_000 , - 2 , 10_000 , - 1 , - 2 , 10 , - 2 );
466+ assertCrossRateEquals (10_000 , - 10 , 10_000 , - 2 , 0 , 0 , 0 ); // It will truncate to 0
467+
468+ // Exponent Edge Tests
469+ assertCrossRateEquals (10_000 , 0 , 100 , 0 , 0 , 100 , 0 );
470+ assertCrossRateEquals (10_000 , 0 , 100 , 0 , - 255 , 100 , - 255 );
471+ // assertCrossRateEquals(10_000, 0, 100, -255, -255, 100, -255);
472+ // assertCrossRateEquals(10_000, -255, 100, 0, 0, 100, 0);
473+
474+ // // End Range Tests
475+ // successTest(int64(type(int64).max), 0, int64(type(int64).max), 0, 1, 0);
476+ // successTest(int64(type(int64).max), 0, 1, 0, int64(type(int64).max), 0);
477+ // successTest(1, 0, int64(type(int64).max), 0, 1 / int64(type(int64).max), 0);
478+ // revertTest(10_000, -2, 10_000, -256);
441479
442- // More Realistic Tests
443- // Test case 1: (StEth/Eth / Eth/USD = ETH/BTC)
444- (int64 price , int32 expo ) = PythUtils.deriveCrossRate (206487956502 , - 8 , 206741615681 , - 8 );
445- assertApproxEqRel (price, 100000000 , 9e17 ); // $1
446- assertEq (expo, - 8 );
447-
448- // Test case 2:
449- (price, expo) = PythUtils.deriveCrossRate (520010 , - 8 , 38591 , - 8 );
450- assertApproxEqRel (price, 1347490347 , 9e17 ); // $1
451- assertEq (expo, - 8 );
480+ // // More Realistic Tests
481+ // // Test case 1: (StEth/Eth / Eth/USD = ETH/BTC)
482+ // (int64 price, int32 expo) = PythUtils.deriveCrossRate(206487956502, -8, 206741615681, -8);
483+ // assertApproxEqRel(price, 100000000, 9e17); // $1
484+ // assertEq(expo, -8);
485+
486+ // // Test case 2:
487+ // (price, expo) = PythUtils.deriveCrossRate(520010, -8, 38591, -8);
488+ // assertApproxEqRel(price, 1347490347, 9e17); // $1
489+ // assertEq(expo, -8);
452490 }
453491}
0 commit comments