-
Notifications
You must be signed in to change notification settings - Fork 55
/
escrow.go
84 lines (76 loc) · 2.26 KB
/
escrow.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)
type Escrow struct {
escrowAddr sdk.AccAddress
deltas map[string]sdk.DecCoins // string(addr) => delta
addrs []sdk.AccAddress // for ordered access on deltas
}
func NewEscrow(escrowAddr sdk.AccAddress) *Escrow {
return &Escrow{
escrowAddr: escrowAddr,
deltas: map[string]sdk.DecCoins{},
}
}
func (e *Escrow) Lock(addr sdk.AccAddress, amt ...sdk.DecCoin) {
saddr := addr.String()
before, ok := e.deltas[saddr]
if !ok {
e.addrs = append(e.addrs, addr)
}
e.deltas[saddr], _ = before.SafeSub(amt)
}
func (e *Escrow) Unlock(addr sdk.AccAddress, amt ...sdk.DecCoin) {
saddr := addr.String()
before, ok := e.deltas[saddr]
if !ok {
e.addrs = append(e.addrs, addr)
}
e.deltas[saddr] = before.Add(amt...)
}
func (e *Escrow) Pays(addr sdk.AccAddress) sdk.Coins {
var pays sdk.Coins
for _, decCoin := range e.deltas[addr.String()] {
if decCoin.IsNegative() {
coin := sdk.NewCoin(decCoin.Denom, decCoin.Amount.Neg().Ceil().TruncateInt())
pays = pays.Add(coin)
}
}
return pays
}
func (e *Escrow) Receives(addr sdk.AccAddress) sdk.Coins {
var receives sdk.Coins
for _, decCoin := range e.deltas[addr.String()] {
if decCoin.IsPositive() {
coin, _ := decCoin.TruncateDecimal()
receives = receives.Add(coin)
}
}
return receives
}
func (e *Escrow) Transact(ctx sdk.Context, bankKeeper BankKeeper) error {
escrow := e.escrowAddr.String()
var (
payInputs, receiveInputs []banktypes.Input
payOutputs, receiveOutputs []banktypes.Output
)
for _, addr := range e.addrs {
saddr := addr.String()
pays := e.Pays(addr)
receives := e.Receives(addr)
if !pays.IsZero() {
payInputs = append(payInputs, banktypes.Input{Address: saddr, Coins: pays})
payOutputs = append(payOutputs, banktypes.Output{Address: escrow, Coins: pays})
}
if !receives.IsZero() {
receiveInputs = append(receiveInputs, banktypes.Input{Address: escrow, Coins: receives})
receiveOutputs = append(receiveOutputs, banktypes.Output{Address: saddr, Coins: receives})
}
}
if err := bankKeeper.InputOutputCoins(ctx, payInputs, payOutputs); err != nil {
return err
}
return bankKeeper.InputOutputCoins(ctx, receiveInputs, receiveOutputs)
}