-
Notifications
You must be signed in to change notification settings - Fork 168
/
ante.go
120 lines (101 loc) · 3.63 KB
/
ante.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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
package ante
import (
wasmtypes "github.com/CosmWasm/wasmd/x/wasm/types"
errorsmod "cosmossdk.io/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
feeshare "github.com/CosmosContracts/juno/v16/x/feeshare/types"
)
// FeeSharePayoutDecorator Run his after we already deduct the fee from the account with
// the ante.NewDeductFeeDecorator() decorator. We pull funds from the FeeCollector ModuleAccount
type FeeSharePayoutDecorator struct {
bankKeeper BankKeeper
feesharekeeper FeeShareKeeper
}
func NewFeeSharePayoutDecorator(bk BankKeeper, fs FeeShareKeeper) FeeSharePayoutDecorator {
return FeeSharePayoutDecorator{
bankKeeper: bk,
feesharekeeper: fs,
}
}
func (fsd FeeSharePayoutDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate bool, next sdk.AnteHandler) (newCtx sdk.Context, err error) {
feeTx, ok := tx.(sdk.FeeTx)
if !ok {
return ctx, errorsmod.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
}
err = FeeSharePayout(ctx, fsd.bankKeeper, feeTx.GetFee(), fsd.feesharekeeper, tx.GetMsgs())
if err != nil {
return ctx, errorsmod.Wrapf(sdkerrors.ErrInsufficientFunds, err.Error())
}
return next(ctx, tx, simulate)
}
// FeePayLogic takes the total fees and splits them based on the governance params
// and the number of contracts we are executing on.
// This returns the amount of fees each contract developer should get.
// tested in ante_test.go
func FeePayLogic(fees sdk.Coins, govPercent sdk.Dec, numPairs int) sdk.Coins {
var splitFees sdk.Coins
for _, c := range fees.Sort() {
rewardAmount := govPercent.MulInt(c.Amount).QuoInt64(int64(numPairs)).RoundInt()
if !rewardAmount.IsZero() {
splitFees = splitFees.Add(sdk.NewCoin(c.Denom, rewardAmount))
}
}
return splitFees
}
// FeeSharePayout takes the total fees and redistributes 50% (or param set) to the contract developers
// provided they opted-in to payments.
func FeeSharePayout(ctx sdk.Context, bankKeeper BankKeeper, totalFees sdk.Coins, revKeeper FeeShareKeeper, msgs []sdk.Msg) error {
params := revKeeper.GetParams(ctx)
if !params.EnableFeeShare {
return nil
}
// Get valid withdraw addresses from contracts
toPay := make([]sdk.AccAddress, 0)
for _, msg := range msgs {
if _, ok := msg.(*wasmtypes.MsgExecuteContract); ok {
contractAddr, err := sdk.AccAddressFromBech32(msg.(*wasmtypes.MsgExecuteContract).Contract)
if err != nil {
return err
}
shareData, _ := revKeeper.GetFeeShare(ctx, contractAddr)
withdrawAddr := shareData.GetWithdrawerAddr()
if withdrawAddr != nil && !withdrawAddr.Empty() {
toPay = append(toPay, withdrawAddr)
}
}
}
// Do nothing if no one needs payment
if len(toPay) == 0 {
return nil
}
// Get only allowed governance fees to be paid (helps for taxes)
var fees sdk.Coins
if len(params.AllowedDenoms) == 0 {
// If empty, we allow all denoms to be used as payment
fees = totalFees
} else {
for _, fee := range totalFees.Sort() {
for _, allowed := range params.AllowedDenoms {
if fee.Denom == allowed {
fees = fees.Add(fee)
}
}
}
}
// FeeShare logic payouts for contracts
numPairs := len(toPay)
if numPairs > 0 {
govPercent := params.DeveloperShares
splitFees := FeePayLogic(fees, govPercent, numPairs)
// pay fees evenly between all withdraw addresses
for _, withdrawAddr := range toPay {
err := bankKeeper.SendCoinsFromModuleToAccount(ctx, authtypes.FeeCollectorName, withdrawAddr, splitFees)
if err != nil {
return errorsmod.Wrapf(feeshare.ErrFeeSharePayment, "failed to pay fees to contract developer: %s", err.Error())
}
}
}
return nil
}