@@ -443,6 +443,211 @@ func TestDiscreteFractionalSupply(t *testing.T) {
443443 assertApproxEq (t , tokensBack , big .NewFloat (10 ), 0.0000000001 , "Tokens from fractional supply" )
444444}
445445
446+ func TestDiscreteTokensForValueExchangeZeroValue (t * testing.T ) {
447+ curve := DefaultDiscreteExponentialCurve ()
448+
449+ // Test with 0 value from various supplies
450+ for _ , supplyVal := range []float64 {0 , 50 , 100 , 1000 , 10000 } {
451+ supply := big .NewFloat (supplyVal )
452+ value := big .NewFloat (0 )
453+ tokens := curve .TokensForValueExchange (supply , value )
454+ if tokens .Cmp (big .NewFloat (0 )) != 0 {
455+ t .Errorf ("0 value from supply %f should yield 0 tokens, got %s" ,
456+ supplyVal , tokens .Text ('f' , 18 ))
457+ }
458+ }
459+ }
460+
461+ func TestDiscreteTokensForValueExchangeWithinSingleStep (t * testing.T ) {
462+ curve := DefaultDiscreteExponentialCurve ()
463+
464+ // Supply at 50, sell tokens within the same step (step 0)
465+ supply := big .NewFloat (50 )
466+ price0 := big .NewFloat (0.01 )
467+
468+ // Value for 25 tokens at price0 = 0.25
469+ valueFor25 := new (big.Float ).Mul (price0 , big .NewFloat (25 ))
470+ tokens := curve .TokensForValueExchange (supply , valueFor25 )
471+ assertApproxEq (t , tokens , big .NewFloat (25 ), 0.0000000001 , "Tokens for value within single step" )
472+ }
473+
474+ func TestDiscreteTokensForValueExchangeCrossingBoundary (t * testing.T ) {
475+ curve := DefaultDiscreteExponentialCurve ()
476+
477+ // Supply at 250, sell tokens crossing step boundaries
478+ supply := big .NewFloat (250 )
479+ sellTokens := big .NewFloat (150 )
480+
481+ // Calculate the value of selling 150 tokens from supply 250
482+ // (that's TokensToValue from supply 100 to 250)
483+ newSupply := new (big.Float ).Sub (supply , sellTokens )
484+ value := curve .TokensToValue (newSupply , sellTokens )
485+
486+ // Now TokensForValueExchange should return 150
487+ tokensResult := curve .TokensForValueExchange (supply , value )
488+ assertApproxEq (t , tokensResult , sellTokens , 1 , "Tokens for value crossing boundary" )
489+ }
490+
491+ func TestDiscreteTokensForValueExchangeRoundtrip (t * testing.T ) {
492+ curve := DefaultDiscreteExponentialCurve ()
493+
494+ testCases := []struct {
495+ supply float64
496+ tokens float64
497+ }{
498+ {100 , 50 },
499+ {100 , 100 },
500+ {250 , 150 },
501+ {500 , 250 },
502+ {1000 , 500 },
503+ {1000 , 1000 },
504+ {10000 , 5000 },
505+ {50000 , 25000 },
506+ }
507+
508+ for _ , tc := range testCases {
509+ supply := big .NewFloat (tc .supply )
510+ sellTokens := big .NewFloat (tc .tokens )
511+
512+ // Calculate value of selling these tokens
513+ newSupply := new (big.Float ).Sub (supply , sellTokens )
514+ value := curve .TokensToValue (newSupply , sellTokens )
515+ if value == nil {
516+ t .Errorf ("TokensToValue returned nil for supply=%f, tokens=%f" , tc .supply , tc .tokens )
517+ continue
518+ }
519+
520+ // Roundtrip: value -> tokens should give back the original tokens
521+ tokensBack := curve .TokensForValueExchange (supply , value )
522+ if tokensBack == nil {
523+ t .Errorf ("TokensForValueExchange returned nil for supply=%f, value=%s" , tc .supply , value .Text ('f' , 18 ))
524+ continue
525+ }
526+
527+ assertApproxEq (t , tokensBack , sellTokens , 1 ,
528+ fmt .Sprintf ("Roundtrip value->tokens for supply=%f, tokens=%f" , tc .supply , tc .tokens ))
529+ }
530+ }
531+
532+ func TestDiscreteTokensForValueExchangeFractionalRoundtrip (t * testing.T ) {
533+ curve := DefaultDiscreteExponentialCurve ()
534+
535+ testCases := []struct {
536+ supply float64
537+ tokens float64
538+ }{
539+ {50.5 , 25.3 },
540+ {100.25 , 50.75 },
541+ {250.123 , 100.456 },
542+ {1000.5 , 500.25 },
543+ {10000.5 , 1234.567 },
544+ }
545+
546+ for _ , tc := range testCases {
547+ supply := big .NewFloat (tc .supply )
548+ sellTokens := big .NewFloat (tc .tokens )
549+
550+ // Calculate value of selling these tokens
551+ newSupply := new (big.Float ).Sub (supply , sellTokens )
552+ value := curve .TokensToValue (newSupply , sellTokens )
553+ if value == nil {
554+ t .Errorf ("TokensToValue returned nil for supply=%f, tokens=%f" , tc .supply , tc .tokens )
555+ continue
556+ }
557+
558+ // Roundtrip: value -> tokens should give back the original tokens
559+ tokensBack := curve .TokensForValueExchange (supply , value )
560+ if tokensBack == nil {
561+ t .Errorf ("TokensForValueExchange returned nil for supply=%f, value=%s" , tc .supply , value .Text ('f' , 18 ))
562+ continue
563+ }
564+
565+ assertApproxEq (t , tokensBack , sellTokens , 0.0000000001 ,
566+ fmt .Sprintf ("Fractional roundtrip value->tokens for supply=%f, tokens=%f" , tc .supply , tc .tokens ))
567+ }
568+ }
569+
570+ func TestDiscreteTokensForValueExchangeEntireSupply (t * testing.T ) {
571+ curve := DefaultDiscreteExponentialCurve ()
572+
573+ // Selling the entire supply should return all tokens
574+ supply := big .NewFloat (1000 )
575+ zero := big .NewFloat (0 )
576+ totalValue := curve .TokensToValue (zero , supply )
577+
578+ tokens := curve .TokensForValueExchange (supply , totalValue )
579+ assertApproxEq (t , tokens , supply , 1 , "Selling entire supply should return all tokens" )
580+ }
581+
582+ func TestDiscreteTokensForValueExchangeExceedsSupplyReturnsNil (t * testing.T ) {
583+ curve := DefaultDiscreteExponentialCurve ()
584+
585+ supply := big .NewFloat (100 )
586+ zero := big .NewFloat (0 )
587+ totalValue := curve .TokensToValue (zero , supply )
588+
589+ // Try to extract more value than the entire supply is worth
590+ excessValue := new (big.Float ).Add (totalValue , big .NewFloat (1 ))
591+ tokens := curve .TokensForValueExchange (supply , excessValue )
592+ if tokens != nil {
593+ t .Errorf ("Value exceeding supply should return nil, got %s" , tokens .Text ('f' , 18 ))
594+ }
595+ }
596+
597+ func TestDiscreteTokensForValueExchangeZeroSupplyReturnsNil (t * testing.T ) {
598+ curve := DefaultDiscreteExponentialCurve ()
599+
600+ // At zero supply, any positive value should return nil
601+ supply := big .NewFloat (0 )
602+ value := big .NewFloat (1 )
603+ tokens := curve .TokensForValueExchange (supply , value )
604+ if tokens != nil {
605+ t .Errorf ("Zero supply with positive value should return nil, got %s" , tokens .Text ('f' , 18 ))
606+ }
607+ }
608+
609+ func TestDiscreteTokensForValueExchangeSellingInPartsEqualsSellingAllAtOnce (t * testing.T ) {
610+ curve := DefaultDiscreteExponentialCurve ()
611+
612+ supply := big .NewFloat (500 )
613+
614+ // Sell 300 tokens total: first sell for some value, then sell more for more value
615+ sellTokens := big .NewFloat (300 )
616+ newSupply := new (big.Float ).Sub (supply , sellTokens )
617+ totalValue := curve .TokensToValue (newSupply , sellTokens )
618+
619+ // Split the value into two parts
620+ value1 := new (big.Float ).Quo (totalValue , big .NewFloat (3 ))
621+ value2 := new (big.Float ).Sub (totalValue , value1 )
622+
623+ // Sell for value1 first
624+ tokens1 := curve .TokensForValueExchange (supply , value1 )
625+ supplyAfterFirstSell := new (big.Float ).Sub (supply , tokens1 )
626+
627+ // Then sell for value2
628+ tokens2 := curve .TokensForValueExchange (supplyAfterFirstSell , value2 )
629+
630+ // Total tokens should equal selling all at once
631+ tokensAll := curve .TokensForValueExchange (supply , totalValue )
632+ tokensParts := new (big.Float ).Add (tokens1 , tokens2 )
633+
634+ assertApproxEq (t , tokensParts , tokensAll , 1 ,
635+ "Selling in parts should equal selling all at once" )
636+ }
637+
638+ func TestDiscreteTokensForValueExchangeLargeAcrossManySteps (t * testing.T ) {
639+ curve := DefaultDiscreteExponentialCurve ()
640+
641+ supply := big .NewFloat (1234567 )
642+ sellTokens := big .NewFloat (10000 )
643+
644+ newSupply := new (big.Float ).Sub (supply , sellTokens )
645+ value := curve .TokensToValue (newSupply , sellTokens )
646+
647+ tokensBack := curve .TokensForValueExchange (supply , value )
648+ assertApproxEq (t , tokensBack , sellTokens , 1 , "Large exchange across many steps roundtrip" )
649+ }
650+
446651func TestGenerateDiscreteCurveTable (t * testing.T ) {
447652 t .Skip ()
448653
0 commit comments