terra-money / classic-core

GO implementation of the Terra Protocol
https://www.terra.money
Other
980 stars 287 forks source link

TIP # 47 Remove Treasury module #740

Closed yun-yeo closed 2 years ago

yun-yeo commented 2 years ago

TIP #: 47

Author: TFL Network: v0.6.x Date:

Summary

Remove the treasury module as it is no longer being used.

Motivation

The tax rate is 0 as of [proposal 172](https://station.terra.money/proposal/172) and the tax logic is no longer used in the protocol. Tax income during usage was negligible, and there is no need for future usage of this tax. Pruning unnecessary logic will keep the Terra core lean and easier to navigate.

Tech Spec

Modules:

Overview

Deprecate tax logic. Remove seigniorage and burn logic from Treasury. New logic will be made in the Market module.

Method

  1. Remove all treasury implementation.
  2. Add store upgrade logic to delete all module state.
  3. Implement legacy querier interface for wasm contracts.

Code

Store Upgrade Logic:

// NewTerraApp returns a reference to an initialized TerraApp.
func NewTerraApp(...){
    ...

    if upgradeInfo.Name == upgradeName && !app.UpgradeKeeper.IsSkipHeight(upgradeInfo.Height) {
        storeUpgrades := store.StoreUpgrades{
            Deleted: []string{legacytreasury.ModuleName},
        }

        // configure store loader that checks if version == upgradeHeight and applies store upgrades
        app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades))
    }

    ...
}

Implement legacy querier for stargate query:

// Query - implement query function
func (querier StargateWasmQuerier) Query(...) ([]byte, error) {
    ...

    // handle legacy queriers
    if bz, err := legacytreasury.QueryLegacyTreasury(request.Stargate.Path); bz != nil || err != nil {
        return bz, err
    }

    ...
}
// QueryLegacyTreasury return empty response for backward compatibility
func QueryLegacyTreasury(path string) (bz []byte, err error) {
    switch path {
    case "/terra.treasury.v1beta1.Query/TaxRate":
        bz, err = protoCodec.Marshal(&QueryTaxRateResponse{TaxRate: sdk.ZeroDec()})
    case "/terra.treasury.v1beta1.Query/TaxCap":
        bz, err = protoCodec.Marshal(&QueryTaxCapResponse{TaxCap: sdk.ZeroInt()})
    case "/terra.treasury.v1beta1.Query/TaxCaps":
        var taxCaps []QueryTaxCapsResponseItem
        bz, err = protoCodec.Marshal(&QueryTaxCapsResponse{TaxCaps: taxCaps})
    case "/terra.treasury.v1beta1.Query/RewardWeight":
        bz, err = protoCodec.Marshal(&QueryRewardWeightResponse{RewardWeight: sdk.ZeroDec()})
    case "/terra.treasury.v1beta1.Query/SeigniorageProceeds":
        bz, err = protoCodec.Marshal(&QuerySeigniorageProceedsResponse{SeigniorageProceeds: sdk.ZeroInt()})
    case "/terra.treasury.v1beta1.Query/TaxProceeds":
        bz, err = protoCodec.Marshal(&QueryTaxProceedsResponse{TaxProceeds: sdk.Coins{}})
    case "/terra.treasury.v1beta1.Query/Indicators":
        bz, err = protoCodec.Marshal(&QueryIndicatorsResponse{
            TRLYear:  sdk.ZeroDec(),
            TRLMonth: sdk.ZeroDec(),
        })
    case "/terra.treasury.v1beta1.Query/Params":
        bz, err = protoCodec.Marshal(&QueryParamsResponse{Params: DefaultParams()})
    }

    return bz, err
}

Implement legacy querier for wasm query binding:

// QueryCustom implements custom query interface
func (querier WasmQuerier) QueryCustom(ctx sdk.Context, data json.RawMessage) ([]byte, error) {
    var query CosmosQuery
    err := json.Unmarshal(data, &query)

    if err != nil {
        return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
    }

    var bz []byte

    if query.TaxRate != nil {
        rate := sdk.ZeroDec()
        bz, err = json.Marshal(TaxRateQueryResponse{Rate: rate.String()})
    } else if query.TaxCap != nil {
        cap := sdk.ZeroInt()
        bz, err = json.Marshal(TaxCapQueryResponse{Cap: cap.String()})
    } else {
        return nil, sdkerrors.ErrInvalidRequest
    }

    if err != nil {
        return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
    }

    return bz, nil
}

Considerations

For backward compatibility for wasm contracts, treasury queriers will remain and return default values. This information can only be accessed by the wasm contracts:

// Default Values
var (
    DefaultTaxPolicy = PolicyConstraints{
        RateMin:       sdk.ZeroDec(),
        RateMax:       sdk.ZeroDec(),
        Cap:           sdk.NewCoin(core.MicroSDRDenom, sdk.ZeroInt()),
        ChangeRateMax: sdk.ZeroDec(),
    }
    DefaultRewardPolicy = PolicyConstraints{
        RateMin:       sdk.ZeroDec(),
        RateMax:       sdk.ZeroDec(),
        Cap:           sdk.NewCoin("unused", sdk.ZeroInt()),
        ChangeRateMax: sdk.ZeroDec(),
    }
    DefaultSeigniorageBurdenTarget = sdk.ZeroDec()
    DefaultMiningIncrement         = sdk.ZeroDec()
    DefaultWindowShort             = uint64(0)
    DefaultWindowLong              = uint64(0)
    DefaultWindowProbation         = uint64(0)
    DefaultTaxRate                 = sdk.ZeroDec()
    DefaultRewardWeight            = sdk.ZeroDec()
)

