Skip to content

Commit

Permalink
feat: tax exemption update (#137)
Browse files Browse the repository at this point in the history
Co-authored-by: nghuyenthevinh2000 <[email protected]>
  • Loading branch information
inon-man and nghuyenthevinh2000 authored Feb 20, 2023
1 parent 1bedd43 commit 649f7c4
Show file tree
Hide file tree
Showing 12 changed files with 423 additions and 265 deletions.
3 changes: 0 additions & 3 deletions app/encoding.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package app

import (
"fmt"

"github.com/cosmos/cosmos-sdk/codec/legacy"
"github.com/cosmos/cosmos-sdk/std"

Expand All @@ -13,7 +11,6 @@ var legacyCodecRegistered = false

// MakeEncodingConfig creates an EncodingConfig for testing
func MakeEncodingConfig() params.EncodingConfig {
fmt.Println("Invoke codeql")
encodingConfig := params.MakeEncodingConfig()
std.RegisterLegacyAminoCodec(encodingConfig.Amino)
std.RegisterInterfaces(encodingConfig.InterfaceRegistry)
Expand Down
4 changes: 2 additions & 2 deletions custom/auth/ante/ante.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,14 +57,14 @@ func NewAnteHandler(options HandlerOptions) (sdk.AnteHandler, error) {
cosmosante.NewSetUpContextDecorator(), // outermost AnteDecorator. SetUpContext must be called first
cosmosante.NewRejectExtensionOptionsDecorator(),
NewSpammingPreventionDecorator(options.OracleKeeper), // spamming prevention
NewTaxFeeDecorator(options.TreasuryKeeper), // mempool gas fee validation & record tax proceeds
cosmosante.NewValidateBasicDecorator(),
NewTaxFeeDecorator(options.TreasuryKeeper), // mempool gas fee validation & record tax proceeds
cosmosante.NewTxTimeoutHeightDecorator(),
cosmosante.NewValidateMemoDecorator(options.AccountKeeper),
cosmosante.NewConsumeGasForTxSizeDecorator(options.AccountKeeper),
cosmosante.NewDeductFeeDecorator(options.AccountKeeper, options.BankKeeper, options.FeegrantKeeper),
NewBurnTaxFeeDecorator(options.AccountKeeper, options.TreasuryKeeper, options.BankKeeper, options.DistributionKeeper), // burn tax proceeds
cosmosante.NewSetPubKeyDecorator(options.AccountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators
cosmosante.NewSetPubKeyDecorator(options.AccountKeeper), // SetPubKeyDecorator must be called before all signature verification decorators
cosmosante.NewValidateSigCountDecorator(options.AccountKeeper),
cosmosante.NewSigGasConsumeDecorator(options.AccountKeeper, sigGasConsumer),
NewSigVerificationDecorator(options.AccountKeeper, options.SignModeHandler),
Expand Down
11 changes: 9 additions & 2 deletions custom/auth/ante/ante_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
"github.com/cosmos/cosmos-sdk/simapp"
simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/tx/signing"
Expand Down Expand Up @@ -63,13 +64,19 @@ func (suite *AnteTestSuite) SetupTest(isCheckTx bool) {
suite.ctx = suite.ctx.WithBlockHeight(1)

// Set up TxConfig.
encodingConfig := suite.SetupEncoding()

suite.clientCtx = client.Context{}.
WithTxConfig(encodingConfig.TxConfig)
}

func (suite *AnteTestSuite) SetupEncoding() simappparams.EncodingConfig {
encodingConfig := simapp.MakeTestEncodingConfig()
// We're using TestMsg encoding in some tests, so register it here.
encodingConfig.Amino.RegisterConcrete(&testdata.TestMsg{}, "testdata.TestMsg", nil)
testdata.RegisterInterfaces(encodingConfig.InterfaceRegistry)

suite.clientCtx = client.Context{}.
WithTxConfig(encodingConfig.TxConfig)
return encodingConfig
}

// CreateTestTx is a helper function to create a tx given multiple inputs.
Expand Down
61 changes: 0 additions & 61 deletions custom/auth/ante/burntax.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
cosmosante "github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/cosmos/cosmos-sdk/x/auth/types"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
)

// TaxPowerUpgradeHeight is when taxes are allowed to go into effect
Expand Down Expand Up @@ -55,66 +54,6 @@ func (btfd BurnTaxFeeDecorator) AnteHandle(ctx sdk.Context, tx sdk.Tx, simulate

// Record tax proceeds
if !taxes.IsZero() {
tainted := false

// Iterate over messages
for _, msg := range msgs {
var recipients []string
var senders []string

// Fetch recipients
switch v := msg.(type) {
case *banktypes.MsgSend:
recipients = append(recipients, v.ToAddress)
senders = append(senders, v.FromAddress)
case *banktypes.MsgMultiSend:
for _, output := range v.Outputs {
recipients = append(recipients, output.Address)
}

for _, input := range v.Inputs {
senders = append(senders, input.Address)
}
default:
// TODO: We might want to return an error if we cannot match the msg types, but as such I think that means we also need to cover MsgSetSendEnabled & MsgUpdateParams
// return ctx, sdkerrors.Wrap(sdkerrors.ErrInvalidType, "Unsupported message type")
}

// Match senders vs. burn tax exemption list
exemptionCount := 0

for _, sender := range senders {
if btfd.treasuryKeeper.HasBurnTaxExemptionAddress(ctx, sender) {
exemptionCount++
}
}

// If all signers are not matched apply burn tax
if len(senders) > exemptionCount {
tainted = true
break
}

// Check recipients
exemptionCount = 0

for _, recipient := range recipients {
if btfd.treasuryKeeper.HasBurnTaxExemptionAddress(ctx, recipient) {
exemptionCount++
}
}

// If all recipients are not matched apply burn tax
if len(recipients) > exemptionCount {
tainted = true
break
}
}

if !tainted {
return next(ctx, tx, simulate)
}

burnSplitRate := btfd.treasuryKeeper.GetBurnSplitRate(ctx)

if burnSplitRate.IsPositive() {
Expand Down
185 changes: 0 additions & 185 deletions custom/auth/ante/burntax_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ import (

"github.com/classic-terra/core/custom/auth/ante"
core "github.com/classic-terra/core/types"
treasury "github.com/classic-terra/core/x/treasury/types"
"github.com/cosmos/cosmos-sdk/types/query"
cosmosante "github.com/cosmos/cosmos-sdk/x/auth/ante"
"github.com/cosmos/cosmos-sdk/x/auth/types"
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
)
Expand Down Expand Up @@ -133,186 +131,3 @@ func (suite *AnteTestSuite) DeductFees(sendAmount int64) sdk.Coins {

return taxes
}

// the following binance addresses should not be applied tax
// go test -v -run ^TestAnteTestSuite/TestFilterRecipient$ github.com/classic-terra/core/custom/auth/ante
func (suite *AnteTestSuite) TestFilterRecipient() {
// keys and addresses
var privs []cryptotypes.PrivKey
var addrs []sdk.AccAddress

// 0, 1: binance
// 2, 3: normal
for i := 0; i < 4; i++ {
priv, _, addr := testdata.KeyTestPubAddr()
privs = append(privs, priv)
addrs = append(addrs, addr)
}

// set send amount
sendAmt := int64(1000000)
sendCoin := sdk.NewInt64Coin(core.MicroSDRDenom, sendAmt)
feeAmt := int64(1000)

cases := []struct {
name string
msgSigner cryptotypes.PrivKey
msgCreator func() []sdk.Msg
burnAmount int64
feeAmount int64
}{
{
name: "MsgSend(binance -> binance)",
msgSigner: privs[0],
msgCreator: func() []sdk.Msg {
var msgs []sdk.Msg

msg1 := banktypes.NewMsgSend(addrs[0], addrs[1], sdk.NewCoins(sendCoin))
msgs = append(msgs, msg1)

return msgs
},
// skip this one hence burn amount is 0
burnAmount: 0,
feeAmount: feeAmt,
}, {
name: "MsgSend(normal -> normal)",
msgSigner: privs[2],
msgCreator: func() []sdk.Msg {
var msgs []sdk.Msg

msg1 := banktypes.NewMsgSend(addrs[2], addrs[3], sdk.NewCoins(sendCoin))
msgs = append(msgs, msg1)

return msgs
},
// tax this one hence burn amount is fee amount
burnAmount: feeAmt / 2,
feeAmount: feeAmt,
}, {
name: "MsgSend(binance -> normal), MsgSend(binance -> binance)",
msgSigner: privs[0],
msgCreator: func() []sdk.Msg {
var msgs []sdk.Msg

msg1 := banktypes.NewMsgSend(addrs[0], addrs[2], sdk.NewCoins(sendCoin))
msgs = append(msgs, msg1)
msg2 := banktypes.NewMsgSend(addrs[0], addrs[1], sdk.NewCoins(sendCoin))
msgs = append(msgs, msg2)

return msgs
},
// tax this one hence burn amount is fee amount
burnAmount: (feeAmt * 2) / 2,
feeAmount: feeAmt * 2,
}, {
name: "MsgSend(binance -> binance), MsgMultiSend(binance -> normal, binance -> binance)",
msgSigner: privs[0],
msgCreator: func() []sdk.Msg {
var msgs []sdk.Msg

msg1 := banktypes.NewMsgSend(addrs[0], addrs[1], sdk.NewCoins(sendCoin))
msgs = append(msgs, msg1)
msg2 := banktypes.NewMsgMultiSend(
[]banktypes.Input{
{
Address: addrs[0].String(),
Coins: sdk.NewCoins(sendCoin),
},
{
Address: addrs[0].String(),
Coins: sdk.NewCoins(sendCoin),
},
},
[]banktypes.Output{
{
Address: addrs[2].String(),
Coins: sdk.NewCoins(sendCoin),
},
{
Address: addrs[1].String(),
Coins: sdk.NewCoins(sendCoin),
},
},
)
msgs = append(msgs, msg2)

return msgs
},
// tax this one hence burn amount is fee amount
burnAmount: (feeAmt * 3) / 2,
feeAmount: feeAmt * 3,
},
}

// there should be no coin in burn module
for _, c := range cases {
suite.SetupTest(true) // setup
require := suite.Require()
tk := suite.app.TreasuryKeeper
ak := suite.app.AccountKeeper
bk := suite.app.BankKeeper

// Set burn split rate to 50%
tk.SetBurnSplitRate(suite.ctx, sdk.NewDecWithPrec(5, 1))

fmt.Printf("CASE = %s \n", c.name)
suite.ctx = suite.ctx.WithBlockHeight(ante.TaxPowerUpgradeHeight)
suite.txBuilder = suite.clientCtx.TxConfig.NewTxBuilder()

tk.AddBurnTaxExemptionAddress(suite.ctx, addrs[0].String())
tk.AddBurnTaxExemptionAddress(suite.ctx, addrs[1].String())

mfd := ante.NewBurnTaxFeeDecorator(ak, tk, bk, suite.app.DistrKeeper)
antehandler := sdk.ChainAnteDecorators(
cosmosante.NewDeductFeeDecorator(ak, bk, suite.app.FeeGrantKeeper),
mfd,
)

for i := 0; i < 4; i++ {
fundCoins := sdk.NewCoins(sdk.NewInt64Coin(core.MicroSDRDenom, 1000000000))
acc := ak.NewAccountWithAddress(suite.ctx, addrs[i])
ak.SetAccount(suite.ctx, acc)
bk.MintCoins(suite.ctx, minttypes.ModuleName, fundCoins)
bk.SendCoinsFromModuleToAccount(suite.ctx, minttypes.ModuleName, addrs[i], fundCoins)
}

// msg and signatures
feeAmount := sdk.NewCoins(sdk.NewInt64Coin(core.MicroSDRDenom, c.feeAmount))
gasLimit := testdata.NewTestGasLimit()
require.NoError(suite.txBuilder.SetMsgs(c.msgCreator()...))
suite.txBuilder.SetFeeAmount(feeAmount)
suite.txBuilder.SetGasLimit(gasLimit)

privs, accNums, accSeqs := []cryptotypes.PrivKey{c.msgSigner}, []uint64{0}, []uint64{0}
tx, err := suite.CreateTestTx(privs, accNums, accSeqs, suite.ctx.ChainID())
require.NoError(err)

// check fee decorator and burn module amount before ante handler
feeCollector := ak.GetModuleAccount(suite.ctx, types.FeeCollectorName)
burnModule := ak.GetModuleAccount(suite.ctx, treasury.BurnModuleName)

amountFeeBefore := bk.GetBalance(suite.ctx, feeCollector.GetAddress(), core.MicroSDRDenom)
amountBurnBefore := bk.GetBalance(suite.ctx, burnModule.GetAddress(), core.MicroSDRDenom)
amountCommunityBefore := suite.app.DistrKeeper.GetFeePool(suite.ctx).CommunityPool.AmountOf(core.MicroSDRDenom)
fmt.Printf("before: fee = %v, burn = %v, community = %v\n", amountFeeBefore, amountFeeBefore, amountCommunityBefore)

_, err = antehandler(suite.ctx, tx, false)
require.NoError(err)

// check fee decorator
amountFee := bk.GetBalance(suite.ctx, feeCollector.GetAddress(), core.MicroSDRDenom)
amountBurn := bk.GetBalance(suite.ctx, burnModule.GetAddress(), core.MicroSDRDenom)
amountCommunity := suite.app.DistrKeeper.GetFeePool(suite.ctx).CommunityPool.AmountOf(core.MicroSDRDenom)
fmt.Printf("after : fee = %v, burn = %v, community = %v\n", amountFee, amountBurn, amountCommunity)

if c.burnAmount > 0 {
require.Equal(amountBurnBefore.Amount.Add(sdk.NewInt(c.burnAmount)), amountBurn.Amount)
require.Equal(amountFeeBefore, amountFee)
require.Equal(amountCommunity, amountBurn.Amount.ToDec())
} else {
require.Equal(amountBurnBefore, amountBurn)
require.Equal(amountFeeBefore.Amount.Add(sdk.NewInt(c.feeAmount)), amountFee.Amount)
}
}
}
2 changes: 1 addition & 1 deletion custom/auth/ante/expected_keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ type TreasuryKeeper interface {
GetTaxRate(ctx sdk.Context) (taxRate sdk.Dec)
GetTaxCap(ctx sdk.Context, denom string) (taxCap sdk.Int)
GetBurnSplitRate(ctx sdk.Context) sdk.Dec
HasBurnTaxExemptionAddress(ctx sdk.Context, address string) bool
HasBurnTaxExemptionAddress(ctx sdk.Context, addresses ...string) bool
}

// OracleKeeper for feeder validation
Expand Down
Loading

0 comments on commit 649f7c4

Please sign in to comment.