func DepositMoneyForUser(user *auth.User, coin string, amount uint64) { err := db.DoBeginSerializable(func(tx *db.ModelTx) { account.UpdateBalanceByWallet(tx, user.Id, account.WALLET_MAIN, coin, int64(amount), false) }) if err != nil { panic(err) } }
// Funds are reserved by moving them to the account.WALLET_RESERVED_ORDER wallet when // the order is saved to the DB. // If there aren't enough funds, the order isn't saved, and an error is returned. // The returned error.Error() is a front-end message. func SaveAndReserveFundsForOrder(order *Order) { err := db.DoBeginSerializable(func(tx *db.ModelTx) { // Save the order, get the id SaveOrder(tx, order) // Reserve the funds if order.Type == ORDER_TYPE_BID { account.UpdateBalanceByWallet(tx, order.UserId, account.WALLET_MAIN, order.BasisCoin, -int64(order.BasisAmount+order.BasisFee), true) account.UpdateBalanceByWallet(tx, order.UserId, account.WALLET_RESERVED_ORDER, order.BasisCoin, int64(order.BasisAmount+order.BasisFee), false) } else { account.UpdateBalanceByWallet(tx, order.UserId, account.WALLET_MAIN, order.Coin, -int64(order.Amount), true) account.UpdateBalanceByWallet(tx, order.UserId, account.WALLET_RESERVED_ORDER, order.Coin, int64(order.Amount), false) } }) if err != nil { panic(err) } }
func injectMoneyForUsers(users []*auth.User, coins []string) { Info("Injecting money for each user") for _, user := range users { for _, coin := range coins { err := db.DoBeginSerializable(func(tx *db.ModelTx) { account.UpdateBalanceByWallet(tx, user.Id, account.WALLET_MAIN, coin, int64(100000000000000), false) }) if err != nil { panic(err) } } } Info("Done injecting money for each user") }
func ReleaseReservedFundsForOrder(tx *db.ModelTx, order *Order) { if order.Status != ORDER_STATUS_COMPLETE && order.Status != ORDER_STATUS_CANCELED { panic(NewError("Cannot release reserved funds for order that isn't complete nor canceled: %v", order.Id)) } if order.Type == ORDER_TYPE_BID { bid := order bidReleaseBasis := (bid.BasisAmount - bid.BasisFilled) + (bid.BasisFee - bid.BasisFeeFilled) if bidReleaseBasis > 0 { account.UpdateBalanceByWallet(tx, bid.UserId, account.WALLET_RESERVED_ORDER, bid.BasisCoin, -int64(bidReleaseBasis), true) account.UpdateBalanceByWallet(tx, bid.UserId, account.WALLET_MAIN, bid.BasisCoin, int64(bidReleaseBasis), false) } } else if order.Type == ORDER_TYPE_ASK { ask := order askReleaseAmount := ask.Amount - ask.Filled if askReleaseAmount > 0 { account.UpdateBalanceByWallet(tx, ask.UserId, account.WALLET_RESERVED_ORDER, ask.Coin, -int64(askReleaseAmount), true) account.UpdateBalanceByWallet(tx, ask.UserId, account.WALLET_MAIN, ask.Coin, int64(askReleaseAmount), false) } } else { panic(NewError("Unexpected order type %v", order.Type)) } }
// Returns false if no withdrawals are available to process. func ProcessUserWithdrawals(coin string) (bool, error) { // Checkout withdrawals // TODO: Gather multiple small withdrawals. wths := account.CheckoutWithdrawals(coin, 1) if len(wths) == 0 { return false, nil } wthIds := Map(wths, "Id") amounts := map[string]uint64{} amountSum := uint64(0) for _, wth := range wths { if wth.Amount <= 0 { panic(NewError("Invalid send amount %v", wth.Amount)) } amounts[wth.ToAddress] += uint64(wth.Amount) amountSum += uint64(wth.Amount) } // figure out which payments to use. signedTx, payments, minerFees, chgAddress, err := ComputeWithdrawalTransaction(coin, amounts) if err != nil { account.StallWithdrawals(wthIds) return false, err } paymentIds := Map(payments, "Id") // save withdrawal info for bookkeeping. wthTx := SaveWithdrawalTx(&WithdrawalTx{ Coin: coin, Type: WITHDRAWAL_TX_TYPE_WITHDRAWAL, Amount: amountSum, MinerFee: minerFees, ChgAddress: chgAddress, RawTx: signedTx, TxId: bitcoin.ComputeTxId(signedTx), }) // checkout those payments. bitcoin.CheckoutPaymentsToSpend(paymentIds, wthTx.Id) // TODO: the Tx should go out to our partners who sign them for us. // TODO: receive the signed Tx. // deduct change amount from system user's "change" wallet. // this creates a negative balance, which will revert to zero // when the change is received. if chgAddress != "" { changeAmount := amounts[chgAddress] err := db.DoBeginSerializable(func(tx *db.ModelTx) { account.UpdateBalanceByWallet(tx, 0, account.WALLET_CHANGE, coin, -int64(changeAmount), false) }) if err != nil { panic(err) } } // broadcast transaction. rpc.SendRawTransaction(coin, signedTx) // update payments as spent. bitcoin.MarkPaymentsAsSpent(paymentIds, wthTx.Id) // update withdrawals as complete. account.CompleteWithdrawals(wths, wthTx.Id) return true, nil }