// DefaultParams creates default treasury module parameters
func DefaultParams() Params {
    return Params{
        TaxPolicy:               DefaultTaxPolicy,
        RewardPolicy:            DefaultRewardPolicy,
        SeigniorageBurdenTarget: DefaultSeigniorageBurdenTarget,
        MiningIncrement:         DefaultMiningIncrement,
        WindowShort:             DefaultWindowShort,
        WindowLong:              DefaultWindowLong,
        WindowProbation:         DefaultWindowProbation,
    }
}

Timeline

NA

Test cases

  1. TestLegacyQuerier_TreasuryQueryBinding ensures the ability to query treasury state via query binding:
func TestLegacyQuerier_TreasuryQueryBinding(t *testing.T) {
    input, _, testerAddr, _ := setupBindingsTesterContract(t)
    ctx, keeper := input.Ctx, input.WasmKeeper

    // can query tax rate
    taxRate := sdk.ZeroDec()
    taxRateQueryMsg := bindingsTesterTaxRateQueryMsg{
        TaxRate: taxRateQueryMsg{},
    }

    bz, err := json.Marshal(taxRateQueryMsg)
    require.NoError(t, err)

    res, err := keeper.queryToContract(ctx, testerAddr, bz)
    require.NoError(t, err)

    var taxRateResponse treasurylegacy.TaxRateQueryResponse
    err = json.Unmarshal(res, &taxRateResponse)
    require.NoError(t, err)

    taxRateDec, err := sdk.NewDecFromStr(taxRateResponse.Rate)
    require.NoError(t, err)
    require.Equal(t, taxRate, taxRateDec)

    // can query tax cap
    taxCap := sdk.ZeroInt()
    taxCapQueryMsg := bindingsTesterTaxCapQueryMsg{
        TaxCap: taxCapQueryMsg{
            Denom: core.MicroSDRDenom,
        },
    }

    bz, err = json.Marshal(taxCapQueryMsg)
    require.NoError(t, err)

    res, err = keeper.queryToContract(ctx, testerAddr, bz)
    require.NoError(t, err)

    var taxCapResponse treasurylegacy.TaxCapQueryResponse
    err = json.Unmarshal(res, &taxCapResponse)
    require.NoError(t, err)
    require.Equal(t, taxCap.String(), taxCapResponse.Cap)
}
  1. TestLegacyQuerier_StargateQuery ensures the ability to query treasury state via Stargate query:
func TestLegacyQuerier_StargateQuery(t *testing.T) {
    input, _, testerAddr, _ := setupReflectContract(t)
    ctx, keeper := input.Ctx, input.WasmKeeper

    // can query tax rate

    // build request bytes
    protoQuery := treasurylegacy.QueryTaxRateRequest{}
    protoQueryBin, err := proto.Marshal(&protoQuery)
    protoRequest := wasmvmtypes.QueryRequest{
        Stargate: &wasmvmtypes.StargateQuery{
            Path: "/terra.treasury.v1beta1.Query/TaxRate",
            Data: protoQueryBin,
        },
    }
    protoQueryBz, err := json.Marshal(ReflectQueryMsg{
        Chain: &ChainQuery{Request: &protoRequest},
    })
    require.NoError(t, err)

    // let the contract query to chain
    protoRes, err := keeper.queryToContract(ctx, contractAddr, protoQueryBz)
    require.NoError(t, err)

    // parse proto response
    var protoChain ChainResponse
    mustParse(t, protoRes, &protoChain)

    // unmarshal raw protobuf response
    var protoResult treasurylegacy.QueryTaxRateResponse
    err = proto.Unmarshal(protoChain.Data, &protoResult)
    require.NoError(t, err)
    assert.Equal(t, sdk.ZeroDec(), protoResult.TaxRate)

    // can query tax cap

    // build request bytes
    // now, try to build a protobuf query
    protoQuery = treasurylegacy.QueryTaxCapRequest{Denom: "uusd"}
    protoQueryBin, err = proto.Marshal(&protoQuery)
    protoRequest = wasmvmtypes.QueryRequest{
        Stargate: &wasmvmtypes.StargateQuery{
            Path: "/terra.treasury.v1beta1.Query/TaxCap",
            Data: protoQueryBin,
        },
    }
    protoQueryBz, err = json.Marshal(ReflectQueryMsg{
        Chain: &ChainQuery{Request: &protoRequest},
    })
    require.NoError(t, err)

    // let the contract query to chain
    protoRes, err = keeper.queryToContract(ctx, contractAddr, protoQueryBz)
    require.NoError(t, err)

    // parse proto response
    var protoChain ChainResponse
    mustParse(t, protoRes, &protoChain)

    // unmarshal raw protobuf response
    var protoResult legacytreasury.QueryTaxCapResponse
    err = proto.Unmarshal(protoChain.Data, &protoResult)
    require.NoError(t, err)
    assert.Equal(t, sdk.ZeroInt(), protoResult.TaxCap)
}