fix: replace float to int in gas operations

This commit is contained in:
Mihail Pestrikov 2025-01-22 20:43:06 +00:00
parent f4b35ec399
commit 74e9a0e7f5

View file

@ -28,11 +28,12 @@ const (
)
const (
createRoomCommission = 4
joinRoomCommission = 2
sendAnswerCommission = 1
gamePrizePoolCommission = 0.2
userCommission = 0.7
createRoomCommission = 4_0000_0000
joinRoomCommission = 2_0000_0000
sendAnswerCommission = 1_0000_0000
gamePrizePoolCommission = 2000_0000
userCommission = 7000_0000
oneGas = 1_0000_0000
)
// STRUCTS
@ -41,8 +42,8 @@ type Room struct {
Id string
Host interop.Hash160
Status string
GamePrizePool float64
RoundPrizePool float64
GamePrizePool int
RoundPrizePool int
RoundWinnersCount int
GameWinnersCount int
Players []Player
@ -70,7 +71,7 @@ type Player struct {
}
// --data '{"m": "0xabc123...", "n": "0xdef456..."}'
func _deploy(data any, isUpdate bool) {
func _deploy(data interface{}, isUpdate bool) {
if isUpdate {
return
}
@ -159,9 +160,15 @@ func sendRewardRoundWinners(ctx storage.Context, room *Room, wonAnswers []Answer
totalVotes += len(answer.Votes)
}
if totalVotes == 0 {
runtime.Log("No votes, skipping reward distribution")
return
}
for _, answer := range wonAnswers {
// reward = pool * weight * userCommission
var reward = int(pool * float64(len(answer.Votes)) / float64(totalVotes) * userCommission)
// + totalVotes/2 is rounding used in integer division to minimize loss of precision
var reward = (pool*len(answer.Votes)*userCommission + totalVotes/2) / totalVotes / oneGas
var result = contract.Call(getMoneyContractHash(ctx), "RewardPlayer", contract.All, answer.Wallet, reward).(bool)
sendMessageToPlayers(
@ -170,7 +177,7 @@ func sendRewardRoundWinners(ctx storage.Context, room *Room, wonAnswers []Answer
}
// After receiving all the rewards, the remaining part of the pool remains with the host.
// Reward for host = pool - pool * 70% (and the float64 inaccuracy)
// Reward for host = pool - pool * 70% (and the integer precision inaccuracy)
room.RoundPrizePool = 0
setRoom(ctx, room)
}
@ -179,9 +186,15 @@ func sendRewardGameWinners(ctx storage.Context, room *Room, wonPlayers []Player)
var pool = room.GamePrizePool
var totalRounds = len(room.Rounds)
if totalRounds == 0 {
runtime.Log("No rounds played, skipping reward distribution")
return
}
for _, player := range wonPlayers {
// reward = pool * weight * userCommission
var reward = int(pool * float64(player.RoundsWon/totalRounds) * userCommission)
// + totalRounds/2 is rounding used in integer division to minimize loss of precision
var reward = (pool*player.RoundsWon*userCommission + totalRounds/2) / totalRounds / oneGas
var result = contract.Call(getMoneyContractHash(ctx), "RewardPlayer", contract.All, player.Wallet, reward).(bool)
sendMessageToPlayers(
@ -190,7 +203,7 @@ func sendRewardGameWinners(ctx storage.Context, room *Room, wonPlayers []Player)
}
// After receiving all the rewards, the remaining part of the pool remains with the host.
// Reward for host = pool - pool * 70% (and the float64 inaccuracy)
// Reward for host = pool - pool * 70% (and the integer precision inaccuracy)
room.GamePrizePool = 0
setRoom(ctx, room)
}
@ -202,7 +215,7 @@ func CreateRoom(RoundWinnersCount int, GameWinnersCount int) string {
var id = uuid.NewString()
var host = getSender()
var withdraw = contract.Call(getMoneyContractHash(ctx), "HostWithdrawal", contract.All, createRoomCommission).(bool)
var withdraw = contract.Call(getMoneyContractHash(ctx), "Deposit", contract.All, host, createRoomCommission).(bool)
if !withdraw {
panic("Host does not have enough tokens to create a room")
}
@ -238,7 +251,7 @@ func JoinRoom(roomId string) bool {
}
}
var withdraw = contract.Call(getMoneyContractHash(ctx), "PlayerDeposit", contract.All, wallet, joinRoomCommission).(bool)
var withdraw = contract.Call(getMoneyContractHash(ctx), "Deposit", contract.All, wallet, joinRoomCommission).(bool)
if !withdraw {
panic("Player does not have enough tokens to join in room")
}
@ -353,7 +366,7 @@ func SendAnswer(roomId string, text string) bool {
return false // Only player can send content, player must be active, room status must be answering
}
var withdraw = contract.Call(getMoneyContractHash(ctx), "PlayerDeposit", contract.All, wallet, sendAnswerCommission).(bool)
var withdraw = contract.Call(getMoneyContractHash(ctx), "Deposit", contract.All, wallet, sendAnswerCommission).(bool)
if !withdraw {
panic("Player does not have enough tokens to send answer")
}
@ -484,7 +497,6 @@ func chooseWonAnswers(round Round, RoundWinnersCount int) []Answer {
return wonAnswers
}
// GetRoundWinner todo: Разные реализации распределения наград можно реализовать в контракте с деньгами
func GetRoundWinner(roomId string) bool {
var ctx = storage.GetContext()
var room = getRoom(ctx, roomId)
@ -617,8 +629,7 @@ func finishGame(ctx storage.Context, room *Room) bool {
sendMessageToPlayers("FinishGame", result)
sendRewardGameWinners(ctx, room, winners)
// Награда хосту остается на кошельке money_contract.go, с которого он может снять деньги на свой личный кошелек
// (хочется ли как-то делать проверку, чтобы он не мог снять во время игры деньги?....)
// Host reward remains on the money_contract.go wallet, from which he can withdraw money to his personal wallet.
room.Status = StatusFinished
setRoom(ctx, room)