code.vegaprotocol.io/vega@v0.79.0/core/collateral/simple_distributor.go (about)

     1  // Copyright (C) 2023 Gobalsky Labs Limited
     2  //
     3  // This program is free software: you can redistribute it and/or modify
     4  // it under the terms of the GNU Affero General Public License as
     5  // published by the Free Software Foundation, either version 3 of the
     6  // License, or (at your option) any later version.
     7  //
     8  // This program is distributed in the hope that it will be useful,
     9  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    10  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    11  // GNU Affero General Public License for more details.
    12  //
    13  // You should have received a copy of the GNU Affero General Public License
    14  // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    15  
    16  package collateral
    17  
    18  import (
    19  	"context"
    20  
    21  	"code.vegaprotocol.io/vega/core/events"
    22  	"code.vegaprotocol.io/vega/core/types"
    23  	"code.vegaprotocol.io/vega/libs/num"
    24  	"code.vegaprotocol.io/vega/logging"
    25  )
    26  
    27  type request struct {
    28  	amount  num.Decimal
    29  	amt     *num.Uint
    30  	request *types.Transfer
    31  }
    32  
    33  type simpleDistributor struct {
    34  	log             *logging.Logger
    35  	marketID        string
    36  	expectCollected *num.Uint
    37  	collected       *num.Uint
    38  	requests        []request
    39  	ts              int64
    40  	lType           types.LossType
    41  }
    42  
    43  func (s *simpleDistributor) LossSocializationEnabled() bool {
    44  	return s.collected.LT(s.expectCollected)
    45  }
    46  
    47  func (s *simpleDistributor) Add(req *types.Transfer) {
    48  	col, exp := num.DecimalFromUint(s.collected), num.DecimalFromUint(s.expectCollected)
    49  	amount := num.DecimalFromUint(req.Amount.Amount).Mul(col.Div(exp)).Floor()
    50  	amt, _ := num.UintFromBig(amount.BigInt())
    51  	s.requests = append(s.requests, request{
    52  		amount:  amount,
    53  		amt:     amt,
    54  		request: req,
    55  	})
    56  }
    57  
    58  func (s *simpleDistributor) Run(ctx context.Context) []events.Event {
    59  	if s.expectCollected.EQ(s.collected) {
    60  		return nil
    61  	}
    62  
    63  	var (
    64  		total  = num.UintZero()
    65  		evts   = make([]events.Event, 0, len(s.requests))
    66  		evt    *events.LossSoc
    67  		netReq *request
    68  	)
    69  	for _, v := range s.requests {
    70  		total.AddSum(v.amt)
    71  		loss, _ := num.UintZero().Delta(v.amt, v.request.Amount.Amount)
    72  		v.request.Amount.Amount = v.amt.Clone()
    73  		if v.request.Owner == types.NetworkParty {
    74  			v := v
    75  			netReq = &v
    76  		}
    77  		evt = events.NewLossSocializationEvent(ctx, v.request.Owner, s.marketID, loss, true, s.ts, s.lType)
    78  		s.log.Warn("loss socialization missing funds to be distributed",
    79  			logging.String("party-id", evt.PartyID()),
    80  			logging.BigInt("amount", evt.Amount()),
    81  			logging.String("market-id", evt.MarketID()))
    82  		evts = append(evts, evt)
    83  	}
    84  
    85  	if total.NEQ(s.collected) {
    86  		mismatch, _ := total.Delta(s.collected, total)
    87  		if netReq != nil {
    88  			netReq.request.Amount.Amount.AddSum(mismatch)
    89  			return evts
    90  		}
    91  		// last one get the remaining bits
    92  		s.requests[len(s.requests)-1].request.Amount.Amount.AddSum(mismatch)
    93  		// if the remainder > the loss amount, this rounding error was profitable
    94  		// so the loss socialisation event should be flagged as profit
    95  		// profit will be true if the shortfall < mismatch amount
    96  		loss, profit := mismatch.Delta(evt.Amount().U, mismatch)
    97  		evts[len(evts)-1] = events.NewLossSocializationEvent(
    98  			evt.Context(),
    99  			evt.PartyID(),
   100  			evt.MarketID(),
   101  			loss,
   102  			!profit, // true if party still lost out, false if mismatch > shortfall
   103  			s.ts,
   104  			s.lType,
   105  		)
   106  	}
   107  	return evts
   108  }