Skip to content

Commit

Permalink
Creator Fees, Add P_I Into Market Pool But Not Payout, Reflecting Cre…
Browse files Browse the repository at this point in the history
…ator Fee Amount (#163)

* Update, remove old server, adding updated prod.

* Attempting to fix mechanics by referencing setup package for economics, however this appears to have caused an error in adduser.go:52

* Fix how appConfig was loaded in initial user creation.

* Fixing market mechanics, allowing fee of 10 for market creation. Market subsidization included in probabilities.
  • Loading branch information
pwdel authored Jun 4, 2024
1 parent c127f92 commit 8760eed
Show file tree
Hide file tree
Showing 12 changed files with 165 additions and 117 deletions.
19 changes: 14 additions & 5 deletions backend/handlers/admin/adduser.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package adminhandlers
import (
"encoding/json"
"fmt"
"log"
"math/rand"
"net/http"
"regexp"
Expand All @@ -15,6 +16,17 @@ import (
"gorm.io/gorm"
)

// appConfig holds the loaded application configuration accessible within the package
var appConfig *setup.EconomicConfig

func init() {
var err error
appConfig, err = setup.LoadEconomicsConfig()
if err != nil {
log.Fatalf("Failed to load configuration: %v", err)
}
}

func AddUserHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Method not supported", http.StatusMethodNotAllowed)
Expand All @@ -41,16 +53,13 @@ func AddUserHandler(w http.ResponseWriter, r *http.Request) {

var user models.User

// load the config constants
config := setup.LoadEconomicsConfig()

user = models.User{
Username: req.Username,
DisplayName: util.UniqueDisplayName(db),
Email: util.UniqueEmail(db),
UserType: "REGULAR",
InitialAccountBalance: config.Economics.User.InitialAccountBalance,
AccountBalance: config.Economics.User.InitialAccountBalance,
InitialAccountBalance: appConfig.Economics.User.InitialAccountBalance,
AccountBalance: appConfig.Economics.User.InitialAccountBalance,
PersonalEmoji: randomEmoji(),
ApiKey: util.GenerateUniqueApiKey(db),
MustChangePassword: true,
Expand Down
31 changes: 0 additions & 31 deletions backend/handlers/bets/betutils/betutils.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,13 @@ package betutils
import (
"errors"
"socialpredict/models"
"socialpredict/setup"
"time"

"gorm.io/gorm"
)

// AppConfig holds the application-wide configuration
type AppConfig struct {
InitialMarketProbability float64
InitialMarketSubsidization int64
// user stuff
MaximumDebtAllowed int64
InitialAccountBalance int64
// betting stuff
MinimumBet int64
BetFee int64
SellSharesFee int64
}

var Appconfig AppConfig

func init() {
// Load configuration
config := setup.LoadEconomicsConfig()

// Populate the appConfig struct
Appconfig = AppConfig{
// market stuff
InitialMarketProbability: config.Economics.MarketCreation.InitialMarketProbability,
InitialMarketSubsidization: config.Economics.MarketCreation.InitialMarketSubsidization,
// user stuff
MaximumDebtAllowed: config.Economics.User.MaximumDebtAllowed,
InitialAccountBalance: config.Economics.User.InitialAccountBalance,
// betting stuff
MinimumBet: config.Economics.Betting.MinimumBet,
BetFee: config.Economics.Betting.BetFee,
SellSharesFee: config.Economics.Betting.SellSharesFee,
}
}

// CheckMarketStatus checks if the market is resolved or closed.
Expand Down
15 changes: 14 additions & 1 deletion backend/handlers/bets/placebethandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,28 @@ package betshandlers

import (
"encoding/json"
"log"
"net/http"
betutils "socialpredict/handlers/bets/betutils"
"socialpredict/logging"
"socialpredict/middleware"
"socialpredict/models"
"socialpredict/setup"
"socialpredict/util"
"time"
)

// appConfig holds the loaded application configuration accessible within the package
var appConfig *setup.EconomicConfig

func init() {
var err error
appConfig, err = setup.LoadEconomicsConfig()
if err != nil {
log.Fatalf("Failed to load configuration: %v", err)
}
}

func PlaceBetHandler(w http.ResponseWriter, r *http.Request) {
// Only allow POST requests
if r.Method != http.MethodPost {
Expand Down Expand Up @@ -39,7 +52,7 @@ func PlaceBetHandler(w http.ResponseWriter, r *http.Request) {

// Check if the user has enough balance to place the bet
// Use the appConfig for configuration values
maximumDebtAllowed := betutils.Appconfig.MaximumDebtAllowed
maximumDebtAllowed := appConfig.Economics.User.MaximumDebtAllowed

// Check if the user's balance after the bet would be lower than the allowed maximum debt
// deduct fee in case of switching sides
Expand Down
36 changes: 36 additions & 0 deletions backend/handlers/markets/createmarket.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,25 @@ import (
"io/ioutil"
"log"
"net/http"
"socialpredict/logging"
"socialpredict/middleware"
"socialpredict/models"
"socialpredict/setup"
"socialpredict/util"
)

// appConfig holds the loaded application configuration accessible within the package
var appConfig *setup.EconomicConfig

func init() {
// Load configuration
var err error
appConfig, err = setup.LoadEconomicsConfig()
if err != nil {
log.Fatalf("Failed to load configuration: %v", err)
}
}

func checkQuestionTitleLength(title string) error {
if len(title) > 160 || len(title) < 1 {
return errors.New("Question Title exceeds 160 characters or is blank")
Expand Down Expand Up @@ -70,6 +84,28 @@ func CreateMarketHandler(w http.ResponseWriter, r *http.Request) {
return
}

// Subtract any Market Creation Fees from Creator, up to maximum debt
marketCreateFee := appConfig.Economics.MarketIncentives.CreateMarketCost
maximumDebtAllowed := appConfig.Economics.User.MaximumDebtAllowed

// Maximum debt allowed check
if user.AccountBalance-marketCreateFee < -maximumDebtAllowed {
http.Error(w, "Insufficient balance", http.StatusBadRequest)
return
}

// deduct fee
logging.LogAnyType(user.AccountBalance, "user.AccountBalance before")
// Deduct the bet and switching sides fee amount from the user's balance
user.AccountBalance -= marketCreateFee
logging.LogAnyType(user.AccountBalance, "user.AccountBalance after")

// Update the user's balance in the database
if err := db.Save(&user).Error; err != nil {
http.Error(w, "Error updating user balance: "+err.Error(), http.StatusInternalServerError)
return
}

// Create the market in the database
result := db.Create(&newMarket)
if result.Error != nil {
Expand Down
27 changes: 26 additions & 1 deletion backend/handlers/math/market/marketvolume.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,26 @@
package marketmath

import "socialpredict/models"
import (
"log"
"socialpredict/models"
"socialpredict/setup"
)

// appConfig holds the loaded application configuration accessible within the package
var appConfig *setup.EconomicConfig

func init() {
// Load configuration
var err error
appConfig, err = setup.LoadEconomicsConfig()
if err != nil {
log.Fatalf("Failed to load configuration: %v", err)
}
}

// getMarketVolume returns the total volume of trades for a given market
func GetMarketVolume(bets []models.Bet) int64 {

var totalVolume int64
for _, bet := range bets {
totalVolume += bet.Amount
Expand All @@ -13,3 +30,11 @@ func GetMarketVolume(bets []models.Bet) int64 {

return totalVolumeUint
}

// returns the market volume + subsidization added into pool,
// subsidzation in pool could be paid out after resolution but not sold mid-market
func GetEndMarketVolume(bets []models.Bet) int64 {

return GetEndMarketVolume(bets) + appConfig.Economics.MarketCreation.InitialMarketSubsidization

}
16 changes: 15 additions & 1 deletion backend/handlers/math/outcomes/dbpm/dbpm_marketshares.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package dbpm

import (
"fmt"
"log"
"math"
marketmath "socialpredict/handlers/math/market"
"socialpredict/handlers/math/probabilities/wpam"
"socialpredict/logging"
"socialpredict/models"
"socialpredict/setup"
)

// holds betting payout information
Expand All @@ -21,6 +23,17 @@ type MarketPosition struct {
YesSharesOwned int64
}

// appConfig holds the loaded application configuration accessible within the package
var appConfig *setup.EconomicConfig

func init() {
var err error
appConfig, err = setup.LoadEconomicsConfig()
if err != nil {
log.Fatalf("Failed to load configuration: %v", err)
}
}

// DivideUpMarketPoolShares divides the market pool into YES and NO pools based on the resolution probability.
// See README/README-MATH-PROB-AND-PAYOUT.md#market-outcome-update-formulae---divergence-based-payout-model-dbpm
func DivideUpMarketPoolSharesDBPM(bets []models.Bet, probabilityChanges []wpam.ProbabilityChange) (int64, int64) {
Expand All @@ -33,7 +46,8 @@ func DivideUpMarketPoolSharesDBPM(bets []models.Bet, probabilityChanges []wpam.P
logging.LogAnyType(R, "R")

// Get the total share pool S as a float for precision
S := float64(marketmath.GetMarketVolume(bets))
// Include the initial market subsidization in the displayed volume
S := float64(marketmath.GetMarketVolume(bets) + appConfig.Economics.MarketCreation.InitialMarketSubsidization)
logging.LogAnyType(S, "S")

// initial condition, shares set to zero
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package wpam

import (
"socialpredict/logging"
"log"
"socialpredict/models"
"socialpredict/setup"
"time"
Expand All @@ -12,59 +12,27 @@ type ProbabilityChange struct {
Timestamp time.Time `json:"timestamp"`
}

// AppConfig holds the application-wide configuration
type AppConfig struct {
InitialMarketProbability float64
InitialMarketSubsidization int64
InitialMarketYes int64
InitialMarketNo int64
CreateMarketCost int64
TraderBonus int64
// user stuff
MaximumDebtAllowed int64
InitialAccountBalance int64
// betting stuff
MinimumBet int64
BetFee int64
SellSharesFee int64
}

var appConfig AppConfig
// appConfig holds the loaded application configuration accessible within the package
var appConfig *setup.EconomicConfig

func init() {
// Load configuration
config := setup.LoadEconomicsConfig()

// Populate the appConfig struct
appConfig = AppConfig{
// market stuff
InitialMarketProbability: config.Economics.MarketCreation.InitialMarketProbability,
InitialMarketSubsidization: config.Economics.MarketCreation.InitialMarketSubsidization,
InitialMarketYes: config.Economics.MarketCreation.InitialMarketYes,
InitialMarketNo: config.Economics.MarketCreation.InitialMarketNo,
CreateMarketCost: config.Economics.MarketIncentives.CreateMarketCost,
TraderBonus: config.Economics.MarketIncentives.TraderBonus,
// user stuff
MaximumDebtAllowed: config.Economics.User.MaximumDebtAllowed,
InitialAccountBalance: config.Economics.User.InitialAccountBalance,
// betting stuff
MinimumBet: config.Economics.Betting.MinimumBet,
BetFee: config.Economics.Betting.BetFee,
SellSharesFee: config.Economics.Betting.SellSharesFee,
var err error
appConfig, err = setup.LoadEconomicsConfig()
if err != nil {
log.Fatalf("Failed to load configuration: %v", err)
}
}

// Modify calculateMarketProbabilities to accept bets directly
// See README/README-MATH-PROB-AND-PAYOUT.md#wpam-formula-for-updating-market-probability
// CalculateMarketProbabilitiesWPAM calculates and returns the probability changes based on bets.
func CalculateMarketProbabilitiesWPAM(marketCreatedAtTime time.Time, bets []models.Bet) []ProbabilityChange {

var probabilityChanges []ProbabilityChange

// Initial state
P_initial := appConfig.InitialMarketProbability
I_initial := appConfig.InitialMarketSubsidization
totalYes := appConfig.InitialMarketYes
totalNo := appConfig.InitialMarketNo
// Initial state using values from appConfig
P_initial := appConfig.Economics.MarketCreation.InitialMarketProbability
I_initial := appConfig.Economics.MarketCreation.InitialMarketSubsidization
totalYes := appConfig.Economics.MarketCreation.InitialMarketYes
totalNo := appConfig.Economics.MarketCreation.InitialMarketNo

// Add initial state
probabilityChanges = append(probabilityChanges, ProbabilityChange{Probability: P_initial, Timestamp: marketCreatedAtTime})
Expand All @@ -81,7 +49,5 @@ func CalculateMarketProbabilitiesWPAM(marketCreatedAtTime time.Time, bets []mode
probabilityChanges = append(probabilityChanges, ProbabilityChange{Probability: newProbability, Timestamp: bet.PlacedAt})
}

logging.LogAnyType(probabilityChanges, "probabilityChanges")

return probabilityChanges
}
13 changes: 9 additions & 4 deletions backend/seed/seed.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,10 @@ import (

func SeedUsers(db *gorm.DB) {

// load the config constants
config := setup.LoadEconomicsConfig()
config, err := setup.LoadEconomicsConfig()
if err != nil {
log.Fatalf("Failed to load configuration: %v", err)
}

// Specific time: October 31st, 2023 at 11:59 PM CST
loc, err := time.LoadLocation("America/Chicago") // CST location
Expand Down Expand Up @@ -61,8 +63,11 @@ func SeedMarket(db *gorm.DB) {
}
specificTime := time.Date(2023, time.November, 1, 23, 59, 0, 0, loc)

// load the config constants
config := setup.LoadEconomicsConfig()
config, err := setup.LoadEconomicsConfig()
if err != nil {
log.Fatalf("Failed to load configuration: %v", err)
}

// Use the config as needed
initialProbability := config.Economics.MarketCreation.InitialMarketProbability

Expand Down
2 changes: 1 addition & 1 deletion backend/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
func Start() {
// CORS handler
c := cors.New(cors.Options{
AllowedOrigins: []string{"http://172.29.0.10:5173/", "https://brierfoxforecast.ngrok.app", "http://localhost:8089"},
AllowedOrigins: []string{"http://172.29.0.10:5173/", "http://localhost:8089"},
AllowedMethods: []string{"GET", "POST", "OPTIONS"},
AllowedHeaders: []string{"Content-Type", "Authorization"},
})
Expand Down
Loading

0 comments on commit 8760eed

Please sign in to comment.