github.com/filecoin-project/specs-actors/v4@v4.0.2/actors/builtin/market/market_balances.go (about) 1 package market 2 3 import ( 4 addr "github.com/filecoin-project/go-address" 5 "github.com/filecoin-project/go-state-types/abi" 6 "github.com/filecoin-project/go-state-types/big" 7 "github.com/filecoin-project/go-state-types/exitcode" 8 "golang.org/x/xerrors" 9 ) 10 11 func (m *marketStateMutation) lockClientAndProviderBalances(proposal *DealProposal) error { 12 if err := m.maybeLockBalance(proposal.Client, proposal.ClientBalanceRequirement()); err != nil { 13 return xerrors.Errorf("failed to lock client funds: %w", err) 14 } 15 if err := m.maybeLockBalance(proposal.Provider, proposal.ProviderCollateral); err != nil { 16 return xerrors.Errorf("failed to lock provider funds: %w", err) 17 } 18 19 m.totalClientLockedCollateral = big.Add(m.totalClientLockedCollateral, proposal.ClientCollateral) 20 m.totalClientStorageFee = big.Add(m.totalClientStorageFee, proposal.TotalStorageFee()) 21 m.totalProviderLockedCollateral = big.Add(m.totalProviderLockedCollateral, proposal.ProviderCollateral) 22 return nil 23 } 24 25 func (m *marketStateMutation) unlockBalance(addr addr.Address, amount abi.TokenAmount, lockReason BalanceLockingReason) error { 26 if amount.LessThan(big.Zero()) { 27 return xerrors.Errorf("unlock negative amount %v", amount) 28 } 29 30 err := m.lockedTable.MustSubtract(addr, amount) 31 if err != nil { 32 return xerrors.Errorf("subtracting from locked balance: %w", err) 33 } 34 35 switch lockReason { 36 case ClientCollateral: 37 m.totalClientLockedCollateral = big.Sub(m.totalClientLockedCollateral, amount) 38 case ClientStorageFee: 39 m.totalClientStorageFee = big.Sub(m.totalClientStorageFee, amount) 40 case ProviderCollateral: 41 m.totalProviderLockedCollateral = big.Sub(m.totalProviderLockedCollateral, amount) 42 } 43 44 return nil 45 } 46 47 // move funds from locked in client to available in provider 48 func (m *marketStateMutation) transferBalance(fromAddr addr.Address, toAddr addr.Address, amount abi.TokenAmount) error { 49 if amount.LessThan(big.Zero()) { 50 return xerrors.Errorf("transfer negative amount %v", amount) 51 } 52 if err := m.escrowTable.MustSubtract(fromAddr, amount); err != nil { 53 return xerrors.Errorf("subtract from escrow: %w", err) 54 } 55 if err := m.unlockBalance(fromAddr, amount, ClientStorageFee); err != nil { 56 return xerrors.Errorf("subtract from locked: %w", err) 57 } 58 if err := m.escrowTable.Add(toAddr, amount); err != nil { 59 return xerrors.Errorf("add to escrow: %w", err) 60 } 61 return nil 62 } 63 64 func (m *marketStateMutation) slashBalance(addr addr.Address, amount abi.TokenAmount, reason BalanceLockingReason) error { 65 if amount.LessThan(big.Zero()) { 66 return xerrors.Errorf("negative amount to slash: %v", amount) 67 } 68 69 if err := m.escrowTable.MustSubtract(addr, amount); err != nil { 70 return xerrors.Errorf("subtract from escrow: %v", err) 71 } 72 73 return m.unlockBalance(addr, amount, reason) 74 } 75 76 func (m *marketStateMutation) maybeLockBalance(addr addr.Address, amount abi.TokenAmount) error { 77 if amount.LessThan(big.Zero()) { 78 return xerrors.Errorf("cannot lock negative amount %v", amount) 79 } 80 81 prevLocked, err := m.lockedTable.Get(addr) 82 if err != nil { 83 return xerrors.Errorf("failed to get locked balance: %w", err) 84 } 85 86 escrowBalance, err := m.escrowTable.Get(addr) 87 if err != nil { 88 return xerrors.Errorf("failed to get escrow balance: %w", err) 89 } 90 91 if big.Add(prevLocked, amount).GreaterThan(escrowBalance) { 92 return exitcode.ErrInsufficientFunds.Wrapf("insufficient balance for addr %s: escrow balance %s < locked %s + required %s", 93 addr, escrowBalance, prevLocked, amount) 94 } 95 96 if err := m.lockedTable.Add(addr, amount); err != nil { 97 return xerrors.Errorf("failed to add locked balance: %w", err) 98 } 99 return nil 100 }