-
Notifications
You must be signed in to change notification settings - Fork 181
/
refund.go
107 lines (86 loc) · 3.07 KB
/
refund.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
package refund
import (
"math/big"
"github.com/okex/exchain/libs/cosmos-sdk/x/auth/ante"
"github.com/okex/exchain/libs/cosmos-sdk/x/auth/keeper"
"github.com/okex/exchain/libs/cosmos-sdk/x/auth/refund"
sdk "github.com/okex/exchain/libs/cosmos-sdk/types"
sdkerrors "github.com/okex/exchain/libs/cosmos-sdk/types/errors"
"github.com/okex/exchain/libs/cosmos-sdk/x/auth"
"github.com/okex/exchain/libs/cosmos-sdk/x/auth/types"
evmtypes "github.com/okex/exchain/x/evm/types"
)
func NewGasRefundHandler(ak auth.AccountKeeper, sk types.SupplyKeeper) sdk.GasRefundHandler {
return func(
ctx sdk.Context, tx sdk.Tx,
) (refundFee sdk.Coins, err error) {
var gasRefundHandler sdk.GasRefundHandler
switch tx.(type) {
case evmtypes.MsgEthereumTx:
gasRefundHandler = NewGasRefundDecorator(ak, sk)
default:
return nil, nil
}
return gasRefundHandler(ctx, tx)
}
}
type Handler struct {
ak keeper.AccountKeeper
supplyKeeper types.SupplyKeeper
}
func (handler Handler) GasRefund(ctx sdk.Context, tx sdk.Tx) (refundGasFee sdk.Coins, err error) {
currentGasMeter := ctx.GasMeter()
TempGasMeter := sdk.NewInfiniteGasMeter()
ctx = ctx.WithGasMeter(TempGasMeter)
defer func() {
ctx = ctx.WithGasMeter(currentGasMeter)
}()
gasLimit := currentGasMeter.Limit()
gasUsed := currentGasMeter.GasConsumed()
if gasUsed >= gasLimit {
return nil, nil
}
feeTx, ok := tx.(ante.FeeTx)
if !ok {
return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "Tx must be a FeeTx")
}
feePayer := feeTx.FeePayer(ctx)
feePayerAcc := handler.ak.GetAccount(ctx, feePayer)
if feePayerAcc == nil {
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownAddress, "fee payer address: %s does not exist", feePayer)
}
gas := feeTx.GetGas()
fees := feeTx.GetFee()
gasFees := caculateRefundFees(ctx, gasUsed, gas, fees)
err = refund.RefundFees(handler.supplyKeeper, ctx, feePayerAcc.GetAddress(), gasFees)
if err != nil {
return nil, err
}
return gasFees, nil
}
func NewGasRefundDecorator(ak auth.AccountKeeper, sk types.SupplyKeeper) sdk.GasRefundHandler {
chandler := Handler{
ak: ak,
supplyKeeper: sk,
}
return func(ctx sdk.Context, tx sdk.Tx) (refund sdk.Coins, err error) {
return chandler.GasRefund(ctx, tx)
}
}
func caculateRefundFees(ctx sdk.Context, gasUsed uint64, gas uint64, fees sdk.DecCoins) sdk.Coins {
refundFees := make(sdk.Coins, len(fees))
for i, fee := range fees {
gasPrice := new(big.Int).Div(fee.Amount.BigInt(), new(big.Int).SetUint64(gas))
gasConsumed := new(big.Int).Mul(gasPrice, new(big.Int).SetUint64(gasUsed))
gasCost := sdk.NewCoin(fee.Denom, sdk.NewDecFromBigIntWithPrec(gasConsumed, sdk.Precision))
gasRefund := fee.Sub(gasCost)
refundFees[i] = gasRefund
}
return refundFees
}
// CaculateRefundFees provides the way to calculate the refunded gas with gasUsed, fees and gasPrice,
// as refunded gas = fees - gasPrice * gasUsed
func CaculateRefundFees(ctx sdk.Context, gasUsed uint64, fees sdk.DecCoins, gasPrice *big.Int) sdk.Coins {
gas := new(big.Int).Div(fees[0].Amount.BigInt(), gasPrice).Uint64()
return caculateRefundFees(ctx, gasUsed, gas, fees)
}