diff --git a/packages/mana/balance.go b/packages/mana/balance.go
index 85ed7b4fc84f05a8a5b1c1bc64c74b9c3cd7b2a0..ebb9c4e5d42ad8afd3bd01bf9ff8234f91c3642f 100644
--- a/packages/mana/balance.go
+++ b/packages/mana/balance.go
@@ -25,10 +25,10 @@ func (balance *Balance) GetValue() uint64 {
 }
 
 func (balance *Balance) AddTransfer(movedCoins uint64, receivedTime uint64, spentTime uint64) {
-	gainedMana, lastErosion, _ := balance.calculator.ManaOfTransferDiscrete(movedCoins, receivedTime, spentTime)
+	gainedMana, _ := balance.calculator.GenerateMana(movedCoins, spentTime-receivedTime)
 
-	if lastErosion >= balance.lastErosion {
-		balance.Erode(lastErosion)
+	if spentTime >= balance.lastErosion {
+		balance.Erode(spentTime)
 	} else {
 		fmt.Println("empty")
 		// revert old actions
@@ -41,7 +41,7 @@ func (balance *Balance) AddTransfer(movedCoins uint64, receivedTime uint64, spen
 
 func (balance *Balance) Erode(erosionTime uint64) {
 	if balance.lastErosion <= erosionTime {
-		balance.currentBalance, balance.lastErosion, _ = balance.calculator.ErodedManaDiscrete(balance.currentBalance, balance.lastErosion, erosionTime)
+		balance.currentBalance, _ = balance.calculator.ErodeMana(balance.currentBalance, erosionTime-balance.lastErosion)
 	} else {
 		fmt.Println("empty")
 		// revert old erosions
diff --git a/packages/mana/calculator.go b/packages/mana/calculator.go
index 7ee676f890085b8067529f608229f978bd64d416..d1ff397f51616f1101e2b1ce2ebd37fde8ec6084 100644
--- a/packages/mana/calculator.go
+++ b/packages/mana/calculator.go
@@ -4,135 +4,60 @@ import (
 	"math"
 )
 
+// A calculator that can be used to calculate the changes of mana due to erosion or mana generation.
 type Calculator struct {
-	decayInterval   uint64
-	decayRate       float64
-	coinsPerMana    uint64
-	decayFactor     float64
-	manaScaleFactor float64
+	decayInterval          float64
+	decayRate              float64
+	options                *CalculatorOptions
+	tokenSupplyScalefactor float64
 }
 
-func NewCalculator(decayInterval uint64, decayRate float64, coinsPerMana uint64) (result *Calculator) {
-	result = &Calculator{
+// Creates a new calculator that can be used to calculate the changes of mana due to erosion or mana generation.
+func NewCalculator(decayInterval float64, decayRate float64, optionalOptions ...CalculatorOption) *Calculator {
+	return &Calculator{
+		// store key settings
 		decayInterval: decayInterval,
 		decayRate:     decayRate,
-		coinsPerMana:  coinsPerMana,
-		decayFactor:   1 - decayRate,
-	}
 
-	// make mana reach exactly the token supply
-	result.manaScaleFactor = result.decayRate / result.decayFactor
+		// configure optional parameters
+		options: DEFAULT_OPTIONS.Override(optionalOptions...),
 
-	return
-}
-
-func (calculator *Calculator) ManaOfTransferDiscrete(movedCoins uint64, receivedTime uint64, spentTime uint64) (result uint64, lastErosion uint64, roundingError float64) {
-	if spentTime <= receivedTime {
-		return 0, 0, 0
+		// derive important factors ...
+		// ... make mana reach exactly the token supply as it's max value (n coins => n mana)
+		tokenSupplyScalefactor: decayRate / (1 - decayRate),
 	}
-
-	baseMana := movedCoins / calculator.coinsPerMana
-	scaleFactor := 1 - calculator.decayRate
-	erosionIntervals := spentTime/calculator.decayInterval - receivedTime/calculator.decayInterval
-
-	var totalManaReceived float64
-
-	switch true {
-	// no decay intervals
-	case erosionIntervals == 0:
-		lastIntervalDuration := spentTime - receivedTime
-		if lastIntervalDuration != 0 {
-			totalManaReceived += float64(CoinTimeDestroyed(baseMana, lastIntervalDuration))
-		}
-
-		lastErosion = 0
-
-	// only 1 decay interval
-	case erosionIntervals == 1:
-		firstIntervalDuration := calculator.decayInterval - receivedTime%calculator.decayInterval
-		gainsInFirstInterval := float64(CoinTimeDestroyed(baseMana, firstIntervalDuration)) * math.Pow(scaleFactor, float64(erosionIntervals))
-		totalManaReceived += gainsInFirstInterval
-
-		lastIntervalDuration := spentTime % calculator.decayInterval
-		if lastIntervalDuration != 0 {
-			totalManaReceived += float64(CoinTimeDestroyed(baseMana, lastIntervalDuration))
-		}
-
-		lastErosion = spentTime - lastIntervalDuration
-
-	// multiple decay intervals
-	default:
-		firstIntervalDuration := calculator.decayInterval - receivedTime%calculator.decayInterval
-		gainsInFirstInterval := float64(CoinTimeDestroyed(baseMana, firstIntervalDuration)) * math.Pow(scaleFactor, float64(erosionIntervals))
-		totalManaReceived += gainsInFirstInterval
-
-		gainsInConsecutiveIntervals := float64(CoinTimeDestroyed(baseMana, calculator.decayInterval)) * scaleFactor * (1 - math.Pow(scaleFactor, float64(erosionIntervals-1))) / (1 - scaleFactor)
-		totalManaReceived += gainsInConsecutiveIntervals
-
-		lastIntervalDuration := spentTime % calculator.decayInterval
-		if lastIntervalDuration != 0 {
-			totalManaReceived += float64(CoinTimeDestroyed(baseMana, lastIntervalDuration))
-		}
-
-		lastErosion = spentTime - lastIntervalDuration
-	}
-
-	result = uint64(totalManaReceived)
-	roundingError = totalManaReceived - float64(result)
-
-	return
 }
 
-func (calculator *Calculator) ManaOfTransferContinuous(movedCoins uint64, heldTime uint64) (result uint64, roundingError float64) {
+// Returns the amount of mana that was generated by holding the given amount of coins for the given time.
+func (calculator *Calculator) GenerateMana(coins uint64, heldTime uint64) (result uint64, roundingError float64) {
+	// calculate results
 	relativeDecayTime := float64(heldTime) / float64(calculator.decayInterval)
+	erosionFactor := (1 - math.Pow(1-calculator.decayRate, float64(relativeDecayTime+1)) - calculator.decayRate) / calculator.decayRate
+	gainedMana := float64(coins) * calculator.options.ManaScaleFactor * calculator.tokenSupplyScalefactor * erosionFactor
 
-	erosionFactor := (1-math.Pow(calculator.decayFactor, float64(relativeDecayTime+1)))/calculator.decayRate - 1
-
-	gainedMana := float64(movedCoins) * calculator.manaScaleFactor * erosionFactor
-
+	// assign rounded results & determine roundingErrors
 	result = uint64(math.Round(gainedMana))
 	roundingError = gainedMana - float64(result)
 
 	return
 }
 
-func (calculator *Calculator) ManaOfTransferContinuous1(movedCoins uint64, heldTime uint64) (result uint64, roundingError float64) {
-	gainsInConsecutiveIntervals := (float64(movedCoins) / calculator.decayRate) * (1 - math.Pow(math.E, -calculator.decayRate*float64(heldTime)))
-
-	result = uint64(gainsInConsecutiveIntervals)
-	roundingError = gainsInConsecutiveIntervals - float64(result)
-
-	return
-}
-
-func (calculator *Calculator) ErodedManaContinuous(mana uint64, erosionTime uint64) (result uint64, roundingError float64) {
-	if erosionTime == 0 {
+// Returns the amount of mana that is left after the erosion of the given amount for the given time.
+func (calculator *Calculator) ErodeMana(mana uint64, decayTime uint64) (result uint64, roundingError float64) {
+	// if no time has passed -> return unchanged values
+	if decayTime == 0 {
 		result = mana
-		roundingError = 0
 
 		return
 	}
 
+	// calculate results
 	growthFactor := math.Log(1-calculator.decayRate) / float64(calculator.decayInterval)
-	erodedMana := float64(mana) * math.Pow(math.E, growthFactor*float64(erosionTime))
+	erodedMana := float64(mana) * math.Pow(math.E, growthFactor*float64(decayTime))
 
-	result = uint64(erodedMana)
+	// assign rounded results & determine roundingErrors
+	result = uint64(math.Round(erodedMana))
 	roundingError = erodedMana - float64(result)
 
 	return
 }
-
-func (calculator *Calculator) ErodedManaDiscrete(mana uint64, erosionStartTime uint64, erosionEndTime uint64) (result uint64, lastErosion uint64, roundingError float64) {
-	if erosionStartTime > erosionEndTime {
-		panic("negative erosion duration")
-	}
-
-	erosionIntervals := erosionEndTime/calculator.decayInterval - erosionStartTime/calculator.decayInterval
-	erodedValue := math.Pow(float64(1-calculator.decayRate), float64(erosionIntervals)) * float64(mana)
-
-	result = uint64(erodedValue)
-	lastErosion = erosionEndTime
-	roundingError = erodedValue - float64(result)
-
-	return
-}
diff --git a/packages/mana/calculator_options.go b/packages/mana/calculator_options.go
new file mode 100644
index 0000000000000000000000000000000000000000..833bf59d44b83d88215d6c11f2bd38eb5be75eb3
--- /dev/null
+++ b/packages/mana/calculator_options.go
@@ -0,0 +1,38 @@
+package mana
+
+// region default options //////////////////////////////////////////////////////////////////////////////////////////////
+
+var DEFAULT_OPTIONS = &CalculatorOptions{
+	ManaScaleFactor: 1,
+}
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// region calculator options ///////////////////////////////////////////////////////////////////////////////////////////
+
+func ManaScaleFactor(manaScaleFactor float64) CalculatorOption {
+	return func(args *CalculatorOptions) {
+		args.ManaScaleFactor = manaScaleFactor
+	}
+}
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+// region type definitions /////////////////////////////////////////////////////////////////////////////////////////////
+
+type CalculatorOptions struct {
+	ManaScaleFactor float64
+}
+
+func (options CalculatorOptions) Override(optionalOptions ...CalculatorOption) *CalculatorOptions {
+	result := &options
+	for _, option := range optionalOptions {
+		option(result)
+	}
+
+	return result
+}
+
+type CalculatorOption func(*CalculatorOptions)
+
+// endregion ///////////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/packages/mana/mana.go b/packages/mana/mana.go
deleted file mode 100644
index 4855d809ad887fc908c8886fccbe6dfc1563aed2..0000000000000000000000000000000000000000
--- a/packages/mana/mana.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package mana
-
-func CoinTimeDestroyed(transferredValue uint64, parkedTime uint64) uint64 {
-	return transferredValue * parkedTime
-}
-
-const (
-	DECAY_INTERVAL = 10
-	DECAY_RATE     = 0.01
-	COINS_PER_MANA = 10
-)
diff --git a/packages/mana/mana_test.go b/packages/mana/mana_test.go
index bfb0589ee2d750c132c6833528428f94e273a0b3..01d7b50c380ecca138537838e52987a4fa59b91c 100644
--- a/packages/mana/mana_test.go
+++ b/packages/mana/mana_test.go
@@ -1,83 +1,47 @@
 package mana
 
 import (
-	"fmt"
-	"math"
 	"testing"
 
 	"github.com/magiconair/properties/assert"
 )
 
-func BenchmarkCalculator_ManaOfTransferContinuous(b *testing.B) {
-	calculator := NewCalculator(10, 0.1, 1)
-
-	b.ResetTimer()
+func BenchmarkCalculator_GenerateMana(b *testing.B) {
+	calculator := NewCalculator(10, 0.1)
 
 	for i := 0; i < b.N; i++ {
-		calculator.ManaOfTransferContinuous(10000000, 100000000000)
+		calculator.GenerateMana(1000000, 100000000000)
 	}
 }
 
-func TestBalance_Erode(t *testing.T) {
-	calculator := NewCalculator(50, 0.1, 9)
-	balance := NewBalance(calculator)
-
-	calculator1 := NewCalculator(5000, 0.2, 1)
-
-	fmt.Println("===")
-	fmt.Println(calculator1.ManaOfTransferContinuous(1000, 5000000))
-	fmt.Println(calculator.ManaOfTransferDiscrete(1000, 0, 50))
-
-	balance.AddTransfer(500, 0, 10)
+func TestCalculator_GenerateMana(t *testing.T) {
+	calculator := NewCalculator(500, 0.1, ManaScaleFactor(2))
 
-	assert.Equal(t, balance.GetValue(), uint64(450))
+	generatedMana, _ := calculator.GenerateMana(1000, 0)
+	assert.Equal(t, generatedMana, uint64(0))
 
-	balance.Erode(20)
+	generatedMana, _ = calculator.GenerateMana(1000, 500)
+	assert.Equal(t, generatedMana, uint64(200))
 
-	assert.Equal(t, balance.GetValue(), uint64(405))
-
-	balance.Erode(40)
-
-	assert.Equal(t, balance.GetValue(), uint64(328))
+	generatedMana, _ = calculator.GenerateMana(1000, 5000000)
+	assert.Equal(t, generatedMana, uint64(2000))
 }
 
-func calcManaContinuous(calculator *Calculator, coins uint64, timeHeld uint64) (result uint64, roundingError float64) {
-	scaleFactor := 1 - math.Pow(1-calculator.decayRate, float64(timeHeld)/float64(calculator.decayInterval))
-	fmt.Println(scaleFactor)
-	erodedGains := float64(coins) * float64(calculator.decayInterval) * scaleFactor
-
-	result = uint64(erodedGains)
-	roundingError = erodedGains - float64(result)
-
-	return
-}
-
-func TestCalculator_ManaOfTransfer(t *testing.T) {
-	manaCalculator := NewCalculator(10, 0.1, 10)
-
-	var mana, lastErosion uint64
-	var roundingError float64
-
-	mana, lastErosion, _ = manaCalculator.ManaOfTransferDiscrete(49, 0, 0)
-	assert.Equal(t, mana, uint64(0))
-	assert.Equal(t, lastErosion, uint64(0))
-
-	fmt.Println(calcManaContinuous(manaCalculator, 50, 10))
-	fmt.Println(manaCalculator.ManaOfTransferDiscrete(50, 0, 10))
-	fmt.Println(calcManaContinuous(manaCalculator, 50, 20))
-	fmt.Println(manaCalculator.ManaOfTransferDiscrete(50, 0, 20))
+func TestCalculator_ManaSymmetry(t *testing.T) {
+	calculator := NewCalculator(500, 0.1, ManaScaleFactor(2))
 
-	mana, lastErosion, _ = manaCalculator.ManaOfTransferDiscrete(49, 0, 1)
-	assert.Equal(t, mana, uint64(4))
-	assert.Equal(t, lastErosion, uint64(0))
+	// 1st case: generate mana by spending two times
+	generatedManaStep1, _ := calculator.GenerateMana(1000, 500)
+	generatedManaStep2, _ := calculator.GenerateMana(1000, 500)
+	generatedManaStep3, _ := calculator.GenerateMana(1000, 500)
 
-	mana, lastErosion, _ = manaCalculator.ManaOfTransferDiscrete(49, 0, 10)
-	assert.Equal(t, mana, uint64(36))
-	assert.Equal(t, lastErosion, uint64(10))
+	// the first "realized" mana part starts decaying while the coins of the 2nd spend are gaining weight again
+	erodedMana1, _ := calculator.ErodeMana(generatedManaStep1, 1000)
+	erodedMana2, _ := calculator.ErodeMana(generatedManaStep2, 500)
 
-	mana, lastErosion, _ = manaCalculator.ManaOfTransferDiscrete(50, 0, 31)
-	assert.Equal(t, mana, uint64(101))
-	assert.Equal(t, lastErosion, uint64(30))
+	// 2nd case: generate mana by spending only once
+	generatedManaWithoutSpends, _ := calculator.GenerateMana(1000, 1500)
 
-	fmt.Println(roundingError)
+	// the two mana values should be equal
+	assert.Equal(t, generatedManaWithoutSpends, erodedMana1+erodedMana2+generatedManaStep3)
 }