[R4R] bump SDK version to v0.38.3 (#421)

* bump SDK version to v0.38.3

Co-authored-by: Denali Marsh <denali@kava.io>
Co-authored-by: Kevin Davis <kjydavis3@gmail.com>
Co-authored-by: Kevin Davis <karzak@users.noreply.github.com>
Co-authored-by: denalimarsh <denalimarsh@gmail.com>
Co-authored-by: rhuairahrighairigh <ruaridh.odonnell@gmail.com>
This commit is contained in:
Federico Kunze 2020-04-23 12:35:58 -04:00 committed by GitHub
parent 0949a912cf
commit a573625df8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
140 changed files with 3247 additions and 2875 deletions

View File

@ -12,12 +12,13 @@ import (
validatorvesting "github.com/kava-labs/kava/x/validator-vesting" validatorvesting "github.com/kava-labs/kava/x/validator-vesting"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/libs/log"
tmos "github.com/tendermint/tendermint/libs/os"
dbm "github.com/tendermint/tm-db" dbm "github.com/tendermint/tm-db"
bam "github.com/cosmos/cosmos-sdk/baseapp" bam "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/simapp"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/version"
@ -26,6 +27,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/crisis" "github.com/cosmos/cosmos-sdk/x/crisis"
distr "github.com/cosmos/cosmos-sdk/x/distribution" distr "github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/evidence"
"github.com/cosmos/cosmos-sdk/x/genutil" "github.com/cosmos/cosmos-sdk/x/genutil"
"github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/mint" "github.com/cosmos/cosmos-sdk/x/mint"
@ -61,6 +63,7 @@ var (
crisis.AppModuleBasic{}, crisis.AppModuleBasic{},
slashing.AppModuleBasic{}, slashing.AppModuleBasic{},
supply.AppModuleBasic{}, supply.AppModuleBasic{},
evidence.AppModuleBasic{},
auction.AppModuleBasic{}, auction.AppModuleBasic{},
cdp.AppModuleBasic{}, cdp.AppModuleBasic{},
pricefeed.AppModuleBasic{}, pricefeed.AppModuleBasic{},
@ -86,7 +89,10 @@ var (
} }
) )
// Extended ABCI application // Verify app interface at compile time
var _ simapp.App = (*App)(nil)
// App represents an extended ABCI application
type App struct { type App struct {
*bam.BaseApp *bam.BaseApp
cdc *codec.Codec cdc *codec.Codec
@ -108,6 +114,7 @@ type App struct {
govKeeper gov.Keeper govKeeper gov.Keeper
crisisKeeper crisis.Keeper crisisKeeper crisis.Keeper
paramsKeeper params.Keeper paramsKeeper params.Keeper
evidenceKeeper evidence.Keeper
vvKeeper validatorvesting.Keeper vvKeeper validatorvesting.Keeper
auctionKeeper auction.Keeper auctionKeeper auction.Keeper
cdpKeeper cdp.Keeper cdpKeeper cdp.Keeper
@ -136,7 +143,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
keys := sdk.NewKVStoreKeys( keys := sdk.NewKVStoreKeys(
bam.MainStoreKey, auth.StoreKey, staking.StoreKey, bam.MainStoreKey, auth.StoreKey, staking.StoreKey,
supply.StoreKey, mint.StoreKey, distr.StoreKey, slashing.StoreKey, supply.StoreKey, mint.StoreKey, distr.StoreKey, slashing.StoreKey,
gov.StoreKey, params.StoreKey, validatorvesting.StoreKey, gov.StoreKey, params.StoreKey, evidence.StoreKey, validatorvesting.StoreKey,
auction.StoreKey, cdp.StoreKey, pricefeed.StoreKey, bep3.StoreKey, auction.StoreKey, cdp.StoreKey, pricefeed.StoreKey, bep3.StoreKey,
kavadist.StoreKey, kavadist.StoreKey,
) )
@ -151,7 +158,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
} }
// init params keeper and subspaces // init params keeper and subspaces
app.paramsKeeper = params.NewKeeper(app.cdc, keys[params.StoreKey], tkeys[params.TStoreKey], params.DefaultCodespace) app.paramsKeeper = params.NewKeeper(app.cdc, keys[params.StoreKey], tkeys[params.TStoreKey])
authSubspace := app.paramsKeeper.Subspace(auth.DefaultParamspace) authSubspace := app.paramsKeeper.Subspace(auth.DefaultParamspace)
bankSubspace := app.paramsKeeper.Subspace(bank.DefaultParamspace) bankSubspace := app.paramsKeeper.Subspace(bank.DefaultParamspace)
stakingSubspace := app.paramsKeeper.Subspace(staking.DefaultParamspace) stakingSubspace := app.paramsKeeper.Subspace(staking.DefaultParamspace)
@ -159,6 +166,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
distrSubspace := app.paramsKeeper.Subspace(distr.DefaultParamspace) distrSubspace := app.paramsKeeper.Subspace(distr.DefaultParamspace)
slashingSubspace := app.paramsKeeper.Subspace(slashing.DefaultParamspace) slashingSubspace := app.paramsKeeper.Subspace(slashing.DefaultParamspace)
govSubspace := app.paramsKeeper.Subspace(gov.DefaultParamspace).WithKeyTable(gov.ParamKeyTable()) govSubspace := app.paramsKeeper.Subspace(gov.DefaultParamspace).WithKeyTable(gov.ParamKeyTable())
evidenceSubspace := app.paramsKeeper.Subspace(evidence.DefaultParamspace)
crisisSubspace := app.paramsKeeper.Subspace(crisis.DefaultParamspace) crisisSubspace := app.paramsKeeper.Subspace(crisis.DefaultParamspace)
auctionSubspace := app.paramsKeeper.Subspace(auction.DefaultParamspace) auctionSubspace := app.paramsKeeper.Subspace(auction.DefaultParamspace)
cdpSubspace := app.paramsKeeper.Subspace(cdp.DefaultParamspace) cdpSubspace := app.paramsKeeper.Subspace(cdp.DefaultParamspace)
@ -171,51 +179,68 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
app.cdc, app.cdc,
keys[auth.StoreKey], keys[auth.StoreKey],
authSubspace, authSubspace,
auth.ProtoBaseAccount) auth.ProtoBaseAccount,
)
app.bankKeeper = bank.NewBaseKeeper( app.bankKeeper = bank.NewBaseKeeper(
app.accountKeeper, app.accountKeeper,
bankSubspace, bankSubspace,
bank.DefaultCodespace, app.ModuleAccountAddrs(),
app.ModuleAccountAddrs()) )
app.supplyKeeper = supply.NewKeeper( app.supplyKeeper = supply.NewKeeper(
app.cdc, app.cdc,
keys[supply.StoreKey], keys[supply.StoreKey],
app.accountKeeper, app.accountKeeper,
app.bankKeeper, app.bankKeeper,
mAccPerms) mAccPerms,
)
stakingKeeper := staking.NewKeeper( stakingKeeper := staking.NewKeeper(
app.cdc, app.cdc,
keys[staking.StoreKey], keys[staking.StoreKey],
app.supplyKeeper, app.supplyKeeper,
stakingSubspace, stakingSubspace,
staking.DefaultCodespace) )
app.mintKeeper = mint.NewKeeper( app.mintKeeper = mint.NewKeeper(
app.cdc, app.cdc,
keys[mint.StoreKey], keys[mint.StoreKey],
mintSubspace, mintSubspace,
&stakingKeeper, &stakingKeeper,
app.supplyKeeper, app.supplyKeeper,
auth.FeeCollectorName) auth.FeeCollectorName,
)
app.distrKeeper = distr.NewKeeper( app.distrKeeper = distr.NewKeeper(
app.cdc, app.cdc,
keys[distr.StoreKey], keys[distr.StoreKey],
distrSubspace, distrSubspace,
&stakingKeeper, &stakingKeeper,
app.supplyKeeper, app.supplyKeeper,
distr.DefaultCodespace,
auth.FeeCollectorName, auth.FeeCollectorName,
app.ModuleAccountAddrs()) app.ModuleAccountAddrs(),
)
app.slashingKeeper = slashing.NewKeeper( app.slashingKeeper = slashing.NewKeeper(
app.cdc, app.cdc,
keys[slashing.StoreKey], keys[slashing.StoreKey],
&stakingKeeper, &stakingKeeper,
slashingSubspace, slashingSubspace,
slashing.DefaultCodespace) )
app.crisisKeeper = crisis.NewKeeper( app.crisisKeeper = crisis.NewKeeper(
crisisSubspace, crisisSubspace,
invCheckPeriod, invCheckPeriod,
app.supplyKeeper, app.supplyKeeper,
auth.FeeCollectorName) auth.FeeCollectorName,
)
// create evidence keeper with router
evidenceKeeper := evidence.NewKeeper(
app.cdc,
keys[evidence.StoreKey],
evidenceSubspace,
&app.stakingKeeper,
app.slashingKeeper,
)
evidenceRouter := evidence.NewRouter()
evidenceKeeper.SetRouter(evidenceRouter)
app.evidenceKeeper = *evidenceKeeper
govRouter := gov.NewRouter() govRouter := gov.NewRouter()
govRouter. govRouter.
AddRoute(gov.RouterKey, gov.ProposalHandler). AddRoute(gov.RouterKey, gov.ProposalHandler).
@ -227,25 +252,28 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
govSubspace, govSubspace,
app.supplyKeeper, app.supplyKeeper,
&stakingKeeper, &stakingKeeper,
gov.DefaultCodespace, govRouter,
govRouter) )
app.vvKeeper = validatorvesting.NewKeeper( app.vvKeeper = validatorvesting.NewKeeper(
app.cdc, app.cdc,
keys[validatorvesting.StoreKey], keys[validatorvesting.StoreKey],
app.accountKeeper, app.accountKeeper,
app.bankKeeper, app.bankKeeper,
app.supplyKeeper, app.supplyKeeper,
&stakingKeeper) &stakingKeeper,
)
app.pricefeedKeeper = pricefeed.NewKeeper( app.pricefeedKeeper = pricefeed.NewKeeper(
app.cdc, app.cdc,
keys[pricefeed.StoreKey], keys[pricefeed.StoreKey],
pricefeedSubspace, pricefeedSubspace,
pricefeed.DefaultCodespace) )
app.auctionKeeper = auction.NewKeeper( app.auctionKeeper = auction.NewKeeper(
app.cdc, app.cdc,
keys[auction.StoreKey], keys[auction.StoreKey],
app.supplyKeeper, app.supplyKeeper,
auctionSubspace) auctionSubspace,
)
app.cdpKeeper = cdp.NewKeeper( app.cdpKeeper = cdp.NewKeeper(
app.cdc, app.cdc,
keys[cdp.StoreKey], keys[cdp.StoreKey],
@ -254,19 +282,18 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
app.auctionKeeper, app.auctionKeeper,
app.supplyKeeper, app.supplyKeeper,
app.accountKeeper, app.accountKeeper,
cdp.DefaultCodespace) )
app.bep3Keeper = bep3.NewKeeper( app.bep3Keeper = bep3.NewKeeper(
app.cdc, app.cdc,
keys[bep3.StoreKey], keys[bep3.StoreKey],
app.supplyKeeper, app.supplyKeeper,
bep3Subspace, bep3Subspace,
bep3.DefaultCodespace) )
app.kavadistKeeper = kavadist.NewKeeper( app.kavadistKeeper = kavadist.NewKeeper(
app.cdc, app.cdc,
keys[kavadist.StoreKey], keys[kavadist.StoreKey],
kavadistSubspace, kavadistSubspace,
app.supplyKeeper, app.supplyKeeper,
kavadist.DefaultCodespace,
) )
// register the staking hooks // register the staking hooks
@ -282,16 +309,17 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
bank.NewAppModule(app.bankKeeper, app.accountKeeper), bank.NewAppModule(app.bankKeeper, app.accountKeeper),
crisis.NewAppModule(&app.crisisKeeper), crisis.NewAppModule(&app.crisisKeeper),
supply.NewAppModule(app.supplyKeeper, app.accountKeeper), supply.NewAppModule(app.supplyKeeper, app.accountKeeper),
distr.NewAppModule(app.distrKeeper, app.supplyKeeper), gov.NewAppModule(app.govKeeper, app.accountKeeper, app.supplyKeeper),
gov.NewAppModule(app.govKeeper, app.supplyKeeper),
mint.NewAppModule(app.mintKeeper), mint.NewAppModule(app.mintKeeper),
slashing.NewAppModule(app.slashingKeeper, app.stakingKeeper), slashing.NewAppModule(app.slashingKeeper, app.accountKeeper, app.stakingKeeper),
distr.NewAppModule(app.distrKeeper, app.accountKeeper, app.supplyKeeper, app.stakingKeeper),
staking.NewAppModule(app.stakingKeeper, app.accountKeeper, app.supplyKeeper), staking.NewAppModule(app.stakingKeeper, app.accountKeeper, app.supplyKeeper),
evidence.NewAppModule(app.evidenceKeeper),
validatorvesting.NewAppModule(app.vvKeeper, app.accountKeeper), validatorvesting.NewAppModule(app.vvKeeper, app.accountKeeper),
auction.NewAppModule(app.auctionKeeper, app.supplyKeeper), auction.NewAppModule(app.auctionKeeper, app.accountKeeper, app.supplyKeeper),
cdp.NewAppModule(app.cdpKeeper, app.pricefeedKeeper, app.supplyKeeper), cdp.NewAppModule(app.cdpKeeper, app.accountKeeper, app.pricefeedKeeper, app.supplyKeeper),
pricefeed.NewAppModule(app.pricefeedKeeper), pricefeed.NewAppModule(app.pricefeedKeeper, app.accountKeeper),
bep3.NewAppModule(app.bep3Keeper, app.supplyKeeper), bep3.NewAppModule(app.bep3Keeper, app.accountKeeper, app.supplyKeeper),
kavadist.NewAppModule(app.kavadistKeeper, app.supplyKeeper), kavadist.NewAppModule(app.kavadistKeeper, app.supplyKeeper),
) )
@ -306,7 +334,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
auth.ModuleName, // loads all accounts - should run before any module with a module account auth.ModuleName, // loads all accounts - should run before any module with a module account
validatorvesting.ModuleName, distr.ModuleName, validatorvesting.ModuleName, distr.ModuleName,
staking.ModuleName, bank.ModuleName, slashing.ModuleName, staking.ModuleName, bank.ModuleName, slashing.ModuleName,
gov.ModuleName, mint.ModuleName, gov.ModuleName, mint.ModuleName, evidence.ModuleName,
pricefeed.ModuleName, cdp.ModuleName, auction.ModuleName, bep3.ModuleName, kavadist.ModuleName, // TODO is this order ok? pricefeed.ModuleName, cdp.ModuleName, auction.ModuleName, bep3.ModuleName, kavadist.ModuleName, // TODO is this order ok?
supply.ModuleName, // calculates the total supply from account - should run after modules that modify accounts in genesis supply.ModuleName, // calculates the total supply from account - should run after modules that modify accounts in genesis
crisis.ModuleName, // runs the invariants at genesis - should run after other modules crisis.ModuleName, // runs the invariants at genesis - should run after other modules
@ -325,15 +353,15 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
validatorvesting.NewAppModule(app.vvKeeper, app.accountKeeper), validatorvesting.NewAppModule(app.vvKeeper, app.accountKeeper),
bank.NewAppModule(app.bankKeeper, app.accountKeeper), bank.NewAppModule(app.bankKeeper, app.accountKeeper),
supply.NewAppModule(app.supplyKeeper, app.accountKeeper), supply.NewAppModule(app.supplyKeeper, app.accountKeeper),
gov.NewAppModule(app.govKeeper, app.supplyKeeper), gov.NewAppModule(app.govKeeper, app.accountKeeper, app.supplyKeeper),
mint.NewAppModule(app.mintKeeper), mint.NewAppModule(app.mintKeeper),
distr.NewAppModule(app.distrKeeper, app.supplyKeeper), distr.NewAppModule(app.distrKeeper, app.accountKeeper, app.supplyKeeper, app.stakingKeeper),
staking.NewAppModule(app.stakingKeeper, app.accountKeeper, app.supplyKeeper), staking.NewAppModule(app.stakingKeeper, app.accountKeeper, app.supplyKeeper),
slashing.NewAppModule(app.slashingKeeper, app.stakingKeeper), slashing.NewAppModule(app.slashingKeeper, app.accountKeeper, app.stakingKeeper),
pricefeed.NewAppModule(app.pricefeedKeeper), pricefeed.NewAppModule(app.pricefeedKeeper, app.accountKeeper),
cdp.NewAppModule(app.cdpKeeper, app.pricefeedKeeper, app.supplyKeeper), cdp.NewAppModule(app.cdpKeeper, app.accountKeeper, app.pricefeedKeeper, app.supplyKeeper),
auction.NewAppModule(app.auctionKeeper, app.supplyKeeper), auction.NewAppModule(app.auctionKeeper, app.accountKeeper, app.supplyKeeper),
bep3.NewAppModule(app.bep3Keeper, app.supplyKeeper), bep3.NewAppModule(app.bep3Keeper, app.accountKeeper, app.supplyKeeper),
kavadist.NewAppModule(app.kavadistKeeper, app.supplyKeeper), kavadist.NewAppModule(app.kavadistKeeper, app.supplyKeeper),
) )
@ -353,7 +381,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
if loadLatest { if loadLatest {
err := app.LoadLatestVersion(app.keys[bam.MainStoreKey]) err := app.LoadLatestVersion(app.keys[bam.MainStoreKey])
if err != nil { if err != nil {
cmn.Exit(err.Error()) tmos.Exit(err.Error())
} }
} }
@ -422,6 +450,11 @@ func (app *App) Codec() *codec.Codec {
return app.cdc return app.cdc
} }
// SimulationManager implements the SimulationApp interface
func (app *App) SimulationManager() *module.SimulationManager {
return app.sm
}
// GetMaccPerms returns a mapping of the application's module account permissions. // GetMaccPerms returns a mapping of the application's module account permissions.
func GetMaccPerms() map[string][]string { func GetMaccPerms() map[string][]string {
perms := make(map[string][]string) perms := make(map[string][]string)

View File

@ -13,10 +13,9 @@ import (
"github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/staking"
) )
// export the state of the app for a genesis file // ExportAppStateAndValidators export the state of the app for a genesis file
func (app *App) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteList []string) ( func (app *App) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteList []string,
appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) { ) (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
// as if they could withdraw from the start of the next block // as if they could withdraw from the start of the next block
ctx := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()}) ctx := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()})
@ -25,7 +24,6 @@ func (app *App) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteList []
} }
genState := app.mm.ExportGenesis(ctx) genState := app.mm.ExportGenesis(ctx)
appState, err = codec.MarshalJSONIndent(app.cdc, genState) appState, err = codec.MarshalJSONIndent(app.cdc, genState)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -35,6 +33,8 @@ func (app *App) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteList []
} }
// prepare for fresh start at zero height // prepare for fresh start at zero height
// NOTE zero height genesis is a temporary feature which will be deprecated
// in favour of export at a block height
func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []string) { func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []string) {
applyWhiteList := false applyWhiteList := false
@ -60,14 +60,24 @@ func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []string
// withdraw all validator commission // withdraw all validator commission
app.stakingKeeper.IterateValidators(ctx, func(_ int64, val staking.ValidatorI) (stop bool) { app.stakingKeeper.IterateValidators(ctx, func(_ int64, val staking.ValidatorI) (stop bool) {
_, _ = app.distrKeeper.WithdrawValidatorCommission(ctx, val.GetOperator()) accumCommission := app.distrKeeper.GetValidatorAccumulatedCommission(ctx, val.GetOperator())
if accumCommission.IsZero() {
return false
}
_, err := app.distrKeeper.WithdrawValidatorCommission(ctx, val.GetOperator())
if err != nil {
log.Fatal(err)
}
return false return false
}) })
// withdraw all delegator rewards // withdraw all delegator rewards
dels := app.stakingKeeper.GetAllDelegations(ctx) dels := app.stakingKeeper.GetAllDelegations(ctx)
for _, delegation := range dels { for _, delegation := range dels {
_, _ = app.distrKeeper.WithdrawDelegationRewards(ctx, delegation.DelegatorAddress, delegation.ValidatorAddress) _, err := app.distrKeeper.WithdrawDelegationRewards(ctx, delegation.DelegatorAddress, delegation.ValidatorAddress)
if err != nil {
log.Fatal(err)
}
} }
// clear validator slash events // clear validator slash events
@ -86,7 +96,7 @@ func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []string
// donate any unwithdrawn outstanding reward fraction tokens to the community pool // donate any unwithdrawn outstanding reward fraction tokens to the community pool
scraps := app.distrKeeper.GetValidatorOutstandingRewards(ctx, val.GetOperator()) scraps := app.distrKeeper.GetValidatorOutstandingRewards(ctx, val.GetOperator())
feePool := app.distrKeeper.GetFeePool(ctx) feePool := app.distrKeeper.GetFeePool(ctx)
feePool.CommunityPool = feePool.CommunityPool.Add(scraps) feePool.CommunityPool = feePool.CommunityPool.Add(scraps...)
app.distrKeeper.SetFeePool(ctx, feePool) app.distrKeeper.SetFeePool(ctx, feePool)
app.distrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator()) app.distrKeeper.Hooks().AfterValidatorCreated(ctx, val.GetOperator())
@ -128,7 +138,6 @@ func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []string
iter := sdk.KVStoreReversePrefixIterator(store, staking.ValidatorsKey) iter := sdk.KVStoreReversePrefixIterator(store, staking.ValidatorsKey)
counter := int16(0) counter := int16(0)
var valConsAddrs []sdk.ConsAddress
for ; iter.Valid(); iter.Next() { for ; iter.Valid(); iter.Next() {
addr := sdk.ValAddress(iter.Key()[1:]) addr := sdk.ValAddress(iter.Key()[1:])
validator, found := app.stakingKeeper.GetValidator(ctx, addr) validator, found := app.stakingKeeper.GetValidator(ctx, addr)
@ -137,7 +146,6 @@ func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []string
} }
validator.UnbondingHeight = 0 validator.UnbondingHeight = 0
valConsAddrs = append(valConsAddrs, validator.ConsAddress())
if applyWhiteList && !whiteListMap[addr.String()] { if applyWhiteList && !whiteListMap[addr.String()] {
validator.Jailed = true validator.Jailed = true
} }

19
app/params/doc.go Normal file
View File

@ -0,0 +1,19 @@
/*
Package params defines the simulation parameters for the Kava app.
It contains the default weights used for each transaction used on the module's
simulation. These weights define the chance for a transaction to be simulated at
any gived operation.
You can repace the default values for the weights by providing a params.json
file with the weights defined for each of the transaction operations:
{
"op_weight_msg_send": 60,
"op_weight_msg_delegate": 100,
}
In the example above, the `MsgSend` has 60% chance to be simulated, while the
`MsgDelegate` will always be simulated.
*/
package params

15
app/params/params.go Normal file
View File

@ -0,0 +1,15 @@
package params
// Simulation parameter constants
const (
StakePerAccount = "stake_per_account"
InitiallyBondedValidators = "initially_bonded_validators"
)
// Default simulation operation weights for messages and gov proposals
const (
DefaultWeightMsgPlaceBid int = 100
DefaultWeightMsgCreateAtomicSwap int = 100
DefaultWeightMsgUpdatePrices int = 100
DefaultWeightMsgCdp int = 100
)

View File

@ -3,69 +3,35 @@ package app
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil"
"math/rand"
"os" "os"
"testing" "testing"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/libs/log"
dbm "github.com/tendermint/tm-db" dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/simapp"
"github.com/cosmos/cosmos-sdk/simapp/helpers"
"github.com/cosmos/cosmos-sdk/store" "github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth"
authsimops "github.com/cosmos/cosmos-sdk/x/auth/simulation/operations"
banksimops "github.com/cosmos/cosmos-sdk/x/bank/simulation/operations"
distr "github.com/cosmos/cosmos-sdk/x/distribution" distr "github.com/cosmos/cosmos-sdk/x/distribution"
distrsimops "github.com/cosmos/cosmos-sdk/x/distribution/simulation/operations"
"github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/gov"
govsimops "github.com/cosmos/cosmos-sdk/x/gov/simulation/operations"
"github.com/cosmos/cosmos-sdk/x/mint" "github.com/cosmos/cosmos-sdk/x/mint"
"github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/params"
paramsimops "github.com/cosmos/cosmos-sdk/x/params/simulation/operations"
"github.com/cosmos/cosmos-sdk/x/simulation" "github.com/cosmos/cosmos-sdk/x/simulation"
"github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/slashing"
slashingsimops "github.com/cosmos/cosmos-sdk/x/slashing/simulation/operations"
"github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/staking"
stakingsimops "github.com/cosmos/cosmos-sdk/x/staking/simulation/operations"
"github.com/cosmos/cosmos-sdk/x/supply" "github.com/cosmos/cosmos-sdk/x/supply"
auctionsimops "github.com/kava-labs/kava/x/auction/simulation/operations"
bep3simops "github.com/kava-labs/kava/x/bep3/simulation/operations"
cdpsimops "github.com/kava-labs/kava/x/cdp/simulation/operations"
pricefeedsimops "github.com/kava-labs/kava/x/pricefeed/simulation/operations"
) )
// Simulation parameter constants type StoreKeysPrefixes struct {
const ( A sdk.StoreKey
StakePerAccount = "stake_per_account" B sdk.StoreKey
InitiallyBondedValidators = "initially_bonded_validators" Prefixes [][]byte
OpWeightDeductFee = "op_weight_deduct_fee" }
OpWeightMsgSend = "op_weight_msg_send"
OpWeightSingleInputMsgMultiSend = "op_weight_single_input_msg_multisend"
OpWeightMsgSetWithdrawAddress = "op_weight_msg_set_withdraw_address"
OpWeightMsgWithdrawDelegationReward = "op_weight_msg_withdraw_delegation_reward"
OpWeightMsgWithdrawValidatorCommission = "op_weight_msg_withdraw_validator_commission"
OpWeightSubmitVotingSlashingTextProposal = "op_weight_submit_voting_slashing_text_proposal"
OpWeightSubmitVotingSlashingCommunitySpendProposal = "op_weight_submit_voting_slashing_community_spend_proposal"
OpWeightSubmitVotingSlashingParamChangeProposal = "op_weight_submit_voting_slashing_param_change_proposal"
OpWeightMsgDeposit = "op_weight_msg_deposit"
OpWeightMsgCreateValidator = "op_weight_msg_create_validator"
OpWeightMsgEditValidator = "op_weight_msg_edit_validator"
OpWeightMsgDelegate = "op_weight_msg_delegate"
OpWeightMsgUndelegate = "op_weight_msg_undelegate"
OpWeightMsgBeginRedelegate = "op_weight_msg_begin_redelegate"
OpWeightMsgUnjail = "op_weight_msg_unjail"
OpWeightMsgPlaceBid = "op_weight_msg_place_bid"
OpWeightMsgPricefeed = "op_weight_msg_pricefeed"
OpWeightMsgCreateAtomicSwap = "op_weight_msg_create_atomic_Swap"
OpWeightMsgCdp = "op_weight_msg_cdp"
)
// TestMain runs setup and teardown code before all tests. // TestMain runs setup and teardown code before all tests.
func TestMain(m *testing.M) { func TestMain(m *testing.M) {
@ -75,251 +41,11 @@ func TestMain(m *testing.M) {
config.Seal() config.Seal()
// load the values from simulation specific flags // load the values from simulation specific flags
simapp.GetSimulatorFlags() simapp.GetSimulatorFlags()
// run tests // run tests
exitCode := m.Run() exitCode := m.Run()
os.Exit(exitCode) os.Exit(exitCode)
} }
func testAndRunTxs(app *App, config simulation.Config) []simulation.WeightedOperation {
ap := make(simulation.AppParams)
paramChanges := app.sm.GenerateParamChanges(config.Seed)
if config.ParamsFile != "" {
bz, err := ioutil.ReadFile(config.ParamsFile)
if err != nil {
panic(err)
}
app.cdc.MustUnmarshalJSON(bz, &ap)
}
// nolint: govet
return []simulation.WeightedOperation{
{
func(_ *rand.Rand) int {
var v int
ap.GetOrGenerate(app.cdc, OpWeightDeductFee, &v, nil,
func(_ *rand.Rand) {
v = 5
})
return v
}(nil),
authsimops.SimulateDeductFee(app.accountKeeper, app.supplyKeeper),
},
{
func(_ *rand.Rand) int {
var v int
ap.GetOrGenerate(app.cdc, OpWeightMsgSend, &v, nil,
func(_ *rand.Rand) {
v = 100
})
return v
}(nil),
banksimops.SimulateMsgSend(app.accountKeeper, app.bankKeeper),
},
{
func(_ *rand.Rand) int {
var v int
ap.GetOrGenerate(app.cdc, OpWeightSingleInputMsgMultiSend, &v, nil,
func(_ *rand.Rand) {
v = 10
})
return v
}(nil),
banksimops.SimulateSingleInputMsgMultiSend(app.accountKeeper, app.bankKeeper),
},
{
func(_ *rand.Rand) int {
var v int
ap.GetOrGenerate(app.cdc, OpWeightMsgSetWithdrawAddress, &v, nil,
func(_ *rand.Rand) {
v = 50
})
return v
}(nil),
distrsimops.SimulateMsgSetWithdrawAddress(app.distrKeeper),
},
{
func(_ *rand.Rand) int {
var v int
ap.GetOrGenerate(app.cdc, OpWeightMsgWithdrawDelegationReward, &v, nil,
func(_ *rand.Rand) {
v = 50
})
return v
}(nil),
distrsimops.SimulateMsgWithdrawDelegatorReward(app.distrKeeper),
},
{
func(_ *rand.Rand) int {
var v int
ap.GetOrGenerate(app.cdc, OpWeightMsgWithdrawValidatorCommission, &v, nil,
func(_ *rand.Rand) {
v = 50
})
return v
}(nil),
distrsimops.SimulateMsgWithdrawValidatorCommission(app.distrKeeper),
},
{
func(_ *rand.Rand) int {
var v int
ap.GetOrGenerate(app.cdc, OpWeightSubmitVotingSlashingTextProposal, &v, nil,
func(_ *rand.Rand) {
v = 5
})
return v
}(nil),
govsimops.SimulateSubmittingVotingAndSlashingForProposal(app.govKeeper, govsimops.SimulateTextProposalContent),
},
{
func(_ *rand.Rand) int {
var v int
ap.GetOrGenerate(app.cdc, OpWeightSubmitVotingSlashingCommunitySpendProposal, &v, nil,
func(_ *rand.Rand) {
v = 5
})
return v
}(nil),
govsimops.SimulateSubmittingVotingAndSlashingForProposal(app.govKeeper, distrsimops.SimulateCommunityPoolSpendProposalContent(app.distrKeeper)),
},
{
func(_ *rand.Rand) int {
var v int
ap.GetOrGenerate(app.cdc, OpWeightSubmitVotingSlashingParamChangeProposal, &v, nil,
func(_ *rand.Rand) {
v = 5
})
return v
}(nil),
govsimops.SimulateSubmittingVotingAndSlashingForProposal(app.govKeeper, paramsimops.SimulateParamChangeProposalContent(paramChanges)),
},
{
func(_ *rand.Rand) int {
var v int
ap.GetOrGenerate(app.cdc, OpWeightMsgDeposit, &v, nil,
func(_ *rand.Rand) {
v = 100
})
return v
}(nil),
govsimops.SimulateMsgDeposit(app.govKeeper),
},
{
func(_ *rand.Rand) int {
var v int
ap.GetOrGenerate(app.cdc, OpWeightMsgCreateValidator, &v, nil,
func(_ *rand.Rand) {
v = 100
})
return v
}(nil),
stakingsimops.SimulateMsgCreateValidator(app.accountKeeper, app.stakingKeeper),
},
{
func(_ *rand.Rand) int {
var v int
ap.GetOrGenerate(app.cdc, OpWeightMsgEditValidator, &v, nil,
func(_ *rand.Rand) {
v = 5
})
return v
}(nil),
stakingsimops.SimulateMsgEditValidator(app.stakingKeeper),
},
{
func(_ *rand.Rand) int {
var v int
ap.GetOrGenerate(app.cdc, OpWeightMsgDelegate, &v, nil,
func(_ *rand.Rand) {
v = 100
})
return v
}(nil),
stakingsimops.SimulateMsgDelegate(app.accountKeeper, app.stakingKeeper),
},
{
func(_ *rand.Rand) int {
var v int
ap.GetOrGenerate(app.cdc, OpWeightMsgUndelegate, &v, nil,
func(_ *rand.Rand) {
v = 100
})
return v
}(nil),
stakingsimops.SimulateMsgUndelegate(app.accountKeeper, app.stakingKeeper),
},
{
func(_ *rand.Rand) int {
var v int
ap.GetOrGenerate(app.cdc, OpWeightMsgBeginRedelegate, &v, nil,
func(_ *rand.Rand) {
v = 100
})
return v
}(nil),
stakingsimops.SimulateMsgBeginRedelegate(app.accountKeeper, app.stakingKeeper),
},
{
func(_ *rand.Rand) int {
var v int
ap.GetOrGenerate(app.cdc, OpWeightMsgUnjail, &v, nil,
func(_ *rand.Rand) {
v = 100
})
return v
}(nil),
slashingsimops.SimulateMsgUnjail(app.slashingKeeper),
},
{
func(_ *rand.Rand) int {
var v int
ap.GetOrGenerate(app.cdc, OpWeightMsgPlaceBid, &v, nil,
func(_ *rand.Rand) {
v = 100
})
return v
}(nil),
auctionsimops.SimulateMsgPlaceBid(app.accountKeeper, app.auctionKeeper),
},
{
func(_ *rand.Rand) int {
var v int
ap.GetOrGenerate(app.cdc, OpWeightMsgCreateAtomicSwap, &v, nil,
func(_ *rand.Rand) {
v = 100
})
return v
}(nil),
bep3simops.SimulateMsgCreateAtomicSwap(app.accountKeeper, app.bep3Keeper),
},
{
func(_ *rand.Rand) int {
var v int
ap.GetOrGenerate(app.cdc, OpWeightMsgPricefeed, &v, nil,
func(_ *rand.Rand) {
v = 100
})
return v
}(nil),
pricefeedsimops.SimulateMsgUpdatePrices(app.pricefeedKeeper, config.NumBlocks),
},
{
func(_ *rand.Rand) int {
var v int
ap.GetOrGenerate(app.cdc, OpWeightMsgCdp, &v, nil,
func(_ *rand.Rand) {
v = 100 // TODO
})
return v
}(nil),
cdpsimops.SimulateMsgCdp(app.accountKeeper, app.cdpKeeper, app.pricefeedKeeper),
},
}
}
// fauxMerkleModeOpt returns a BaseApp option to use a dbStoreAdapter instead of // fauxMerkleModeOpt returns a BaseApp option to use a dbStoreAdapter instead of
// an IAVLStore for faster simulation speed. // an IAVLStore for faster simulation speed.
func fauxMerkleModeOpt(bapp *baseapp.BaseApp) { func fauxMerkleModeOpt(bapp *baseapp.BaseApp) {
@ -332,197 +58,96 @@ func interBlockCacheOpt() func(*baseapp.BaseApp) {
return baseapp.SetInterBlockCache(store.NewCommitKVStoreCacheManager()) return baseapp.SetInterBlockCache(store.NewCommitKVStoreCacheManager())
} }
// Profile with:
// /usr/local/go/bin/go test -benchmem -run=^$ github.com/cosmos/cosmos-sdk/GaiaApp -bench ^BenchmarkFullAppSimulation$ -Commit=true -cpuprofile cpu.out
func BenchmarkFullAppSimulation(b *testing.B) {
logger := log.NewNopLogger()
config := simapp.NewConfigFromFlags()
var db dbm.DB
dir, _ := ioutil.TempDir("", "goleveldb-app-sim")
db, _ = sdk.NewLevelDB("Simulation", dir)
defer func() {
db.Close()
_ = os.RemoveAll(dir)
}()
app := NewApp(logger, db, nil, true, simapp.FlagPeriodValue, interBlockCacheOpt())
// Run randomized simulation
// TODO: parameterize numbers, save for a later PR
_, simParams, simErr := simulation.SimulateFromSeed(
b, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.sm),
testAndRunTxs(app, config), app.ModuleAccountAddrs(), config,
)
// export state and params before the simulation error is checked
if config.ExportStatePath != "" {
if err := ExportStateToJSON(app, config.ExportStatePath); err != nil {
fmt.Println(err)
b.Fail()
}
}
if config.ExportParamsPath != "" {
if err := simapp.ExportParamsToJSON(simParams, config.ExportParamsPath); err != nil {
fmt.Println(err)
b.Fail()
}
}
if simErr != nil {
fmt.Println(simErr)
b.FailNow()
}
if config.Commit {
fmt.Println("\nGoLevelDB Stats")
fmt.Println(db.Stats()["leveldb.stats"])
fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"])
}
}
// TestFullAppSimulation runs a standard simulation of the app, modified by cmd line flag values.
func TestFullAppSimulation(t *testing.T) { func TestFullAppSimulation(t *testing.T) {
if !simapp.FlagEnabledValue { config, db, dir, logger, skip, err := simapp.SetupSimulation("leveldb-app-sim", "Simulation")
if skip {
t.Skip("skipping application simulation") t.Skip("skipping application simulation")
} }
require.NoError(t, err, "simulation setup failed")
var logger log.Logger
config := simapp.NewConfigFromFlags()
if simapp.FlagVerboseValue {
logger = log.TestingLogger()
} else {
logger = log.NewNopLogger()
}
var db dbm.DB
dir, _ := ioutil.TempDir("", "goleveldb-app-sim")
db, _ = sdk.NewLevelDB("Simulation", dir)
defer func() { defer func() {
db.Close() db.Close()
_ = os.RemoveAll(dir) require.NoError(t, os.RemoveAll(dir))
}() }()
app := NewApp(logger, db, nil, true, simapp.FlagPeriodValue, fauxMerkleModeOpt) app := NewApp(logger, db, nil, true, simapp.FlagPeriodValue, fauxMerkleModeOpt)
require.Equal(t, "kava", app.Name()) require.Equal(t, appName, app.Name())
// Run randomized simulation // run randomized simulation
_, simParams, simErr := simulation.SimulateFromSeed( _, simParams, simErr := simulation.SimulateFromSeed(
t, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.sm), t, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.SimulationManager()),
testAndRunTxs(app, config), app.ModuleAccountAddrs(), config, simapp.SimulationOperations(app, app.Codec(), config),
) app.ModuleAccountAddrs(), config,
// export state and params before the simulation error is checked
if config.ExportStatePath != "" {
err := ExportStateToJSON(app, config.ExportStatePath)
require.NoError(t, err)
}
if config.ExportParamsPath != "" {
err := simapp.ExportParamsToJSON(simParams, config.ExportParamsPath)
require.NoError(t, err)
}
require.NoError(t, simErr)
if config.Commit {
// for memdb:
// fmt.Println("Database Size", db.Stats()["database.size"])
fmt.Println("\nGoLevelDB Stats")
fmt.Println(db.Stats()["leveldb.stats"])
fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"])
}
}
// TestAppImportExport runs a simulation, exports the state, imports it, then checks the db state is same after import as it was before export.
func TestAppImportExport(t *testing.T) {
if !simapp.FlagEnabledValue {
t.Skip("skipping application import/export simulation")
}
var logger log.Logger
config := simapp.NewConfigFromFlags()
if simapp.FlagVerboseValue {
logger = log.TestingLogger()
} else {
logger = log.NewNopLogger()
}
var db dbm.DB
dir, _ := ioutil.TempDir("", "goleveldb-app-sim")
db, _ = sdk.NewLevelDB("Simulation", dir)
defer func() {
db.Close()
_ = os.RemoveAll(dir)
}()
app := NewApp(logger, db, nil, true, simapp.FlagPeriodValue, fauxMerkleModeOpt)
require.Equal(t, "kava", app.Name())
// Run randomized simulation
_, simParams, simErr := simulation.SimulateFromSeed(
t, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.sm),
testAndRunTxs(app, config), app.ModuleAccountAddrs(), config,
) )
// export state and simParams before the simulation error is checked // export state and simParams before the simulation error is checked
if config.ExportStatePath != "" { err = simapp.CheckExportSimulation(app, config, simParams)
err := ExportStateToJSON(app, config.ExportStatePath)
require.NoError(t, err) require.NoError(t, err)
}
if config.ExportParamsPath != "" {
err := simapp.ExportParamsToJSON(simParams, config.ExportParamsPath)
require.NoError(t, err)
}
require.NoError(t, simErr) require.NoError(t, simErr)
if config.Commit { if config.Commit {
// for memdb: simapp.PrintStats(db)
// fmt.Println("Database Size", db.Stats()["database.size"]) }
fmt.Println("\nGoLevelDB Stats") }
fmt.Println(db.Stats()["leveldb.stats"])
fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"]) func TestAppImportExport(t *testing.T) {
config, db, dir, logger, skip, err := simapp.SetupSimulation("leveldb-app-sim", "Simulation")
if skip {
t.Skip("skipping application import/export simulation")
}
require.NoError(t, err, "simulation setup failed")
defer func() {
db.Close()
require.NoError(t, os.RemoveAll(dir))
}()
app := NewApp(logger, db, nil, true, simapp.FlagPeriodValue, fauxMerkleModeOpt)
require.Equal(t, appName, app.Name())
// Run randomized simulation
_, simParams, simErr := simulation.SimulateFromSeed(
t, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.SimulationManager()),
simapp.SimulationOperations(app, app.Codec(), config),
app.ModuleAccountAddrs(), config,
)
// export state and simParams before the simulation error is checked
err = simapp.CheckExportSimulation(app, config, simParams)
require.NoError(t, err)
require.NoError(t, simErr)
if config.Commit {
simapp.PrintStats(db)
} }
fmt.Printf("exporting genesis...\n") fmt.Printf("exporting genesis...\n")
appState, _, err := app.ExportAppStateAndValidators(false, []string{}) appState, _, err := app.ExportAppStateAndValidators(false, []string{})
require.NoError(t, err) require.NoError(t, err)
fmt.Printf("importing genesis...\n") fmt.Printf("importing genesis...\n")
newDir, _ := ioutil.TempDir("", "goleveldb-app-sim-2") _, newDB, newDir, _, _, err := simapp.SetupSimulation("leveldb-app-sim-2", "Simulation-2")
newDB, _ := sdk.NewLevelDB("Simulation-2", dir) require.NoError(t, err, "simulation setup failed")
defer func() { defer func() {
newDB.Close() newDB.Close()
_ = os.RemoveAll(newDir) require.NoError(t, os.RemoveAll(newDir))
}() }()
newApp := NewApp(log.NewNopLogger(), newDB, nil, true, simapp.FlagPeriodValue, fauxMerkleModeOpt) newApp := NewApp(log.NewNopLogger(), newDB, nil, true, simapp.FlagPeriodValue, fauxMerkleModeOpt)
require.Equal(t, "kava", newApp.Name()) require.Equal(t, appName, newApp.Name())
var genesisState simapp.GenesisState var genesisState GenesisState
err = app.cdc.UnmarshalJSON(appState, &genesisState) err = app.Codec().UnmarshalJSON(appState, &genesisState)
require.NoError(t, err) require.NoError(t, err)
ctxA := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()})
ctxB := newApp.NewContext(true, abci.Header{Height: app.LastBlockHeight()}) ctxB := newApp.NewContext(true, abci.Header{Height: app.LastBlockHeight()})
newApp.mm.InitGenesis(ctxB, genesisState) newApp.mm.InitGenesis(ctxB, genesisState)
fmt.Printf("comparing stores...\n") fmt.Printf("comparing stores...\n")
ctxA := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()})
type StoreKeysPrefixes struct {
A sdk.StoreKey
B sdk.StoreKey
Prefixes [][]byte
}
storeKeysPrefixes := []StoreKeysPrefixes{ storeKeysPrefixes := []StoreKeysPrefixes{
{app.keys[baseapp.MainStoreKey], newApp.keys[baseapp.MainStoreKey], [][]byte{}}, {app.keys[baseapp.MainStoreKey], newApp.keys[baseapp.MainStoreKey], [][]byte{}},
@ -539,118 +164,84 @@ func TestAppImportExport(t *testing.T) {
{app.keys[gov.StoreKey], newApp.keys[gov.StoreKey], [][]byte{}}, {app.keys[gov.StoreKey], newApp.keys[gov.StoreKey], [][]byte{}},
} }
for _, storeKeysPrefix := range storeKeysPrefixes { for _, skp := range storeKeysPrefixes {
storeKeyA := storeKeysPrefix.A storeA := ctxA.KVStore(skp.A)
storeKeyB := storeKeysPrefix.B storeB := ctxB.KVStore(skp.B)
prefixes := storeKeysPrefix.Prefixes
storeA := ctxA.KVStore(storeKeyA) failedKVAs, failedKVBs := sdk.DiffKVStores(storeA, storeB, skp.Prefixes)
storeB := ctxB.KVStore(storeKeyB)
failedKVAs, failedKVBs := sdk.DiffKVStores(storeA, storeB, prefixes)
require.Equal(t, len(failedKVAs), len(failedKVBs), "unequal sets of key-values to compare") require.Equal(t, len(failedKVAs), len(failedKVBs), "unequal sets of key-values to compare")
fmt.Printf("compared %d key/value pairs between %s and %s\n", len(failedKVAs), storeKeyA, storeKeyB) fmt.Printf("compared %d key/value pairs between %s and %s\n", len(failedKVAs), skp.A, skp.B)
require.Len(t, failedKVAs, 0, simapp.GetSimulationLog(storeKeyA.Name(), app.sm.StoreDecoders, app.cdc, failedKVAs, failedKVBs)) require.Equal(t, len(failedKVAs), 0, simapp.GetSimulationLog(skp.A.Name(), app.SimulationManager().StoreDecoders, app.Codec(), failedKVAs, failedKVBs))
} }
} }
// TestAppSimulationAfterImport runs a simulation, exports it, imports it and runs another simulation.
func TestAppSimulationAfterImport(t *testing.T) { func TestAppSimulationAfterImport(t *testing.T) {
if !simapp.FlagEnabledValue { config, db, dir, logger, skip, err := simapp.SetupSimulation("leveldb-app-sim", "Simulation")
if skip {
t.Skip("skipping application simulation after import") t.Skip("skipping application simulation after import")
} }
require.NoError(t, err, "simulation setup failed")
var logger log.Logger
config := simapp.NewConfigFromFlags()
if simapp.FlagVerboseValue {
logger = log.TestingLogger()
} else {
logger = log.NewNopLogger()
}
dir, _ := ioutil.TempDir("", "goleveldb-app-sim")
db, _ := sdk.NewLevelDB("Simulation", dir)
defer func() { defer func() {
db.Close() db.Close()
_ = os.RemoveAll(dir) require.NoError(t, os.RemoveAll(dir))
}() }()
app := NewApp(logger, db, nil, true, simapp.FlagPeriodValue, fauxMerkleModeOpt) app := NewApp(logger, db, nil, true, simapp.FlagPeriodValue, fauxMerkleModeOpt)
require.Equal(t, "kava", app.Name()) require.Equal(t, appName, app.Name())
// Run randomized simulation
// Run randomized simulation // Run randomized simulation
stopEarly, simParams, simErr := simulation.SimulateFromSeed( stopEarly, simParams, simErr := simulation.SimulateFromSeed(
t, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.sm), t, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.SimulationManager()),
testAndRunTxs(app, config), app.ModuleAccountAddrs(), config, simapp.SimulationOperations(app, app.Codec(), config),
app.ModuleAccountAddrs(), config,
) )
// export state and params before the simulation error is checked // export state and simParams before the simulation error is checked
if config.ExportStatePath != "" { err = simapp.CheckExportSimulation(app, config, simParams)
err := ExportStateToJSON(app, config.ExportStatePath)
require.NoError(t, err) require.NoError(t, err)
}
if config.ExportParamsPath != "" {
err := simapp.ExportParamsToJSON(simParams, config.ExportParamsPath)
require.NoError(t, err)
}
require.NoError(t, simErr) require.NoError(t, simErr)
if config.Commit { if config.Commit {
// for memdb: simapp.PrintStats(db)
// fmt.Println("Database Size", db.Stats()["database.size"])
fmt.Println("\nGoLevelDB Stats")
fmt.Println(db.Stats()["leveldb.stats"])
fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"])
} }
if stopEarly { if stopEarly {
// we can't export or import a zero-validator genesis fmt.Println("can't export or import a zero-validator genesis, exiting test...")
fmt.Printf("We can't export or import a zero-validator genesis, exiting test...\n")
return return
} }
fmt.Printf("Exporting genesis...\n") fmt.Printf("exporting genesis...\n")
appState, _, err := app.ExportAppStateAndValidators(true, []string{}) appState, _, err := app.ExportAppStateAndValidators(true, []string{})
if err != nil { require.NoError(t, err)
panic(err)
}
fmt.Printf("Importing genesis...\n") fmt.Printf("importing genesis...\n")
newDir, _ := ioutil.TempDir("", "goleveldb-app-sim-2") _, newDB, newDir, _, _, err := simapp.SetupSimulation("leveldb-app-sim-2", "Simulation-2")
newDB, _ := sdk.NewLevelDB("Simulation-2", dir) require.NoError(t, err, "simulation setup failed")
defer func() { defer func() {
newDB.Close() newDB.Close()
_ = os.RemoveAll(newDir) require.NoError(t, os.RemoveAll(newDir))
}() }()
newApp := NewApp(log.NewNopLogger(), newDB, nil, true, 0, fauxMerkleModeOpt) newApp := NewApp(log.NewNopLogger(), newDB, nil, true, simapp.FlagPeriodValue, fauxMerkleModeOpt)
require.Equal(t, "kava", newApp.Name()) require.Equal(t, appName, newApp.Name())
newApp.InitChain(abci.RequestInitChain{ newApp.InitChain(abci.RequestInitChain{
AppStateBytes: appState, AppStateBytes: appState,
}) })
// Run randomized simulation on imported app
_, _, err = simulation.SimulateFromSeed( _, _, err = simulation.SimulateFromSeed(
t, os.Stdout, newApp.BaseApp, simapp.AppStateFn(app.Codec(), app.sm), t, os.Stdout, newApp.BaseApp, simapp.AppStateFn(app.Codec(), app.SimulationManager()),
testAndRunTxs(newApp, config), newApp.ModuleAccountAddrs(), config, simapp.SimulationOperations(newApp, newApp.Codec(), config),
newApp.ModuleAccountAddrs(), config,
) )
require.NoError(t, err) require.NoError(t, err)
} }
// TODO: Make another test for the fuzzer itself, which just has noOp txs
// and doesn't depend on the application.
// TestAppStateDeterminism runs several sims with the same seed and checks the states are equal.
func TestAppStateDeterminism(t *testing.T) { func TestAppStateDeterminism(t *testing.T) {
if !simapp.FlagEnabledValue { if !simapp.FlagEnabledValue {
t.Skip("skipping application simulation") t.Skip("skipping application simulation")
@ -661,6 +252,7 @@ func TestAppStateDeterminism(t *testing.T) {
config.ExportParamsPath = "" config.ExportParamsPath = ""
config.OnOperation = false config.OnOperation = false
config.AllInvariants = false config.AllInvariants = false
config.ChainID = helpers.SimAppChainID
numTimesToRunPerSeed := 2 numTimesToRunPerSeed := 2
appHashList := make([]json.RawMessage, numTimesToRunPerSeed) appHashList := make([]json.RawMessage, numTimesToRunPerSeed)
@ -676,8 +268,9 @@ func TestAppStateDeterminism(t *testing.T) {
) )
_, _, err := simulation.SimulateFromSeed( _, _, err := simulation.SimulateFromSeed(
t, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.sm), t, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.SimulationManager()),
testAndRunTxs(app, config), app.ModuleAccountAddrs(), config, simapp.SimulationOperations(app, app.Codec(), config),
app.ModuleAccountAddrs(), config,
) )
require.NoError(t, err) require.NoError(t, err)
@ -692,63 +285,3 @@ func TestAppStateDeterminism(t *testing.T) {
} }
} }
} }
func BenchmarkInvariants(b *testing.B) {
logger := log.NewNopLogger()
config := simapp.NewConfigFromFlags()
config.AllInvariants = false
dir, _ := ioutil.TempDir("", "goleveldb-app-invariant-bench")
db, _ := sdk.NewLevelDB("simulation", dir)
defer func() {
db.Close()
os.RemoveAll(dir)
}()
app := NewApp(logger, db, nil, true, simapp.FlagPeriodValue, interBlockCacheOpt())
// 2. Run parameterized simulation (w/o invariants)
_, simParams, simErr := simulation.SimulateFromSeed(
b, ioutil.Discard, app.BaseApp, simapp.AppStateFn(app.Codec(), app.sm),
testAndRunTxs(app, config), app.ModuleAccountAddrs(), config,
)
// export state and params before the simulation error is checked
if config.ExportStatePath != "" {
if err := ExportStateToJSON(app, config.ExportStatePath); err != nil {
fmt.Println(err)
b.Fail()
}
}
if config.ExportParamsPath != "" {
if err := simapp.ExportParamsToJSON(simParams, config.ExportParamsPath); err != nil {
fmt.Println(err)
b.Fail()
}
}
if simErr != nil {
fmt.Println(simErr)
b.FailNow()
}
ctx := app.NewContext(true, abci.Header{Height: app.LastBlockHeight() + 1})
// 3. Benchmark each invariant separately
//
// NOTE: We use the crisis keeper as it has all the invariants registered with
// their respective metadata which makes it useful for testing/benchmarking.
for _, cr := range app.crisisKeeper.Routes() {
b.Run(fmt.Sprintf("%s/%s", cr.ModuleName, cr.Route), func(b *testing.B) {
for n := 0; n < b.N; n++ {
if res, stop := cr.Invar(ctx); stop {
fmt.Printf("broken invariant at block %d of %d\n%s", ctx.BlockHeight()-1, config.NumBlocks, res)
b.FailNow()
}
}
})
}
}

View File

@ -50,6 +50,10 @@ type TestApp struct {
} }
func NewTestApp() TestApp { func NewTestApp() TestApp {
config := sdk.GetConfig()
SetBech32AddressPrefixes(config)
SetBip44CoinType(config)
db := tmdb.NewMemDB() db := tmdb.NewMemDB()
app := NewApp(log.NewNopLogger(), db, nil, true, 0) app := NewApp(log.NewNopLogger(), db, nil, true, 0)
return TestApp{App: *app} return TestApp{App: *app}

View File

@ -14,7 +14,6 @@ import (
tmtypes "github.com/tendermint/tendermint/types" tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/client"
clientkeys "github.com/cosmos/cosmos-sdk/client/keys" clientkeys "github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/crypto/keys"
@ -208,7 +207,7 @@ func (f *Fixtures) UnsafeResetAll(flags ...string) {
// NOTE: GDInit sets the ChainID for the Fixtures instance // NOTE: GDInit sets the ChainID for the Fixtures instance
func (f *Fixtures) GDInit(moniker string, flags ...string) { func (f *Fixtures) GDInit(moniker string, flags ...string) {
cmd := fmt.Sprintf("%s init -o --home=%s %s", f.GaiadBinary, f.GaiadHome, moniker) cmd := fmt.Sprintf("%s init -o --home=%s %s", f.GaiadBinary, f.GaiadHome, moniker)
_, stderr := tests.ExecuteT(f.T, addFlags(cmd, flags), client.DefaultKeyPass) _, stderr := tests.ExecuteT(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
var chainID string var chainID string
var initRes map[string]json.RawMessage var initRes map[string]json.RawMessage
@ -231,13 +230,13 @@ func (f *Fixtures) AddGenesisAccount(address sdk.AccAddress, coins sdk.Coins, fl
// GenTx is gaiad gentx // GenTx is gaiad gentx
func (f *Fixtures) GenTx(name string, flags ...string) { func (f *Fixtures) GenTx(name string, flags ...string) {
cmd := fmt.Sprintf("%s gentx --name=%s --home=%s --home-client=%s", f.GaiadBinary, name, f.GaiadHome, f.GaiacliHome) cmd := fmt.Sprintf("%s gentx --name=%s --home=%s --home-client=%s", f.GaiadBinary, name, f.GaiadHome, f.GaiacliHome)
executeWriteCheckErr(f.T, addFlags(cmd, flags), client.DefaultKeyPass) executeWriteCheckErr(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
} }
// CollectGenTxs is gaiad collect-gentxs // CollectGenTxs is gaiad collect-gentxs
func (f *Fixtures) CollectGenTxs(flags ...string) { func (f *Fixtures) CollectGenTxs(flags ...string) {
cmd := fmt.Sprintf("%s collect-gentxs --home=%s", f.GaiadBinary, f.GaiadHome) cmd := fmt.Sprintf("%s collect-gentxs --home=%s", f.GaiadBinary, f.GaiadHome)
executeWriteCheckErr(f.T, addFlags(cmd, flags), client.DefaultKeyPass) executeWriteCheckErr(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
} }
// GDStart runs gaiad start with the appropriate flags and returns a process // GDStart runs gaiad start with the appropriate flags and returns a process
@ -276,19 +275,19 @@ func (f *Fixtures) KeysDelete(name string, flags ...string) {
// KeysAdd is gaiacli keys add // KeysAdd is gaiacli keys add
func (f *Fixtures) KeysAdd(name string, flags ...string) { func (f *Fixtures) KeysAdd(name string, flags ...string) {
cmd := fmt.Sprintf("%s keys add --home=%s %s", f.GaiacliBinary, f.GaiacliHome, name) cmd := fmt.Sprintf("%s keys add --home=%s %s", f.GaiacliBinary, f.GaiacliHome, name)
executeWriteCheckErr(f.T, addFlags(cmd, flags), client.DefaultKeyPass) executeWriteCheckErr(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
} }
// KeysAddRecover prepares gaiacli keys add --recover // KeysAddRecover prepares gaiacli keys add --recover
func (f *Fixtures) KeysAddRecover(name, mnemonic string, flags ...string) (exitSuccess bool, stdout, stderr string) { func (f *Fixtures) KeysAddRecover(name, mnemonic string, flags ...string) (exitSuccess bool, stdout, stderr string) {
cmd := fmt.Sprintf("%s keys add --home=%s --recover %s", f.GaiacliBinary, f.GaiacliHome, name) cmd := fmt.Sprintf("%s keys add --home=%s --recover %s", f.GaiacliBinary, f.GaiacliHome, name)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass, mnemonic) return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass, mnemonic)
} }
// KeysAddRecoverHDPath prepares gaiacli keys add --recover --account --index // KeysAddRecoverHDPath prepares gaiacli keys add --recover --account --index
func (f *Fixtures) KeysAddRecoverHDPath(name, mnemonic string, account uint32, index uint32, flags ...string) { func (f *Fixtures) KeysAddRecoverHDPath(name, mnemonic string, account uint32, index uint32, flags ...string) {
cmd := fmt.Sprintf("%s keys add --home=%s --recover %s --account %d --index %d", f.GaiacliBinary, f.GaiacliHome, name, account, index) cmd := fmt.Sprintf("%s keys add --home=%s --recover %s --account %d --index %d", f.GaiacliBinary, f.GaiacliHome, name, account, index)
executeWriteCheckErr(f.T, addFlags(cmd, flags), client.DefaultKeyPass, mnemonic) executeWriteCheckErr(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass, mnemonic)
} }
// KeysShow is gaiacli keys show // KeysShow is gaiacli keys show
@ -324,25 +323,25 @@ func (f *Fixtures) CLIConfig(key, value string, flags ...string) {
// TxSend is gaiacli tx send // TxSend is gaiacli tx send
func (f *Fixtures) TxSend(from string, to sdk.AccAddress, amount sdk.Coin, flags ...string) (bool, string, string) { func (f *Fixtures) TxSend(from string, to sdk.AccAddress, amount sdk.Coin, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("%s tx send %s %s %s %v", f.GaiacliBinary, from, to, amount, f.Flags()) cmd := fmt.Sprintf("%s tx send %s %s %s %v", f.GaiacliBinary, from, to, amount, f.Flags())
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass) return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
} }
// TxSign is gaiacli tx sign // TxSign is gaiacli tx sign
func (f *Fixtures) TxSign(signer, fileName string, flags ...string) (bool, string, string) { func (f *Fixtures) TxSign(signer, fileName string, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("%s tx sign %v --from=%s %v", f.GaiacliBinary, f.Flags(), signer, fileName) cmd := fmt.Sprintf("%s tx sign %v --from=%s %v", f.GaiacliBinary, f.Flags(), signer, fileName)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass) return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
} }
// TxBroadcast is gaiacli tx broadcast // TxBroadcast is gaiacli tx broadcast
func (f *Fixtures) TxBroadcast(fileName string, flags ...string) (bool, string, string) { func (f *Fixtures) TxBroadcast(fileName string, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("%s tx broadcast %v %v", f.GaiacliBinary, f.Flags(), fileName) cmd := fmt.Sprintf("%s tx broadcast %v %v", f.GaiacliBinary, f.Flags(), fileName)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass) return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
} }
// TxEncode is gaiacli tx encode // TxEncode is gaiacli tx encode
func (f *Fixtures) TxEncode(fileName string, flags ...string) (bool, string, string) { func (f *Fixtures) TxEncode(fileName string, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("%s tx encode %v %v", f.GaiacliBinary, f.Flags(), fileName) cmd := fmt.Sprintf("%s tx encode %v %v", f.GaiacliBinary, f.Flags(), fileName)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass) return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
} }
// TxMultisign is gaiacli tx multisign // TxMultisign is gaiacli tx multisign
@ -364,13 +363,13 @@ func (f *Fixtures) TxStakingCreateValidator(from, consPubKey string, amount sdk.
cmd += fmt.Sprintf(" --amount=%v --moniker=%v --commission-rate=%v", amount, from, "0.05") cmd += fmt.Sprintf(" --amount=%v --moniker=%v --commission-rate=%v", amount, from, "0.05")
cmd += fmt.Sprintf(" --commission-max-rate=%v --commission-max-change-rate=%v", "0.20", "0.10") cmd += fmt.Sprintf(" --commission-max-rate=%v --commission-max-change-rate=%v", "0.20", "0.10")
cmd += fmt.Sprintf(" --min-self-delegation=%v", "1") cmd += fmt.Sprintf(" --min-self-delegation=%v", "1")
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass) return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
} }
// TxStakingUnbond is gaiacli tx staking unbond // TxStakingUnbond is gaiacli tx staking unbond
func (f *Fixtures) TxStakingUnbond(from, shares string, validator sdk.ValAddress, flags ...string) bool { func (f *Fixtures) TxStakingUnbond(from, shares string, validator sdk.ValAddress, flags ...string) bool {
cmd := fmt.Sprintf("%s tx staking unbond %s %v --from=%s %v", f.GaiacliBinary, validator, shares, from, f.Flags()) cmd := fmt.Sprintf("%s tx staking unbond %s %v --from=%s %v", f.GaiacliBinary, validator, shares, from, f.Flags())
return executeWrite(f.T, addFlags(cmd, flags), client.DefaultKeyPass) return executeWrite(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
} }
//___________________________________________________________________________________ //___________________________________________________________________________________
@ -380,19 +379,19 @@ func (f *Fixtures) TxStakingUnbond(from, shares string, validator sdk.ValAddress
func (f *Fixtures) TxGovSubmitProposal(from, typ, title, description string, deposit sdk.Coin, flags ...string) (bool, string, string) { func (f *Fixtures) TxGovSubmitProposal(from, typ, title, description string, deposit sdk.Coin, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("%s tx gov submit-proposal %v --from=%s --type=%s", f.GaiacliBinary, f.Flags(), from, typ) cmd := fmt.Sprintf("%s tx gov submit-proposal %v --from=%s --type=%s", f.GaiacliBinary, f.Flags(), from, typ)
cmd += fmt.Sprintf(" --title=%s --description=%s --deposit=%s", title, description, deposit) cmd += fmt.Sprintf(" --title=%s --description=%s --deposit=%s", title, description, deposit)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass) return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
} }
// TxGovDeposit is gaiacli tx gov deposit // TxGovDeposit is gaiacli tx gov deposit
func (f *Fixtures) TxGovDeposit(proposalID int, from string, amount sdk.Coin, flags ...string) (bool, string, string) { func (f *Fixtures) TxGovDeposit(proposalID int, from string, amount sdk.Coin, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("%s tx gov deposit %d %s --from=%s %v", f.GaiacliBinary, proposalID, amount, from, f.Flags()) cmd := fmt.Sprintf("%s tx gov deposit %d %s --from=%s %v", f.GaiacliBinary, proposalID, amount, from, f.Flags())
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass) return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
} }
// TxGovVote is gaiacli tx gov vote // TxGovVote is gaiacli tx gov vote
func (f *Fixtures) TxGovVote(proposalID int, option gov.VoteOption, from string, flags ...string) (bool, string, string) { func (f *Fixtures) TxGovVote(proposalID int, option gov.VoteOption, from string, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("%s tx gov vote %d %s --from=%s %v", f.GaiacliBinary, proposalID, option, from, f.Flags()) cmd := fmt.Sprintf("%s tx gov vote %d %s --from=%s %v", f.GaiacliBinary, proposalID, option, from, f.Flags())
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass) return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
} }
// TxGovSubmitParamChangeProposal executes a CLI parameter change proposal // TxGovSubmitParamChangeProposal executes a CLI parameter change proposal
@ -406,7 +405,7 @@ func (f *Fixtures) TxGovSubmitParamChangeProposal(
f.GaiacliBinary, proposalPath, from, f.Flags(), f.GaiacliBinary, proposalPath, from, f.Flags(),
) )
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass) return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
} }
// TxGovSubmitCommunityPoolSpendProposal executes a CLI community pool spend proposal // TxGovSubmitCommunityPoolSpendProposal executes a CLI community pool spend proposal
@ -420,7 +419,7 @@ func (f *Fixtures) TxGovSubmitCommunityPoolSpendProposal(
f.GaiacliBinary, proposalPath, from, f.Flags(), f.GaiacliBinary, proposalPath, from, f.Flags(),
) )
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass) return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
} }
//___________________________________________________________________________________ //___________________________________________________________________________________

View File

@ -12,6 +12,7 @@ import (
"github.com/tendermint/tendermint/libs/cli" "github.com/tendermint/tendermint/libs/cli"
"github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/lcd" "github.com/cosmos/cosmos-sdk/client/lcd"
"github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/client/rpc"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
@ -48,7 +49,7 @@ func main() {
} }
// Add --chain-id to persistent flags and mark it required // Add --chain-id to persistent flags and mark it required
rootCmd.PersistentFlags().String(client.FlagChainID, "", "Chain ID of tendermint node") rootCmd.PersistentFlags().String(flags.FlagChainID, "", "Chain ID of tendermint node")
rootCmd.PersistentPreRunE = func(_ *cobra.Command, _ []string) error { rootCmd.PersistentPreRunE = func(_ *cobra.Command, _ []string) error {
return initConfig(rootCmd) return initConfig(rootCmd)
} }
@ -59,13 +60,13 @@ func main() {
client.ConfigCmd(app.DefaultCLIHome), client.ConfigCmd(app.DefaultCLIHome),
queryCmd(cdc), queryCmd(cdc),
txCmd(cdc), txCmd(cdc),
client.LineBreak, flags.LineBreak,
lcd.ServeCommand(cdc, registerRoutes), lcd.ServeCommand(cdc, registerRoutes),
client.LineBreak, flags.LineBreak,
getModifiedKeysCmd(), getModifiedKeysCmd(),
client.LineBreak, flags.LineBreak,
version.Cmd, version.Cmd,
client.NewCompletionCmd(rootCmd, true), flags.NewCompletionCmd(rootCmd, true),
) )
// Add flags and prefix all env exposed with KA // Add flags and prefix all env exposed with KA
@ -87,12 +88,12 @@ func queryCmd(cdc *amino.Codec) *cobra.Command {
queryCmd.AddCommand( queryCmd.AddCommand(
authcmd.GetAccountCmd(cdc), authcmd.GetAccountCmd(cdc),
client.LineBreak, flags.LineBreak,
rpc.ValidatorCommand(cdc), rpc.ValidatorCommand(cdc),
rpc.BlockCommand(), rpc.BlockCommand(),
authcmd.QueryTxsByEventsCmd(cdc), authcmd.QueryTxsByEventsCmd(cdc),
authcmd.QueryTxCmd(cdc), authcmd.QueryTxCmd(cdc),
client.LineBreak, flags.LineBreak,
) )
// add modules' query commands // add modules' query commands
@ -109,14 +110,14 @@ func txCmd(cdc *amino.Codec) *cobra.Command {
txCmd.AddCommand( txCmd.AddCommand(
bankcmd.SendTxCmd(cdc), bankcmd.SendTxCmd(cdc),
client.LineBreak, flags.LineBreak,
authcmd.GetSignCommand(cdc), authcmd.GetSignCommand(cdc),
authcmd.GetMultiSignCommand(cdc), authcmd.GetMultiSignCommand(cdc),
client.LineBreak, flags.LineBreak,
authcmd.GetBroadcastCommand(cdc), authcmd.GetBroadcastCommand(cdc),
authcmd.GetEncodeCommand(cdc), authcmd.GetEncodeCommand(cdc),
authcmd.GetDecodeCommand(cdc), authcmd.GetDecodeCommand(cdc),
client.LineBreak, flags.LineBreak,
) )
// add modules' tx commands // add modules' tx commands
@ -156,7 +157,7 @@ func initConfig(cmd *cobra.Command) error {
return err return err
} }
} }
if err := viper.BindPFlag(client.FlagChainID, cmd.PersistentFlags().Lookup(client.FlagChainID)); err != nil { if err := viper.BindPFlag(flags.FlagChainID, cmd.PersistentFlags().Lookup(flags.FlagChainID)); err != nil {
return err return err
} }
if err := viper.BindPFlag(cli.EncodingFlag, cmd.PersistentFlags().Lookup(cli.EncodingFlag)); err != nil { if err := viper.BindPFlag(cli.EncodingFlag, cmd.PersistentFlags().Lookup(cli.EncodingFlag)); err != nil {

View File

@ -14,7 +14,7 @@ import (
dbm "github.com/tendermint/tm-db" dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/store" "github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
@ -59,7 +59,7 @@ func main() {
app.DefaultCLIHome)) app.DefaultCLIHome))
rootCmd.AddCommand(genutilcli.ValidateGenesisCmd(ctx, cdc, app.ModuleBasics)) rootCmd.AddCommand(genutilcli.ValidateGenesisCmd(ctx, cdc, app.ModuleBasics))
rootCmd.AddCommand(AddGenesisAccountCmd(ctx, cdc, app.DefaultNodeHome, app.DefaultCLIHome)) rootCmd.AddCommand(AddGenesisAccountCmd(ctx, cdc, app.DefaultNodeHome, app.DefaultCLIHome))
rootCmd.AddCommand(client.NewCompletionCmd(rootCmd, true)) rootCmd.AddCommand(flags.NewCompletionCmd(rootCmd, true))
server.AddCommands(ctx, cdc, rootCmd, newApp, exportAppStateAndTMValidators) server.AddCommands(ctx, cdc, rootCmd, newApp, exportAppStateAndTMValidators)

17
go.mod
View File

@ -4,15 +4,14 @@ go 1.13
require ( require (
github.com/btcsuite/btcd v0.20.1-beta // indirect github.com/btcsuite/btcd v0.20.1-beta // indirect
github.com/cosmos/cosmos-sdk v0.34.4-0.20191010193331-18de630d0ae1 github.com/cosmos/cosmos-sdk v0.38.3
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d // indirect
github.com/gorilla/mux v1.7.3 github.com/gorilla/mux v1.7.3
github.com/spf13/cobra v0.0.5 github.com/spf13/cobra v0.0.6
github.com/spf13/viper v1.4.0 github.com/spf13/viper v1.6.2
github.com/stretchr/testify v1.4.0 github.com/stretchr/testify v1.5.1
github.com/tendermint/go-amino v0.15.0 github.com/tendermint/go-amino v0.15.1
github.com/tendermint/tendermint v0.32.7 github.com/tendermint/tendermint v0.33.3
github.com/tendermint/tm-db v0.2.0 github.com/tendermint/tm-db v0.5.0
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3 // indirect golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3 // indirect
gopkg.in/yaml.v2 v2.2.4 gopkg.in/yaml.v2 v2.2.8
) )

409
go.sum
View File

@ -1,21 +1,40 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/99designs/keyring v1.1.2 h1:JJauROcU6x6Nh9uZb+8JgXFvyo0GUESLo1ixhpA0Kmw= cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/99designs/keyring v1.1.2/go.mod h1:657DQuMrBZRtuL/voxVyiyb6zpMehlm5vLB9Qwrv904= github.com/99designs/keyring v1.1.3 h1:mEV3iyZWjkxQ7R8ia8GcG97vCX5zQQ7n4o8R2BylwQY=
github.com/99designs/keyring v1.1.3/go.mod h1:657DQuMrBZRtuL/voxVyiyb6zpMehlm5vLB9Qwrv904=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/ChainSafe/go-schnorrkel v0.0.0-20200102211924-4bcbc698314f h1:4O1om+UVU+Hfcihr1timk8YNXHxzZWgCo7ofnrZRApw=
github.com/ChainSafe/go-schnorrkel v0.0.0-20200102211924-4bcbc698314f/go.mod h1:URdX5+vg25ts3aCh8H5IFZybJYKWhJHYMTnf+ULtoC4=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo=
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI=
github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE= github.com/VividCortex/gohistogram v1.0.0 h1:6+hBz+qvs0JOrrNhhmR7lFxo5sINxBCGXrdtl/UvroE=
github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g= github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/4+TcAqDqk/vUH7g=
github.com/Workiva/go-datastructures v1.0.50/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA= github.com/Workiva/go-datastructures v1.0.52/go.mod h1:Z+F2Rca0qCsVYDS8z7bAGm8f3UkzuWYS/oBZz5a7VVA=
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII= github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/apache/thrift v0.13.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d h1:1aAija9gr0Hyv4KfQcRcwlmFIrhkDmIj2dz5bkg/s/8= github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d h1:1aAija9gr0Hyv4KfQcRcwlmFIrhkDmIj2dz5bkg/s/8=
github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d/go.mod h1:icNx/6QdFblhsEjZehARqbNumymUT/ydwlLojFdv7Sk= github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d/go.mod h1:icNx/6QdFblhsEjZehARqbNumymUT/ydwlLojFdv7Sk=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0= github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0=
@ -30,24 +49,36 @@ github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVa
github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc= github.com/btcsuite/snappy-go v0.0.0-20151229074030-0bdef8d06723/go.mod h1:8woku9dyThutzjeg+3xrA5iCpBRH8XEEg3lh6TiUghc=
github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY= github.com/btcsuite/websocket v0.0.0-20150119174127-31079b680792/go.mod h1:ghJtEyQwv5/p4Mg4C0fgbePVuGr935/5ddU9Z3TmDRY=
github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs= github.com/btcsuite/winsvc v1.0.0/go.mod h1:jsenWakMcC0zFBFurPLEAyrnc/teJEM1O46fmI40EZs=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk= github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cosmos/cosmos-sdk v0.34.4-0.20191010193331-18de630d0ae1 h1:yb+E8HGzFnO0YwLS6OCBIAVWtN8KfCYoKeO9mgAmQN0= github.com/cosmos/cosmos-sdk v0.38.3 h1:qIBTiw+2T9POaSUJ5rvbBbXeq8C8btBlJxnSegPBd3Y=
github.com/cosmos/cosmos-sdk v0.34.4-0.20191010193331-18de630d0ae1/go.mod h1:IGBhkbOK1ebLqMWjtgo99zUxWHsA5IOb6N9CI8nHs0Y= github.com/cosmos/cosmos-sdk v0.38.3/go.mod h1:rzWOofbKfRt3wxiylmYWEFHnxxGj0coyqgWl2I9obAw=
github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y=
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU=
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y=
github.com/cosmos/ledger-cosmos-go v0.10.3 h1:Qhi5yTR5Pg1CaTpd00pxlGwNl4sFRdtK1J96OTjeFFc= github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4=
github.com/cosmos/ledger-cosmos-go v0.10.3/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= github.com/cosmos/ledger-cosmos-go v0.11.1/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY=
github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI= github.com/cosmos/ledger-go v0.9.2 h1:Nnao/dLwaVTk1Q5U9THldpUMMXU94BOTWPddSmVB6pI=
github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI= github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/danieljoos/wincred v1.0.2 h1:zf4bhty2iLuwgjgpraD2E9UbvO+fe54XXGJbOwe23fU= github.com/danieljoos/wincred v1.0.2 h1:zf4bhty2iLuwgjgpraD2E9UbvO+fe54XXGJbOwe23fU=
github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U= github.com/danieljoos/wincred v1.0.2/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U=
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@ -56,9 +87,18 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a h1:mq+R6XEM6lJX5VlLyZIrUSP8tSuJp82xTK89hvBwJbU= github.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a h1:mq+R6XEM6lJX5VlLyZIrUSP8tSuJp82xTK89hvBwJbU=
github.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM= github.com/dvsekhvalnov/jose2go v0.0.0-20180829124132-7f401d37b68a/go.mod h1:7BvyPhdbLxMXIYTFPLsyJRFMsKmOZnQmzh6Gb+uquuM=
github.com/etcd-io/bbolt v1.3.2/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/envoyproxy/go-control-plane v0.6.9/go.mod h1:SBwIajubJHhxtWwsL9s8ss4safvEdbitLhGGK48rN6g=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/etcd-io/bbolt v1.3.3 h1:gSJmxrs37LgTqR/oyJBWok6k6SvXEUerFTbltIhXkBM= github.com/etcd-io/bbolt v1.3.3 h1:gSJmxrs37LgTqR/oyJBWok6k6SvXEUerFTbltIhXkBM=
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw= github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ= github.com/facebookgo/ensure v0.0.0-20160127193407-b4ab57deab51 h1:0JZ+dUmQeA8IIVUMzysrX4/AKuQwWhV2dYQuPZdvdSQ=
@ -67,69 +107,126 @@ github.com/facebookgo/stack v0.0.0-20160209184415-751773369052 h1:JWuenKqqX8nojt
github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg= github.com/facebookgo/stack v0.0.0-20160209184415-751773369052/go.mod h1:UbMTZqLaRiH3MsBH8va0n7s1pQYcu3uTb8G4tygF4Zg=
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870 h1:E2s37DuLxFhQDg5gKsWoLBOB0n+ZW8s599zru8FJ2/Y=
github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0= github.com/facebookgo/subset v0.0.0-20150612182917-8dac2c3c4870/go.mod h1:5tD+neXqOorC30/tWg0LCSkrqj/AR6gu8yY8/fpw1q0=
github.com/fortytw2/leaktest v1.2.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw=
github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4=
github.com/franela/goreq v0.0.0-20171204163338-bcd34c9993f8/go.mod h1:ZhphrRTfi2rbfLwlschooIH4+wKKDR4Pdxhh+TRoA20=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-kit/kit v0.6.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.10.0 h1:dXFJfIHVvUcpSgDOV+Ne6t7jXri8Tfv2uOLHUZ2XNuo=
github.com/go-kit/kit v0.10.0/go.mod h1:xUsJbQ/Fp4kEt7AFgCuvyX4a71u8h9jB8tj/ORgOZ7o=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih4=
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
github.com/go-sql-driver/mysql v1.4.0/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk= github.com/go-stack/stack v1.8.0 h1:5SgMzNM5HxrEjV0ww2lTmX6E2Izsfxas4+YHWRs3Lsk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2 h1:ZpnhV/YsD2/4cESfV5+Hoeu/iUR3ruzNvZ+yQfO03a0=
github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4= github.com/godbus/dbus v0.0.0-20190726142602-4481cbc300e2/go.mod h1:bBOAhwG1umN6/6ZUMtDFBMQR8jRg9O75tm9K00oMsK4=
github.com/gogo/googleapis v1.1.0/go.mod h1:gf4bu3Q80BeJ6H1S1vYPm8/ELATdvryBaNFGgqEef3s=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.3.0 h1:G8O7TerXerS4F6sx9OV7/nRfJdnXgHZu/S/7F2SN+UE= github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o= github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129 h1:tT8iWCYw4uOem71yYA3htfH+LNopJvcqZQshm56G5L4= github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129 h1:tT8iWCYw4uOem71yYA3htfH+LNopJvcqZQshm56G5L4=
github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/mock v1.3.1-0.20190508161146-9fa652df1129/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4 h1:87PNWwrRvUSnqS4dlcBU/ftvOIBep4sYuBLlh6rX2wk=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw= github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v1.2.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs= github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY= github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c h1:6rhixN/i8ZofjG1Y75iExal34USq5p+wiN1tpie8IrU=
github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0= github.com/gsterjov/go-libsecret v0.0.0-20161001094733-a6f4afe4910c/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0=
github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk= github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f h1:8N8XWLZelZNibkhM1FuF+3Ad3YIbgirjdMiVA0eUkaM=
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4= github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f/go.mod h1:T86dnYJhcGOh5BjZFCJWTDeTK7XW8uE+E21Cy/bIQ+s=
github.com/gtank/ristretto255 v0.1.2 h1:JEqUCPA1NvLq5DwYtuzigd7ss8fwbYay9fi4/5uMzcc=
github.com/gtank/ristretto255 v0.1.2/go.mod h1:Ph5OpO6c7xKUGROZfWVLiJf9icMDwUeIvY4OmlYW69o=
github.com/hashicorp/consul/api v1.3.0/go.mod h1:MmDNSzIMUjNpY/mQ398R4bk2FnqQLoPndWW5VkKPlCE=
github.com/hashicorp/consul/sdk v0.3.0/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU=
github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU=
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmKTg=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/influxdata/influxdb1-client v0.0.0-20191209144304-8bf82d3c094d/go.mod h1:qj24IKcXYK6Iy9ceXlo3Tc+vtHo9lIhSX5JddghvEPo=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U= github.com/jmhodges/levigo v1.0.0 h1:q5EC36kV79HWeTBWsod3mG11EgStG3qArTKcvlksN1U=
github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ= github.com/jmhodges/levigo v1.0.0/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ= github.com/jrick/logrotate v1.0.0/go.mod h1:LNinyqDIJnpAur+b8yyulnQw/wDuN1+BYKlTRt3OuAQ=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM= github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d h1:Z+RDyXzjKE0i2sTjZ/b1uxiGtPhFy34Ou/Tk0qwN0kM=
github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc= github.com/keybase/go-keychain v0.0.0-20190712205309-48d3d31d256d/go.mod h1:JJNrCn9otv/2QP4D7SMJBgaleKpOf66PnW6F5WGNRIc=
@ -138,7 +235,6 @@ github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQL
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4= github.com/kkdai/bstream v0.0.0-20161212061736-f391b8402d23/go.mod h1:J+Gs4SYgM6CZQHDETBtE9HaSEkGmuNXF86RwHhHUvq4=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
@ -147,108 +243,187 @@ github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs= github.com/libp2p/go-buffer-pool v0.0.2 h1:QNK2iAFa8gjAe1SPz6mHSMuCcjs+X1wlHzeOSqcmlfs=
github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM= github.com/libp2p/go-buffer-pool v0.0.2/go.mod h1:MvaB6xw5vOrDl8rYZGLFdKAuk/hRoRZd1Vi32+RXyFM=
github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM=
github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4=
github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-isatty v0.0.10 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643 h1:hLDRPB66XQT/8+wG9WsDpiCvZf1yKO7sz7scAjSlBa0=
github.com/mimoo/StrobeGo v0.0.0-20181016162300-f8f6d4d2b643/go.mod h1:43+3pMjjKimDBf5Kr4ZFNGbLql1zKkbImw+fZbw3geM=
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
github.com/nats-io/jwt v0.3.2/go.mod h1:/euKqTS1ZD+zzjYrY7pseZrTtWQSjujC7xjPc8wL6eU=
github.com/nats-io/nats-server/v2 v2.1.2/go.mod h1:Afk+wRZqkMQs/p45uXdrVLuab3gwv3Z8C4HTBu8GD/k=
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs=
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/opentracing-contrib/go-observer v0.0.0-20170622124052-a52f23424492/go.mod h1:Ngi6UdF0k5OKD5t5wlmGhe/EDKPoUM3BXZSSfIuJbis=
github.com/opentracing/basictracer-go v1.0.0/go.mod h1:QfBfYuafItcjQuMwinw9GhYKwFXS9KnPs5lxoYwgW74=
github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
github.com/openzipkin-contrib/zipkin-go-opentracing v0.4.5/go.mod h1:/wsWhb9smxSfWAKL3wpBW7V8scJMt8N8gnaMCS9E/cA=
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw=
github.com/openzipkin/zipkin-go v0.2.1/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/openzipkin/zipkin-go v0.2.2/go.mod h1:NaW6tEwdmWMaCDZzg8sh+IBNOxHMPnhQw8ySjnjRyN4=
github.com/pact-foundation/pact-go v1.0.4/go.mod h1:uExwJY4kCzNPcHRj+hCR/HBbOOIwwtUjcrb0b5/5kLM=
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.5.0 h1:5BakdOZdtKJ1FFk6QdL8iSGrMWsXgchNJcrnarjbmJQ= github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4=
github.com/pelletier/go-toml v1.5.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys= github.com/pelletier/go-toml v1.6.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac=
github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8= github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
github.com/prometheus/client_golang v1.3.0/go.mod h1:hJaj2vgQTGQmVCsAACORcieXFeDPbaTKGT+JTgUa3og=
github.com/prometheus/client_golang v1.5.0 h1:Ctq0iGpCmr3jeP77kbF2UxgvRwzWWz+4Bh9/vJTyg1A=
github.com/prometheus/client_golang v1.5.0/go.mod h1:e9GMxYsXl05ICDXkRhurwBS4Q3OK1iX/F2sw+iXX5zU=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181020173914-7e9e6cabbd39/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.1.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0 h1:7etb9YClo3a6HjLzfl6rIQaU+FDfi0VSX39io3aQ+DM= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.7.0/go.mod h1:DjGbpBbp5NYNiECxcL/VnbXCCaQpKd3tt26CguLLsqA=
github.com/prometheus/common v0.9.1 h1:KOMtN28tlbam3/7ZKEYKHhKoJZYYj3gMH4uc62x7X7U=
github.com/prometheus/common v0.9.1/go.mod h1:yhUN8i9wzaXS3w1O07YhxHEBxD+W35wd8bs7vj7HSQ4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084 h1:sofwID9zm4tzrgykg80hfFph1mryUeLRsUfoocVVmRY= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.8 h1:+fpWZdT24pJBiqJdAwYBjPSk+5YmQzYNPYzQsdzLkt8=
github.com/prometheus/procfs v0.0.8/go.mod h1:7Qr8sr6344vo1JqZ6HhLceV9o3AJ1Ff+GxbHq6oeK9A=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rakyll/statik v0.1.6 h1:uICcfUXpgqtw2VopbIncslhAmE5hwc4g20TEyEENBNs= github.com/rakyll/statik v0.1.6 h1:uICcfUXpgqtw2VopbIncslhAmE5hwc4g20TEyEENBNs=
github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs= github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs=
github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 h1:nkcn14uNmFEuGCb2mBZbBb24RdNRL08b/wb+xBOYpuk= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ=
github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik=
github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E=
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4= github.com/snikch/goodman v0.0.0-20171125024755-10e37e294daa/go.mod h1:oJyF+mSPHbB5mVY2iO9KV3pTt/QbIkGaO8gQ2WrDbP4=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.1 h1:qgMbHoJbPbw579P+1zVY+6n4nIFuIchaIjzZ/I/Yq8M= github.com/spf13/afero v1.2.1 h1:qgMbHoJbPbw579P+1zVY+6n4nIFuIchaIjzZ/I/Yq8M=
github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s= github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs=
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v0.0.6/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.0.0/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/spf13/viper v1.6.2 h1:7aKfF+e8/k68gda3LOjo5RxiUqddoFxVq4BKBPrxk5E=
github.com/spf13/viper v1.6.2/go.mod h1:t3iDnF5Jlj76alVNuyFBk5oUMCvsrkbvZK0WQdfDi5k=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48= github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stumble/gorocksdb v0.0.3 h1:9UU+QA1pqFYJuf9+5p7z1IqdE5k0mma4UAeu2wmX8kA= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
github.com/stumble/gorocksdb v0.0.3/go.mod h1:v6IHdFBXk5DJ1K4FZ0xi+eY737quiiBxYtSWXadLybY= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965 h1:1oFLiOyVl+W7bnBzGhf7BbIv9loSFQcieWWYIjLqcAw= github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d h1:gZZadD8H+fF+n9CmNhYL1Y0dJB+kLOmKd7FbPJLeGHs=
github.com/syndtr/goleveldb v1.0.1-0.20190923125748-758128399b1d/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c h1:g+WoO5jjkqGAzHWCjJB1zZfXPIAaDpzXIEJ0eS6B5Ok=
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c/go.mod h1:ahpPrc7HpcfEWDQRZEmnXMzHY03mLDYMCxeDzy46i+8=
github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s= github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s=
github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U= github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U=
github.com/tendermint/crypto v0.0.0-20190823183015-45b1026d81ae h1:AOXNM7c2Vvo45SjAgeWF8Wy+NS7/NCqzRNpUc+HPAec= github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 h1:hqAk8riJvK4RMWx1aInLzndwxKalgi5rTqgfXxOxbEI=
github.com/tendermint/crypto v0.0.0-20190823183015-45b1026d81ae/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk= github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk=
github.com/tendermint/go-amino v0.14.1/go.mod h1:i/UKE5Uocn+argJJBb12qTZsCDBcAYMbR92AaJVmKso= github.com/tendermint/go-amino v0.14.1/go.mod h1:i/UKE5Uocn+argJJBb12qTZsCDBcAYMbR92AaJVmKso=
github.com/tendermint/go-amino v0.15.0 h1:TC4e66P59W7ML9+bxio17CPKnxW3nKIRAYskntMAoRk= github.com/tendermint/go-amino v0.15.1 h1:D2uk35eT4iTsvJd9jWIetzthE5C0/k2QmMFkCN+4JgQ=
github.com/tendermint/go-amino v0.15.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME=
github.com/tendermint/iavl v0.12.4 h1:hd1woxUGISKkfUWBA4mmmTwOua6PQZTJM/F0FDrmMV8= github.com/tendermint/iavl v0.13.2 h1:O1m08/Ciy53l9IYmf75uIRVvrNsfjEbre8u/yCu/oqk=
github.com/tendermint/iavl v0.12.4/go.mod h1:8LHakzt8/0G3/I8FUU0ReNx98S/EP6eyPJkAUvEXT/o= github.com/tendermint/iavl v0.13.2/go.mod h1:vE1u0XAGXYjHykd4BLp8p/yivrw2PF1TuoljBcsQoGA=
github.com/tendermint/tendermint v0.32.1/go.mod h1:jmPDAKuNkev9793/ivn/fTBnfpA9mGBww8MPRNPNxnU= github.com/tendermint/tendermint v0.33.2/go.mod h1:25DqB7YvV1tN3tHsjWoc2vFtlwICfrub9XO6UBO+4xk=
github.com/tendermint/tendermint v0.32.6/go.mod h1:D2+A3pNjY+Po72X0mTfaXorFhiVI8dh/Zg640FGyGtE= github.com/tendermint/tendermint v0.33.3 h1:6lMqjEoCGejCzAghbvfQgmw87snGSqEhDTo/jw+W8CI=
github.com/tendermint/tendermint v0.32.7 h1:Szu5Fm1L3pvn3t4uQxPAcP+7ndZEQKgLie/yokM56rU= github.com/tendermint/tendermint v0.33.3/go.mod h1:25DqB7YvV1tN3tHsjWoc2vFtlwICfrub9XO6UBO+4xk=
github.com/tendermint/tendermint v0.32.7/go.mod h1:D2+A3pNjY+Po72X0mTfaXorFhiVI8dh/Zg640FGyGtE= github.com/tendermint/tm-db v0.4.1/go.mod h1:JsJ6qzYkCGiGwm5GHl/H5GLI9XLb6qZX7PRe425dHAY=
github.com/tendermint/tm-db v0.1.1/go.mod h1:0cPKWu2Mou3IlxecH+MEUSYc1Ch537alLe6CpFrKzgw= github.com/tendermint/tm-db v0.5.0 h1:qtM5UTr1dlRnHtDY6y7MZO5Di8XAE2j3lc/pCnKJ5hQ=
github.com/tendermint/tm-db v0.2.0 h1:rJxgdqn6fIiVJZy4zLpY1qVlyD0TU6vhkT4kEf71TQQ= github.com/tendermint/tm-db v0.5.0/go.mod h1:lSq7q5WRR/njf1LnhiZ/lIJHk2S8Y1Zyq5oP/3o9C2U=
github.com/tendermint/tm-db v0.2.0/go.mod h1:0cPKWu2Mou3IlxecH+MEUSYc1Ch537alLe6CpFrKzgw= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8= github.com/zondax/hid v0.9.0 h1:eiT3P6vNxAEVxXMw66eZUAAnU2zD33JBkfG/EnfAKl8=
@ -256,79 +431,157 @@ github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWp
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 h1:ULYEB3JvPRE/IfO+9uO7vKV/xzVTO7XPAwm8xbf4w2g=
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3 h1:6KET3Sqa7fkVfD63QnAM81ZeYg5n4HwApOJkufONnHA= golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3 h1:6KET3Sqa7fkVfD63QnAM81ZeYg5n4HwApOJkufONnHA=
golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190930134127-c5a3c61f89f3/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190712062909-fae7ac547cb7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/sys v0.0.0-20191220142924-d4481acd189f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82 h1:ywK/j/KkyTHcdyYSZNXGjMwgmDSfjglYZ3vStQ/gSCU=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2 h1:67iHsV9djwGdZpdZNbLuQj6FOzCaZe3w+vhLjn5AcFA= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/grpc v1.13.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/genproto v0.0.0-20190530194941-fb225487d101/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55 h1:gSJIx1SDwno+2ElGhA4+qG2zF97qiUzTM+rQ0klBOcE=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.0/go.mod h1:chYK+tFQF0nDUGJgXMSgLCQk3phJEuONr2DCgLDdAQM=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1 h1:q4XQuHFC6I28BKZpo6IYyb3mNO+l7lSOxRuYTCiDfXk= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0 h1:bO/TA4OxCOummhSf10siHuG7vJOiwh7SpRpFZDkOgl4=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gcfg.v1 v1.2.3/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
gopkg.in/ini.v1 v1.51.0 h1:AQvPpx3LzTDM0AjnIRlVFwFFGC+npRopjZxLJj6gdno=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo= gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74= gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.5/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
sourcegraph.com/sourcegraph/appdash v0.0.0-20190731080439-ebfcffb1b5c0/go.mod h1:hI742Nqp5OhwiqlzhgfbWU4mW4yO10fP+LoT9WOswdU=

View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"bufio"
"bytes" "bytes"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
@ -398,8 +399,8 @@ func sendMsgToBlockchain(cdc *amino.Codec, address string, keyname string,
// get the account number and sequence number // get the account number and sequence number
accountNumber, sequenceNumber := getAccountNumberAndSequenceNumber(cdc, address) accountNumber, sequenceNumber := getAccountNumberAndSequenceNumber(cdc, address)
inBuf := bufio.NewReader(os.Stdin)
txBldr := auth.NewTxBuilderFromCLI(). txBldr := auth.NewTxBuilderFromCLI(inBuf).
WithTxEncoder(authclient.GetTxEncoder(cdc)).WithChainID("testing"). WithTxEncoder(authclient.GetTxEncoder(cdc)).WithChainID("testing").
WithKeybase(keybase).WithAccountNumber(accountNumber). WithKeybase(keybase).WithAccountNumber(accountNumber).
WithSequence(sequenceNumber).WithGas(500000) WithSequence(sequenceNumber).WithGas(500000)

View File

@ -1,8 +1,3 @@
// nolint
// autogenerated code using github.com/rigelrozanski/multitool
// aliases generated for the following subdirectories:
// ALIASGEN: github.com/kava-labs/kava/x/auction/keeper
// ALIASGEN: github.com/kava-labs/kava/x/auction/types
package auction package auction
import ( import (
@ -10,22 +5,13 @@ import (
"github.com/kava-labs/kava/x/auction/types" "github.com/kava-labs/kava/x/auction/types"
) )
// nolint
// autogenerated code using github.com/rigelrozanski/multitool
// aliases generated for the following subdirectories:
// ALIASGEN: github.com/kava-labs/kava/x/auction/keeper
// ALIASGEN: github.com/kava-labs/kava/x/auction/types
const ( const (
DefaultCodespace = types.DefaultCodespace
CodeInvalidInitialAuctionID = types.CodeInvalidInitialAuctionID
CodeInvalidModulePermissions = types.CodeInvalidModulePermissions
CodeUnrecognizedAuctionType = types.CodeUnrecognizedAuctionType
CodeAuctionNotFound = types.CodeAuctionNotFound
CodeAuctionHasNotExpired = types.CodeAuctionHasNotExpired
CodeAuctionHasExpired = types.CodeAuctionHasExpired
CodeInvalidBidDenom = types.CodeInvalidBidDenom
CodeInvalidLotDenom = types.CodeInvalidLotDenom
CodeBidTooSmall = types.CodeBidTooSmall
CodeBidTooLarge = types.CodeBidTooLarge
CodeLotTooSmall = types.CodeLotTooSmall
CodeLotTooLarge = types.CodeLotTooLarge
CodeCollateralAuctionIsInReversePhase = types.CodeCollateralAuctionIsInReversePhase
CodeCollateralAuctionIsInForwardPhase = types.CodeCollateralAuctionIsInForwardPhase
EventTypeAuctionStart = types.EventTypeAuctionStart EventTypeAuctionStart = types.EventTypeAuctionStart
EventTypeAuctionBid = types.EventTypeAuctionBid EventTypeAuctionBid = types.EventTypeAuctionBid
EventTypeAuctionClose = types.EventTypeAuctionClose EventTypeAuctionClose = types.EventTypeAuctionClose

View File

@ -6,8 +6,8 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
"github.com/kava-labs/kava/x/auction/types" "github.com/kava-labs/kava/x/auction/types"
@ -21,7 +21,7 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
Short: "Querying commands for the auction module", Short: "Querying commands for the auction module",
} }
auctionQueryCmd.AddCommand(client.GetCommands( auctionQueryCmd.AddCommand(flags.GetCommands(
QueryGetAuctionCmd(queryRoute, cdc), QueryGetAuctionCmd(queryRoute, cdc),
QueryGetAuctionsCmd(queryRoute, cdc), QueryGetAuctionsCmd(queryRoute, cdc),
QueryParamsCmd(queryRoute, cdc), QueryParamsCmd(queryRoute, cdc),

View File

@ -1,14 +1,15 @@
package cli package cli
import ( import (
"bufio"
"fmt" "fmt"
"strconv" "strconv"
"strings" "strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/version"
@ -25,7 +26,7 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command {
Short: "auction transactions subcommands", Short: "auction transactions subcommands",
} }
auctionTxCmd.AddCommand(client.PostCommands( auctionTxCmd.AddCommand(flags.PostCommands(
GetCmdPlaceBid(cdc), GetCmdPlaceBid(cdc),
)...) )...)
@ -45,8 +46,9 @@ $ %s tx %s bid 34 1000usdx --from myKeyName
`, version.ClientName, types.ModuleName)), `, version.ClientName, types.ModuleName)),
Args: cobra.ExactArgs(2), Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
cliCtx := context.NewCLIContext().WithCodec(cdc) cliCtx := context.NewCLIContext().WithCodec(cdc)
txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
id, err := strconv.ParseUint(args[0], 10, 64) id, err := strconv.ParseUint(args[0], 10, 64)
if err != nil { if err != nil {

View File

@ -22,7 +22,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper types.SupplyKeeper
for _, a := range gs.Auctions { for _, a := range gs.Auctions {
keeper.SetAuction(ctx, a) keeper.SetAuction(ctx, a)
// find the total coins that should be present in the module account // find the total coins that should be present in the module account
totalAuctionCoins = totalAuctionCoins.Add(a.GetModuleAccountCoins()) totalAuctionCoins = totalAuctionCoins.Add(a.GetModuleAccountCoins()...)
} }
// check if the module account exists // check if the module account exists

View File

@ -1,32 +1,31 @@
package auction package auction
import ( import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/kava-labs/kava/x/auction/types" "github.com/kava-labs/kava/x/auction/types"
) )
// NewHandler returns a function to handle all "auction" type messages. // NewHandler returns a function to handle all "auction" type messages.
func NewHandler(keeper Keeper) sdk.Handler { func NewHandler(keeper Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager()) ctx = ctx.WithEventManager(sdk.NewEventManager())
switch msg := msg.(type) { switch msg := msg.(type) {
case MsgPlaceBid: case MsgPlaceBid:
return handleMsgPlaceBid(ctx, keeper, msg) return handleMsgPlaceBid(ctx, keeper, msg)
default: default:
return sdk.ErrUnknownRequest(fmt.Sprintf("Unrecognized auction msg type: %T", msg)).Result() return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg)
} }
} }
} }
func handleMsgPlaceBid(ctx sdk.Context, keeper Keeper, msg MsgPlaceBid) sdk.Result { func handleMsgPlaceBid(ctx sdk.Context, keeper Keeper, msg MsgPlaceBid) (*sdk.Result, error) {
err := keeper.PlaceBid(ctx, msg.AuctionID, msg.Bidder, msg.Amount) err := keeper.PlaceBid(ctx, msg.AuctionID, msg.Bidder, msg.Amount)
if err != nil { if err != nil {
return err.Result() return nil, err
} }
ctx.EventManager().EmitEvent( ctx.EventManager().EmitEvent(
@ -37,7 +36,7 @@ func handleMsgPlaceBid(ctx sdk.Context, keeper Keeper, msg MsgPlaceBid) sdk.Resu
), ),
) )
return sdk.Result{ return &sdk.Result{
Events: ctx.EventManager().Events(), Events: ctx.EventManager().Events(),
} }, nil
} }

View File

@ -5,18 +5,19 @@ import (
"time" "time"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/supply" "github.com/cosmos/cosmos-sdk/x/supply"
"github.com/kava-labs/kava/x/auction/types" "github.com/kava-labs/kava/x/auction/types"
) )
// StartSurplusAuction starts a new surplus (forward) auction. // StartSurplusAuction starts a new surplus (forward) auction.
func (k Keeper) StartSurplusAuction(ctx sdk.Context, seller string, lot sdk.Coin, bidDenom string) (uint64, sdk.Error) { func (k Keeper) StartSurplusAuction(ctx sdk.Context, seller string, lot sdk.Coin, bidDenom string) (uint64, error) {
auction := types.NewSurplusAuction( auction := types.NewSurplusAuction(
seller, seller,
lot, lot,
bidDenom, bidDenom,
types.DistantFuture) types.DistantFuture,
)
err := k.supplyKeeper.SendCoinsFromModuleToModule(ctx, seller, types.ModuleName, sdk.NewCoins(lot)) err := k.supplyKeeper.SendCoinsFromModuleToModule(ctx, seller, types.ModuleName, sdk.NewCoins(lot))
if err != nil { if err != nil {
@ -41,7 +42,7 @@ func (k Keeper) StartSurplusAuction(ctx sdk.Context, seller string, lot sdk.Coin
} }
// StartDebtAuction starts a new debt (reverse) auction. // StartDebtAuction starts a new debt (reverse) auction.
func (k Keeper) StartDebtAuction(ctx sdk.Context, buyer string, bid sdk.Coin, initialLot sdk.Coin, debt sdk.Coin) (uint64, sdk.Error) { func (k Keeper) StartDebtAuction(ctx sdk.Context, buyer string, bid sdk.Coin, initialLot sdk.Coin, debt sdk.Coin) (uint64, error) {
auction := types.NewDebtAuction( auction := types.NewDebtAuction(
buyer, buyer,
@ -53,7 +54,7 @@ func (k Keeper) StartDebtAuction(ctx sdk.Context, buyer string, bid sdk.Coin, in
// This auction type mints coins at close. Need to check module account has minting privileges to avoid potential err in endblocker. // This auction type mints coins at close. Need to check module account has minting privileges to avoid potential err in endblocker.
macc := k.supplyKeeper.GetModuleAccount(ctx, buyer) macc := k.supplyKeeper.GetModuleAccount(ctx, buyer)
if !macc.HasPermission(supply.Minter) { if !macc.HasPermission(supply.Minter) {
return 0, types.ErrInvalidModulePermissions(k.codespace, supply.Minter) return 0, sdkerrors.Wrap(types.ErrInvalidModulePermissions, supply.Minter)
} }
err := k.supplyKeeper.SendCoinsFromModuleToModule(ctx, buyer, types.ModuleName, sdk.NewCoins(debt)) err := k.supplyKeeper.SendCoinsFromModuleToModule(ctx, buyer, types.ModuleName, sdk.NewCoins(debt))
@ -79,8 +80,10 @@ func (k Keeper) StartDebtAuction(ctx sdk.Context, buyer string, bid sdk.Coin, in
} }
// StartCollateralAuction starts a new collateral (2-phase) auction. // StartCollateralAuction starts a new collateral (2-phase) auction.
func (k Keeper) StartCollateralAuction(ctx sdk.Context, seller string, lot sdk.Coin, maxBid sdk.Coin, lotReturnAddrs []sdk.AccAddress, lotReturnWeights []sdk.Int, debt sdk.Coin) (uint64, sdk.Error) { func (k Keeper) StartCollateralAuction(
ctx sdk.Context, seller string, lot, maxBid sdk.Coin,
lotReturnAddrs []sdk.AccAddress, lotReturnWeights []sdk.Int, debt sdk.Coin,
) (uint64, error) {
weightedAddresses, err := types.NewWeightedAddresses(lotReturnAddrs, lotReturnWeights) weightedAddresses, err := types.NewWeightedAddresses(lotReturnAddrs, lotReturnWeights)
if err != nil { if err != nil {
return 0, err return 0, err
@ -91,7 +94,8 @@ func (k Keeper) StartCollateralAuction(ctx sdk.Context, seller string, lot sdk.C
types.DistantFuture, types.DistantFuture,
maxBid, maxBid,
weightedAddresses, weightedAddresses,
debt) debt,
)
err = k.supplyKeeper.SendCoinsFromModuleToModule(ctx, seller, types.ModuleName, sdk.NewCoins(lot)) err = k.supplyKeeper.SendCoinsFromModuleToModule(ctx, seller, types.ModuleName, sdk.NewCoins(lot))
if err != nil { if err != nil {
@ -120,42 +124,41 @@ func (k Keeper) StartCollateralAuction(ctx sdk.Context, seller string, lot sdk.C
} }
// PlaceBid places a bid on any auction. // PlaceBid places a bid on any auction.
func (k Keeper) PlaceBid(ctx sdk.Context, auctionID uint64, bidder sdk.AccAddress, newAmount sdk.Coin) sdk.Error { func (k Keeper) PlaceBid(ctx sdk.Context, auctionID uint64, bidder sdk.AccAddress, newAmount sdk.Coin) error {
auction, found := k.GetAuction(ctx, auctionID) auction, found := k.GetAuction(ctx, auctionID)
if !found { if !found {
return types.ErrAuctionNotFound(k.codespace, auctionID) return sdkerrors.Wrapf(types.ErrAuctionNotFound, "%d", auctionID)
} }
// validation common to all auctions // validation common to all auctions
if ctx.BlockTime().After(auction.GetEndTime()) { if ctx.BlockTime().After(auction.GetEndTime()) {
return types.ErrAuctionHasExpired(k.codespace, auctionID) return sdkerrors.Wrapf(types.ErrAuctionHasExpired, "%d", auctionID)
} }
// move coins and return updated auction // move coins and return updated auction
var err sdk.Error var (
var updatedAuction types.Auction err error
updatedAuction types.Auction
)
switch a := auction.(type) { switch a := auction.(type) {
case types.SurplusAuction: case types.SurplusAuction:
if updatedAuction, err = k.PlaceBidSurplus(ctx, a, bidder, newAmount); err != nil { updatedAuction, err = k.PlaceBidSurplus(ctx, a, bidder, newAmount)
return err
}
case types.DebtAuction: case types.DebtAuction:
if updatedAuction, err = k.PlaceBidDebt(ctx, a, bidder, newAmount); err != nil { updatedAuction, err = k.PlaceBidDebt(ctx, a, bidder, newAmount)
return err
}
case types.CollateralAuction: case types.CollateralAuction:
if !a.IsReversePhase() { if !a.IsReversePhase() {
updatedAuction, err = k.PlaceForwardBidCollateral(ctx, a, bidder, newAmount) updatedAuction, err = k.PlaceForwardBidCollateral(ctx, a, bidder, newAmount)
} else { } else {
updatedAuction, err = k.PlaceReverseBidCollateral(ctx, a, bidder, newAmount) updatedAuction, err = k.PlaceReverseBidCollateral(ctx, a, bidder, newAmount)
} }
default:
err = sdkerrors.Wrap(types.ErrUnrecognizedAuctionType, auction.GetType())
}
if err != nil { if err != nil {
return err return err
} }
default:
return types.ErrUnrecognizedAuctionType(k.codespace)
}
k.SetAuction(ctx, updatedAuction) k.SetAuction(ctx, updatedAuction)
@ -163,10 +166,10 @@ func (k Keeper) PlaceBid(ctx sdk.Context, auctionID uint64, bidder sdk.AccAddres
} }
// PlaceBidSurplus places a forward bid on a surplus auction, moving coins and returning the updated auction. // PlaceBidSurplus places a forward bid on a surplus auction, moving coins and returning the updated auction.
func (k Keeper) PlaceBidSurplus(ctx sdk.Context, a types.SurplusAuction, bidder sdk.AccAddress, bid sdk.Coin) (types.SurplusAuction, sdk.Error) { func (k Keeper) PlaceBidSurplus(ctx sdk.Context, a types.SurplusAuction, bidder sdk.AccAddress, bid sdk.Coin) (types.SurplusAuction, error) {
// Validate new bid // Validate new bid
if bid.Denom != a.Bid.Denom { if bid.Denom != a.Bid.Denom {
return a, types.ErrInvalidBidDenom(k.codespace, bid.Denom, a.Bid.Denom) return a, sdkerrors.Wrapf(types.ErrInvalidBidDenom, "%s ≠ %s)", bid.Denom, a.Bid.Denom)
} }
minNewBidAmt := a.Bid.Amount.Add( // new bids must be some % greater than old bid, and at least 1 larger to avoid replacing an old bid at no cost minNewBidAmt := a.Bid.Amount.Add( // new bids must be some % greater than old bid, and at least 1 larger to avoid replacing an old bid at no cost
sdk.MaxInt( sdk.MaxInt(
@ -175,7 +178,7 @@ func (k Keeper) PlaceBidSurplus(ctx sdk.Context, a types.SurplusAuction, bidder
), ),
) )
if bid.Amount.LT(minNewBidAmt) { if bid.Amount.LT(minNewBidAmt) {
return a, types.ErrBidTooSmall(k.codespace, bid, sdk.Coin{Denom: a.Bid.Denom, Amount: minNewBidAmt}) // not using NewCoin as it can panic return a, sdkerrors.Wrapf(types.ErrBidTooSmall, "%s ≤ %s%s", bid, minNewBidAmt, a.Bid.Denom)
} }
// New bidder pays back old bidder // New bidder pays back old bidder
@ -223,13 +226,13 @@ func (k Keeper) PlaceBidSurplus(ctx sdk.Context, a types.SurplusAuction, bidder
} }
// PlaceForwardBidCollateral places a forward bid on a collateral auction, moving coins and returning the updated auction. // PlaceForwardBidCollateral places a forward bid on a collateral auction, moving coins and returning the updated auction.
func (k Keeper) PlaceForwardBidCollateral(ctx sdk.Context, a types.CollateralAuction, bidder sdk.AccAddress, bid sdk.Coin) (types.CollateralAuction, sdk.Error) { func (k Keeper) PlaceForwardBidCollateral(ctx sdk.Context, a types.CollateralAuction, bidder sdk.AccAddress, bid sdk.Coin) (types.CollateralAuction, error) {
// Validate new bid // Validate new bid
if bid.Denom != a.Bid.Denom { if bid.Denom != a.Bid.Denom {
return a, types.ErrInvalidBidDenom(k.codespace, bid.Denom, a.Bid.Denom) return a, sdkerrors.Wrapf(types.ErrInvalidBidDenom, "%s ≠ %s", bid.Denom, a.Bid.Denom)
} }
if a.IsReversePhase() { if a.IsReversePhase() {
return a, types.ErrCollateralAuctionIsInReversePhase(k.codespace, a.ID) return a, sdkerrors.Wrapf(types.ErrCollateralAuctionIsInReversePhase, "%d", a.ID)
} }
minNewBidAmt := a.Bid.Amount.Add( // new bids must be some % greater than old bid, and at least 1 larger to avoid replacing an old bid at no cost minNewBidAmt := a.Bid.Amount.Add( // new bids must be some % greater than old bid, and at least 1 larger to avoid replacing an old bid at no cost
sdk.MaxInt( sdk.MaxInt(
@ -239,10 +242,10 @@ func (k Keeper) PlaceForwardBidCollateral(ctx sdk.Context, a types.CollateralAuc
) )
minNewBidAmt = sdk.MinInt(minNewBidAmt, a.MaxBid.Amount) // allow new bids to hit MaxBid even though it may be less than the increment % minNewBidAmt = sdk.MinInt(minNewBidAmt, a.MaxBid.Amount) // allow new bids to hit MaxBid even though it may be less than the increment %
if bid.Amount.LT(minNewBidAmt) { if bid.Amount.LT(minNewBidAmt) {
return a, types.ErrBidTooSmall(k.codespace, bid, sdk.Coin{Denom: a.Bid.Denom, Amount: minNewBidAmt}) // not using NewCoin as it can panic return a, sdkerrors.Wrapf(types.ErrBidTooSmall, "%s ≤ %s%s", bid, minNewBidAmt, a.Bid.Denom)
} }
if a.MaxBid.IsLT(bid) { if a.MaxBid.IsLT(bid) {
return a, types.ErrBidTooLarge(k.codespace, bid, a.MaxBid) return a, sdkerrors.Wrapf(types.ErrBidTooLarge, "%s > %s", bid, a.MaxBid)
} }
// New bidder pays back old bidder // New bidder pays back old bidder
@ -299,13 +302,13 @@ func (k Keeper) PlaceForwardBidCollateral(ctx sdk.Context, a types.CollateralAuc
} }
// PlaceReverseBidCollateral places a reverse bid on a collateral auction, moving coins and returning the updated auction. // PlaceReverseBidCollateral places a reverse bid on a collateral auction, moving coins and returning the updated auction.
func (k Keeper) PlaceReverseBidCollateral(ctx sdk.Context, a types.CollateralAuction, bidder sdk.AccAddress, lot sdk.Coin) (types.CollateralAuction, sdk.Error) { func (k Keeper) PlaceReverseBidCollateral(ctx sdk.Context, a types.CollateralAuction, bidder sdk.AccAddress, lot sdk.Coin) (types.CollateralAuction, error) {
// Validate new bid // Validate new bid
if lot.Denom != a.Lot.Denom { if lot.Denom != a.Lot.Denom {
return a, types.ErrInvalidLotDenom(k.codespace, lot.Denom, a.Lot.Denom) return a, sdkerrors.Wrapf(types.ErrInvalidLotDenom, lot.Denom, a.Lot.Denom)
} }
if !a.IsReversePhase() { if !a.IsReversePhase() {
return a, types.ErrCollateralAuctionIsInForwardPhase(k.codespace, a.ID) return a, sdkerrors.Wrapf(types.ErrCollateralAuctionIsInForwardPhase, "%d", a.ID)
} }
maxNewLotAmt := a.Lot.Amount.Sub( // new lot must be some % less than old lot, and at least 1 smaller to avoid replacing an old bid at no cost maxNewLotAmt := a.Lot.Amount.Sub( // new lot must be some % less than old lot, and at least 1 smaller to avoid replacing an old bid at no cost
sdk.MaxInt( sdk.MaxInt(
@ -314,10 +317,10 @@ func (k Keeper) PlaceReverseBidCollateral(ctx sdk.Context, a types.CollateralAuc
), ),
) )
if lot.Amount.GT(maxNewLotAmt) { if lot.Amount.GT(maxNewLotAmt) {
return a, types.ErrLotTooLarge(k.codespace, lot, sdk.Coin{Denom: a.Lot.Denom, Amount: maxNewLotAmt}) // not using NewCoin as it can panic return a, sdkerrors.Wrapf(types.ErrLotTooLarge, "%s > %s%s", lot, maxNewLotAmt, a.Lot.Denom)
} }
if lot.IsNegative() { if lot.IsNegative() {
return a, types.ErrLotTooSmall(k.codespace, lot, sdk.Coin{Denom: a.Lot.Denom, Amount: sdk.ZeroInt()}) return a, sdkerrors.Wrapf(types.ErrLotTooSmall, "%s ≤ %s%s", lot, sdk.ZeroInt(), a.Lot.Denom)
} }
// New bidder pays back old bidder // New bidder pays back old bidder
@ -368,10 +371,10 @@ func (k Keeper) PlaceReverseBidCollateral(ctx sdk.Context, a types.CollateralAuc
} }
// PlaceBidDebt places a reverse bid on a debt auction, moving coins and returning the updated auction. // PlaceBidDebt places a reverse bid on a debt auction, moving coins and returning the updated auction.
func (k Keeper) PlaceBidDebt(ctx sdk.Context, a types.DebtAuction, bidder sdk.AccAddress, lot sdk.Coin) (types.DebtAuction, sdk.Error) { func (k Keeper) PlaceBidDebt(ctx sdk.Context, a types.DebtAuction, bidder sdk.AccAddress, lot sdk.Coin) (types.DebtAuction, error) {
// Validate new bid // Validate new bid
if lot.Denom != a.Lot.Denom { if lot.Denom != a.Lot.Denom {
return a, types.ErrInvalidLotDenom(k.codespace, lot.Denom, a.Lot.Denom) return a, sdkerrors.Wrapf(types.ErrInvalidLotDenom, lot.Denom, a.Lot.Denom)
} }
maxNewLotAmt := a.Lot.Amount.Sub( // new lot must be some % less than old lot, and at least 1 smaller to avoid replacing an old bid at no cost maxNewLotAmt := a.Lot.Amount.Sub( // new lot must be some % less than old lot, and at least 1 smaller to avoid replacing an old bid at no cost
sdk.MaxInt( sdk.MaxInt(
@ -380,10 +383,10 @@ func (k Keeper) PlaceBidDebt(ctx sdk.Context, a types.DebtAuction, bidder sdk.Ac
), ),
) )
if lot.Amount.GT(maxNewLotAmt) { if lot.Amount.GT(maxNewLotAmt) {
return a, types.ErrLotTooLarge(k.codespace, lot, sdk.Coin{Denom: a.Lot.Denom, Amount: maxNewLotAmt}) // not using NewCoin as it can panic return a, sdkerrors.Wrapf(types.ErrLotTooLarge, "%s > %s%s", lot, maxNewLotAmt, a.Lot.Denom)
} }
if lot.IsNegative() { if lot.IsNegative() {
return a, types.ErrLotTooSmall(k.codespace, lot, sdk.Coin{Denom: a.Lot.Denom, Amount: sdk.ZeroInt()}) return a, sdkerrors.Wrapf(types.ErrLotTooSmall, "%s ≤ %s%s", lot, sdk.ZeroInt(), a.Lot.Denom)
} }
// New bidder pays back old bidder // New bidder pays back old bidder
@ -434,15 +437,15 @@ func (k Keeper) PlaceBidDebt(ctx sdk.Context, a types.DebtAuction, bidder sdk.Ac
} }
// CloseAuction closes an auction and distributes funds to the highest bidder. // CloseAuction closes an auction and distributes funds to the highest bidder.
func (k Keeper) CloseAuction(ctx sdk.Context, auctionID uint64) sdk.Error { func (k Keeper) CloseAuction(ctx sdk.Context, auctionID uint64) error {
auction, found := k.GetAuction(ctx, auctionID) auction, found := k.GetAuction(ctx, auctionID)
if !found { if !found {
return types.ErrAuctionNotFound(k.codespace, auctionID) return sdkerrors.Wrapf(types.ErrAuctionNotFound, "%d", auctionID)
} }
if ctx.BlockTime().Before(auction.GetEndTime()) { if ctx.BlockTime().Before(auction.GetEndTime()) {
return types.ErrAuctionHasNotExpired(k.codespace, ctx.BlockTime(), auction.GetEndTime()) return sdkerrors.Wrapf(types.ErrAuctionHasNotExpired, "block time %s, auction end time %s", ctx.BlockTime().UTC(), auction.GetEndTime().UTC())
} }
// payout to the last bidder // payout to the last bidder
@ -460,7 +463,7 @@ func (k Keeper) CloseAuction(ctx sdk.Context, auctionID uint64) sdk.Error {
return err return err
} }
default: default:
return types.ErrUnrecognizedAuctionType(k.codespace) return sdkerrors.Wrap(types.ErrUnrecognizedAuctionType, auc.GetType())
} }
k.DeleteAuction(ctx, auctionID) k.DeleteAuction(ctx, auctionID)
@ -475,7 +478,7 @@ func (k Keeper) CloseAuction(ctx sdk.Context, auctionID uint64) sdk.Error {
} }
// PayoutDebtAuction pays out the proceeds for a debt auction, first minting the coins. // PayoutDebtAuction pays out the proceeds for a debt auction, first minting the coins.
func (k Keeper) PayoutDebtAuction(ctx sdk.Context, a types.DebtAuction) sdk.Error { func (k Keeper) PayoutDebtAuction(ctx sdk.Context, a types.DebtAuction) error {
err := k.supplyKeeper.MintCoins(ctx, a.Initiator, sdk.NewCoins(a.Lot)) err := k.supplyKeeper.MintCoins(ctx, a.Initiator, sdk.NewCoins(a.Lot))
if err != nil { if err != nil {
return err return err
@ -494,7 +497,7 @@ func (k Keeper) PayoutDebtAuction(ctx sdk.Context, a types.DebtAuction) sdk.Erro
} }
// PayoutSurplusAuction pays out the proceeds for a surplus auction. // PayoutSurplusAuction pays out the proceeds for a surplus auction.
func (k Keeper) PayoutSurplusAuction(ctx sdk.Context, a types.SurplusAuction) sdk.Error { func (k Keeper) PayoutSurplusAuction(ctx sdk.Context, a types.SurplusAuction) error {
err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, a.Bidder, sdk.NewCoins(a.Lot)) err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, a.Bidder, sdk.NewCoins(a.Lot))
if err != nil { if err != nil {
return err return err
@ -503,7 +506,7 @@ func (k Keeper) PayoutSurplusAuction(ctx sdk.Context, a types.SurplusAuction) sd
} }
// PayoutCollateralAuction pays out the proceeds for a collateral auction. // PayoutCollateralAuction pays out the proceeds for a collateral auction.
func (k Keeper) PayoutCollateralAuction(ctx sdk.Context, a types.CollateralAuction) sdk.Error { func (k Keeper) PayoutCollateralAuction(ctx sdk.Context, a types.CollateralAuction) error {
err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, a.Bidder, sdk.NewCoins(a.Lot)) err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, a.Bidder, sdk.NewCoins(a.Lot))
if err != nil { if err != nil {
return err return err
@ -518,7 +521,7 @@ func (k Keeper) PayoutCollateralAuction(ctx sdk.Context, a types.CollateralAucti
} }
// CloseExpiredAuctions finds all auctions that are past (or at) their ending times and closes them, paying out to the highest bidder. // CloseExpiredAuctions finds all auctions that are past (or at) their ending times and closes them, paying out to the highest bidder.
func (k Keeper) CloseExpiredAuctions(ctx sdk.Context) sdk.Error { func (k Keeper) CloseExpiredAuctions(ctx sdk.Context) error {
var expiredAuctions []uint64 var expiredAuctions []uint64
k.IterateAuctionsByTime(ctx, ctx.BlockTime(), func(id uint64) bool { k.IterateAuctionsByTime(ctx, ctx.BlockTime(), func(id uint64) bool {
expiredAuctions = append(expiredAuctions, id) expiredAuctions = append(expiredAuctions, id)
@ -542,10 +545,10 @@ func earliestTime(t1, t2 time.Time) time.Time {
} }
// splitCoinIntoWeightedBuckets divides up some amount of coins according to some weights. // splitCoinIntoWeightedBuckets divides up some amount of coins according to some weights.
func splitCoinIntoWeightedBuckets(coin sdk.Coin, buckets []sdk.Int) ([]sdk.Coin, sdk.Error) { func splitCoinIntoWeightedBuckets(coin sdk.Coin, buckets []sdk.Int) ([]sdk.Coin, error) {
for _, bucket := range buckets { for _, bucket := range buckets {
if bucket.IsNegative() { if bucket.IsNegative() {
return nil, sdk.ErrInternal("cannot split coin into bucket with negative weight") return nil, fmt.Errorf("cannot split %s into bucket with negative weight (%s)", coin.String(), bucket.String())
} }
} }
amounts := splitIntIntoWeightedBuckets(coin.Amount, buckets) amounts := splitIntIntoWeightedBuckets(coin.Amount, buckets)

View File

@ -267,30 +267,31 @@ func TestStartSurplusAuction(t *testing.T) {
blockTime time.Time blockTime time.Time
args args args args
expectPass bool expectPass bool
expPanic bool
}{ }{
{ {
"normal", "normal",
someTime, someTime,
args{cdp.LiquidatorMacc, c("stable", 10), "gov"}, args{cdp.LiquidatorMacc, c("stable", 10), "gov"},
true, true, false,
}, },
{ {
"no module account", "no module account",
someTime, someTime,
args{"nonExistentModule", c("stable", 10), "gov"}, args{"nonExistentModule", c("stable", 10), "gov"},
false, false, true,
}, },
{ {
"not enough coins", "not enough coins",
someTime, someTime,
args{cdp.LiquidatorMacc, c("stable", 101), "gov"}, args{cdp.LiquidatorMacc, c("stable", 101), "gov"},
false, false, false,
}, },
{ {
"incorrect denom", "incorrect denom",
someTime, someTime,
args{cdp.LiquidatorMacc, c("notacoin", 10), "gov"}, args{cdp.LiquidatorMacc, c("notacoin", 10), "gov"},
false, false, false,
}, },
} }
for _, tc := range testCases { for _, tc := range testCases {
@ -308,7 +309,15 @@ func TestStartSurplusAuction(t *testing.T) {
keeper := tApp.GetAuctionKeeper() keeper := tApp.GetAuctionKeeper()
// run function under test // run function under test
id, err := keeper.StartSurplusAuction(ctx, tc.args.seller, tc.args.lot, tc.args.bidDenom) var (
id uint64
err error
)
if tc.expPanic {
require.Panics(t, func() { _, _ = keeper.StartSurplusAuction(ctx, tc.args.seller, tc.args.lot, tc.args.bidDenom) }, tc.name)
} else {
id, err = keeper.StartSurplusAuction(ctx, tc.args.seller, tc.args.lot, tc.args.bidDenom)
}
// check // check
sk := tApp.GetSupplyKeeper() sk := tApp.GetSupplyKeeper()
@ -316,11 +325,11 @@ func TestStartSurplusAuction(t *testing.T) {
actualAuc, found := keeper.GetAuction(ctx, id) actualAuc, found := keeper.GetAuction(ctx, id)
if tc.expectPass { if tc.expectPass {
require.NoError(t, err) require.NoError(t, err, tc.name)
// check coins moved // check coins moved
require.Equal(t, initialLiquidatorCoins.Sub(cs(tc.args.lot)), liquidatorCoins) require.Equal(t, initialLiquidatorCoins.Sub(cs(tc.args.lot)), liquidatorCoins, tc.name)
// check auction in store and is correct // check auction in store and is correct
require.True(t, found) require.True(t, found, tc.name)
expectedAuction := types.Auction(types.SurplusAuction{BaseAuction: types.BaseAuction{ expectedAuction := types.Auction(types.SurplusAuction{BaseAuction: types.BaseAuction{
ID: id, ID: id,
Initiator: tc.args.seller, Initiator: tc.args.seller,
@ -331,13 +340,13 @@ func TestStartSurplusAuction(t *testing.T) {
EndTime: types.DistantFuture, EndTime: types.DistantFuture,
MaxEndTime: types.DistantFuture, MaxEndTime: types.DistantFuture,
}}) }})
require.Equal(t, expectedAuction, actualAuc) require.Equal(t, expectedAuction, actualAuc, tc.name)
} else { } else if !tc.expPanic && !tc.expectPass {
require.Error(t, err) require.Error(t, err, tc.name)
// check coins not moved // check coins not moved
require.Equal(t, initialLiquidatorCoins, liquidatorCoins) require.Equal(t, initialLiquidatorCoins, liquidatorCoins, tc.name)
// check auction not in store // check auction not in store
require.False(t, found) require.False(t, found, tc.name)
} }
}) })
} }

View File

@ -1,6 +1,7 @@
package keeper_test package keeper_test
import ( import (
"errors"
"strings" "strings"
"testing" "testing"
"time" "time"
@ -55,319 +56,347 @@ func TestAuctionBidding(t *testing.T) {
auctionArgs auctionArgs auctionArgs auctionArgs
setupBids []bidArgs setupBids []bidArgs
bidArgs bidArgs bidArgs bidArgs
expectedError sdk.CodeType expectedError error
expectedEndTime time.Time expectedEndTime time.Time
expectedBidder sdk.AccAddress expectedBidder sdk.AccAddress
expectedBid sdk.Coin expectedBid sdk.Coin
expectpass bool expectPass bool
expectPanic bool
}{ }{
{ {
"basic: auction doesn't exist", "basic: auction doesn't exist",
auctionArgs{Surplus, "", c("token1", 1), c("token2", 1), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}}, auctionArgs{Surplus, "", c("token1", 1), c("token2", 1), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
nil, nil,
bidArgs{buyer, c("token2", 10)}, bidArgs{buyer, c("token2", 10)},
types.CodeAuctionNotFound, types.ErrAuctionNotFound,
someTime.Add(types.DefaultBidDuration), someTime.Add(types.DefaultBidDuration),
buyer, buyer,
c("token2", 10), c("token2", 10),
false, false,
true,
}, },
{ {
"basic: closed auction", "basic: closed auction",
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}}, auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
nil, nil,
bidArgs{buyer, c("token2", 10)}, bidArgs{buyer, c("token2", 10)},
types.CodeAuctionHasExpired, types.ErrAuctionHasExpired,
types.DistantFuture, types.DistantFuture,
nil, nil,
c("token2", 0), c("token2", 0),
false, false,
false,
}, },
{ {
"surplus: normal", "surplus: normal",
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}}, auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
nil, nil,
bidArgs{buyer, c("token2", 10)}, bidArgs{buyer, c("token2", 10)},
sdk.CodeType(0), nil,
someTime.Add(types.DefaultBidDuration), someTime.Add(types.DefaultBidDuration),
buyer, buyer,
c("token2", 10), c("token2", 10),
true, true,
false,
}, },
{ {
"surplus: second bidder", "surplus: second bidder",
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}}, auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
[]bidArgs{{buyer, c("token2", 10)}}, []bidArgs{{buyer, c("token2", 10)}},
bidArgs{secondBuyer, c("token2", 11)}, bidArgs{secondBuyer, c("token2", 11)},
sdk.CodeType(0), nil,
someTime.Add(types.DefaultBidDuration), someTime.Add(types.DefaultBidDuration),
secondBuyer, secondBuyer,
c("token2", 11), c("token2", 11),
true, true,
false,
}, },
{ {
"surplus: invalid bid denom", "surplus: invalid bid denom",
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}}, auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
nil, nil,
bidArgs{buyer, c("badtoken", 10)}, bidArgs{buyer, c("badtoken", 10)},
types.CodeInvalidBidDenom, types.ErrInvalidBidDenom,
types.DistantFuture, types.DistantFuture,
nil, // surplus auctions are created with initial bidder as a nil address nil, // surplus auctions are created with initial bidder as a nil address
c("token2", 0), c("token2", 0),
false, false,
false,
}, },
{ {
"surplus: invalid bid (less than)", "surplus: invalid bid (less than)",
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 0), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}}, auctionArgs{Surplus, modName, c("token1", 100), c("token2", 0), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
[]bidArgs{{buyer, c("token2", 100)}}, []bidArgs{{buyer, c("token2", 100)}},
bidArgs{buyer, c("token2", 99)}, bidArgs{buyer, c("token2", 99)},
types.CodeBidTooSmall, types.ErrBidTooSmall,
someTime.Add(types.DefaultBidDuration), someTime.Add(types.DefaultBidDuration),
buyer, buyer,
c("token2", 100), c("token2", 100),
false, false,
false,
}, },
{ {
"surplus: invalid bid (equal)", "surplus: invalid bid (equal)",
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 0), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}}, auctionArgs{Surplus, modName, c("token1", 100), c("token2", 0), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
nil, nil,
bidArgs{buyer, c("token2", 0)}, // min bid is technically 0 at default 5%, but it's capped at 1 bidArgs{buyer, c("token2", 0)}, // min bid is technically 0 at default 5%, but it's capped at 1
types.CodeBidTooSmall, types.ErrBidTooSmall,
types.DistantFuture, types.DistantFuture,
nil, // surplus auctions are created with initial bidder as a nil address nil, // surplus auctions are created with initial bidder as a nil address
c("token2", 0), c("token2", 0),
false, false,
false,
}, },
{ {
"surplus: invalid bid (less than min increment)", "surplus: invalid bid (less than min increment)",
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 0), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}}, auctionArgs{Surplus, modName, c("token1", 100), c("token2", 0), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
[]bidArgs{{buyer, c("token2", 100)}}, []bidArgs{{buyer, c("token2", 100)}},
bidArgs{buyer, c("token2", 104)}, // min bid is 105 at default 5% bidArgs{buyer, c("token2", 104)}, // min bid is 105 at default 5%
types.CodeBidTooSmall, types.ErrBidTooSmall,
someTime.Add(types.DefaultBidDuration), someTime.Add(types.DefaultBidDuration),
buyer, buyer,
c("token2", 100), c("token2", 100),
false, false,
false,
}, },
{ {
"debt: normal", "debt: normal",
auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}}, // initial bid, lot auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}}, // initial bid, lot
nil, nil,
bidArgs{buyer, c("token1", 10)}, bidArgs{buyer, c("token1", 10)},
sdk.CodeType(0), nil,
someTime.Add(types.DefaultBidDuration), someTime.Add(types.DefaultBidDuration),
buyer, buyer,
c("token2", 100), c("token2", 100),
true, true,
false,
}, },
{ {
"debt: second bidder", "debt: second bidder",
auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}}, // initial bid, lot auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}}, // initial bid, lot
[]bidArgs{{buyer, c("token1", 10)}}, []bidArgs{{buyer, c("token1", 10)}},
bidArgs{secondBuyer, c("token1", 9)}, bidArgs{secondBuyer, c("token1", 9)},
sdk.CodeType(0), nil,
someTime.Add(types.DefaultBidDuration), someTime.Add(types.DefaultBidDuration),
secondBuyer, secondBuyer,
c("token2", 100), c("token2", 100),
true, true,
false,
}, },
{ {
"debt: invalid lot denom", "debt: invalid lot denom",
auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}}, // initial bid, lot auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}}, // initial bid, lot
nil, nil,
bidArgs{buyer, c("badtoken", 10)}, bidArgs{buyer, c("badtoken", 10)},
types.CodeInvalidLotDenom, types.ErrInvalidLotDenom,
types.DistantFuture, types.DistantFuture,
supply.NewModuleAddress(modName), supply.NewModuleAddress(modName),
c("token2", 100), c("token2", 100),
false, false,
false,
}, },
{ {
"debt: invalid lot size (larger)", "debt: invalid lot size (larger)",
auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}}, auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}},
nil, nil,
bidArgs{buyer, c("token1", 21)}, bidArgs{buyer, c("token1", 21)},
types.CodeLotTooLarge, types.ErrLotTooLarge,
types.DistantFuture, types.DistantFuture,
supply.NewModuleAddress(modName), supply.NewModuleAddress(modName),
c("token2", 100), c("token2", 100),
false, false,
false,
}, },
{ {
"debt: invalid lot size (equal)", "debt: invalid lot size (equal)",
auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}}, auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}},
nil, nil,
bidArgs{buyer, c("token1", 20)}, bidArgs{buyer, c("token1", 20)},
types.CodeLotTooLarge, types.ErrLotTooLarge,
types.DistantFuture, types.DistantFuture,
supply.NewModuleAddress(modName), supply.NewModuleAddress(modName),
c("token2", 100), c("token2", 100),
false, false,
false,
}, },
{ {
"debt: invalid lot size (larger than min increment)", "debt: invalid lot size (larger than min increment)",
auctionArgs{Debt, modName, c("token1", 60), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}}, auctionArgs{Debt, modName, c("token1", 60), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}},
nil, nil,
bidArgs{buyer, c("token1", 58)}, // max lot at default 5% is 57 bidArgs{buyer, c("token1", 58)}, // max lot at default 5% is 57
types.CodeLotTooLarge, types.ErrLotTooLarge,
types.DistantFuture, types.DistantFuture,
supply.NewModuleAddress(modName), supply.NewModuleAddress(modName),
c("token2", 100), c("token2", 100),
false, false, false,
}, },
{ {
"collateral [forward]: normal", "collateral [forward]: normal",
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
nil, nil,
bidArgs{buyer, c("token2", 10)}, bidArgs{buyer, c("token2", 10)},
sdk.CodeType(0), nil,
someTime.Add(types.DefaultBidDuration), someTime.Add(types.DefaultBidDuration),
buyer, buyer,
c("token2", 10), c("token2", 10),
true, true,
false,
}, },
{ {
"collateral [forward]: second bidder", "collateral [forward]: second bidder",
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
[]bidArgs{{buyer, c("token2", 10)}}, []bidArgs{{buyer, c("token2", 10)}},
bidArgs{secondBuyer, c("token2", 11)}, bidArgs{secondBuyer, c("token2", 11)},
sdk.CodeType(0), nil,
someTime.Add(types.DefaultBidDuration), someTime.Add(types.DefaultBidDuration),
secondBuyer, secondBuyer,
c("token2", 11), c("token2", 11),
true, true,
false,
}, },
{ {
"collateral [forward]: invalid bid denom", "collateral [forward]: invalid bid denom",
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
nil, nil,
bidArgs{buyer, c("badtoken", 10)}, bidArgs{buyer, c("badtoken", 10)},
types.CodeInvalidBidDenom, types.ErrInvalidBidDenom,
types.DistantFuture, types.DistantFuture,
nil, nil,
c("token2", 0), c("token2", 0),
false, false,
false,
}, },
{ {
"collateral [forward]: invalid bid size (smaller)", "collateral [forward]: invalid bid size (smaller)",
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
[]bidArgs{{buyer, c("token2", 10)}}, []bidArgs{{buyer, c("token2", 10)}},
bidArgs{buyer, c("token2", 9)}, bidArgs{buyer, c("token2", 9)},
types.CodeBidTooSmall, types.ErrBidTooSmall,
someTime.Add(types.DefaultBidDuration), someTime.Add(types.DefaultBidDuration),
buyer, buyer,
c("token2", 10), c("token2", 10),
false, false,
false,
}, },
{ {
"collateral [forward]: invalid bid size (equal)", "collateral [forward]: invalid bid size (equal)",
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
nil, nil,
bidArgs{buyer, c("token2", 0)}, bidArgs{buyer, c("token2", 0)},
types.CodeBidTooSmall, types.ErrBidTooSmall,
types.DistantFuture, types.DistantFuture,
nil, nil,
c("token2", 0), c("token2", 0),
false, false,
false,
}, },
{ {
"collateral [forward]: invalid bid size (less than min increment)", "collateral [forward]: invalid bid size (less than min increment)",
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
[]bidArgs{{buyer, c("token2", 50)}}, []bidArgs{{buyer, c("token2", 50)}},
bidArgs{buyer, c("token2", 51)}, bidArgs{buyer, c("token2", 51)},
types.CodeBidTooSmall, types.ErrBidTooSmall,
someTime.Add(types.DefaultBidDuration), someTime.Add(types.DefaultBidDuration),
buyer, buyer,
c("token2", 50), c("token2", 50),
false, false,
false,
}, },
{ {
"collateral [forward]: less than min increment but equal to maxBid", "collateral [forward]: less than min increment but equal to maxBid",
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
[]bidArgs{{buyer, c("token2", 99)}}, []bidArgs{{buyer, c("token2", 99)}},
bidArgs{buyer, c("token2", 100)}, // min bid at default 5% is 104 bidArgs{buyer, c("token2", 100)}, // min bid at default 5% is 104
sdk.CodeType(0), nil,
someTime.Add(types.DefaultBidDuration), someTime.Add(types.DefaultBidDuration),
buyer, buyer,
c("token2", 100), c("token2", 100),
true, true,
false,
}, },
{ {
"collateral [forward]: invalid bid size (greater than max)", "collateral [forward]: invalid bid size (greater than max)",
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
nil, nil,
bidArgs{buyer, c("token2", 101)}, bidArgs{buyer, c("token2", 101)},
types.CodeBidTooLarge, types.ErrBidTooLarge,
types.DistantFuture, types.DistantFuture,
nil, nil,
c("token2", 0), c("token2", 0),
false, false,
false,
}, },
{ {
"collateral [reverse]: normal", "collateral [reverse]: normal",
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
[]bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase []bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase
bidArgs{buyer, c("token1", 15)}, bidArgs{buyer, c("token1", 15)},
sdk.CodeType(0), nil,
someTime.Add(types.DefaultBidDuration), someTime.Add(types.DefaultBidDuration),
buyer, buyer,
c("token2", 50), c("token2", 50),
true, true,
false,
}, },
{ {
"collateral [reverse]: second bidder", "collateral [reverse]: second bidder",
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
[]bidArgs{{buyer, c("token2", 50)}, {buyer, c("token1", 15)}}, // put auction into reverse phase, and add a reverse phase bid []bidArgs{{buyer, c("token2", 50)}, {buyer, c("token1", 15)}}, // put auction into reverse phase, and add a reverse phase bid
bidArgs{secondBuyer, c("token1", 14)}, bidArgs{secondBuyer, c("token1", 14)},
sdk.CodeType(0), nil,
someTime.Add(types.DefaultBidDuration), someTime.Add(types.DefaultBidDuration),
secondBuyer, secondBuyer,
c("token2", 50), c("token2", 50),
true, true,
false,
}, },
{ {
"collateral [reverse]: invalid lot denom", "collateral [reverse]: invalid lot denom",
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
[]bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase []bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase
bidArgs{buyer, c("badtoken", 15)}, bidArgs{buyer, c("badtoken", 15)},
types.CodeInvalidLotDenom, types.ErrInvalidLotDenom,
someTime.Add(types.DefaultBidDuration), someTime.Add(types.DefaultBidDuration),
buyer, buyer,
c("token2", 50), c("token2", 50),
false, false,
false,
}, },
{ {
"collateral [reverse]: invalid lot size (greater)", "collateral [reverse]: invalid lot size (greater)",
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
[]bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase []bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase
bidArgs{buyer, c("token1", 21)}, bidArgs{buyer, c("token1", 21)},
types.CodeLotTooLarge, types.ErrLotTooLarge,
someTime.Add(types.DefaultBidDuration), someTime.Add(types.DefaultBidDuration),
buyer, buyer,
c("token2", 50), c("token2", 50),
false, false,
false,
}, },
{ {
"collateral [reverse]: invalid lot size (equal)", "collateral [reverse]: invalid lot size (equal)",
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid auctionArgs{Collateral, modName, c("token1", 20), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
[]bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase []bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase
bidArgs{buyer, c("token1", 20)}, bidArgs{buyer, c("token1", 20)},
types.CodeLotTooLarge, types.ErrLotTooLarge,
someTime.Add(types.DefaultBidDuration), someTime.Add(types.DefaultBidDuration),
buyer, buyer,
c("token2", 50), c("token2", 50),
false, false,
false,
}, },
{ {
"collateral [reverse]: invalid lot size (larger than min increment)", "collateral [reverse]: invalid lot size (larger than min increment)",
auctionArgs{Collateral, modName, c("token1", 60), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid auctionArgs{Collateral, modName, c("token1", 60), c("token2", 50), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
[]bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase []bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase
bidArgs{buyer, c("token1", 58)}, // max lot at default 5% is 57 bidArgs{buyer, c("token1", 58)}, // max lot at default 5% is 57
types.CodeLotTooLarge, types.ErrLotTooLarge,
someTime.Add(types.DefaultBidDuration), someTime.Add(types.DefaultBidDuration),
buyer, buyer,
c("token2", 50), c("token2", 50),
false, false,
false,
}, },
} }
for _, tc := range tests { for _, tc := range tests {
@ -394,17 +423,26 @@ func TestAuctionBidding(t *testing.T) {
// Start Auction // Start Auction
var id uint64 var id uint64
var err sdk.Error var err error
switch tc.auctionArgs.auctionType { switch tc.auctionArgs.auctionType {
case Surplus: case Surplus:
id, _ = keeper.StartSurplusAuction(ctx, tc.auctionArgs.seller, tc.auctionArgs.lot, tc.auctionArgs.bid.Denom) if tc.expectPanic {
require.Panics(t, func() {
id, err = keeper.StartSurplusAuction(ctx, tc.auctionArgs.seller, tc.auctionArgs.lot, tc.auctionArgs.bid.Denom)
})
} else {
id, err = keeper.StartSurplusAuction(ctx, tc.auctionArgs.seller, tc.auctionArgs.lot, tc.auctionArgs.bid.Denom)
}
case Debt: case Debt:
id, _ = keeper.StartDebtAuction(ctx, tc.auctionArgs.seller, tc.auctionArgs.bid, tc.auctionArgs.lot, tc.auctionArgs.debt) id, err = keeper.StartDebtAuction(ctx, tc.auctionArgs.seller, tc.auctionArgs.bid, tc.auctionArgs.lot, tc.auctionArgs.debt)
case Collateral: case Collateral:
id, _ = keeper.StartCollateralAuction(ctx, tc.auctionArgs.seller, tc.auctionArgs.lot, tc.auctionArgs.bid, tc.auctionArgs.addresses, tc.auctionArgs.weights, tc.auctionArgs.debt) // seller, lot, maxBid, otherPerson id, err = keeper.StartCollateralAuction(ctx, tc.auctionArgs.seller, tc.auctionArgs.lot, tc.auctionArgs.bid, tc.auctionArgs.addresses, tc.auctionArgs.weights, tc.auctionArgs.debt) // seller, lot, maxBid, otherPerson
default: default:
t.Fail() t.Fail()
} }
require.NoError(t, err)
// Place setup bids // Place setup bids
for _, b := range tc.setupBids { for _, b := range tc.setupBids {
require.NoError(t, keeper.PlaceBid(ctx, id, b.bidder, b.amount)) require.NoError(t, keeper.PlaceBid(ctx, id, b.bidder, b.amount))
@ -428,7 +466,7 @@ func TestAuctionBidding(t *testing.T) {
err = keeper.PlaceBid(ctx, id, tc.bidArgs.bidder, tc.bidArgs.amount) err = keeper.PlaceBid(ctx, id, tc.bidArgs.bidder, tc.bidArgs.amount)
// Check success/failure // Check success/failure
if tc.expectpass { if tc.expectPass {
require.Nil(t, err) require.Nil(t, err)
// Check auction was found // Check auction was found
newAuction, found := keeper.GetAuction(ctx, id) newAuction, found := keeper.GetAuction(ctx, id)
@ -445,7 +483,8 @@ func TestAuctionBidding(t *testing.T) {
case Debt: case Debt:
bidAmt = oldAuction.GetBid() bidAmt = oldAuction.GetBid()
case Collateral: case Collateral:
collatAuction, _ := oldAuction.(types.CollateralAuction) collatAuction, ok := oldAuction.(types.CollateralAuction)
require.True(t, ok, tc.name)
if collatAuction.IsReversePhase() { if collatAuction.IsReversePhase() {
bidAmt = oldAuction.GetBid() bidAmt = oldAuction.GetBid()
} }
@ -453,18 +492,18 @@ func TestAuctionBidding(t *testing.T) {
if oldBidder.Equals(tc.bidArgs.bidder) { // same bidder if oldBidder.Equals(tc.bidArgs.bidder) { // same bidder
require.Equal(t, newBidderOldCoins.Sub(cs(bidAmt.Sub(oldAuction.GetBid()))), bank.GetCoins(ctx, tc.bidArgs.bidder)) require.Equal(t, newBidderOldCoins.Sub(cs(bidAmt.Sub(oldAuction.GetBid()))), bank.GetCoins(ctx, tc.bidArgs.bidder))
} else { } else {
require.Equal(t, cs(newBidderOldCoins.Sub(cs(bidAmt))...), bank.GetCoins(ctx, tc.bidArgs.bidder)) // wrapping in cs() to avoid comparing nil and empty coins require.Equal(t, newBidderOldCoins.Sub(cs(bidAmt)), bank.GetCoins(ctx, tc.bidArgs.bidder)) // wrapping in cs() to avoid comparing nil and empty coins
if oldBidder.Equals(supply.NewModuleAddress(oldAuction.GetInitiator())) { // handle checking debt coins for case debt auction has had no bids placed yet TODO make this less confusing if oldBidder.Equals(supply.NewModuleAddress(oldAuction.GetInitiator())) { // handle checking debt coins for case debt auction has had no bids placed yet TODO make this less confusing
require.Equal(t, cs(oldBidderOldCoins.Add(cs(oldAuction.GetBid()))...).Add(cs(c("debt", oldAuction.GetBid().Amount.Int64()))), bank.GetCoins(ctx, oldBidder)) require.Equal(t, oldBidderOldCoins.Add(oldAuction.GetBid()).Add(c("debt", oldAuction.GetBid().Amount.Int64())), bank.GetCoins(ctx, oldBidder))
} else { } else {
require.Equal(t, cs(oldBidderOldCoins.Add(cs(oldAuction.GetBid()))...), bank.GetCoins(ctx, oldBidder)) require.Equal(t, cs(oldBidderOldCoins.Add(oldAuction.GetBid())...), bank.GetCoins(ctx, oldBidder))
} }
} }
} else { } else {
// Check expected error code type // Check expected error code type
require.NotNil(t, err, "PlaceBid did not return an error") // catch nil values before they cause a panic below require.NotNil(t, err, "PlaceBid did not return an error") // catch nil values before they cause a panic below
require.Equal(t, tc.expectedError, err.Result().Code) require.True(t, errors.Is(err, tc.expectedError))
// Check auction values // Check auction values
newAuction, found := keeper.GetAuction(ctx, id) newAuction, found := keeper.GetAuction(ctx, id)

View File

@ -21,7 +21,7 @@ func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) {
ValidIndexInvariant(k)) ValidIndexInvariant(k))
} }
// ModuleAccountInvariant checks that the module account's coins matches those stored in auctions // ModuleAccountInvariants checks that the module account's coins matches those stored in auctions
func ModuleAccountInvariants(k Keeper) sdk.Invariant { func ModuleAccountInvariants(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) (string, bool) { return func(ctx sdk.Context) (string, bool) {
@ -31,7 +31,7 @@ func ModuleAccountInvariants(k Keeper) sdk.Invariant {
if !ok { if !ok {
panic("stored auction type does not fulfill GenesisAuction interface") panic("stored auction type does not fulfill GenesisAuction interface")
} }
totalAuctionCoins = totalAuctionCoins.Add(a.GetModuleAccountCoins()) totalAuctionCoins = totalAuctionCoins.Add(a.GetModuleAccountCoins()...)
return false return false
}) })

View File

@ -18,7 +18,6 @@ type Keeper struct {
storeKey sdk.StoreKey storeKey sdk.StoreKey
cdc *codec.Codec cdc *codec.Codec
paramSubspace subspace.Subspace paramSubspace subspace.Subspace
codespace sdk.CodespaceType
} }
// NewKeeper returns a new auction keeper. // NewKeeper returns a new auction keeper.
@ -26,11 +25,16 @@ func NewKeeper(cdc *codec.Codec, storeKey sdk.StoreKey, supplyKeeper types.Suppl
if addr := supplyKeeper.GetModuleAddress(types.ModuleName); addr == nil { if addr := supplyKeeper.GetModuleAddress(types.ModuleName); addr == nil {
panic(fmt.Sprintf("%s module account has not been set", types.ModuleName)) panic(fmt.Sprintf("%s module account has not been set", types.ModuleName))
} }
if !paramstore.HasKeyTable() {
paramstore = paramstore.WithKeyTable(types.ParamKeyTable())
}
return Keeper{ return Keeper{
supplyKeeper: supplyKeeper, supplyKeeper: supplyKeeper,
storeKey: storeKey, storeKey: storeKey,
cdc: cdc, cdc: cdc,
paramSubspace: paramstore.WithKeyTable(types.ParamKeyTable()), paramSubspace: paramstore,
} }
} }
@ -46,17 +50,17 @@ func (k Keeper) SetNextAuctionID(ctx sdk.Context, id uint64) {
} }
// GetNextAuctionID reads the next available global ID from store // GetNextAuctionID reads the next available global ID from store
func (k Keeper) GetNextAuctionID(ctx sdk.Context) (uint64, sdk.Error) { func (k Keeper) GetNextAuctionID(ctx sdk.Context) (uint64, error) {
store := ctx.KVStore(k.storeKey) store := ctx.KVStore(k.storeKey)
bz := store.Get(types.NextAuctionIDKey) bz := store.Get(types.NextAuctionIDKey)
if bz == nil { if bz == nil {
return 0, types.ErrInvalidInitialAuctionID(k.codespace) return 0, types.ErrInvalidInitialAuctionID
} }
return types.Uint64FromBytes(bz), nil return types.Uint64FromBytes(bz), nil
} }
// IncrementNextAuctionID increments the next auction ID in the store by 1. // IncrementNextAuctionID increments the next auction ID in the store by 1.
func (k Keeper) IncrementNextAuctionID(ctx sdk.Context) sdk.Error { func (k Keeper) IncrementNextAuctionID(ctx sdk.Context) error {
id, err := k.GetNextAuctionID(ctx) id, err := k.GetNextAuctionID(ctx)
if err != nil { if err != nil {
return err return err
@ -66,7 +70,7 @@ func (k Keeper) IncrementNextAuctionID(ctx sdk.Context) sdk.Error {
} }
// StoreNewAuction stores an auction, adding a new ID // StoreNewAuction stores an auction, adding a new ID
func (k Keeper) StoreNewAuction(ctx sdk.Context, auction types.Auction) (uint64, sdk.Error) { func (k Keeper) StoreNewAuction(ctx sdk.Context, auction types.Auction) (uint64, error) {
newAuctionID, err := k.GetNextAuctionID(ctx) newAuctionID, err := k.GetNextAuctionID(ctx)
if err != nil { if err != nil {
return 0, err return 0, err

View File

@ -1,16 +1,18 @@
package keeper package keeper
import ( import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
abci "github.com/tendermint/tendermint/abci/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/kava-labs/kava/x/auction/types" "github.com/kava-labs/kava/x/auction/types"
) )
// NewQuerier is the module level router for state queries // NewQuerier is the module level router for state queries
func NewQuerier(keeper Keeper) sdk.Querier { func NewQuerier(keeper Keeper) sdk.Querier {
return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err error) {
switch path[0] { switch path[0] {
case types.QueryGetAuction: case types.QueryGetAuction:
return queryAuction(ctx, req, keeper) return queryAuction(ctx, req, keeper)
@ -19,35 +21,35 @@ func NewQuerier(keeper Keeper) sdk.Querier {
case types.QueryGetParams: case types.QueryGetParams:
return queryGetParams(ctx, req, keeper) return queryGetParams(ctx, req, keeper)
default: default:
return nil, sdk.ErrUnknownRequest("unknown auction query endpoint") return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint", types.ModuleName)
} }
} }
} }
func queryAuction(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { func queryAuction(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
// Decode request // Decode request
var requestParams types.QueryAuctionParams var requestParams types.QueryAuctionParams
err := keeper.cdc.UnmarshalJSON(req.Data, &requestParams) err := types.ModuleCdc.UnmarshalJSON(req.Data, &requestParams)
if err != nil { if err != nil {
return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
} }
// Lookup auction // Lookup auction
auction, found := keeper.GetAuction(ctx, requestParams.AuctionID) auction, found := keeper.GetAuction(ctx, requestParams.AuctionID)
if !found { if !found {
return nil, types.ErrAuctionNotFound(types.DefaultCodespace, requestParams.AuctionID) return nil, sdkerrors.Wrapf(types.ErrAuctionNotFound, "%d", requestParams.AuctionID)
} }
// Encode results // Encode results
bz, err := codec.MarshalJSONIndent(keeper.cdc, auction) bz, err := codec.MarshalJSONIndent(keeper.cdc, auction)
if err != nil { if err != nil {
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
} }
return bz, nil return bz, nil
} }
func queryAuctions(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { func queryAuctions(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
// Get all auctions // Get all auctions
auctionsList := types.Auctions{} auctionsList := types.Auctions{}
keeper.IterateAuctions(ctx, func(a types.Auction) bool { keeper.IterateAuctions(ctx, func(a types.Auction) bool {
@ -58,21 +60,21 @@ func queryAuctions(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byt
// Encode Results // Encode Results
bz, err := codec.MarshalJSONIndent(keeper.cdc, auctionsList) bz, err := codec.MarshalJSONIndent(keeper.cdc, auctionsList)
if err != nil { if err != nil {
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
} }
return bz, nil return bz, nil
} }
// query params in the auction store // query params in the auction store
func queryGetParams(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { func queryGetParams(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
// Get params // Get params
params := keeper.GetParams(ctx) params := keeper.GetParams(ctx)
// Encode results // Encode results
bz, err := codec.MarshalJSONIndent(keeper.cdc, params) bz, err := codec.MarshalJSONIndent(keeper.cdc, params)
if err != nil { if err != nil {
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
} }
return bz, nil return bz, nil

View File

@ -12,6 +12,7 @@ import (
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/auth"
sim "github.com/cosmos/cosmos-sdk/x/simulation" sim "github.com/cosmos/cosmos-sdk/x/simulation"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
@ -24,7 +25,7 @@ import (
var ( var (
_ module.AppModule = AppModule{} _ module.AppModule = AppModule{}
_ module.AppModuleBasic = AppModuleBasic{} _ module.AppModuleBasic = AppModuleBasic{}
_ module.AppModuleSimulation = AppModuleSimulation{} _ module.AppModuleSimulation = AppModule{}
) )
// AppModuleBasic implements the sdk.AppModuleBasic interface. // AppModuleBasic implements the sdk.AppModuleBasic interface.
@ -72,40 +73,21 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command {
//____________________________________________________________________________ //____________________________________________________________________________
// AppModuleSimulation defines the module simulation functions used by the auction module.
type AppModuleSimulation struct{}
// RegisterStoreDecoder registers a decoder for auction module's types
func (AppModuleSimulation) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
sdr[StoreKey] = simulation.DecodeStore
}
// GenerateGenesisState creates a randomized GenState of the auction module
func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) {
simulation.RandomizedGenState(simState)
}
// RandomizedParams creates randomized auction param changes for the simulator.
func (AppModuleSimulation) RandomizedParams(r *rand.Rand) []sim.ParamChange {
return simulation.ParamChanges(r)
}
//____________________________________________________________________________
// AppModule implements the sdk.AppModule interface. // AppModule implements the sdk.AppModule interface.
type AppModule struct { type AppModule struct {
AppModuleBasic AppModuleBasic
AppModuleSimulation
keeper Keeper keeper Keeper
accountKeeper auth.AccountKeeper
supplyKeeper types.SupplyKeeper supplyKeeper types.SupplyKeeper
} }
// NewAppModule creates a new AppModule object // NewAppModule creates a new AppModule object
func NewAppModule(keeper Keeper, supplyKeeper types.SupplyKeeper) AppModule { func NewAppModule(keeper Keeper, accountKeeper auth.AccountKeeper, supplyKeeper types.SupplyKeeper) AppModule {
return AppModule{ return AppModule{
AppModuleBasic: AppModuleBasic{}, AppModuleBasic: AppModuleBasic{},
keeper: keeper, keeper: keeper,
accountKeeper: accountKeeper,
supplyKeeper: supplyKeeper, supplyKeeper: supplyKeeper,
} }
} }
@ -159,3 +141,30 @@ func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) {
func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
return []abci.ValidatorUpdate{} return []abci.ValidatorUpdate{}
} }
//____________________________________________________________________________
// GenerateGenesisState creates a randomized GenState of the auction module
func (AppModuleBasic) GenerateGenesisState(simState *module.SimulationState) {
simulation.RandomizedGenState(simState)
}
// ProposalContents doesn't return any content functions for governance proposals.
func (AppModuleBasic) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent {
return nil
}
// RandomizedParams returns nil because auction has no params.
func (AppModuleBasic) RandomizedParams(r *rand.Rand) []sim.ParamChange {
return simulation.ParamChanges(r)
}
// RegisterStoreDecoder registers a decoder for auction module's types
func (AppModuleBasic) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
sdr[StoreKey] = simulation.DecodeStore
}
// WeightedOperations returns the all the auction module operations with their respective weights.
func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation {
return simulation.WeightedOperations(simState.AppParams, simState.Cdc, am.accountKeeper, am.keeper)
}

View File

@ -5,14 +5,15 @@ import (
"encoding/binary" "encoding/binary"
"fmt" "fmt"
"github.com/tendermint/tendermint/libs/kv"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/kava-labs/kava/x/auction/types" "github.com/kava-labs/kava/x/auction/types"
) )
// DecodeStore unmarshals the KVPair's Value to the corresponding auction type // DecodeStore unmarshals the KVPair's Value to the corresponding auction type
func DecodeStore(cdc *codec.Codec, kvA, kvB cmn.KVPair) string { func DecodeStore(cdc *codec.Codec, kvA, kvB kv.Pair) string {
switch { switch {
case bytes.Equal(kvA.Key[:1], types.AuctionKeyPrefix): case bytes.Equal(kvA.Key[:1], types.AuctionKeyPrefix):
var auctionA, auctionB types.Auction var auctionA, auctionB types.Auction

View File

@ -6,8 +6,7 @@ import (
"time" "time"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/libs/kv"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
@ -28,11 +27,11 @@ func TestDecodeDistributionStore(t *testing.T) {
oneCoin := sdk.NewCoin("coin", sdk.OneInt()) oneCoin := sdk.NewCoin("coin", sdk.OneInt())
auction := types.NewSurplusAuction("me", oneCoin, "coin", time.Now().UTC()) auction := types.NewSurplusAuction("me", oneCoin, "coin", time.Now().UTC())
kvPairs := cmn.KVPairs{ kvPairs := kv.Pairs{
cmn.KVPair{Key: types.AuctionKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(&auction)}, kv.Pair{Key: types.AuctionKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(&auction)},
cmn.KVPair{Key: types.AuctionByTimeKeyPrefix, Value: sdk.Uint64ToBigEndian(2)}, kv.Pair{Key: types.AuctionByTimeKeyPrefix, Value: sdk.Uint64ToBigEndian(2)},
cmn.KVPair{Key: types.NextAuctionIDKey, Value: sdk.Uint64ToBigEndian(10)}, kv.Pair{Key: types.NextAuctionIDKey, Value: sdk.Uint64ToBigEndian(10)},
cmn.KVPair{Key: []byte{0x99}, Value: []byte{0x99}}, kv.Pair{Key: []byte{0x99}, Value: []byte{0x99}},
} }
tests := []struct { tests := []struct {

View File

@ -88,7 +88,7 @@ func RandomizedGenState(simState *module.SimulationState) {
if !ok { if !ok {
panic("can't convert Auction to GenesisAuction") panic("can't convert Auction to GenesisAuction")
} }
totalAuctionCoins = totalAuctionCoins.Add(a.GetModuleAccountCoins()) totalAuctionCoins = totalAuctionCoins.Add(a.GetModuleAccountCoins()...)
} }
auctionGenesis.NextAuctionID = startingID + uint64(len(auctions)) auctionGenesis.NextAuctionID = startingID + uint64(len(auctions))
auctionGenesis.Auctions = append(auctionGenesis.Auctions, auctions...) auctionGenesis.Auctions = append(auctionGenesis.Auctions, auctions...)
@ -112,7 +112,7 @@ func RandomizedGenState(simState *module.SimulationState) {
panic("bidder not found") panic("bidder not found")
} }
bidderCoins := sdk.NewCoins(sdk.NewInt64Coin("usdx", 10000000000)) bidderCoins := sdk.NewCoins(sdk.NewInt64Coin("usdx", 10000000000))
if err := bidder.SetCoins(bidder.GetCoins().Add(bidderCoins)); err != nil { if err := bidder.SetCoins(bidder.GetCoins().Add(bidderCoins...)); err != nil {
panic(err) panic(err)
} }
authGenesis.Accounts = replaceOrAppendAccount(authGenesis.Accounts, bidder) authGenesis.Accounts = replaceOrAppendAccount(authGenesis.Accounts, bidder)
@ -123,7 +123,7 @@ func RandomizedGenState(simState *module.SimulationState) {
// TODO find some way for this to happen automatically / move it elsewhere // TODO find some way for this to happen automatically / move it elsewhere
var supplyGenesis supply.GenesisState var supplyGenesis supply.GenesisState
simState.Cdc.MustUnmarshalJSON(simState.GenState[supply.ModuleName], &supplyGenesis) simState.Cdc.MustUnmarshalJSON(simState.GenState[supply.ModuleName], &supplyGenesis)
supplyGenesis.Supply = supplyGenesis.Supply.Add(totalAuctionCoins).Add(bidderCoins) supplyGenesis.Supply = supplyGenesis.Supply.Add(totalAuctionCoins...).Add(bidderCoins...)
simState.GenState[supply.ModuleName] = simState.Cdc.MustMarshalJSON(supplyGenesis) simState.GenState[supply.ModuleName] = simState.Cdc.MustMarshalJSON(supplyGenesis)
// TODO liquidator mod account doesn't need to be initialized for this example // TODO liquidator mod account doesn't need to be initialized for this example

View File

@ -0,0 +1,251 @@
package simulation
import (
"errors"
"fmt"
"math/big"
"math/rand"
"time"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/simapp/helpers"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
"github.com/cosmos/cosmos-sdk/x/simulation"
appparams "github.com/kava-labs/kava/app/params"
"github.com/kava-labs/kava/x/auction/keeper"
"github.com/kava-labs/kava/x/auction/types"
)
var (
errorNotEnoughCoins = errors.New("account doesn't have enough coins")
errorCantReceiveBids = errors.New("auction can't receive bids (lot = 0 in reverse auction)")
)
// Simulation operation weights constants
const (
OpWeightMsgPlaceBid = "op_weight_msg_place_bid"
)
// WeightedOperations returns all the operations from the module with their respective weights
func WeightedOperations(
appParams simulation.AppParams, cdc *codec.Codec, ak auth.AccountKeeper, k keeper.Keeper,
) simulation.WeightedOperations {
var weightMsgPlaceBid int
appParams.GetOrGenerate(cdc, OpWeightMsgPlaceBid, &weightMsgPlaceBid, nil,
func(_ *rand.Rand) {
weightMsgPlaceBid = appparams.DefaultWeightMsgPlaceBid
},
)
return simulation.WeightedOperations{
simulation.NewWeightedOperation(
weightMsgPlaceBid,
SimulateMsgPlaceBid(ak, k),
),
}
}
// SimulateMsgPlaceBid returns a function that runs a random state change on the module keeper.
// There's two error paths
// - return a OpMessage, but nil error - this will log a message but keep running the simulation
// - return an error - this will stop the simulation
func SimulateMsgPlaceBid(ak auth.AccountKeeper, keeper keeper.Keeper) simulation.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string,
) (simulation.OperationMsg, []simulation.FutureOperation, error) {
// get open auctions
openAuctions := types.Auctions{}
keeper.IterateAuctions(ctx, func(a types.Auction) bool {
openAuctions = append(openAuctions, a)
return false
})
// shuffle auctions slice so that bids are evenly distributed across auctions
r.Shuffle(len(openAuctions), func(i, j int) {
openAuctions[i], openAuctions[j] = openAuctions[j], openAuctions[i]
})
// search through auctions and an accounts to find a pair where a bid can be placed (ie account has enough coins to place bid on auction)
blockTime := ctx.BlockHeader().Time
params := keeper.GetParams(ctx)
bidder, openAuction, found := findValidAccountAuctionPair(accs, openAuctions, func(acc simulation.Account, auc types.Auction) bool {
account := ak.GetAccount(ctx, acc.Address)
_, err := generateBidAmount(r, params, auc, account, blockTime)
if err == errorNotEnoughCoins || err == errorCantReceiveBids {
return false // keep searching
} else if err != nil {
panic(err) // raise errors
}
return true // found valid pair
})
if !found {
return simulation.NewOperationMsgBasic(types.ModuleName, "no-operation (no valid auction and bidder)", "", false, nil), nil, nil
}
bidderAcc := ak.GetAccount(ctx, bidder.Address)
if bidderAcc == nil {
return simulation.NoOpMsg(types.ModuleName), nil, fmt.Errorf("couldn't find account %s", bidder.Address)
}
// pick a bid amount for the chosen auction and bidder
amount, err := generateBidAmount(r, params, openAuction, bidderAcc, blockTime)
if err != nil { // shouldn't happen given the checks above
return simulation.NoOpMsg(types.ModuleName), nil, err
}
// create and deliver a tx
msg := types.NewMsgPlaceBid(openAuction.GetID(), bidder.Address, amount)
tx := helpers.GenTx(
[]sdk.Msg{msg},
sdk.NewCoins(), // TODO pick a random amount fees
helpers.DefaultGenTxGas,
chainID,
[]uint64{bidderAcc.GetAccountNumber()},
[]uint64{bidderAcc.GetSequence()},
bidder.PrivKey,
)
_, result, err := app.Deliver(tx)
if err != nil {
// to aid debugging, add the stack trace to the comment field of the returned opMsg
return simulation.NewOperationMsg(msg, false, fmt.Sprintf("%+v", err)), nil, err
}
// to aid debugging, add the result log to the comment field
return simulation.NewOperationMsg(msg, true, result.Log), nil, nil
}
}
func generateBidAmount(
r *rand.Rand, params types.Params, auc types.Auction,
bidder authexported.Account, blockTime time.Time) (sdk.Coin, error) {
bidderBalance := bidder.SpendableCoins(blockTime)
switch a := auc.(type) {
case types.DebtAuction:
// Check bidder has enough (stable coin) to pay in
if bidderBalance.AmountOf(a.Bid.Denom).LT(a.Bid.Amount) { // stable coin
return sdk.Coin{}, errorNotEnoughCoins
}
// Check auction can still receive new bids
if a.Lot.Amount.Equal(sdk.ZeroInt()) {
return sdk.Coin{}, errorCantReceiveBids
}
// Generate a new lot amount (gov coin)
maxNewLotAmt := a.Lot.Amount.Sub( // new lot must be some % less than old lot, and at least 1 smaller to avoid replacing an old bid at no cost
sdk.MaxInt(
sdk.NewInt(1),
sdk.NewDecFromInt(a.Lot.Amount).Mul(params.IncrementDebt).RoundInt(),
),
)
amt, err := RandIntInclusive(r, sdk.ZeroInt(), maxNewLotAmt) // maxNewLotAmt shouldn't be < 0 given the check above
if err != nil {
panic(err)
}
return sdk.NewCoin(a.Lot.Denom, amt), nil // gov coin
case types.SurplusAuction:
// Check the bidder has enough (gov coin) to pay in
minNewBidAmt := a.Bid.Amount.Add( // new bids must be some % greater than old bid, and at least 1 larger to avoid replacing an old bid at no cost
sdk.MaxInt(
sdk.NewInt(1),
sdk.NewDecFromInt(a.Bid.Amount).Mul(params.IncrementSurplus).RoundInt(),
),
)
if bidderBalance.AmountOf(a.Bid.Denom).LT(minNewBidAmt) { // gov coin
return sdk.Coin{}, errorNotEnoughCoins
}
// Generate a new bid amount (gov coin)
amt, err := RandIntInclusive(r, minNewBidAmt, bidderBalance.AmountOf(a.Bid.Denom))
if err != nil {
panic(err)
}
return sdk.NewCoin(a.Bid.Denom, amt), nil // gov coin
case types.CollateralAuction:
// Check the bidder has enough (stable coin) to pay in
minNewBidAmt := a.Bid.Amount.Add( // new bids must be some % greater than old bid, and at least 1 larger to avoid replacing an old bid at no cost
sdk.MaxInt(
sdk.NewInt(1),
sdk.NewDecFromInt(a.Bid.Amount).Mul(params.IncrementCollateral).RoundInt(),
),
)
minNewBidAmt = sdk.MinInt(minNewBidAmt, a.MaxBid.Amount) // allow new bids to hit MaxBid even though it may be less than the increment %
if bidderBalance.AmountOf(a.Bid.Denom).LT(minNewBidAmt) {
return sdk.Coin{}, errorNotEnoughCoins
}
// Check auction can still receive new bids
if a.IsReversePhase() && a.Lot.Amount.Equal(sdk.ZeroInt()) {
return sdk.Coin{}, errorCantReceiveBids
}
// Generate a new bid amount (collateral coin in reverse phase)
if a.IsReversePhase() {
maxNewLotAmt := a.Lot.Amount.Sub( // new lot must be some % less than old lot, and at least 1 smaller to avoid replacing an old bid at no cost
sdk.MaxInt(
sdk.NewInt(1),
sdk.NewDecFromInt(a.Lot.Amount).Mul(params.IncrementCollateral).RoundInt(),
),
)
amt, err := RandIntInclusive(r, sdk.ZeroInt(), maxNewLotAmt) // maxNewLotAmt shouldn't be < 0 given the check above
if err != nil {
panic(err)
}
return sdk.NewCoin(a.Lot.Denom, amt), nil // collateral coin
// Generate a new bid amount (stable coin in forward phase)
} else {
amt, err := RandIntInclusive(r, minNewBidAmt, sdk.MinInt(bidderBalance.AmountOf(a.Bid.Denom), a.MaxBid.Amount))
if err != nil {
panic(err)
}
// when the bidder has enough coins, pick the MaxBid amount more frequently to increase chance auctions phase get into reverse phase
if r.Intn(2) == 0 && bidderBalance.AmountOf(a.Bid.Denom).GTE(a.MaxBid.Amount) { // 50%
amt = a.MaxBid.Amount
}
return sdk.NewCoin(a.Bid.Denom, amt), nil // stable coin
}
default:
return sdk.Coin{}, fmt.Errorf("unknown auction type")
}
}
// findValidAccountAuctionPair finds an auction and account for which the callback func returns true
func findValidAccountAuctionPair(accounts []simulation.Account, auctions types.Auctions, cb func(simulation.Account, types.Auction) bool) (simulation.Account, types.Auction, bool) {
for _, auc := range auctions {
for _, acc := range accounts {
if isValid := cb(acc, auc); isValid {
return acc, auc, true
}
}
}
return simulation.Account{}, nil, false
}
// RandIntInclusive randomly generates an sdk.Int in the range [inclusiveMin, inclusiveMax]. It works for negative and positive integers.
func RandIntInclusive(r *rand.Rand, inclusiveMin, inclusiveMax sdk.Int) (sdk.Int, error) {
if inclusiveMin.GT(inclusiveMax) {
return sdk.Int{}, fmt.Errorf("min larger than max")
}
return RandInt(r, inclusiveMin, inclusiveMax.Add(sdk.OneInt()))
}
// RandInt randomly generates an sdk.Int in the range [inclusiveMin, exclusiveMax). It works for negative and positive integers.
func RandInt(r *rand.Rand, inclusiveMin, exclusiveMax sdk.Int) (sdk.Int, error) {
// validate input
if inclusiveMin.GTE(exclusiveMax) {
return sdk.Int{}, fmt.Errorf("min larger or equal to max")
}
// shift the range to start at 0
shiftedRange := exclusiveMax.Sub(inclusiveMin) // should always be positive given the check above
// randomly pick from the shifted range
shiftedRandInt := sdk.NewIntFromBigInt(new(big.Int).Rand(r, shiftedRange.BigInt()))
// shift back to the original range
return shiftedRandInt.Add(inclusiveMin), nil
}

View File

@ -1,177 +0,0 @@
package operations
import (
"errors"
"fmt"
"math/big"
"math/rand"
"time"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
"github.com/cosmos/cosmos-sdk/x/simulation"
"github.com/kava-labs/kava/x/auction"
)
var (
noOpMsg = simulation.NoOpMsg(auction.ModuleName)
ErrorNotEnoughCoins = errors.New("account doesn't have enough coins")
)
// Return a function that runs a random state change on the module keeper.
// There's two error paths
// - return a OpMessage, but nil error - this will log a message but keep running the simulation
// - return an error - this will stop the simulation
func SimulateMsgPlaceBid(authKeeper auth.AccountKeeper, keeper auction.Keeper) simulation.Operation {
handler := auction.NewHandler(keeper)
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account) (
simulation.OperationMsg, []simulation.FutureOperation, error) {
// get open auctions
openAuctions := auction.Auctions{}
keeper.IterateAuctions(ctx, func(a auction.Auction) bool {
openAuctions = append(openAuctions, a)
return false
})
// shuffle auctions slice so that bids are evenly distributed across auctions
r.Shuffle(len(openAuctions), func(i, j int) {
openAuctions[i], openAuctions[j] = openAuctions[j], openAuctions[i]
})
// TODO do the same for accounts?
var accounts []authexported.Account
for _, acc := range accs {
accounts = append(accounts, authKeeper.GetAccount(ctx, acc.Address))
}
// search through auctions and an accounts to find a pair where a bid can be placed (ie account has enough coins to place bid on auction)
blockTime := ctx.BlockHeader().Time
bidder, openAuction, found := findValidAccountAuctionPair(accounts, openAuctions, func(acc authexported.Account, auc auction.Auction) bool {
_, err := generateBidAmount(r, auc, acc, blockTime)
if err == ErrorNotEnoughCoins {
return false // keep searching
} else if err != nil {
panic(err) // raise errors
}
return true // found valid pair
})
if !found {
return simulation.NewOperationMsgBasic(auction.ModuleName, "no-operation (no valid auction and bidder)", "", false, nil), nil, nil
}
// pick a bid amount for the chosen auction and bidder
amount, _ := generateBidAmount(r, openAuction, bidder, blockTime)
// create a msg
msg := auction.NewMsgPlaceBid(openAuction.GetID(), bidder.GetAddress(), amount)
if err := msg.ValidateBasic(); err != nil { // don't submit errors that fail ValidateBasic, use unit tests for testing ValidateBasic
return noOpMsg, nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
}
// submit the msg
result := submitMsg(ctx, handler, msg)
// Return an operationMsg indicating whether the msg was submitted successfully
// Using result.Log as the comment field as it contains any error message emitted by the keeper
return simulation.NewOperationMsg(msg, result.IsOK(), result.Log), nil, nil
}
}
func submitMsg(ctx sdk.Context, handler sdk.Handler, msg sdk.Msg) sdk.Result {
ctx, write := ctx.CacheContext()
result := handler(ctx, msg)
if result.IsOK() {
write()
}
return result
}
func generateBidAmount(r *rand.Rand, auc auction.Auction, bidder authexported.Account, blockTime time.Time) (sdk.Coin, error) {
bidderBalance := bidder.SpendableCoins(blockTime)
switch a := auc.(type) {
case auction.DebtAuction:
if bidderBalance.AmountOf(a.Bid.Denom).LT(a.Bid.Amount) { // stable coin
return sdk.Coin{}, ErrorNotEnoughCoins
}
amt, err := RandIntInclusive(r, sdk.ZeroInt(), a.Lot.Amount) // pick amount less than current lot amount // TODO min bid increments
if err != nil {
panic(err)
}
return sdk.NewCoin(a.Lot.Denom, amt), nil // gov coin
case auction.SurplusAuction:
if bidderBalance.AmountOf(a.Bid.Denom).LT(a.Bid.Amount) { // gov coin // TODO account for bid increments
return sdk.Coin{}, ErrorNotEnoughCoins
}
amt, err := RandIntInclusive(r, a.Bid.Amount, bidderBalance.AmountOf(a.Bid.Denom))
if err != nil {
panic(err)
}
return sdk.NewCoin(a.Bid.Denom, amt), nil // gov coin
case auction.CollateralAuction:
if bidderBalance.AmountOf(a.Bid.Denom).LT(a.Bid.Amount) { // stable coin // TODO account for bid increments (in forward phase)
return sdk.Coin{}, ErrorNotEnoughCoins
}
if a.IsReversePhase() {
amt, err := RandIntInclusive(r, sdk.ZeroInt(), a.Lot.Amount) // pick amount less than current lot amount
if err != nil {
panic(err)
}
return sdk.NewCoin(a.Lot.Denom, amt), nil // collateral coin
} else {
amt, err := RandIntInclusive(r, a.Bid.Amount, sdk.MinInt(bidderBalance.AmountOf(a.Bid.Denom), a.MaxBid.Amount))
if err != nil {
panic(err)
}
// pick the MaxBid amount more frequently to increase chance auctions phase get into reverse phase
if r.Intn(10) == 0 { // 10%
amt = a.MaxBid.Amount
}
return sdk.NewCoin(a.Bid.Denom, amt), nil // stable coin
}
default:
return sdk.Coin{}, fmt.Errorf("unknown auction type")
}
}
// findValidAccountAuctionPair finds an auction and account for which the callback func returns true
func findValidAccountAuctionPair(accounts []authexported.Account, auctions auction.Auctions, cb func(authexported.Account, auction.Auction) bool) (authexported.Account, auction.Auction, bool) {
for _, auc := range auctions {
for _, acc := range accounts {
if isValid := cb(acc, auc); isValid {
return acc, auc, true
}
}
}
return nil, nil, false
}
// RandInt randomly generates an sdk.Int in the range [inclusiveMin, inclusiveMax]. It works for negative and positive integers.
func RandIntInclusive(r *rand.Rand, inclusiveMin, inclusiveMax sdk.Int) (sdk.Int, error) {
if inclusiveMin.GT(inclusiveMax) {
return sdk.Int{}, fmt.Errorf("min larger than max")
}
return RandInt(r, inclusiveMin, inclusiveMax.Add(sdk.OneInt()))
}
// RandInt randomly generates an sdk.Int in the range [inclusiveMin, exclusiveMax). It works for negative and positive integers.
func RandInt(r *rand.Rand, inclusiveMin, exclusiveMax sdk.Int) (sdk.Int, error) {
// validate input
if inclusiveMin.GTE(exclusiveMax) {
return sdk.Int{}, fmt.Errorf("min larger or equal to max")
}
// shift the range to start at 0
shiftedRange := exclusiveMax.Sub(inclusiveMin) // should always be positive given the check above
// randomly pick from the shifted range
shiftedRandInt := sdk.NewIntFromBigInt(new(big.Int).Rand(r, shiftedRange.BigInt()))
// shift back to the original range
return shiftedRandInt.Add(inclusiveMin), nil
}

View File

@ -17,29 +17,29 @@ func ParamChanges(r *rand.Rand) []simulation.ParamChange {
// as strings in JSON (such as time.Duration) have the escaped quotes. // as strings in JSON (such as time.Duration) have the escaped quotes.
// TODO should we encode the values properly with ModuleCdc.MustMarshalJSON()? // TODO should we encode the values properly with ModuleCdc.MustMarshalJSON()?
return []simulation.ParamChange{ return []simulation.ParamChange{
simulation.NewSimParamChange(types.ModuleName, string(types.KeyBidDuration), "", simulation.NewSimParamChange(types.ModuleName, string(types.KeyBidDuration),
func(r *rand.Rand) string { func(r *rand.Rand) string {
return fmt.Sprintf("\"%d\"", GenBidDuration(r)) return fmt.Sprintf("%d", GenBidDuration(r))
}, },
), ),
simulation.NewSimParamChange(types.ModuleName, string(types.KeyMaxAuctionDuration), "", simulation.NewSimParamChange(types.ModuleName, string(types.KeyMaxAuctionDuration),
func(r *rand.Rand) string { func(r *rand.Rand) string {
return fmt.Sprintf("\"%d\"", GenMaxAuctionDuration(r)) return fmt.Sprintf("%d", GenMaxAuctionDuration(r))
}, },
), ),
simulation.NewSimParamChange(types.ModuleName, string(types.KeyIncrementCollateral), "", simulation.NewSimParamChange(types.ModuleName, string(types.KeyIncrementCollateral),
func(r *rand.Rand) string { func(r *rand.Rand) string {
return fmt.Sprintf("\"%d\"", GenIncrementCollateral(r)) return fmt.Sprintf("%d", GenIncrementCollateral(r))
}, },
), ),
simulation.NewSimParamChange(types.ModuleName, string(types.KeyIncrementDebt), "", simulation.NewSimParamChange(types.ModuleName, string(types.KeyIncrementDebt),
func(r *rand.Rand) string { func(r *rand.Rand) string {
return fmt.Sprintf("\"%d\"", GenIncrementDebt(r)) return fmt.Sprintf("%d", GenIncrementDebt(r))
}, },
), ),
simulation.NewSimParamChange(types.ModuleName, string(types.KeyIncrementSurplus), "", simulation.NewSimParamChange(types.ModuleName, string(types.KeyIncrementSurplus),
func(r *rand.Rand) string { func(r *rand.Rand) string {
return fmt.Sprintf("\"%d\"", GenIncrementSurplus(r)) return fmt.Sprintf("%d", GenIncrementSurplus(r))
}, },
), ),
} }

View File

@ -204,7 +204,7 @@ func (a CollateralAuction) GetType() string { return "collateral" }
// It is used in genesis initialize the module account correctly. // It is used in genesis initialize the module account correctly.
func (a CollateralAuction) GetModuleAccountCoins() sdk.Coins { func (a CollateralAuction) GetModuleAccountCoins() sdk.Coins {
// a.Bid is paid out on bids, so is never stored in the module account // a.Bid is paid out on bids, so is never stored in the module account
return sdk.NewCoins(a.Lot).Add(sdk.NewCoins(a.CorrespondingDebt)) return sdk.NewCoins(a.Lot).Add(sdk.NewCoins(a.CorrespondingDebt)...)
} }
// IsReversePhase returns whether the auction has switched over to reverse phase or not. // IsReversePhase returns whether the auction has switched over to reverse phase or not.
@ -276,24 +276,25 @@ type WeightedAddresses struct {
} }
// NewWeightedAddresses returns a new list addresses with weights. // NewWeightedAddresses returns a new list addresses with weights.
func NewWeightedAddresses(addrs []sdk.AccAddress, weights []sdk.Int) (WeightedAddresses, sdk.Error) { func NewWeightedAddresses(addrs []sdk.AccAddress, weights []sdk.Int) (WeightedAddresses, error) {
wa := WeightedAddresses{ wa := WeightedAddresses{
Addresses: addrs, Addresses: addrs,
Weights: weights, Weights: weights,
} }
if err := wa.Validate(); err != nil { if err := wa.Validate(); err != nil {
return WeightedAddresses{}, sdk.ErrInternal(err.Error()) return WeightedAddresses{}, err
} }
return wa, nil return wa, nil
} }
// Validate checks for that the weights are not negative and that lengths match.
func (wa WeightedAddresses) Validate() error { func (wa WeightedAddresses) Validate() error {
if len(wa.Addresses) != len(wa.Weights) { if len(wa.Addresses) != len(wa.Weights) {
return fmt.Errorf("number of addresses doesn't match number of weights") return fmt.Errorf("number of addresses doesn't match number of weights, %d ≠ %d", len(wa.Addresses), len(wa.Weights))
} }
for _, w := range wa.Weights { for _, w := range wa.Weights {
if w.IsNegative() { if w.IsNegative() {
return fmt.Errorf("weights contain a negative amount") return fmt.Errorf("weights contain a negative amount: %s", w)
} }
} }
return nil return nil

View File

@ -1,98 +1,36 @@
// DONTCOVER
package types package types
import ( import sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"fmt"
"time"
sdk "github.com/cosmos/cosmos-sdk/types" // DONTCOVER
)
// Error codes specific to auction module
const (
DefaultCodespace sdk.CodespaceType = ModuleName
CodeInvalidInitialAuctionID sdk.CodeType = 1
CodeInvalidModulePermissions sdk.CodeType = 2
CodeUnrecognizedAuctionType sdk.CodeType = 3
CodeAuctionNotFound sdk.CodeType = 4
CodeAuctionHasNotExpired sdk.CodeType = 5
CodeAuctionHasExpired sdk.CodeType = 6
CodeInvalidBidDenom sdk.CodeType = 7
CodeInvalidLotDenom sdk.CodeType = 8
CodeBidTooSmall sdk.CodeType = 9
CodeBidTooLarge sdk.CodeType = 10
CodeLotTooSmall sdk.CodeType = 11
CodeLotTooLarge sdk.CodeType = 12
CodeCollateralAuctionIsInReversePhase sdk.CodeType = 13
CodeCollateralAuctionIsInForwardPhase sdk.CodeType = 14
)
var (
// ErrInvalidInitialAuctionID error for when the initial auction ID hasn't been set // ErrInvalidInitialAuctionID error for when the initial auction ID hasn't been set
func ErrInvalidInitialAuctionID(codespace sdk.CodespaceType) sdk.Error { ErrInvalidInitialAuctionID = sdkerrors.Register(ModuleName, 2, "initial auction ID hasn't been set")
return sdk.NewError(codespace, CodeInvalidInitialAuctionID, fmt.Sprintf("initial auction ID hasn't been set"))
}
// ErrInvalidModulePermissions error for when module doesn't have valid permissions // ErrInvalidModulePermissions error for when module doesn't have valid permissions
func ErrInvalidModulePermissions(codespace sdk.CodespaceType, permission string) sdk.Error { ErrInvalidModulePermissions = sdkerrors.Register(ModuleName, 3, "module does not have required permission")
return sdk.NewError(codespace, CodeInvalidModulePermissions, fmt.Sprintf("module does not have required permission '%s'", permission))
}
// ErrUnrecognizedAuctionType error for unrecognized auction type // ErrUnrecognizedAuctionType error for unrecognized auction type
func ErrUnrecognizedAuctionType(codespace sdk.CodespaceType) sdk.Error { ErrUnrecognizedAuctionType = sdkerrors.Register(ModuleName, 4, "unrecognized auction type")
return sdk.NewError(codespace, CodeUnrecognizedAuctionType, fmt.Sprintf("unrecognized auction type"))
}
// ErrAuctionNotFound error for when an auction is not found // ErrAuctionNotFound error for when an auction is not found
func ErrAuctionNotFound(codespace sdk.CodespaceType, id uint64) sdk.Error { ErrAuctionNotFound = sdkerrors.Register(ModuleName, 5, "auction not found")
return sdk.NewError(codespace, CodeAuctionNotFound, fmt.Sprintf("auction %d was not found", id))
}
// ErrAuctionHasNotExpired error for attempting to close an auction that has not passed its end time // ErrAuctionHasNotExpired error for attempting to close an auction that has not passed its end time
func ErrAuctionHasNotExpired(codespace sdk.CodespaceType, blockTime time.Time, endTime time.Time) sdk.Error { ErrAuctionHasNotExpired = sdkerrors.Register(ModuleName, 6, "auction can't be closed as curent block time has not passed auction end time")
return sdk.NewError(codespace, CodeAuctionHasNotExpired, fmt.Sprintf("auction can't be closed as curent block time (%v) has not passed auction end time (%v)", blockTime, endTime))
}
// ErrAuctionHasExpired error for when an auction is closed and unavailable for bidding // ErrAuctionHasExpired error for when an auction is closed and unavailable for bidding
func ErrAuctionHasExpired(codespace sdk.CodespaceType, id uint64) sdk.Error { ErrAuctionHasExpired = sdkerrors.Register(ModuleName, 7, "auction has closed")
return sdk.NewError(codespace, CodeAuctionHasExpired, fmt.Sprintf("auction %d has closed", id))
}
// ErrInvalidBidDenom error for when bid denom doesn't match auction bid denom // ErrInvalidBidDenom error for when bid denom doesn't match auction bid denom
func ErrInvalidBidDenom(codespace sdk.CodespaceType, bidDenom string, auctionBidDenom string) sdk.Error { ErrInvalidBidDenom = sdkerrors.Register(ModuleName, 8, "bid denom doesn't match auction bid denom")
return sdk.NewError(codespace, CodeInvalidBidDenom, fmt.Sprintf("bid denom %s doesn't match auction bid denom %s", bidDenom, auctionBidDenom))
}
// ErrInvalidLotDenom error for when lot denom doesn't match auction lot denom // ErrInvalidLotDenom error for when lot denom doesn't match auction lot denom
func ErrInvalidLotDenom(codespace sdk.CodespaceType, lotDenom string, auctionLotDenom string) sdk.Error { ErrInvalidLotDenom = sdkerrors.Register(ModuleName, 9, "lot denom doesn't match auction lot denom")
return sdk.NewError(codespace, CodeInvalidLotDenom, fmt.Sprintf("lot denom %s doesn't match auction lot denom %s", lotDenom, auctionLotDenom))
}
// ErrBidTooSmall error for when bid is not greater than auction's min bid amount // ErrBidTooSmall error for when bid is not greater than auction's min bid amount
func ErrBidTooSmall(codespace sdk.CodespaceType, bid sdk.Coin, minBid sdk.Coin) sdk.Error { ErrBidTooSmall = sdkerrors.Register(ModuleName, 10, "bid is not greater than auction's min new bid amount")
return sdk.NewError(codespace, CodeBidTooSmall, fmt.Sprintf("bid %s is not greater than auction's min new bid amount %s", bid.String(), minBid.String()))
}
// ErrBidTooLarge error for when bid is larger than auction's maximum allowed bid // ErrBidTooLarge error for when bid is larger than auction's maximum allowed bid
func ErrBidTooLarge(codespace sdk.CodespaceType, bid sdk.Coin, maxBid sdk.Coin) sdk.Error { ErrBidTooLarge = sdkerrors.Register(ModuleName, 11, "bid is greater than auction's max bid")
return sdk.NewError(codespace, CodeBidTooLarge, fmt.Sprintf("bid %s is greater than auction's max bid %s", bid.String(), maxBid.String())) // ErrLotTooSmall error for when lot is less than zero
} ErrLotTooSmall = sdkerrors.Register(ModuleName, 12, "lot is not greater than auction's min new lot amount")
// ErrLotToosmall error for when lot is less than zero
func ErrLotTooSmall(codespace sdk.CodespaceType, lot sdk.Coin, minLot sdk.Coin) sdk.Error {
return sdk.NewError(codespace, CodeLotTooSmall, fmt.Sprintf("lot %s is not greater than auction's min new lot amount %s", lot.String(), minLot.String()))
}
// ErrLotTooLarge error for when lot is not smaller than auction's max new lot amount // ErrLotTooLarge error for when lot is not smaller than auction's max new lot amount
func ErrLotTooLarge(codespace sdk.CodespaceType, lot sdk.Coin, maxLot sdk.Coin) sdk.Error { ErrLotTooLarge = sdkerrors.Register(ModuleName, 13, "lot is greater than auction's max new lot amount")
return sdk.NewError(codespace, CodeLotTooLarge, fmt.Sprintf("lot %s is greater than auction's max new lot amount %s", lot.String(), maxLot.String()))
}
// ErrCollateralAuctionIsInReversePhase error for when attempting to place a forward bid on a collateral auction in reverse phase // ErrCollateralAuctionIsInReversePhase error for when attempting to place a forward bid on a collateral auction in reverse phase
func ErrCollateralAuctionIsInReversePhase(codespace sdk.CodespaceType, id uint64) sdk.Error { ErrCollateralAuctionIsInReversePhase = sdkerrors.Register(ModuleName, 14, "invalid bid: auction is in reverse phase")
return sdk.NewError(codespace, CodeCollateralAuctionIsInReversePhase, fmt.Sprintf("invalid bid - auction %d is in reverse phase", id))
}
// ErrCollateralAuctionIsInForwardPhase error for when attempting to place a reverse bid on a collateral auction in forward phase // ErrCollateralAuctionIsInForwardPhase error for when attempting to place a reverse bid on a collateral auction in forward phase
func ErrCollateralAuctionIsInForwardPhase(codespace sdk.CodespaceType, id uint64) sdk.Error { ErrCollateralAuctionIsInForwardPhase = sdkerrors.Register(ModuleName, 15, "invalid bid: auction is in forward phase")
return sdk.NewError(codespace, CodeCollateralAuctionIsInForwardPhase, fmt.Sprintf("invalid bid - auction %d is in forward phase", id)) )
}

View File

@ -10,10 +10,10 @@ type SupplyKeeper interface {
GetModuleAddress(name string) sdk.AccAddress GetModuleAddress(name string) sdk.AccAddress
GetModuleAccount(ctx sdk.Context, moduleName string) supplyexported.ModuleAccountI GetModuleAccount(ctx sdk.Context, moduleName string) supplyexported.ModuleAccountI
SendCoinsFromModuleToModule(ctx sdk.Context, sender, recipient string, amt sdk.Coins) sdk.Error SendCoinsFromModuleToModule(ctx sdk.Context, sender, recipient string, amt sdk.Coins) error
SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) sdk.Error BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) error
MintCoins(ctx sdk.Context, name string, amt sdk.Coins) sdk.Error MintCoins(ctx sdk.Context, name string, amt sdk.Coins) error
} }

View File

@ -2,7 +2,9 @@ package types
import ( import (
"fmt" "fmt"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
) )
// ensure Msg interface compliance at compile time // ensure Msg interface compliance at compile time
@ -31,12 +33,12 @@ func (msg MsgPlaceBid) Route() string { return RouterKey }
func (msg MsgPlaceBid) Type() string { return "place_bid" } func (msg MsgPlaceBid) Type() string { return "place_bid" }
// ValidateBasic does a simple validation check that doesn't require access to state. // ValidateBasic does a simple validation check that doesn't require access to state.
func (msg MsgPlaceBid) ValidateBasic() sdk.Error { func (msg MsgPlaceBid) ValidateBasic() error {
if msg.Bidder.Empty() { if msg.Bidder.Empty() {
return sdk.ErrInvalidAddress("invalid (empty) bidder address") return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "bidder address cannot be empty")
} }
if !msg.Amount.IsValid() { if !msg.Amount.IsValid() {
return sdk.ErrInvalidCoins(fmt.Sprintf("invalid bid amount: %s", msg.Amount)) return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "bid amount %s", msg.Amount)
} }
return nil return nil
} }
@ -51,3 +53,12 @@ func (msg MsgPlaceBid) GetSignBytes() []byte {
func (msg MsgPlaceBid) GetSigners() []sdk.AccAddress { func (msg MsgPlaceBid) GetSigners() []sdk.AccAddress {
return []sdk.AccAddress{msg.Bidder} return []sdk.AccAddress{msg.Bidder}
} }
func (msg MsgPlaceBid) String() string {
// String implements the Stringer interface
return fmt.Sprintf(`Place Bid Message:
Auction ID: %d
Bidder: %s
Amount: %s
`, msg.AuctionID, msg.Bidder, msg.Amount)
}

View File

@ -2,13 +2,17 @@ package types
import ( import (
"bytes" "bytes"
"errors"
"fmt" "fmt"
"time" "time"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/cosmos-sdk/x/params/subspace" "github.com/cosmos/cosmos-sdk/x/params/subspace"
) )
var emptyDec = sdk.Dec{}
// Defaults for auction params // Defaults for auction params
const ( const (
// DefaultMaxAuctionDuration max length of auction // DefaultMaxAuctionDuration max length of auction
@ -69,11 +73,11 @@ func ParamKeyTable() subspace.KeyTable {
// ParamSetPairs implements the ParamSet interface and returns all the key/value pairs. // ParamSetPairs implements the ParamSet interface and returns all the key/value pairs.
func (p *Params) ParamSetPairs() subspace.ParamSetPairs { func (p *Params) ParamSetPairs() subspace.ParamSetPairs {
return subspace.ParamSetPairs{ return subspace.ParamSetPairs{
{Key: KeyBidDuration, Value: &p.BidDuration}, params.NewParamSetPair(KeyBidDuration, &p.BidDuration, validateBidDurationParam),
{Key: KeyMaxAuctionDuration, Value: &p.MaxAuctionDuration}, params.NewParamSetPair(KeyMaxAuctionDuration, &p.MaxAuctionDuration, validateMaxAuctionDurationParam),
{Key: KeyIncrementSurplus, Value: &p.IncrementSurplus}, params.NewParamSetPair(KeyIncrementSurplus, &p.IncrementSurplus, validateIncrementSurplusParam),
{Key: KeyIncrementDebt, Value: &p.IncrementDebt}, params.NewParamSetPair(KeyIncrementDebt, &p.IncrementDebt, validateIncrementDebtParam),
{Key: KeyIncrementCollateral, Value: &p.IncrementCollateral}, params.NewParamSetPair(KeyIncrementCollateral, &p.IncrementCollateral, validateIncrementCollateralParam),
} }
} }
@ -97,26 +101,102 @@ func (p Params) String() string {
// Validate checks that the parameters have valid values. // Validate checks that the parameters have valid values.
func (p Params) Validate() error { func (p Params) Validate() error {
if p.BidDuration < 0 { if err := validateBidDurationParam(p.BidDuration); err != nil {
return sdk.ErrInternal("bid duration cannot be negative") return err
} }
if p.MaxAuctionDuration < 0 {
return sdk.ErrInternal("max auction duration cannot be negative") if err := validateMaxAuctionDurationParam(p.MaxAuctionDuration); err != nil {
return err
} }
if p.BidDuration > p.MaxAuctionDuration { if p.BidDuration > p.MaxAuctionDuration {
return sdk.ErrInternal("bid duration param cannot be larger than max auction duration") return errors.New("bid duration param cannot be larger than max auction duration")
} }
if p.IncrementSurplus == (sdk.Dec{}) || p.IncrementDebt == (sdk.Dec{}) || p.IncrementCollateral == (sdk.Dec{}) {
return sdk.ErrInternal("auction increment values cannot be nil") if err := validateIncrementSurplusParam(p.IncrementSurplus); err != nil {
return err
} }
if p.IncrementSurplus.IsNegative() {
return sdk.ErrInternal("surplus auction increment cannot be less than zero") if err := validateIncrementDebtParam(p.IncrementDebt); err != nil {
return err
} }
if p.IncrementDebt.IsNegative() {
return sdk.ErrInternal("debt auction increment cannot be less than zero") return validateIncrementCollateralParam(p.IncrementCollateral)
} }
if p.IncrementCollateral.IsNegative() {
return sdk.ErrInternal("collateral auction increment cannot be less than zero") func validateBidDurationParam(i interface{}) error {
bidDuration, ok := i.(time.Duration)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
} }
if bidDuration < 0 {
return fmt.Errorf("bid duration cannot be negative %d", bidDuration)
}
return nil
}
func validateMaxAuctionDurationParam(i interface{}) error {
maxAuctionDuration, ok := i.(time.Duration)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
if maxAuctionDuration < 0 {
return fmt.Errorf("max auction duration cannot be negative %d", maxAuctionDuration)
}
return nil
}
func validateIncrementSurplusParam(i interface{}) error {
incrementSurplus, ok := i.(sdk.Dec)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
if incrementSurplus == emptyDec || incrementSurplus.IsNil() {
return errors.New("surplus auction increment cannot be nil or empty")
}
if incrementSurplus.IsNegative() {
return fmt.Errorf("surplus auction increment cannot be less than zero %s", incrementSurplus)
}
return nil
}
func validateIncrementDebtParam(i interface{}) error {
incrementDebt, ok := i.(sdk.Dec)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
if incrementDebt == emptyDec || incrementDebt.IsNil() {
return errors.New("debt auction increment cannot be nil or empty")
}
if incrementDebt.IsNegative() {
return fmt.Errorf("debt auction increment cannot be less than zero %s", incrementDebt)
}
return nil
}
func validateIncrementCollateralParam(i interface{}) error {
incrementCollateral, ok := i.(sdk.Dec)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
if incrementCollateral == emptyDec || incrementCollateral.IsNil() {
return errors.New("collateral auction increment cannot be nil or empty")
}
if incrementCollateral.IsNegative() {
return fmt.Errorf("collateral auction increment cannot be less than zero %s", incrementCollateral)
}
return nil return nil
} }

View File

@ -3,12 +3,14 @@ package bep3_test
import ( import (
"testing" "testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
cmn "github.com/tendermint/tendermint/libs/common" tmbytes "github.com/tendermint/tendermint/libs/bytes"
tmtime "github.com/tendermint/tendermint/types/time" tmtime "github.com/tendermint/tendermint/types/time"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/app" "github.com/kava-labs/kava/app"
"github.com/kava-labs/kava/x/bep3" "github.com/kava-labs/kava/x/bep3"
) )
@ -19,8 +21,8 @@ type ABCITestSuite struct {
app app.TestApp app app.TestApp
ctx sdk.Context ctx sdk.Context
addrs []sdk.AccAddress addrs []sdk.AccAddress
swapIDs []cmn.HexBytes swapIDs []tmbytes.HexBytes
randomNumbers []cmn.HexBytes randomNumbers []tmbytes.HexBytes
} }
func (suite *ABCITestSuite) SetupTest() { func (suite *ABCITestSuite) SetupTest() {
@ -46,8 +48,8 @@ func (suite *ABCITestSuite) SetupTest() {
func (suite *ABCITestSuite) ResetKeeper() { func (suite *ABCITestSuite) ResetKeeper() {
suite.keeper = suite.app.GetBep3Keeper() suite.keeper = suite.app.GetBep3Keeper()
var swapIDs []cmn.HexBytes var swapIDs []tmbytes.HexBytes
var randomNumbers []cmn.HexBytes var randomNumbers []tmbytes.HexBytes
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
// Set up atomic swap variables // Set up atomic swap variables
expireHeight := int64(360) expireHeight := int64(360)

View File

@ -1,5 +1,3 @@
// nolint
// DO NOT EDIT - generated by aliasgen tool (github.com/rhuairahrighairidh/aliasgen)
package bep3 package bep3
import ( import (
@ -26,24 +24,8 @@ const (
AttributeValueCategory = types.AttributeValueCategory AttributeValueCategory = types.AttributeValueCategory
CalcSwapID = types.CalcSwapID CalcSwapID = types.CalcSwapID
ClaimAtomicSwap = types.ClaimAtomicSwap ClaimAtomicSwap = types.ClaimAtomicSwap
CodeAssetNotActive = types.CodeAssetNotActive
CodeAssetNotSupported = types.CodeAssetNotSupported
CodeAssetSupplyNotFound = types.CodeAssetSupplyNotFound
CodeAtomicSwapAlreadyExists = types.CodeAtomicSwapAlreadyExists
CodeAtomicSwapNotFound = types.CodeAtomicSwapNotFound
CodeExceedsAvailableSupply = types.CodeExceedsAvailableSupply
CodeExceedsSupplyLimit = types.CodeExceedsSupplyLimit
CodeInvalidClaimSecret = types.CodeInvalidClaimSecret
CodeInvalidCurrentSupply = types.CodeInvalidCurrentSupply
CodeInvalidHeightSpan = types.CodeInvalidHeightSpan
CodeInvalidIncomingSupply = types.CodeInvalidIncomingSupply
CodeInvalidOutgoingSupply = types.CodeInvalidOutgoingSupply
CodeInvalidTimestamp = types.CodeInvalidTimestamp
CodeSwapNotClaimable = types.CodeSwapNotClaimable
CodeSwapNotRefundable = types.CodeSwapNotRefundable
Completed = types.Completed Completed = types.Completed
CreateAtomicSwap = types.CreateAtomicSwap CreateAtomicSwap = types.CreateAtomicSwap
DefaultCodespace = types.DefaultCodespace
DefaultLongtermStorageDuration = types.DefaultLongtermStorageDuration DefaultLongtermStorageDuration = types.DefaultLongtermStorageDuration
DefaultParamspace = types.DefaultParamspace DefaultParamspace = types.DefaultParamspace
DepositAtomicSwap = types.DepositAtomicSwap DepositAtomicSwap = types.DepositAtomicSwap
@ -144,7 +126,6 @@ type (
AssetSupply = types.AssetSupply AssetSupply = types.AssetSupply
AtomicSwap = types.AtomicSwap AtomicSwap = types.AtomicSwap
AtomicSwaps = types.AtomicSwaps AtomicSwaps = types.AtomicSwaps
CodeType = types.CodeType
GenesisState = types.GenesisState GenesisState = types.GenesisState
MsgClaimAtomicSwap = types.MsgClaimAtomicSwap MsgClaimAtomicSwap = types.MsgClaimAtomicSwap
MsgCreateAtomicSwap = types.MsgCreateAtomicSwap MsgCreateAtomicSwap = types.MsgCreateAtomicSwap

View File

@ -6,8 +6,8 @@ import (
"strconv" "strconv"
"strings" "strings"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -24,7 +24,7 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
Short: "Querying commands for the bep3 module", Short: "Querying commands for the bep3 module",
} }
bep3QueryCmd.AddCommand(client.GetCommands( bep3QueryCmd.AddCommand(flags.GetCommands(
QueryCalcSwapIDCmd(queryRoute, cdc), QueryCalcSwapIDCmd(queryRoute, cdc),
QueryCalcRandomNumberHashCmd(queryRoute, cdc), QueryCalcRandomNumberHashCmd(queryRoute, cdc),
QueryGetAtomicSwapCmd(queryRoute, cdc), QueryGetAtomicSwapCmd(queryRoute, cdc),

View File

@ -1,13 +1,14 @@
package cli package cli
import ( import (
"bufio"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"strconv" "strconv"
"strings" "strings"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/version"
@ -25,7 +26,7 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command {
Short: "bep3 transactions subcommands", Short: "bep3 transactions subcommands",
} }
bep3TxCmd.AddCommand(client.PostCommands( bep3TxCmd.AddCommand(flags.PostCommands(
GetCmdCreateAtomicSwap(cdc), GetCmdCreateAtomicSwap(cdc),
GetCmdClaimAtomicSwap(cdc), GetCmdClaimAtomicSwap(cdc),
GetCmdRefundAtomicSwap(cdc), GetCmdRefundAtomicSwap(cdc),
@ -43,8 +44,9 @@ func GetCmdCreateAtomicSwap(cdc *codec.Codec) *cobra.Command {
version.ClientName, types.ModuleName), version.ClientName, types.ModuleName),
Args: cobra.ExactArgs(8), Args: cobra.ExactArgs(8),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
cliCtx := context.NewCLIContext().WithCodec(cdc) cliCtx := context.NewCLIContext().WithCodec(cdc)
txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
from := cliCtx.GetFromAddress() // same as KavaExecutor.DeputyAddress (for cross-chain) from := cliCtx.GetFromAddress() // same as KavaExecutor.DeputyAddress (for cross-chain)
to, err := sdk.AccAddressFromBech32(args[0]) to, err := sdk.AccAddressFromBech32(args[0])
@ -119,8 +121,9 @@ func GetCmdClaimAtomicSwap(cdc *codec.Codec) *cobra.Command {
Example: fmt.Sprintf("%s tx %s claim 6682c03cc3856879c8fb98c9733c6b0c30758299138166b6523fe94628b1d3af 56f13e6a5cd397447f8b5f8c82fdb5bbf56127db75269f5cc14e50acd8ac9a4c --from accA", version.ClientName, types.ModuleName), Example: fmt.Sprintf("%s tx %s claim 6682c03cc3856879c8fb98c9733c6b0c30758299138166b6523fe94628b1d3af 56f13e6a5cd397447f8b5f8c82fdb5bbf56127db75269f5cc14e50acd8ac9a4c --from accA", version.ClientName, types.ModuleName),
Args: cobra.ExactArgs(2), Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
cliCtx := context.NewCLIContext().WithCodec(cdc) cliCtx := context.NewCLIContext().WithCodec(cdc)
txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
from := cliCtx.GetFromAddress() from := cliCtx.GetFromAddress()
@ -158,8 +161,9 @@ func GetCmdRefundAtomicSwap(cdc *codec.Codec) *cobra.Command {
Example: fmt.Sprintf("%s tx %s refund 6682c03cc3856879c8fb98c9733c6b0c30758299138166b6523fe94628b1d3af --from accA", version.ClientName, types.ModuleName), Example: fmt.Sprintf("%s tx %s refund 6682c03cc3856879c8fb98c9733c6b0c30758299138166b6523fe94628b1d3af --from accA", version.ClientName, types.ModuleName),
Args: cobra.ExactArgs(1), Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
cliCtx := context.NewCLIContext().WithCodec(cdc) cliCtx := context.NewCLIContext().WithCodec(cdc)
txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
from := cliCtx.GetFromAddress() from := cliCtx.GetFromAddress()

View File

@ -3,10 +3,11 @@ package rest
import ( import (
"github.com/gorilla/mux" "github.com/gorilla/mux"
tmbytes "github.com/tendermint/tendermint/libs/bytes"
"github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/context"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/rest" "github.com/cosmos/cosmos-sdk/types/rest"
cmn "github.com/tendermint/tendermint/libs/common"
) )
// RegisterRoutes registers bep3-related REST handlers to a router // RegisterRoutes registers bep3-related REST handlers to a router
@ -22,7 +23,7 @@ type PostCreateSwapReq struct {
To sdk.AccAddress `json:"to" yaml:"to"` To sdk.AccAddress `json:"to" yaml:"to"`
RecipientOtherChain string `json:"recipient_other_chain" yaml:"recipient_other_chain"` RecipientOtherChain string `json:"recipient_other_chain" yaml:"recipient_other_chain"`
SenderOtherChain string `json:"sender_other_chain" yaml:"sender_other_chain"` SenderOtherChain string `json:"sender_other_chain" yaml:"sender_other_chain"`
RandomNumberHash cmn.HexBytes `json:"random_number_hash" yaml:"random_number_hash"` RandomNumberHash tmbytes.HexBytes `json:"random_number_hash" yaml:"random_number_hash"`
Timestamp int64 `json:"timestamp" yaml:"timestamp"` Timestamp int64 `json:"timestamp" yaml:"timestamp"`
Amount sdk.Coins `json:"amount" yaml:"amount"` Amount sdk.Coins `json:"amount" yaml:"amount"`
ExpectedIncome string `json:"expected_income" yaml:"expected_income"` ExpectedIncome string `json:"expected_income" yaml:"expected_income"`
@ -34,13 +35,13 @@ type PostCreateSwapReq struct {
type PostClaimSwapReq struct { type PostClaimSwapReq struct {
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
From sdk.AccAddress `json:"from" yaml:"from"` From sdk.AccAddress `json:"from" yaml:"from"`
SwapID cmn.HexBytes `json:"swap_id" yaml:"swap_id"` SwapID tmbytes.HexBytes `json:"swap_id" yaml:"swap_id"`
RandomNumber cmn.HexBytes `json:"random_number" yaml:"random_number"` RandomNumber tmbytes.HexBytes `json:"random_number" yaml:"random_number"`
} }
// PostRefundSwapReq defines the properties of swap refund request's body // PostRefundSwapReq defines the properties of swap refund request's body
type PostRefundSwapReq struct { type PostRefundSwapReq struct {
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
From sdk.AccAddress `json:"from" yaml:"from"` From sdk.AccAddress `json:"from" yaml:"from"`
SwapID cmn.HexBytes `json:"swap_id" yaml:"swap_id"` SwapID tmbytes.HexBytes `json:"swap_id" yaml:"swap_id"`
} }

View File

@ -71,9 +71,9 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper SupplyKeeper, gs G
case Open: case Open:
// This index expires unclaimed swaps // This index expires unclaimed swaps
keeper.InsertIntoByBlockIndex(ctx, swap) keeper.InsertIntoByBlockIndex(ctx, swap)
incomingSupplies = incomingSupplies.Add(swap.Amount) incomingSupplies = incomingSupplies.Add(swap.Amount...)
case Expired: case Expired:
incomingSupplies = incomingSupplies.Add(swap.Amount) incomingSupplies = incomingSupplies.Add(swap.Amount...)
case Completed: case Completed:
// This index stores swaps until deletion // This index stores swaps until deletion
keeper.InsertIntoLongtermStorage(ctx, swap) keeper.InsertIntoLongtermStorage(ctx, swap)
@ -84,9 +84,9 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper SupplyKeeper, gs G
switch swap.Status { switch swap.Status {
case Open: case Open:
keeper.InsertIntoByBlockIndex(ctx, swap) keeper.InsertIntoByBlockIndex(ctx, swap)
outgoingSupplies = outgoingSupplies.Add(swap.Amount) outgoingSupplies = outgoingSupplies.Add(swap.Amount...)
case Expired: case Expired:
outgoingSupplies = outgoingSupplies.Add(swap.Amount) outgoingSupplies = outgoingSupplies.Add(swap.Amount...)
case Completed: case Completed:
keeper.InsertIntoLongtermStorage(ctx, swap) keeper.InsertIntoLongtermStorage(ctx, swap)
default: default:

View File

@ -1,14 +1,13 @@
package bep3 package bep3
import ( import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
) )
// NewHandler creates an sdk.Handler for all the bep3 type messages // NewHandler creates an sdk.Handler for all the bep3 type messages
func NewHandler(k Keeper) sdk.Handler { func NewHandler(k Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
ctx = ctx.WithEventManager(sdk.NewEventManager()) ctx = ctx.WithEventManager(sdk.NewEventManager())
switch msg := msg.(type) { switch msg := msg.(type) {
case MsgCreateAtomicSwap: case MsgCreateAtomicSwap:
@ -18,19 +17,18 @@ func NewHandler(k Keeper) sdk.Handler {
case MsgRefundAtomicSwap: case MsgRefundAtomicSwap:
return handleMsgRefundAtomicSwap(ctx, k, msg) return handleMsgRefundAtomicSwap(ctx, k, msg)
default: default:
errMsg := fmt.Sprintf("unrecognized %s message type: %T", ModuleName, msg) return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg)
return sdk.ErrUnknownRequest(errMsg).Result()
} }
} }
} }
// handleMsgCreateAtomicSwap handles requests to create a new AtomicSwap // handleMsgCreateAtomicSwap handles requests to create a new AtomicSwap
func handleMsgCreateAtomicSwap(ctx sdk.Context, k Keeper, msg MsgCreateAtomicSwap) sdk.Result { func handleMsgCreateAtomicSwap(ctx sdk.Context, k Keeper, msg MsgCreateAtomicSwap) (*sdk.Result, error) {
err := k.CreateAtomicSwap(ctx, msg.RandomNumberHash, msg.Timestamp, msg.HeightSpan, msg.From, msg.To, err := k.CreateAtomicSwap(ctx, msg.RandomNumberHash, msg.Timestamp, msg.HeightSpan, msg.From, msg.To,
msg.SenderOtherChain, msg.RecipientOtherChain, msg.Amount, msg.ExpectedIncome, msg.CrossChain) msg.SenderOtherChain, msg.RecipientOtherChain, msg.Amount, msg.ExpectedIncome, msg.CrossChain)
if err != nil { if err != nil {
return err.Result() return nil, err
} }
ctx.EventManager().EmitEvent( ctx.EventManager().EmitEvent(
@ -41,17 +39,17 @@ func handleMsgCreateAtomicSwap(ctx sdk.Context, k Keeper, msg MsgCreateAtomicSwa
), ),
) )
return sdk.Result{ return &sdk.Result{
Events: ctx.EventManager().Events(), Events: ctx.EventManager().Events(),
} }, nil
} }
// handleMsgClaimAtomicSwap handles requests to claim funds in an active AtomicSwap // handleMsgClaimAtomicSwap handles requests to claim funds in an active AtomicSwap
func handleMsgClaimAtomicSwap(ctx sdk.Context, k Keeper, msg MsgClaimAtomicSwap) sdk.Result { func handleMsgClaimAtomicSwap(ctx sdk.Context, k Keeper, msg MsgClaimAtomicSwap) (*sdk.Result, error) {
err := k.ClaimAtomicSwap(ctx, msg.From, msg.SwapID, msg.RandomNumber) err := k.ClaimAtomicSwap(ctx, msg.From, msg.SwapID, msg.RandomNumber)
if err != nil { if err != nil {
return err.Result() return nil, err
} }
ctx.EventManager().EmitEvent( ctx.EventManager().EmitEvent(
@ -62,17 +60,17 @@ func handleMsgClaimAtomicSwap(ctx sdk.Context, k Keeper, msg MsgClaimAtomicSwap)
), ),
) )
return sdk.Result{ return &sdk.Result{
Events: ctx.EventManager().Events(), Events: ctx.EventManager().Events(),
} }, nil
} }
// handleMsgRefundAtomicSwap handles requests to refund an active AtomicSwap // handleMsgRefundAtomicSwap handles requests to refund an active AtomicSwap
func handleMsgRefundAtomicSwap(ctx sdk.Context, k Keeper, msg MsgRefundAtomicSwap) sdk.Result { func handleMsgRefundAtomicSwap(ctx sdk.Context, k Keeper, msg MsgRefundAtomicSwap) (*sdk.Result, error) {
err := k.RefundAtomicSwap(ctx, msg.From, msg.SwapID) err := k.RefundAtomicSwap(ctx, msg.From, msg.SwapID)
if err != nil { if err != nil {
return err.Result() return nil, err
} }
ctx.EventManager().EmitEvent( ctx.EventManager().EmitEvent(
@ -83,7 +81,7 @@ func handleMsgRefundAtomicSwap(ctx sdk.Context, k Keeper, msg MsgRefundAtomicSwa
), ),
) )
return sdk.Result{ return &sdk.Result{
Events: ctx.EventManager().Events(), Events: ctx.EventManager().Events(),
} }, nil
} }

View File

@ -1,17 +1,16 @@
package bep3_test package bep3_test
import ( import (
"encoding/hex"
"fmt"
"strings"
"testing" "testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/stretchr/testify/suite" "github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
cmn "github.com/tendermint/tendermint/libs/common" tmbytes "github.com/tendermint/tendermint/libs/bytes"
tmtime "github.com/tendermint/tendermint/types/time" tmtime "github.com/tendermint/tendermint/types/time"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/app" "github.com/kava-labs/kava/app"
"github.com/kava-labs/kava/x/bep3" "github.com/kava-labs/kava/x/bep3"
) )
@ -47,7 +46,7 @@ func (suite *HandlerTestSuite) SetupTest() {
suite.ctx = ctx suite.ctx = ctx
} }
func (suite *HandlerTestSuite) AddAtomicSwap() (cmn.HexBytes, cmn.HexBytes) { func (suite *HandlerTestSuite) AddAtomicSwap() (tmbytes.HexBytes, tmbytes.HexBytes) {
expireHeight := int64(360) expireHeight := int64(360)
amount := cs(c("bnb", int64(50000))) amount := cs(c("bnb", int64(50000)))
timestamp := ts(0) timestamp := ts(0)
@ -74,8 +73,9 @@ func (suite *HandlerTestSuite) TestMsgCreateAtomicSwap() {
suite.addrs[0], suite.addrs[2], TestRecipientOtherChain, TestSenderOtherChain, suite.addrs[0], suite.addrs[2], TestRecipientOtherChain, TestSenderOtherChain,
randomNumberHash, timestamp, amount, amount.String(), int64(300), true) randomNumberHash, timestamp, amount, amount.String(), int64(300), true)
res := suite.handler(suite.ctx, msg) res, err := suite.handler(suite.ctx, msg)
suite.True(res.IsOK()) suite.Require().NoError(err)
suite.Require().NotNil(res)
} }
func (suite *HandlerTestSuite) TestMsgClaimAtomicSwap() { func (suite *HandlerTestSuite) TestMsgClaimAtomicSwap() {
@ -84,15 +84,16 @@ func (suite *HandlerTestSuite) TestMsgClaimAtomicSwap() {
badRandomNumberHash := bep3.CalculateRandomHash(badRandomNumber.Bytes(), ts(0)) badRandomNumberHash := bep3.CalculateRandomHash(badRandomNumber.Bytes(), ts(0))
badSwapID := bep3.CalculateSwapID(badRandomNumberHash, suite.addrs[0], TestSenderOtherChain) badSwapID := bep3.CalculateSwapID(badRandomNumberHash, suite.addrs[0], TestSenderOtherChain)
badMsg := bep3.NewMsgClaimAtomicSwap(suite.addrs[0], badSwapID, badRandomNumber.Bytes()) badMsg := bep3.NewMsgClaimAtomicSwap(suite.addrs[0], badSwapID, badRandomNumber.Bytes())
badRes := suite.handler(suite.ctx, badMsg) badRes, err := suite.handler(suite.ctx, badMsg)
suite.False(badRes.IsOK()) suite.Require().Error(err)
suite.True(strings.Contains(badRes.Log, fmt.Sprintf("AtomicSwap %s was not found", hex.EncodeToString(badSwapID)))) suite.Require().Nil(badRes)
// Add an atomic swap before attempting new claim msg // Add an atomic swap before attempting new claim msg
swapID, randomNumber := suite.AddAtomicSwap() swapID, randomNumber := suite.AddAtomicSwap()
msg := bep3.NewMsgClaimAtomicSwap(suite.addrs[0], swapID, randomNumber) msg := bep3.NewMsgClaimAtomicSwap(suite.addrs[0], swapID, randomNumber)
res := suite.handler(suite.ctx, msg) res, err := suite.handler(suite.ctx, msg)
suite.True(res.IsOK()) suite.Require().NoError(err)
suite.Require().NotNil(res)
} }
func (suite *HandlerTestSuite) TestMsgRefundAtomicSwap() { func (suite *HandlerTestSuite) TestMsgRefundAtomicSwap() {
@ -101,30 +102,31 @@ func (suite *HandlerTestSuite) TestMsgRefundAtomicSwap() {
badRandomNumberHash := bep3.CalculateRandomHash(badRandomNumber.Bytes(), ts(0)) badRandomNumberHash := bep3.CalculateRandomHash(badRandomNumber.Bytes(), ts(0))
badSwapID := bep3.CalculateSwapID(badRandomNumberHash, suite.addrs[0], TestSenderOtherChain) badSwapID := bep3.CalculateSwapID(badRandomNumberHash, suite.addrs[0], TestSenderOtherChain)
badMsg := bep3.NewMsgRefundAtomicSwap(suite.addrs[0], badSwapID) badMsg := bep3.NewMsgRefundAtomicSwap(suite.addrs[0], badSwapID)
badRes := suite.handler(suite.ctx, badMsg) badRes, err := suite.handler(suite.ctx, badMsg)
suite.False(badRes.IsOK()) suite.Require().Error(err)
suite.True(strings.Contains(badRes.Log, fmt.Sprintf("AtomicSwap %s was not found", hex.EncodeToString(badSwapID)))) suite.Require().Nil(badRes)
// Add an atomic swap and build refund msg // Add an atomic swap and build refund msg
swapID, _ := suite.AddAtomicSwap() swapID, _ := suite.AddAtomicSwap()
msg := bep3.NewMsgRefundAtomicSwap(suite.addrs[0], swapID) msg := bep3.NewMsgRefundAtomicSwap(suite.addrs[0], swapID)
// Attempt to refund active atomic swap // Attempt to refund active atomic swap
res1 := suite.handler(suite.ctx, msg) res1, err := suite.handler(suite.ctx, msg)
suite.True(strings.Contains(res1.Log, "atomic swap is still active and cannot be refunded")) suite.Require().Error(err)
suite.False(res1.IsOK()) suite.Require().Nil(res1)
// Expire the atomic swap with begin blocker and attempt refund // Expire the atomic swap with begin blocker and attempt refund
laterCtx := suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + 400) laterCtx := suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + 400)
bep3.BeginBlocker(laterCtx, suite.keeper) bep3.BeginBlocker(laterCtx, suite.keeper)
res2 := suite.handler(laterCtx, msg) res2, err := suite.handler(laterCtx, msg)
suite.True(res2.IsOK()) suite.Require().NoError(err)
suite.Require().NotNil(res2)
} }
func (suite *HandlerTestSuite) TestInvalidMsg() { func (suite *HandlerTestSuite) TestInvalidMsg() {
res := suite.handler(suite.ctx, sdk.NewTestMsg()) res, err := suite.handler(suite.ctx, sdk.NewTestMsg())
suite.False(res.IsOK()) suite.Require().Error(err)
suite.True(strings.Contains(res.Log, "unrecognized bep3 message type")) suite.Require().Nil(res)
} }
func TestHandlerTestSuite(t *testing.T) { func TestHandlerTestSuite(t *testing.T) {

View File

@ -2,19 +2,21 @@ package keeper
import ( import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/kava-labs/kava/x/bep3/types" "github.com/kava-labs/kava/x/bep3/types"
) )
// IncrementCurrentAssetSupply increments an asset's supply by the coin // IncrementCurrentAssetSupply increments an asset's supply by the coin
func (k Keeper) IncrementCurrentAssetSupply(ctx sdk.Context, coin sdk.Coin) sdk.Error { func (k Keeper) IncrementCurrentAssetSupply(ctx sdk.Context, coin sdk.Coin) error {
supply, found := k.GetAssetSupply(ctx, []byte(coin.Denom)) supply, found := k.GetAssetSupply(ctx, []byte(coin.Denom))
if !found { if !found {
return types.ErrAssetNotSupported(k.codespace, coin.Denom) return sdkerrors.Wrap(types.ErrAssetNotSupported, coin.Denom)
} }
// Resulting current supply must be under asset's limit // Resulting current supply must be under asset's limit
if !supply.Limit.IsGTE(supply.CurrentSupply.Add(coin)) { if !supply.Limit.IsGTE(supply.CurrentSupply.Add(coin)) {
return types.ErrExceedsSupplyLimit(k.codespace, coin, supply.CurrentSupply, supply.Limit) return sdkerrors.Wrapf(types.ErrExceedsSupplyLimit, "increase %s, asset supply %s, limit %s", coin, supply.CurrentSupply, supply.Limit)
} }
supply.CurrentSupply = supply.CurrentSupply.Add(coin) supply.CurrentSupply = supply.CurrentSupply.Add(coin)
@ -23,16 +25,16 @@ func (k Keeper) IncrementCurrentAssetSupply(ctx sdk.Context, coin sdk.Coin) sdk.
} }
// DecrementCurrentAssetSupply decrement an asset's supply by the coin // DecrementCurrentAssetSupply decrement an asset's supply by the coin
func (k Keeper) DecrementCurrentAssetSupply(ctx sdk.Context, coin sdk.Coin) sdk.Error { func (k Keeper) DecrementCurrentAssetSupply(ctx sdk.Context, coin sdk.Coin) error {
supply, found := k.GetAssetSupply(ctx, []byte(coin.Denom)) supply, found := k.GetAssetSupply(ctx, []byte(coin.Denom))
if !found { if !found {
return types.ErrAssetNotSupported(k.codespace, coin.Denom) return sdkerrors.Wrap(types.ErrAssetNotSupported, coin.Denom)
} }
// Resulting current supply must be greater than or equal to 0 // Resulting current supply must be greater than or equal to 0
// Use sdk.Int instead of sdk.Coin to prevent panic if true // Use sdk.Int instead of sdk.Coin to prevent panic if true
if supply.CurrentSupply.Amount.Sub(coin.Amount).IsNegative() { if supply.CurrentSupply.Amount.Sub(coin.Amount).IsNegative() {
return types.ErrInvalidCurrentSupply(k.codespace, coin, supply.CurrentSupply) return sdkerrors.Wrapf(types.ErrInvalidCurrentSupply, "decrease %s, asset supply %s", coin, supply.CurrentSupply)
} }
supply.CurrentSupply = supply.CurrentSupply.Sub(coin) supply.CurrentSupply = supply.CurrentSupply.Sub(coin)
@ -41,16 +43,16 @@ func (k Keeper) DecrementCurrentAssetSupply(ctx sdk.Context, coin sdk.Coin) sdk.
} }
// IncrementIncomingAssetSupply increments an asset's incoming supply // IncrementIncomingAssetSupply increments an asset's incoming supply
func (k Keeper) IncrementIncomingAssetSupply(ctx sdk.Context, coin sdk.Coin) sdk.Error { func (k Keeper) IncrementIncomingAssetSupply(ctx sdk.Context, coin sdk.Coin) error {
supply, found := k.GetAssetSupply(ctx, []byte(coin.Denom)) supply, found := k.GetAssetSupply(ctx, []byte(coin.Denom))
if !found { if !found {
return types.ErrAssetNotSupported(k.codespace, coin.Denom) return sdkerrors.Wrap(types.ErrAssetNotSupported, coin.Denom)
} }
// Result of (current + incoming + amount) must be under asset's limit // Result of (current + incoming + amount) must be under asset's limit
totalSupply := supply.CurrentSupply.Add(supply.IncomingSupply) totalSupply := supply.CurrentSupply.Add(supply.IncomingSupply)
if !supply.Limit.IsGTE(totalSupply.Add(coin)) { if !supply.Limit.IsGTE(totalSupply.Add(coin)) {
return types.ErrExceedsSupplyLimit(k.codespace, coin, totalSupply, supply.Limit) return sdkerrors.Wrapf(types.ErrExceedsSupplyLimit, "increase %s, asset supply %s, limit %s", coin, totalSupply, supply.Limit)
} }
supply.IncomingSupply = supply.IncomingSupply.Add(coin) supply.IncomingSupply = supply.IncomingSupply.Add(coin)
@ -59,16 +61,16 @@ func (k Keeper) IncrementIncomingAssetSupply(ctx sdk.Context, coin sdk.Coin) sdk
} }
// DecrementIncomingAssetSupply decrements an asset's incoming supply // DecrementIncomingAssetSupply decrements an asset's incoming supply
func (k Keeper) DecrementIncomingAssetSupply(ctx sdk.Context, coin sdk.Coin) sdk.Error { func (k Keeper) DecrementIncomingAssetSupply(ctx sdk.Context, coin sdk.Coin) error {
supply, found := k.GetAssetSupply(ctx, []byte(coin.Denom)) supply, found := k.GetAssetSupply(ctx, []byte(coin.Denom))
if !found { if !found {
return types.ErrAssetNotSupported(k.codespace, coin.Denom) return sdkerrors.Wrap(types.ErrAssetNotSupported, coin.Denom)
} }
// Resulting incoming supply must be greater than or equal to 0 // Resulting incoming supply must be greater than or equal to 0
// Use sdk.Int instead of sdk.Coin to prevent panic if true // Use sdk.Int instead of sdk.Coin to prevent panic if true
if supply.IncomingSupply.Amount.Sub(coin.Amount).IsNegative() { if supply.IncomingSupply.Amount.Sub(coin.Amount).IsNegative() {
return types.ErrInvalidIncomingSupply(k.codespace, coin, supply.IncomingSupply) return sdkerrors.Wrapf(types.ErrInvalidIncomingSupply, "decrease %s, incoming supply %s", coin, supply.IncomingSupply)
} }
supply.IncomingSupply = supply.IncomingSupply.Sub(coin) supply.IncomingSupply = supply.IncomingSupply.Sub(coin)
@ -77,15 +79,15 @@ func (k Keeper) DecrementIncomingAssetSupply(ctx sdk.Context, coin sdk.Coin) sdk
} }
// IncrementOutgoingAssetSupply increments an asset's outoing supply // IncrementOutgoingAssetSupply increments an asset's outoing supply
func (k Keeper) IncrementOutgoingAssetSupply(ctx sdk.Context, coin sdk.Coin) sdk.Error { func (k Keeper) IncrementOutgoingAssetSupply(ctx sdk.Context, coin sdk.Coin) error {
supply, found := k.GetAssetSupply(ctx, []byte(coin.Denom)) supply, found := k.GetAssetSupply(ctx, []byte(coin.Denom))
if !found { if !found {
return types.ErrAssetNotSupported(k.codespace, coin.Denom) return sdkerrors.Wrap(types.ErrAssetNotSupported, coin.Denom)
} }
// Result of (outgoing + amount) must be less than current supply // Result of (outgoing + amount) must be less than current supply
if !supply.CurrentSupply.IsGTE(supply.OutgoingSupply.Add(coin)) { if !supply.CurrentSupply.IsGTE(supply.OutgoingSupply.Add(coin)) {
return types.ErrExceedsAvailableSupply(k.codespace, coin, return sdkerrors.Wrapf(types.ErrExceedsAvailableSupply, "swap amount %s, available supply %s", coin,
supply.CurrentSupply.Amount.Sub(supply.OutgoingSupply.Amount)) supply.CurrentSupply.Amount.Sub(supply.OutgoingSupply.Amount))
} }
@ -95,16 +97,16 @@ func (k Keeper) IncrementOutgoingAssetSupply(ctx sdk.Context, coin sdk.Coin) sdk
} }
// DecrementOutgoingAssetSupply decrements an asset's outoing supply // DecrementOutgoingAssetSupply decrements an asset's outoing supply
func (k Keeper) DecrementOutgoingAssetSupply(ctx sdk.Context, coin sdk.Coin) sdk.Error { func (k Keeper) DecrementOutgoingAssetSupply(ctx sdk.Context, coin sdk.Coin) error {
supply, found := k.GetAssetSupply(ctx, []byte(coin.Denom)) supply, found := k.GetAssetSupply(ctx, []byte(coin.Denom))
if !found { if !found {
return types.ErrAssetNotSupported(k.codespace, coin.Denom) return sdkerrors.Wrap(types.ErrAssetNotSupported, coin.Denom)
} }
// Resulting outgoing supply must be greater than or equal to 0 // Resulting outgoing supply must be greater than or equal to 0
// Use sdk.Int instead of sdk.Coin to prevent panic if true // Use sdk.Int instead of sdk.Coin to prevent panic if true
if supply.OutgoingSupply.Amount.Sub(coin.Amount).IsNegative() { if supply.OutgoingSupply.Amount.Sub(coin.Amount).IsNegative() {
return types.ErrInvalidOutgoingSupply(k.codespace, coin, supply.OutgoingSupply) return sdkerrors.Wrapf(types.ErrInvalidOutgoingSupply, "decrease %s, outgoing supply %s", coin, supply.OutgoingSupply)
} }
supply.OutgoingSupply = supply.OutgoingSupply.Sub(coin) supply.OutgoingSupply = supply.OutgoingSupply.Sub(coin)

View File

@ -17,20 +17,23 @@ type Keeper struct {
cdc *codec.Codec cdc *codec.Codec
paramSubspace subspace.Subspace paramSubspace subspace.Subspace
supplyKeeper types.SupplyKeeper supplyKeeper types.SupplyKeeper
codespace sdk.CodespaceType
} }
// NewKeeper creates a bep3 keeper // NewKeeper creates a bep3 keeper
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, sk types.SupplyKeeper, paramstore subspace.Subspace, codespace sdk.CodespaceType) Keeper { func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, sk types.SupplyKeeper, paramstore subspace.Subspace) Keeper {
if addr := sk.GetModuleAddress(types.ModuleName); addr == nil { if addr := sk.GetModuleAddress(types.ModuleName); addr == nil {
panic(fmt.Sprintf("%s module account has not been set", types.ModuleName)) panic(fmt.Sprintf("%s module account has not been set", types.ModuleName))
} }
if !paramstore.HasKeyTable() {
paramstore = paramstore.WithKeyTable(types.ParamKeyTable())
}
keeper := Keeper{ keeper := Keeper{
key: key, key: key,
cdc: cdc, cdc: cdc,
paramSubspace: paramstore.WithKeyTable(types.ParamKeyTable()), paramSubspace: paramstore,
supplyKeeper: sk, supplyKeeper: sk,
codespace: codespace,
} }
return keeper return keeper
} }

View File

@ -2,6 +2,8 @@ package keeper
import ( import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/kava-labs/kava/x/bep3/types" "github.com/kava-labs/kava/x/bep3/types"
) )
@ -63,13 +65,13 @@ func (k Keeper) GetAssetByCoinID(ctx sdk.Context, coinID int) (types.AssetParam,
} }
// ValidateLiveAsset checks if an asset is both supported and active // ValidateLiveAsset checks if an asset is both supported and active
func (k Keeper) ValidateLiveAsset(ctx sdk.Context, coin sdk.Coin) sdk.Error { func (k Keeper) ValidateLiveAsset(ctx sdk.Context, coin sdk.Coin) error {
asset, found := k.GetAssetByDenom(ctx, coin.Denom) asset, found := k.GetAssetByDenom(ctx, coin.Denom)
if !found { if !found {
return types.ErrAssetNotSupported(k.codespace, coin.Denom) return sdkerrors.Wrap(types.ErrAssetNotSupported, coin.Denom)
} }
if !asset.Active { if !asset.Active {
return types.ErrAssetNotActive(k.codespace, asset.Denom) return sdkerrors.Wrap(types.ErrAssetNotActive, asset.Denom)
} }
return nil return nil
} }

View File

@ -1,6 +1,7 @@
package keeper_test package keeper_test
import ( import (
"errors"
"testing" "testing"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
@ -92,7 +93,7 @@ func (suite *AssetTestSuite) TestValidateLiveAsset() {
testCases := []struct { testCases := []struct {
name string name string
args args args args
expectedError sdk.CodeType expectedError error
expectPass bool expectPass bool
}{ }{
{ {
@ -100,7 +101,7 @@ func (suite *AssetTestSuite) TestValidateLiveAsset() {
args{ args{
coin: c("bnb", 1), coin: c("bnb", 1),
}, },
sdk.CodeType(0), nil,
true, true,
}, },
{ {
@ -108,7 +109,7 @@ func (suite *AssetTestSuite) TestValidateLiveAsset() {
args{ args{
coin: c("bad", 1), coin: c("bad", 1),
}, },
types.CodeAssetNotSupported, types.ErrAssetNotSupported,
false, false,
}, },
{ {
@ -116,7 +117,7 @@ func (suite *AssetTestSuite) TestValidateLiveAsset() {
args{ args{
coin: c("inc", 1), coin: c("inc", 1),
}, },
types.CodeAssetNotActive, types.ErrAssetNotActive,
false, false,
}, },
} }
@ -127,10 +128,10 @@ func (suite *AssetTestSuite) TestValidateLiveAsset() {
err := suite.keeper.ValidateLiveAsset(suite.ctx, tc.args.coin) err := suite.keeper.ValidateLiveAsset(suite.ctx, tc.args.coin)
if tc.expectPass { if tc.expectPass {
suite.NoError(err) suite.Require().NoError(err)
} else { } else {
suite.Error(err) suite.Require().Error(err)
suite.Equal(tc.expectedError, err.Result().Code) suite.Require().True(errors.Is(err, tc.expectedError))
} }
}) })
} }

View File

@ -1,15 +1,18 @@
package keeper package keeper
import ( import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/kava-labs/kava/x/bep3/types" "github.com/kava-labs/kava/x/bep3/types"
abci "github.com/tendermint/tendermint/abci/types"
) )
// NewQuerier is the module level router for state queries // NewQuerier is the module level router for state queries
func NewQuerier(keeper Keeper) sdk.Querier { func NewQuerier(keeper Keeper) sdk.Querier {
return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err error) {
switch path[0] { switch path[0] {
case types.QueryGetAssetSupply: case types.QueryGetAssetSupply:
return queryAssetSupply(ctx, req, keeper) return queryAssetSupply(ctx, req, keeper)
@ -20,57 +23,57 @@ func NewQuerier(keeper Keeper) sdk.Querier {
case types.QueryGetParams: case types.QueryGetParams:
return queryGetParams(ctx, req, keeper) return queryGetParams(ctx, req, keeper)
default: default:
return nil, sdk.ErrUnknownRequest("unknown bep3 query endpoint") return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint", types.ModuleName)
} }
} }
} }
func queryAssetSupply(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { func queryAssetSupply(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
// Decode request // Decode request
var requestParams types.QueryAssetSupply var requestParams types.QueryAssetSupply
err := keeper.cdc.UnmarshalJSON(req.Data, &requestParams) err := types.ModuleCdc.UnmarshalJSON(req.Data, &requestParams)
if err != nil { if err != nil {
return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
} }
assetSupply, found := keeper.GetAssetSupply(ctx, []byte(requestParams.Denom)) assetSupply, found := keeper.GetAssetSupply(ctx, []byte(requestParams.Denom))
if !found { if !found {
return nil, sdk.ErrInternal("Not found") return nil, sdkerrors.Wrap(types.ErrAssetSupplyNotFound, string(requestParams.Denom))
} }
// Encode results // Encode results
bz, err := codec.MarshalJSONIndent(keeper.cdc, assetSupply) bz, err := codec.MarshalJSONIndent(types.ModuleCdc, assetSupply)
if err != nil { if err != nil {
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
} }
return bz, nil return bz, nil
} }
func queryAtomicSwap(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { func queryAtomicSwap(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
// Decode request // Decode request
var requestParams types.QueryAtomicSwapByID var requestParams types.QueryAtomicSwapByID
err := keeper.cdc.UnmarshalJSON(req.Data, &requestParams) err := types.ModuleCdc.UnmarshalJSON(req.Data, &requestParams)
if err != nil { if err != nil {
return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
} }
// Lookup atomic swap // Lookup atomic swap
atomicSwap, found := keeper.GetAtomicSwap(ctx, requestParams.SwapID) atomicSwap, found := keeper.GetAtomicSwap(ctx, requestParams.SwapID)
if !found { if !found {
return nil, sdk.ErrInternal("Not found") return nil, sdkerrors.Wrapf(types.ErrAtomicSwapNotFound, "%d", requestParams.SwapID)
} }
// Encode results // Encode results
bz, err := codec.MarshalJSONIndent(keeper.cdc, atomicSwap) bz, err := codec.MarshalJSONIndent(types.ModuleCdc, atomicSwap)
if err != nil { if err != nil {
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
} }
return bz, nil return bz, nil
} }
func queryAtomicSwaps(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) (res []byte, err sdk.Error) { func queryAtomicSwaps(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) (res []byte, err error) {
var swaps types.AtomicSwaps var swaps types.AtomicSwaps
keeper.IterateAtomicSwaps(ctx, func(s types.AtomicSwap) bool { keeper.IterateAtomicSwaps(ctx, func(s types.AtomicSwap) bool {
@ -78,23 +81,23 @@ func queryAtomicSwaps(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) (re
return false return false
}) })
bz, err2 := codec.MarshalJSONIndent(keeper.cdc, swaps) bz, err2 := codec.MarshalJSONIndent(types.ModuleCdc, swaps)
if err2 != nil { if err2 != nil {
return nil, sdk.ErrInternal("could not marshal result to JSON") return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
} }
return bz, nil return bz, nil
} }
// query params in the bep3 store // query params in the bep3 store
func queryGetParams(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { func queryGetParams(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
// Get params // Get params
params := keeper.GetParams(ctx) params := keeper.GetParams(ctx)
// Encode results // Encode results
bz, err := codec.MarshalJSONIndent(keeper.cdc, params) bz, err := codec.MarshalJSONIndent(types.ModuleCdc, params)
if err != nil { if err != nil {
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
} }
return bz, nil return bz, nil
} }

View File

@ -5,14 +5,17 @@ import (
"strings" "strings"
"testing" "testing"
"github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types"
tmbytes "github.com/tendermint/tendermint/libs/bytes"
tmtime "github.com/tendermint/tendermint/types/time"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/app" "github.com/kava-labs/kava/app"
"github.com/kava-labs/kava/x/bep3/keeper" "github.com/kava-labs/kava/x/bep3/keeper"
"github.com/kava-labs/kava/x/bep3/types" "github.com/kava-labs/kava/x/bep3/types"
"github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types"
cmn "github.com/tendermint/tendermint/libs/common"
tmtime "github.com/tendermint/tendermint/types/time"
) )
const ( const (
@ -27,7 +30,7 @@ type QuerierTestSuite struct {
querier sdk.Querier querier sdk.Querier
addrs []sdk.AccAddress addrs []sdk.AccAddress
isSupplyDenom map[string]bool isSupplyDenom map[string]bool
swapIDs []cmn.HexBytes swapIDs []tmbytes.HexBytes
isSwapID map[string]bool isSwapID map[string]bool
} }
@ -55,7 +58,7 @@ func (suite *QuerierTestSuite) SetupTest() {
suite.addrs = addrs suite.addrs = addrs
// Create atomic swaps and save IDs // Create atomic swaps and save IDs
var swapIDs []cmn.HexBytes var swapIDs []tmbytes.HexBytes
isSwapID := make(map[string]bool) isSwapID := make(map[string]bool)
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
// Set up atomic swap variables // Set up atomic swap variables
@ -87,7 +90,7 @@ func (suite *QuerierTestSuite) TestQueryAssetSupply() {
denom := "bnb" denom := "bnb"
query := abci.RequestQuery{ query := abci.RequestQuery{
Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryGetAssetSupply}, "/"), Path: strings.Join([]string{custom, types.QuerierRoute, types.QueryGetAssetSupply}, "/"),
Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryAssetSupply(cmn.HexBytes(denom))), Data: types.ModuleCdc.MustMarshalJSON(types.NewQueryAssetSupply(tmbytes.HexBytes(denom))),
} }
// Execute query and check the []byte result // Execute query and check the []byte result

View File

@ -7,40 +7,37 @@ import (
"time" "time"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/kava-labs/kava/x/bep3/types" "github.com/kava-labs/kava/x/bep3/types"
) )
// CreateAtomicSwap creates a new AtomicSwap // CreateAtomicSwap creates a new AtomicSwap
func (k Keeper) CreateAtomicSwap(ctx sdk.Context, randomNumberHash []byte, timestamp int64, heightSpan int64, func (k Keeper) CreateAtomicSwap(ctx sdk.Context, randomNumberHash []byte, timestamp int64, heightSpan int64,
sender sdk.AccAddress, recipient sdk.AccAddress, senderOtherChain, recipientOtherChain string, sender sdk.AccAddress, recipient sdk.AccAddress, senderOtherChain, recipientOtherChain string,
amount sdk.Coins, expectedIncome string, crossChain bool) sdk.Error { amount sdk.Coins, expectedIncome string, crossChain bool) error {
// Confirm that this is not a duplicate swap // Confirm that this is not a duplicate swap
swapID := types.CalculateSwapID(randomNumberHash, sender, senderOtherChain) swapID := types.CalculateSwapID(randomNumberHash, sender, senderOtherChain)
_, found := k.GetAtomicSwap(ctx, swapID) _, found := k.GetAtomicSwap(ctx, swapID)
if found { if found {
return types.ErrAtomicSwapAlreadyExists(k.codespace, swapID) return sdkerrors.Wrap(types.ErrAtomicSwapAlreadyExists, hex.EncodeToString(swapID))
} }
// The heightSpan period should be more than 10 minutes and less than one week // The heightSpan period should be more than 10 minutes and less than one week
// Assume average block time interval is 10 second. 10 mins = 60 blocks, 1 week = 60480 blocks // Assume average block time interval is 10 second. 10 mins = 60 blocks, 1 week = 60480 blocks
if heightSpan < k.GetMinBlockLock(ctx) || heightSpan > k.GetMaxBlockLock(ctx) { if heightSpan < k.GetMinBlockLock(ctx) || heightSpan > k.GetMaxBlockLock(ctx) {
return types.ErrInvalidHeightSpan(k.codespace, heightSpan, k.GetMinBlockLock(ctx), k.GetMaxBlockLock(ctx)) return sdkerrors.Wrapf(types.ErrInvalidHeightSpan, "height span %d, range %d - %d", heightSpan, k.GetMinBlockLock(ctx), k.GetMaxBlockLock(ctx))
} }
// Unix timestamp must be in range [-15 mins, 30 mins] of the current time // Unix timestamp must be in range [-15 mins, 30 mins] of the current time
pastTimestampLimit := ctx.BlockTime().Add(time.Duration(-15) * time.Minute).Unix() pastTimestampLimit := ctx.BlockTime().Add(time.Duration(-15) * time.Minute).Unix()
futureTimestampLimit := ctx.BlockTime().Add(time.Duration(30) * time.Minute).Unix() futureTimestampLimit := ctx.BlockTime().Add(time.Duration(30) * time.Minute).Unix()
if timestamp < pastTimestampLimit || timestamp >= futureTimestampLimit { if timestamp < pastTimestampLimit || timestamp >= futureTimestampLimit {
return types.ErrInvalidTimestamp(k.codespace) return sdkerrors.Wrap(types.ErrInvalidTimestamp, time.Unix(timestamp, 0).UTC().String())
}
// Sanity check on recipient address
if recipient.Empty() {
return sdk.ErrInvalidAddress("invalid (empty) recipient address")
} }
if len(amount) != 1 { if len(amount) != 1 {
return sdk.ErrInternal("amount must contain exactly one coin") return fmt.Errorf("amount must contain exactly one coin")
} }
err := k.ValidateLiveAsset(ctx, amount[0]) err := k.ValidateLiveAsset(ctx, amount[0])
@ -58,18 +55,16 @@ func (k Keeper) CreateAtomicSwap(ctx sdk.Context, randomNumberHash []byte, times
switch direction { switch direction {
case types.Incoming: case types.Incoming:
err := k.IncrementIncomingAssetSupply(ctx, amount[0]) err = k.IncrementIncomingAssetSupply(ctx, amount[0])
if err != nil {
return err
}
case types.Outgoing: case types.Outgoing:
err := k.IncrementOutgoingAssetSupply(ctx, amount[0]) err = k.IncrementOutgoingAssetSupply(ctx, amount[0])
default:
err = fmt.Errorf("invalid swap direction: %s", direction.String())
}
if err != nil { if err != nil {
return err return err
} }
default:
return sdk.ErrInternal("invalid swap direction")
}
// Transfer coins to module // Transfer coins to module
err = k.supplyKeeper.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, amount) err = k.supplyKeeper.SendCoinsFromAccountToModule(ctx, sender, types.ModuleName, amount)
@ -86,16 +81,16 @@ func (k Keeper) CreateAtomicSwap(ctx sdk.Context, randomNumberHash []byte, times
ctx.EventManager().EmitEvent( ctx.EventManager().EmitEvent(
sdk.NewEvent( sdk.NewEvent(
types.EventTypeCreateAtomicSwap, types.EventTypeCreateAtomicSwap,
sdk.NewAttribute(types.AttributeKeySender, fmt.Sprintf("%s", atomicSwap.Sender)), sdk.NewAttribute(types.AttributeKeySender, atomicSwap.Sender.String()),
sdk.NewAttribute(types.AttributeKeyRecipient, fmt.Sprintf("%s", atomicSwap.Recipient)), sdk.NewAttribute(types.AttributeKeyRecipient, atomicSwap.Recipient.String()),
sdk.NewAttribute(types.AttributeKeyAtomicSwapID, fmt.Sprintf("%s", hex.EncodeToString(atomicSwap.GetSwapID()))), sdk.NewAttribute(types.AttributeKeyAtomicSwapID, hex.EncodeToString(atomicSwap.GetSwapID())),
sdk.NewAttribute(types.AttributeKeyRandomNumberHash, fmt.Sprintf("%s", hex.EncodeToString(atomicSwap.RandomNumberHash))), sdk.NewAttribute(types.AttributeKeyRandomNumberHash, hex.EncodeToString(atomicSwap.RandomNumberHash)),
sdk.NewAttribute(types.AttributeKeyTimestamp, fmt.Sprintf("%d", atomicSwap.Timestamp)), sdk.NewAttribute(types.AttributeKeyTimestamp, fmt.Sprintf("%d", atomicSwap.Timestamp)),
sdk.NewAttribute(types.AttributeKeySenderOtherChain, fmt.Sprintf("%s", atomicSwap.SenderOtherChain)), sdk.NewAttribute(types.AttributeKeySenderOtherChain, atomicSwap.SenderOtherChain),
sdk.NewAttribute(types.AttributeKeyExpireHeight, fmt.Sprintf("%d", atomicSwap.ExpireHeight)), sdk.NewAttribute(types.AttributeKeyExpireHeight, fmt.Sprintf("%d", atomicSwap.ExpireHeight)),
sdk.NewAttribute(types.AttributeKeyAmount, fmt.Sprintf("%s", atomicSwap.Amount[0].String())), sdk.NewAttribute(types.AttributeKeyAmount, atomicSwap.Amount[0].String()),
sdk.NewAttribute(types.AttributeKeyExpectedIncome, fmt.Sprintf("%s", expectedIncome)), sdk.NewAttribute(types.AttributeKeyExpectedIncome, expectedIncome),
sdk.NewAttribute(types.AttributeKeyDirection, fmt.Sprintf("%s", atomicSwap.Direction.String())), sdk.NewAttribute(types.AttributeKeyDirection, atomicSwap.Direction.String()),
), ),
) )
@ -105,15 +100,15 @@ func (k Keeper) CreateAtomicSwap(ctx sdk.Context, randomNumberHash []byte, times
} }
// ClaimAtomicSwap validates a claim attempt, and if successful, sends the escrowed amount and closes the AtomicSwap // ClaimAtomicSwap validates a claim attempt, and if successful, sends the escrowed amount and closes the AtomicSwap
func (k Keeper) ClaimAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []byte, randomNumber []byte) sdk.Error { func (k Keeper) ClaimAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []byte, randomNumber []byte) error {
atomicSwap, found := k.GetAtomicSwap(ctx, swapID) atomicSwap, found := k.GetAtomicSwap(ctx, swapID)
if !found { if !found {
return types.ErrAtomicSwapNotFound(k.codespace, swapID) return sdkerrors.Wrapf(types.ErrAtomicSwapNotFound, "%d", swapID)
} }
// Only open atomic swaps can be claimed // Only open atomic swaps can be claimed
if atomicSwap.Status != types.Open { if atomicSwap.Status != types.Open {
return types.ErrSwapNotClaimable(k.codespace) return types.ErrSwapNotClaimable
} }
// Calculate hashed secret using submitted number // Calculate hashed secret using submitted number
@ -122,34 +117,33 @@ func (k Keeper) ClaimAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []b
// Confirm that secret unlocks the atomic swap // Confirm that secret unlocks the atomic swap
if !bytes.Equal(hashedSecret, atomicSwap.GetSwapID()) { if !bytes.Equal(hashedSecret, atomicSwap.GetSwapID()) {
return types.ErrInvalidClaimSecret(k.codespace, hashedSecret, atomicSwap.GetSwapID()) return sdkerrors.Wrapf(types.ErrInvalidClaimSecret, "%s ≠ %s", hex.EncodeToString(hashedSecret), hex.EncodeToString(atomicSwap.GetSwapID()))
} }
var err error
switch atomicSwap.Direction { switch atomicSwap.Direction {
case types.Incoming: case types.Incoming:
err := k.DecrementIncomingAssetSupply(ctx, atomicSwap.Amount[0]) err := k.DecrementIncomingAssetSupply(ctx, atomicSwap.Amount[0])
if err != nil { if err != nil {
return err break
} }
err = k.IncrementCurrentAssetSupply(ctx, atomicSwap.Amount[0]) err = k.IncrementCurrentAssetSupply(ctx, atomicSwap.Amount[0])
if err != nil {
return err
}
case types.Outgoing: case types.Outgoing:
err := k.DecrementOutgoingAssetSupply(ctx, atomicSwap.Amount[0]) err = k.DecrementOutgoingAssetSupply(ctx, atomicSwap.Amount[0])
if err != nil { if err != nil {
return err break
} }
err = k.DecrementCurrentAssetSupply(ctx, atomicSwap.Amount[0]) err = k.DecrementCurrentAssetSupply(ctx, atomicSwap.Amount[0])
default:
err = fmt.Errorf("invalid swap direction: %s", atomicSwap.Direction.String())
}
if err != nil { if err != nil {
return err return err
} }
default:
return sdk.ErrInternal("invalid swap direction")
}
// Send intended recipient coins // Send intended recipient coins
err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, atomicSwap.Recipient, atomicSwap.Amount) err = k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, atomicSwap.Recipient, atomicSwap.Amount)
if err != nil { if err != nil {
return err return err
} }
@ -158,11 +152,11 @@ func (k Keeper) ClaimAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []b
ctx.EventManager().EmitEvent( ctx.EventManager().EmitEvent(
sdk.NewEvent( sdk.NewEvent(
types.EventTypeClaimAtomicSwap, types.EventTypeClaimAtomicSwap,
sdk.NewAttribute(types.AttributeKeyClaimSender, fmt.Sprintf("%s", from)), sdk.NewAttribute(types.AttributeKeyClaimSender, from.String()),
sdk.NewAttribute(types.AttributeKeyRecipient, fmt.Sprintf("%s", atomicSwap.Recipient)), sdk.NewAttribute(types.AttributeKeyRecipient, atomicSwap.Recipient.String()),
sdk.NewAttribute(types.AttributeKeyAtomicSwapID, fmt.Sprintf("%s", hex.EncodeToString(atomicSwap.GetSwapID()))), sdk.NewAttribute(types.AttributeKeyAtomicSwapID, hex.EncodeToString(atomicSwap.GetSwapID())),
sdk.NewAttribute(types.AttributeKeyRandomNumberHash, fmt.Sprintf("%s", hex.EncodeToString(atomicSwap.RandomNumberHash))), sdk.NewAttribute(types.AttributeKeyRandomNumberHash, hex.EncodeToString(atomicSwap.RandomNumberHash)),
sdk.NewAttribute(types.AttributeKeyRandomNumber, fmt.Sprintf("%s", hex.EncodeToString(randomNumber))), sdk.NewAttribute(types.AttributeKeyRandomNumber, hex.EncodeToString(randomNumber)),
), ),
) )
@ -178,33 +172,32 @@ func (k Keeper) ClaimAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []b
} }
// RefundAtomicSwap refunds an AtomicSwap, sending assets to the original sender and closing the AtomicSwap // RefundAtomicSwap refunds an AtomicSwap, sending assets to the original sender and closing the AtomicSwap
func (k Keeper) RefundAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []byte) sdk.Error { func (k Keeper) RefundAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []byte) error {
atomicSwap, found := k.GetAtomicSwap(ctx, swapID) atomicSwap, found := k.GetAtomicSwap(ctx, swapID)
if !found { if !found {
return types.ErrAtomicSwapNotFound(k.codespace, swapID) return sdkerrors.Wrapf(types.ErrAtomicSwapNotFound, "%s", swapID)
} }
// Only expired swaps may be refunded // Only expired swaps may be refunded
if atomicSwap.Status != types.Expired { if atomicSwap.Status != types.Expired {
return types.ErrSwapNotRefundable(k.codespace) return types.ErrSwapNotRefundable
} }
var err error
switch atomicSwap.Direction { switch atomicSwap.Direction {
case types.Incoming: case types.Incoming:
err := k.DecrementIncomingAssetSupply(ctx, atomicSwap.Amount[0]) err = k.DecrementIncomingAssetSupply(ctx, atomicSwap.Amount[0])
if err != nil {
return err
}
case types.Outgoing: case types.Outgoing:
err := k.DecrementOutgoingAssetSupply(ctx, atomicSwap.Amount[0]) err = k.DecrementOutgoingAssetSupply(ctx, atomicSwap.Amount[0])
default:
err = fmt.Errorf("invalid swap direction: %s", atomicSwap.Direction.String())
}
if err != nil { if err != nil {
return err return err
} }
default:
return sdk.ErrInternal("invalid swap direction")
}
// Refund coins to original swap sender // Refund coins to original swap sender
err := k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, atomicSwap.Sender, atomicSwap.Amount) err = k.supplyKeeper.SendCoinsFromModuleToAccount(ctx, types.ModuleName, atomicSwap.Sender, atomicSwap.Amount)
if err != nil { if err != nil {
return err return err
} }
@ -231,7 +224,7 @@ func (k Keeper) RefundAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []
} }
// UpdateExpiredAtomicSwaps finds all AtomicSwaps that are past (or at) their ending times and expires them. // UpdateExpiredAtomicSwaps finds all AtomicSwaps that are past (or at) their ending times and expires them.
func (k Keeper) UpdateExpiredAtomicSwaps(ctx sdk.Context) sdk.Error { func (k Keeper) UpdateExpiredAtomicSwaps(ctx sdk.Context) error {
var expiredSwaps [][]byte var expiredSwaps [][]byte
k.IterateAtomicSwapsByBlock(ctx, uint64(ctx.BlockHeight()), func(id []byte) bool { k.IterateAtomicSwapsByBlock(ctx, uint64(ctx.BlockHeight()), func(id []byte) bool {
expiredSwaps = append(expiredSwaps, id) expiredSwaps = append(expiredSwaps, id)
@ -249,7 +242,7 @@ func (k Keeper) UpdateExpiredAtomicSwaps(ctx sdk.Context) sdk.Error {
} }
// DeleteClosedAtomicSwapsFromLongtermStorage removes swaps one week after completion // DeleteClosedAtomicSwapsFromLongtermStorage removes swaps one week after completion
func (k Keeper) DeleteClosedAtomicSwapsFromLongtermStorage(ctx sdk.Context) sdk.Error { func (k Keeper) DeleteClosedAtomicSwapsFromLongtermStorage(ctx sdk.Context) error {
var swapsToDelete [][]byte var swapsToDelete [][]byte
k.IterateAtomicSwapsLongtermStorage(ctx, uint64(ctx.BlockHeight()), func(id []byte) bool { k.IterateAtomicSwapsLongtermStorage(ctx, uint64(ctx.BlockHeight()), func(id []byte) bool {
swapsToDelete = append(swapsToDelete, id) swapsToDelete = append(swapsToDelete, id)

View File

@ -5,15 +5,18 @@ import (
"testing" "testing"
"time" "time"
"github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types"
tmbytes "github.com/tendermint/tendermint/libs/bytes"
tmtime "github.com/tendermint/tendermint/types/time"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/app" "github.com/kava-labs/kava/app"
"github.com/kava-labs/kava/x/bep3" "github.com/kava-labs/kava/x/bep3"
"github.com/kava-labs/kava/x/bep3/keeper" "github.com/kava-labs/kava/x/bep3/keeper"
"github.com/kava-labs/kava/x/bep3/types" "github.com/kava-labs/kava/x/bep3/types"
"github.com/stretchr/testify/suite"
abci "github.com/tendermint/tendermint/abci/types"
cmn "github.com/tendermint/tendermint/libs/common"
tmtime "github.com/tendermint/tendermint/types/time"
) )
type AtomicSwapTestSuite struct { type AtomicSwapTestSuite struct {
@ -25,9 +28,9 @@ type AtomicSwapTestSuite struct {
deputy sdk.AccAddress deputy sdk.AccAddress
addrs []sdk.AccAddress addrs []sdk.AccAddress
timestamps []int64 timestamps []int64
randomNumberHashes []cmn.HexBytes randomNumberHashes []tmbytes.HexBytes
swapIDs []cmn.HexBytes swapIDs []tmbytes.HexBytes
randomNumbers []cmn.HexBytes randomNumbers []tmbytes.HexBytes
} }
const ( const (
@ -65,8 +68,8 @@ func (suite *AtomicSwapTestSuite) SetupTest() {
func (suite *AtomicSwapTestSuite) GenerateSwapDetails() { func (suite *AtomicSwapTestSuite) GenerateSwapDetails() {
var timestamps []int64 var timestamps []int64
var randomNumberHashes []cmn.HexBytes var randomNumberHashes []tmbytes.HexBytes
var randomNumbers []cmn.HexBytes var randomNumbers []tmbytes.HexBytes
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
// Set up atomic swap details // Set up atomic swap details
timestamp := ts(i) timestamp := ts(i)

View File

@ -8,6 +8,7 @@ import (
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/auth"
sim "github.com/cosmos/cosmos-sdk/x/simulation" sim "github.com/cosmos/cosmos-sdk/x/simulation"
"github.com/gorilla/mux" "github.com/gorilla/mux"
"github.com/spf13/cobra" "github.com/spf13/cobra"
@ -21,7 +22,7 @@ import (
var ( var (
_ module.AppModule = AppModule{} _ module.AppModule = AppModule{}
_ module.AppModuleBasic = AppModuleBasic{} _ module.AppModuleBasic = AppModuleBasic{}
_ module.AppModuleSimulation = AppModuleSimulation{} _ module.AppModuleSimulation = AppModule{}
) )
// AppModuleBasic defines the basic application module used by the bep3 module. // AppModuleBasic defines the basic application module used by the bep3 module.
@ -70,40 +71,21 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command {
//____________________________________________________________________________ //____________________________________________________________________________
// AppModuleSimulation defines the module simulation functions used by the auction module.
type AppModuleSimulation struct{}
// RegisterStoreDecoder registers a decoder for auction module's types
func (AppModuleSimulation) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
sdr[StoreKey] = simulation.DecodeStore
}
// GenerateGenesisState creates a randomized GenState of the auction module
func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) {
simulation.RandomizedGenState(simState)
}
// RandomizedParams creates randomized auction param changes for the simulator.
func (AppModuleSimulation) RandomizedParams(r *rand.Rand) []sim.ParamChange {
return simulation.ParamChanges(r)
}
//____________________________________________________________________________
// AppModule implements the sdk.AppModule interface. // AppModule implements the sdk.AppModule interface.
type AppModule struct { type AppModule struct {
AppModuleBasic AppModuleBasic
AppModuleSimulation
keeper Keeper keeper Keeper
accountKeeper auth.AccountKeeper
supplyKeeper SupplyKeeper supplyKeeper SupplyKeeper
} }
// NewAppModule creates a new AppModule object // NewAppModule creates a new AppModule object
func NewAppModule(keeper Keeper, supplyKeeper SupplyKeeper) AppModule { func NewAppModule(keeper Keeper, accountKeeper auth.AccountKeeper, supplyKeeper SupplyKeeper) AppModule {
return AppModule{ return AppModule{
AppModuleBasic: AppModuleBasic{}, AppModuleBasic: AppModuleBasic{},
keeper: keeper, keeper: keeper,
accountKeeper: accountKeeper,
supplyKeeper: supplyKeeper, supplyKeeper: supplyKeeper,
} }
} }
@ -161,3 +143,30 @@ func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) {
func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
return []abci.ValidatorUpdate{} return []abci.ValidatorUpdate{}
} }
//____________________________________________________________________________
// GenerateGenesisState creates a randomized GenState of the bep3 module
func (AppModuleBasic) GenerateGenesisState(simState *module.SimulationState) {
simulation.RandomizedGenState(simState)
}
// ProposalContents doesn't return any content functions for governance proposals.
func (AppModuleBasic) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent {
return nil
}
// RandomizedParams returns nil because bep3 has no params.
func (AppModuleBasic) RandomizedParams(r *rand.Rand) []sim.ParamChange {
return simulation.ParamChanges(r)
}
// RegisterStoreDecoder registers a decoder for bep3 module's types
func (AppModuleBasic) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
sdr[StoreKey] = simulation.DecodeStore
}
// WeightedOperations returns the all the bep3 module operations with their respective weights.
func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation {
return simulation.WeightedOperations(simState.AppParams, simState.Cdc, am.accountKeeper, am.keeper)
}

View File

@ -4,14 +4,16 @@ import (
"bytes" "bytes"
"fmt" "fmt"
tmbytes "github.com/tendermint/tendermint/libs/bytes"
"github.com/tendermint/tendermint/libs/kv"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/kava-labs/kava/x/bep3/types" "github.com/kava-labs/kava/x/bep3/types"
) )
// DecodeStore unmarshals the KVPair's Value to the module's corresponding type // DecodeStore unmarshals the KVPair's Value to the module's corresponding type
func DecodeStore(cdc *codec.Codec, kvA, kvB cmn.KVPair) string { func DecodeStore(cdc *codec.Codec, kvA, kvB kv.Pair) string {
switch { switch {
case bytes.Equal(kvA.Key[:1], types.AtomicSwapKeyPrefix): case bytes.Equal(kvA.Key[:1], types.AtomicSwapKeyPrefix):
var swapA, swapB types.AtomicSwap var swapA, swapB types.AtomicSwap
@ -27,8 +29,8 @@ func DecodeStore(cdc *codec.Codec, kvA, kvB cmn.KVPair) string {
case bytes.Equal(kvA.Key[:1], types.AtomicSwapByBlockPrefix), case bytes.Equal(kvA.Key[:1], types.AtomicSwapByBlockPrefix),
bytes.Equal(kvA.Key[:1], types.AtomicSwapLongtermStoragePrefix): bytes.Equal(kvA.Key[:1], types.AtomicSwapLongtermStoragePrefix):
var bytesA cmn.HexBytes = kvA.Value var bytesA tmbytes.HexBytes = kvA.Value
var bytesB cmn.HexBytes = kvA.Value var bytesB tmbytes.HexBytes = kvA.Value
return fmt.Sprintf("%s\n%s", bytesA.String(), bytesB.String()) return fmt.Sprintf("%s\n%s", bytesA.String(), bytesB.String())
default: default:

View File

@ -6,7 +6,8 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
cmn "github.com/tendermint/tendermint/libs/common" tmbytes "github.com/tendermint/tendermint/libs/bytes"
"github.com/tendermint/tendermint/libs/kv"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
@ -27,14 +28,14 @@ func TestDecodeDistributionStore(t *testing.T) {
oneCoin := sdk.NewCoin("coin", sdk.OneInt()) oneCoin := sdk.NewCoin("coin", sdk.OneInt())
swap := types.NewAtomicSwap(sdk.Coins{oneCoin}, nil, 10, 100, nil, nil, "otherChainSender", "otherChainRec", 200, types.Completed, true, types.Outgoing) swap := types.NewAtomicSwap(sdk.Coins{oneCoin}, nil, 10, 100, nil, nil, "otherChainSender", "otherChainRec", 200, types.Completed, true, types.Outgoing)
supply := types.AssetSupply{Denom: "coin", IncomingSupply: oneCoin, OutgoingSupply: oneCoin, CurrentSupply: oneCoin, Limit: oneCoin} supply := types.AssetSupply{Denom: "coin", IncomingSupply: oneCoin, OutgoingSupply: oneCoin, CurrentSupply: oneCoin, Limit: oneCoin}
bz := cmn.HexBytes([]byte{1, 2}) bz := tmbytes.HexBytes([]byte{1, 2})
kvPairs := cmn.KVPairs{ kvPairs := kv.Pairs{
cmn.KVPair{Key: types.AtomicSwapKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(swap)}, kv.Pair{Key: types.AtomicSwapKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(swap)},
cmn.KVPair{Key: types.AssetSupplyKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(supply)}, kv.Pair{Key: types.AssetSupplyKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(supply)},
cmn.KVPair{Key: types.AtomicSwapByBlockPrefix, Value: bz}, kv.Pair{Key: types.AtomicSwapByBlockPrefix, Value: bz},
cmn.KVPair{Key: types.AtomicSwapByBlockPrefix, Value: bz}, kv.Pair{Key: types.AtomicSwapByBlockPrefix, Value: bz},
cmn.KVPair{Key: []byte{0x99}, Value: []byte{0x99}}, kv.Pair{Key: []byte{0x99}, Value: []byte{0x99}},
} }
tests := []struct { tests := []struct {

View File

@ -25,13 +25,14 @@ const (
var ( var (
MaxSupplyLimit = sdk.NewInt(1000000000000) MaxSupplyLimit = sdk.NewInt(1000000000000)
Accs []simulation.Account accs []simulation.Account
ConsistentDenoms = [3]string{"bnb", "xrp", "btc"} ConsistentDenoms = [3]string{"bnb", "xrp", "btc"}
) )
// GenBnbDeputyAddress randomized BnbDeputyAddress // GenRandBnbDeputy randomized BnbDeputyAddress
func GenBnbDeputyAddress(r *rand.Rand) sdk.AccAddress { func GenRandBnbDeputy(r *rand.Rand) simulation.Account {
return simulation.RandomAcc(r, Accs).Address acc, _ := simulation.RandomAcc(r, accs)
return acc
} }
// GenMinBlockLock randomized MinBlockLock // GenMinBlockLock randomized MinBlockLock
@ -77,7 +78,7 @@ func genSupportedAsset(r *rand.Rand, denom string) types.AssetParam {
// RandomizedGenState generates a random GenesisState // RandomizedGenState generates a random GenesisState
func RandomizedGenState(simState *module.SimulationState) { func RandomizedGenState(simState *module.SimulationState) {
Accs = simState.Accounts accs = simState.Accounts
bep3Genesis := loadRandomBep3GenState(simState) bep3Genesis := loadRandomBep3GenState(simState)
fmt.Printf("Selected randomly generated %s parameters:\n%s\n", types.ModuleName, codec.MustMarshalJSONIndent(simState.Cdc, bep3Genesis)) fmt.Printf("Selected randomly generated %s parameters:\n%s\n", types.ModuleName, codec.MustMarshalJSONIndent(simState.Cdc, bep3Genesis))
@ -90,13 +91,13 @@ func RandomizedGenState(simState *module.SimulationState) {
var supplyGenesis supply.GenesisState var supplyGenesis supply.GenesisState
simState.Cdc.MustUnmarshalJSON(simState.GenState[supply.ModuleName], &supplyGenesis) simState.Cdc.MustUnmarshalJSON(simState.GenState[supply.ModuleName], &supplyGenesis)
for _, deputyCoin := range totalCoins { for _, deputyCoin := range totalCoins {
supplyGenesis.Supply = supplyGenesis.Supply.Add(deputyCoin) supplyGenesis.Supply = supplyGenesis.Supply.Add(deputyCoin...)
} }
simState.GenState[supply.ModuleName] = simState.Cdc.MustMarshalJSON(supplyGenesis) simState.GenState[supply.ModuleName] = simState.Cdc.MustMarshalJSON(supplyGenesis)
} }
func loadRandomBep3GenState(simState *module.SimulationState) types.GenesisState { func loadRandomBep3GenState(simState *module.SimulationState) types.GenesisState {
bnbDeputyAddress := simulation.RandomAcc(simState.Rand, simState.Accounts).Address bnbDeputy := GenRandBnbDeputy(simState.Rand)
// min/max block lock are hardcoded to 50/100 for expected -NumBlocks=100 // min/max block lock are hardcoded to 50/100 for expected -NumBlocks=100
minBlockLock := int64(types.AbsoluteMinimumBlockLock) minBlockLock := int64(types.AbsoluteMinimumBlockLock)
@ -110,7 +111,7 @@ func loadRandomBep3GenState(simState *module.SimulationState) types.GenesisState
bep3Genesis := types.GenesisState{ bep3Genesis := types.GenesisState{
Params: types.Params{ Params: types.Params{
BnbDeputyAddress: bnbDeputyAddress, BnbDeputyAddress: bnbDeputy.Address,
MinBlockLock: minBlockLock, MinBlockLock: minBlockLock,
MaxBlockLock: maxBlockLock, MaxBlockLock: maxBlockLock,
SupportedAssets: supportedAssets, SupportedAssets: supportedAssets,
@ -134,7 +135,7 @@ func loadAuthGenState(simState *module.SimulationState, bep3Genesis types.Genesi
var totalCoins []sdk.Coins var totalCoins []sdk.Coins
for _, asset := range bep3Genesis.Params.SupportedAssets { for _, asset := range bep3Genesis.Params.SupportedAssets {
assetCoin := sdk.NewCoins(sdk.NewCoin(asset.Denom, asset.Limit)) assetCoin := sdk.NewCoins(sdk.NewCoin(asset.Denom, asset.Limit))
if err := deputy.SetCoins(deputy.GetCoins().Add(assetCoin)); err != nil { if err := deputy.SetCoins(deputy.GetCoins().Add(assetCoin...)); err != nil {
panic(err) panic(err)
} }
totalCoins = append(totalCoins, assetCoin) totalCoins = append(totalCoins, assetCoin)

View File

@ -0,0 +1,210 @@
package simulation
import (
"fmt"
"math"
"math/rand"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/simapp/helpers"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/simulation"
appparams "github.com/kava-labs/kava/app/params"
"github.com/kava-labs/kava/x/bep3/keeper"
"github.com/kava-labs/kava/x/bep3/types"
)
var (
noOpMsg = simulation.NoOpMsg(types.ModuleName)
)
// Simulation operation weights constants
const (
OpWeightMsgCreateAtomicSwap = "op_weight_msg_create_atomic_swap"
)
// WeightedOperations returns all the operations from the module with their respective weights
func WeightedOperations(
appParams simulation.AppParams, cdc *codec.Codec, ak auth.AccountKeeper, k keeper.Keeper,
) simulation.WeightedOperations {
var weightCreateAtomicSwap int
appParams.GetOrGenerate(cdc, OpWeightMsgCreateAtomicSwap, &weightCreateAtomicSwap, nil,
func(_ *rand.Rand) {
weightCreateAtomicSwap = appparams.DefaultWeightMsgCreateAtomicSwap
},
)
return simulation.WeightedOperations{
simulation.NewWeightedOperation(
weightCreateAtomicSwap,
SimulateMsgCreateAtomicSwap(ak, k),
),
}
}
// SimulateMsgCreateAtomicSwap generates a MsgCreateAtomicSwap with random values
func SimulateMsgCreateAtomicSwap(ak auth.AccountKeeper, k keeper.Keeper) simulation.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string,
) (simulation.OperationMsg, []simulation.FutureOperation, error) {
senderAddr := k.GetBnbDeputyAddress(ctx)
sender, found := simulation.FindAccount(accs, senderAddr)
if !found {
return noOpMsg, nil, nil
}
recipient, _ := simulation.RandomAcc(r, accs)
recipientOtherChain := simulation.RandStringOfLength(r, 43)
senderOtherChain := simulation.RandStringOfLength(r, 43)
// Generate cryptographically strong pseudo-random number
randomNumber, err := simulation.RandPositiveInt(r, sdk.NewInt(math.MaxInt64))
if err != nil {
return noOpMsg, nil, err
}
// Must use current blocktime instead of 'now' since initial blocktime was randomly generated
timestamp := ctx.BlockTime().Unix()
randomNumberHash := types.CalculateRandomHash(randomNumber.BigInt().Bytes(), timestamp)
// Randomly select an asset from supported assets
assets, found := k.GetAssets(ctx)
if !found {
return noOpMsg, nil, fmt.Errorf("no supported assets found")
}
asset := assets[r.Intn(len(assets))]
// Check that the sender has coins of this type
senderAcc := ak.GetAccount(ctx, senderAddr)
fees, err := simulation.RandomFees(r, ctx, senderAcc.SpendableCoins(ctx.BlockTime()))
if err != nil {
return simulation.NoOpMsg(types.ModuleName), nil, err
}
availableAmount := senderAcc.SpendableCoins(ctx.BlockTime()).Sub(fees).AmountOf(asset.Denom)
// Get an amount of coins between 0.1 and 2% of total coins
amount := availableAmount.Quo(sdk.NewInt(int64(simulation.RandIntBetween(r, 50, 1000))))
if amount.IsZero() {
return simulation.NewOperationMsgBasic(types.ModuleName, fmt.Sprintf("no-operation (all funds exhausted for asset %s)", asset.Denom), "", false, nil), nil, nil
}
coin := sdk.NewCoin(asset.Denom, amount)
coins := sdk.NewCoins(coin)
expectedIncome := coin.String()
// We're assuming that sims are run with -NumBlocks=100
heightSpan := int64(55)
crossChain := true
msg := types.NewMsgCreateAtomicSwap(
senderAddr, recipient.Address, recipientOtherChain, senderOtherChain, randomNumberHash,
timestamp, coins, expectedIncome, heightSpan, crossChain,
)
tx := helpers.GenTx(
[]sdk.Msg{msg},
fees,
helpers.DefaultGenTxGas,
chainID,
[]uint64{senderAcc.GetAccountNumber()},
[]uint64{senderAcc.GetSequence()},
sender.PrivKey,
)
_, result, err := app.Deliver(tx)
if err != nil {
return simulation.NoOpMsg(types.ModuleName), nil, err
}
// If created, construct a MsgClaimAtomicSwap or MsgRefundAtomicSwap future operation
var futureOp simulation.FutureOperation
swapID := types.CalculateSwapID(msg.RandomNumberHash, msg.From, msg.SenderOtherChain)
if r.Intn(100) < 50 {
// Claim future operation
executionBlock := ctx.BlockHeight() + (msg.HeightSpan / 2)
futureOp = simulation.FutureOperation{
BlockHeight: int(executionBlock),
Op: operationClaimAtomicSwap(ak, k, swapID, randomNumber.BigInt().Bytes()),
}
} else {
// Refund future operation
executionBlock := ctx.BlockHeight() + msg.HeightSpan
futureOp = simulation.FutureOperation{
BlockHeight: int(executionBlock),
Op: operationRefundAtomicSwap(ak, k, swapID),
}
}
return simulation.NewOperationMsg(msg, true, result.Log), []simulation.FutureOperation{futureOp}, nil
}
}
func operationClaimAtomicSwap(ak auth.AccountKeeper, k keeper.Keeper, swapID []byte, randomNumber []byte) simulation.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string,
) (simulation.OperationMsg, []simulation.FutureOperation, error) {
simAccount, _ := simulation.RandomAcc(r, accs)
acc := ak.GetAccount(ctx, simAccount.Address)
msg := types.NewMsgClaimAtomicSwap(acc.GetAddress(), swapID, randomNumber)
fees, err := simulation.RandomFees(r, ctx, acc.SpendableCoins(ctx.BlockTime()))
if err != nil {
return simulation.NoOpMsg(types.ModuleName), nil, err
}
tx := helpers.GenTx(
[]sdk.Msg{msg},
fees,
helpers.DefaultGenTxGas,
chainID,
[]uint64{acc.GetAccountNumber()},
[]uint64{acc.GetSequence()},
simAccount.PrivKey,
)
_, result, err := app.Deliver(tx)
if err != nil {
return simulation.NoOpMsg(types.ModuleName), nil, err
}
return simulation.NewOperationMsg(msg, true, result.Log), nil, nil
}
}
func operationRefundAtomicSwap(ak auth.AccountKeeper, k keeper.Keeper, swapID []byte) simulation.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string,
) (simulation.OperationMsg, []simulation.FutureOperation, error) {
simAccount, _ := simulation.RandomAcc(r, accs)
acc := ak.GetAccount(ctx, simAccount.Address)
msg := types.NewMsgRefundAtomicSwap(acc.GetAddress(), swapID)
fees, err := simulation.RandomFees(r, ctx, acc.SpendableCoins(ctx.BlockTime()))
if err != nil {
return simulation.NoOpMsg(types.ModuleName), nil, err
}
tx := helpers.GenTx(
[]sdk.Msg{msg},
fees,
helpers.DefaultGenTxGas,
chainID,
[]uint64{acc.GetAccountNumber()},
[]uint64{acc.GetSequence()},
simAccount.PrivKey,
)
_, result, err := app.Deliver(tx)
if err != nil {
return simulation.NoOpMsg(types.ModuleName), nil, err
}
return simulation.NewOperationMsg(msg, true, result.Log), nil, nil
}
}

View File

@ -1,146 +0,0 @@
package operations
import (
"fmt"
"math"
"math/rand"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/simulation"
"github.com/kava-labs/kava/x/bep3"
"github.com/kava-labs/kava/x/bep3/keeper"
"github.com/kava-labs/kava/x/bep3/types"
)
var (
noOpMsg = simulation.NoOpMsg(bep3.ModuleName)
)
// SimulateMsgCreateAtomicSwap generates a MsgCreateAtomicSwap with random values
func SimulateMsgCreateAtomicSwap(ak auth.AccountKeeper, k keeper.Keeper) simulation.Operation {
handler := bep3.NewHandler(k)
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account) (
simulation.OperationMsg, []simulation.FutureOperation, error) {
sender := k.GetBnbDeputyAddress(ctx)
recipient := simulation.RandomAcc(r, accs).Address
recipientOtherChain := simulation.RandStringOfLength(r, 43)
senderOtherChain := simulation.RandStringOfLength(r, 43)
// Generate cryptographically strong pseudo-random number
randomNumber, err := simulation.RandPositiveInt(r, sdk.NewInt(math.MaxInt64))
if err != nil {
return noOpMsg, nil, err
}
// Must use current blocktime instead of 'now' since initial blocktime was randomly generated
timestamp := ctx.BlockTime().Unix()
randomNumberHash := types.CalculateRandomHash(randomNumber.BigInt().Bytes(), timestamp)
// Randomly select an asset from supported assets
assets, found := k.GetAssets(ctx)
if !found {
return noOpMsg, nil, fmt.Errorf("no supported assets found")
}
asset := assets[r.Intn(len(assets))]
// Check that the sender has coins of this type
availableAmount := ak.GetAccount(ctx, sender).GetCoins().AmountOf(asset.Denom)
// Get an amount of coins between 0.1 and 2% of total coins
amount := availableAmount.Quo(sdk.NewInt(int64(simulation.RandIntBetween(r, 50, 1000))))
if amount.IsZero() {
return simulation.NewOperationMsgBasic(bep3.ModuleName, fmt.Sprintf("no-operation (all funds exhausted for asset %s)", asset.Denom), "", false, nil), nil, nil
}
coin := sdk.NewCoin(asset.Denom, amount)
coins := sdk.NewCoins(coin)
expectedIncome := coin.String()
// We're assuming that sims are run with -NumBlocks=100
heightSpan := int64(55)
crossChain := true
msg := types.NewMsgCreateAtomicSwap(
sender, recipient, recipientOtherChain, senderOtherChain, randomNumberHash,
timestamp, coins, expectedIncome, heightSpan, crossChain)
if err := msg.ValidateBasic(); err != nil {
return noOpMsg, nil, fmt.Errorf("expected MsgCreateAtomicSwap to pass ValidateBasic: %s", err)
}
// Submit msg
ok := submitMsg(ctx, handler, msg)
// If created, construct a MsgClaimAtomicSwap or MsgRefundAtomicSwap future operation
var futureOp simulation.FutureOperation
if ok {
swapID := types.CalculateSwapID(msg.RandomNumberHash, msg.From, msg.SenderOtherChain)
acc := simulation.RandomAcc(r, accs)
evenOdd := r.Intn(2) + 1
if evenOdd%2 == 0 {
// Claim future operation
executionBlock := ctx.BlockHeight() + (msg.HeightSpan / 2)
futureOp = loadClaimFutureOp(acc.Address, swapID, randomNumber.BigInt().Bytes(), executionBlock, handler)
} else {
// Refund future operation
executionBlock := ctx.BlockHeight() + msg.HeightSpan
futureOp = loadRefundFutureOp(acc.Address, swapID, executionBlock, handler)
}
}
return simulation.NewOperationMsg(msg, ok, ""), []simulation.FutureOperation{futureOp}, nil
}
}
func loadClaimFutureOp(sender sdk.AccAddress, swapID []byte, randomNumber []byte, height int64, handler sdk.Handler) simulation.FutureOperation {
claimOp := func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account) (
simulation.OperationMsg, []simulation.FutureOperation, error) {
// Build the refund msg and validate basic
claimMsg := types.NewMsgClaimAtomicSwap(sender, swapID, randomNumber)
if err := claimMsg.ValidateBasic(); err != nil {
return noOpMsg, nil, fmt.Errorf("expected MsgClaimAtomicSwap to pass ValidateBasic: %s", err)
}
// Test msg submission at target block height
ok := handler(ctx.WithBlockHeight(height), claimMsg).IsOK()
return simulation.NewOperationMsg(claimMsg, ok, ""), nil, nil
}
return simulation.FutureOperation{
BlockHeight: int(height),
Op: claimOp,
}
}
func loadRefundFutureOp(sender sdk.AccAddress, swapID []byte, height int64, handler sdk.Handler) simulation.FutureOperation {
refundOp := func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account) (
simulation.OperationMsg, []simulation.FutureOperation, error) {
// Build the refund msg and validate basic
refundMsg := types.NewMsgRefundAtomicSwap(sender, swapID)
if err := refundMsg.ValidateBasic(); err != nil {
return noOpMsg, nil, fmt.Errorf("expected MsgRefundAtomicSwap to pass ValidateBasic: %s", err)
}
// Test msg submission at target block height
ok := handler(ctx.WithBlockHeight(height), refundMsg).IsOK()
return simulation.NewOperationMsg(refundMsg, ok, ""), nil, nil
}
return simulation.FutureOperation{
BlockHeight: int(height),
Op: refundOp,
}
}
func submitMsg(ctx sdk.Context, handler sdk.Handler, msg sdk.Msg) (ok bool) {
ctx, write := ctx.CacheContext()
ok = handler(ctx, msg).IsOK()
if ok {
write()
}
return ok
}

View File

@ -22,22 +22,22 @@ func ParamChanges(r *rand.Rand) []simulation.ParamChange {
minBlockLockVal := GenMinBlockLock(r) minBlockLockVal := GenMinBlockLock(r)
return []simulation.ParamChange{ return []simulation.ParamChange{
simulation.NewSimParamChange(types.ModuleName, keyBnbDeputyAddress, "", simulation.NewSimParamChange(types.ModuleName, keyBnbDeputyAddress,
func(r *rand.Rand) string { func(r *rand.Rand) string {
return fmt.Sprintf("\"%s\"", GenBnbDeputyAddress(r)) return fmt.Sprintf("\"%s\"", GenRandBnbDeputy(r).Address)
}, },
), ),
simulation.NewSimParamChange(types.ModuleName, keyMinBlockLock, "", simulation.NewSimParamChange(types.ModuleName, keyMinBlockLock,
func(r *rand.Rand) string { func(r *rand.Rand) string {
return fmt.Sprintf("\"%d\"", minBlockLockVal) return fmt.Sprintf("\"%d\"", minBlockLockVal)
}, },
), ),
simulation.NewSimParamChange(types.ModuleName, keyMaxBlockLock, "", simulation.NewSimParamChange(types.ModuleName, keyMaxBlockLock,
func(r *rand.Rand) string { func(r *rand.Rand) string {
return fmt.Sprintf("\"%d\"", GenMaxBlockLock(r, minBlockLockVal)) return fmt.Sprintf("\"%d\"", GenMaxBlockLock(r, minBlockLockVal))
}, },
), ),
simulation.NewSimParamChange(types.ModuleName, keySupportedAssets, "", simulation.NewSimParamChange(types.ModuleName, keySupportedAssets,
func(r *rand.Rand) string { func(r *rand.Rand) string {
return fmt.Sprintf("\"%v\"", GenSupportedAssets(r)) return fmt.Sprintf("\"%v\"", GenSupportedAssets(r))
}, },

View File

@ -1,118 +1,40 @@
package types package types
import ( import (
"encoding/hex" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
cmn "github.com/tendermint/tendermint/libs/common"
) )
// CodeType is the local code type // DONTCOVER
type CodeType = sdk.CodeType
const (
// DefaultCodespace default bep3 codespace
DefaultCodespace sdk.CodespaceType = ModuleName
CodeInvalidTimestamp CodeType = 1
CodeInvalidHeightSpan CodeType = 2
CodeAssetNotSupported CodeType = 3
CodeAssetNotActive CodeType = 4
CodeAssetSupplyNotFound CodeType = 5
CodeExceedsSupplyLimit CodeType = 6
CodeExceedsAvailableSupply CodeType = 7
CodeInvalidCurrentSupply CodeType = 8
CodeInvalidIncomingSupply CodeType = 9
CodeInvalidOutgoingSupply CodeType = 10
CodeInvalidClaimSecret CodeType = 11
CodeAtomicSwapAlreadyExists CodeType = 12
CodeAtomicSwapNotFound CodeType = 13
CodeSwapNotRefundable CodeType = 14
CodeSwapNotClaimable CodeType = 15
)
var (
// ErrInvalidTimestamp error for when an timestamp is outside of bounds. Assumes block time of 10 seconds. // ErrInvalidTimestamp error for when an timestamp is outside of bounds. Assumes block time of 10 seconds.
func ErrInvalidTimestamp(codespace sdk.CodespaceType) sdk.Error { ErrInvalidTimestamp = sdkerrors.Register(ModuleName, 2, "timestamp can neither be 15 minutes ahead of the current time, nor 30 minutes later")
return sdk.NewError(codespace, CodeInvalidTimestamp, fmt.Sprintf("Timestamp can neither be 15 minutes ahead of the current time, nor 30 minutes later"))
}
// ErrInvalidHeightSpan error a proposed height span is outside of lock time range // ErrInvalidHeightSpan error a proposed height span is outside of lock time range
func ErrInvalidHeightSpan(codespace sdk.CodespaceType, heightspan int64, minLockTime int64, maxLockTime int64) sdk.Error { ErrInvalidHeightSpan = sdkerrors.Register(ModuleName, 3, "height span is outside acceptable range")
return sdk.NewError(codespace, CodeInvalidHeightSpan, fmt.Sprintf("height span %d is outside acceptable range %d - %d", heightspan, minLockTime, maxLockTime))
}
// ErrAssetNotSupported error for when an asset is not supported // ErrAssetNotSupported error for when an asset is not supported
func ErrAssetNotSupported(codespace sdk.CodespaceType, denom string) sdk.Error { ErrAssetNotSupported = sdkerrors.Register(ModuleName, 4, "asset not on the list of supported assets")
return sdk.NewError(codespace, CodeAssetNotSupported, fmt.Sprintf("asset %s is not on the list of supported assets", denom))
}
// ErrAssetNotActive error for when an asset is currently inactive // ErrAssetNotActive error for when an asset is currently inactive
func ErrAssetNotActive(codespace sdk.CodespaceType, denom string) sdk.Error { ErrAssetNotActive = sdkerrors.Register(ModuleName, 5, "asset is currently inactive")
return sdk.NewError(codespace, CodeAssetNotActive, fmt.Sprintf("asset %s is currently inactive", denom))
}
// ErrAssetSupplyNotFound error for when an asset's supply is not found in the store // ErrAssetSupplyNotFound error for when an asset's supply is not found in the store
func ErrAssetSupplyNotFound(codespace sdk.CodespaceType, denom string) sdk.Error { ErrAssetSupplyNotFound = sdkerrors.Register(ModuleName, 6, "asset supply not found in store")
return sdk.NewError(codespace, CodeAssetSupplyNotFound, fmt.Sprintf("%s asset supply not found in store", denom))
}
// ErrExceedsSupplyLimit error for when the proposed supply increase would put the supply above limit // ErrExceedsSupplyLimit error for when the proposed supply increase would put the supply above limit
func ErrExceedsSupplyLimit(codespace sdk.CodespaceType, increase, current, limit sdk.Coin) sdk.Error { ErrExceedsSupplyLimit = sdkerrors.Register(ModuleName, 7, "asset supply over limit")
return sdk.NewError(codespace, CodeExceedsSupplyLimit,
fmt.Sprintf("a supply increase of %s puts current asset supply %s over supply limit %s", increase, current, limit))
}
// ErrExceedsAvailableSupply error for when the proposed outgoing amount exceeds the total available supply // ErrExceedsAvailableSupply error for when the proposed outgoing amount exceeds the total available supply
func ErrExceedsAvailableSupply(codespace sdk.CodespaceType, increase sdk.Coin, available sdk.Int) sdk.Error { ErrExceedsAvailableSupply = sdkerrors.Register(ModuleName, 8, "outgoing swap exceeds total available supply")
return sdk.NewError(codespace, CodeExceedsAvailableSupply, // ErrInvalidCurrentSupply error for when the proposed decrease would result in a negative current supplyx
fmt.Sprintf("an outgoing swap with amount %s exceeds total available supply %s", ErrInvalidCurrentSupply = sdkerrors.Register(ModuleName, 9, "supply decrease puts current asset supply below 0")
increase, sdk.NewCoin(increase.Denom, available)))
}
// ErrInvalidCurrentSupply error for when the proposed decrease would result in a negative current supply
func ErrInvalidCurrentSupply(codespace sdk.CodespaceType, decrease, current sdk.Coin) sdk.Error {
return sdk.NewError(codespace, CodeInvalidCurrentSupply,
fmt.Sprintf("a supply decrease of %s puts current asset supply %s below 0", decrease, current))
}
// ErrInvalidIncomingSupply error for when the proposed decrease would result in a negative incoming supply // ErrInvalidIncomingSupply error for when the proposed decrease would result in a negative incoming supply
func ErrInvalidIncomingSupply(codespace sdk.CodespaceType, decrease, incoming sdk.Coin) sdk.Error { ErrInvalidIncomingSupply = sdkerrors.Register(ModuleName, 10, "supply decrease puts incoming asset supply below 0")
return sdk.NewError(codespace, CodeInvalidIncomingSupply,
fmt.Sprintf("a supply decrease of %s puts incoming asset supply %s below 0", decrease, incoming))
}
// ErrInvalidOutgoingSupply error for when the proposed decrease would result in a negative outgoing supply // ErrInvalidOutgoingSupply error for when the proposed decrease would result in a negative outgoing supply
func ErrInvalidOutgoingSupply(codespace sdk.CodespaceType, decrease, outgoing sdk.Coin) sdk.Error { ErrInvalidOutgoingSupply = sdkerrors.Register(ModuleName, 11, "supply decrease puts outgoing asset supply below 0")
return sdk.NewError(codespace, CodeInvalidOutgoingSupply,
fmt.Sprintf("a supply decrease of %s puts outgoing asset supply %s below 0", decrease, outgoing))
}
// ErrInvalidClaimSecret error when a submitted secret doesn't match an AtomicSwap's swapID // ErrInvalidClaimSecret error when a submitted secret doesn't match an AtomicSwap's swapID
func ErrInvalidClaimSecret(codespace sdk.CodespaceType, submittedSecret []byte, swapID []byte) sdk.Error { ErrInvalidClaimSecret = sdkerrors.Register(ModuleName, 12, "hashed claim attempt does not match")
return sdk.NewError(codespace, CodeInvalidClaimSecret,
fmt.Sprintf("hashed claim attempt %s does not match %s",
hex.EncodeToString(submittedSecret),
hex.EncodeToString(swapID),
),
)
}
// ErrAtomicSwapAlreadyExists error for when an AtomicSwap with this swapID already exists // ErrAtomicSwapAlreadyExists error for when an AtomicSwap with this swapID already exists
func ErrAtomicSwapAlreadyExists(codespace sdk.CodespaceType, swapID cmn.HexBytes) sdk.Error { ErrAtomicSwapAlreadyExists = sdkerrors.Register(ModuleName, 13, "atomic swap already exists")
return sdk.NewError(codespace, CodeAtomicSwapAlreadyExists, fmt.Sprintf("atomic swap %s already exists", swapID))
}
// ErrAtomicSwapNotFound error for when an atomic swap is not found // ErrAtomicSwapNotFound error for when an atomic swap is not found
func ErrAtomicSwapNotFound(codespace sdk.CodespaceType, id []byte) sdk.Error { ErrAtomicSwapNotFound = sdkerrors.Register(ModuleName, 14, "atomic swap not found")
return sdk.NewError(codespace, CodeAtomicSwapNotFound, fmt.Sprintf("AtomicSwap %s was not found", hex.EncodeToString(id)))
}
// ErrSwapNotRefundable error for when an AtomicSwap has not expired and cannot be refunded // ErrSwapNotRefundable error for when an AtomicSwap has not expired and cannot be refunded
func ErrSwapNotRefundable(codespace sdk.CodespaceType) sdk.Error { ErrSwapNotRefundable = sdkerrors.Register(ModuleName, 15, "atomic swap is still active and cannot be refunded")
return sdk.NewError(codespace, CodeSwapNotRefundable, fmt.Sprintf("atomic swap is still active and cannot be refunded"))
}
// ErrSwapNotClaimable error for when an atomic swap is not open and cannot be claimed // ErrSwapNotClaimable error for when an atomic swap is not open and cannot be claimed
func ErrSwapNotClaimable(codespace sdk.CodespaceType) sdk.Error { ErrSwapNotClaimable = sdkerrors.Register(ModuleName, 16, "atomic swap is not claimable")
return sdk.NewError(codespace, CodeSwapNotClaimable, fmt.Sprintf("atomic swap is not claimable")) )
}

View File

@ -10,10 +10,10 @@ type SupplyKeeper interface {
GetModuleAddress(name string) sdk.AccAddress GetModuleAddress(name string) sdk.AccAddress
GetModuleAccount(ctx sdk.Context, moduleName string) supplyexported.ModuleAccountI GetModuleAccount(ctx sdk.Context, moduleName string) supplyexported.ModuleAccountI
SendCoinsFromModuleToModule(ctx sdk.Context, sender, recipient string, amt sdk.Coins) sdk.Error SendCoinsFromModuleToModule(ctx sdk.Context, sender, recipient string, amt sdk.Coins) error
SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) sdk.Error BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) error
MintCoins(ctx sdk.Context, name string, amt sdk.Coins) sdk.Error MintCoins(ctx sdk.Context, name string, amt sdk.Coins) error
} }

View File

@ -1,11 +1,15 @@
package types package types
import ( import (
"errors"
"fmt" "fmt"
"strings"
"github.com/tendermint/tendermint/crypto"
tmbytes "github.com/tendermint/tendermint/libs/bytes"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/tendermint/tendermint/crypto" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
cmn "github.com/tendermint/tendermint/libs/common"
) )
const ( const (
@ -40,7 +44,7 @@ type MsgCreateAtomicSwap struct {
To sdk.AccAddress `json:"to" yaml:"to"` To sdk.AccAddress `json:"to" yaml:"to"`
RecipientOtherChain string `json:"recipient_other_chain" yaml:"recipient_other_chain"` RecipientOtherChain string `json:"recipient_other_chain" yaml:"recipient_other_chain"`
SenderOtherChain string `json:"sender_other_chain" yaml:"sender_other_chain"` SenderOtherChain string `json:"sender_other_chain" yaml:"sender_other_chain"`
RandomNumberHash cmn.HexBytes `json:"random_number_hash" yaml:"random_number_hash"` RandomNumberHash tmbytes.HexBytes `json:"random_number_hash" yaml:"random_number_hash"`
Timestamp int64 `json:"timestamp" yaml:"timestamp"` Timestamp int64 `json:"timestamp" yaml:"timestamp"`
Amount sdk.Coins `json:"amount" yaml:"amount"` Amount sdk.Coins `json:"amount" yaml:"amount"`
ExpectedIncome string `json:"expected_income" yaml:"expected_income"` ExpectedIncome string `json:"expected_income" yaml:"expected_income"`
@ -50,7 +54,7 @@ type MsgCreateAtomicSwap struct {
// NewMsgCreateAtomicSwap initializes a new MsgCreateAtomicSwap // NewMsgCreateAtomicSwap initializes a new MsgCreateAtomicSwap
func NewMsgCreateAtomicSwap(from sdk.AccAddress, to sdk.AccAddress, recipientOtherChain, func NewMsgCreateAtomicSwap(from sdk.AccAddress, to sdk.AccAddress, recipientOtherChain,
senderOtherChain string, randomNumberHash cmn.HexBytes, timestamp int64, senderOtherChain string, randomNumberHash tmbytes.HexBytes, timestamp int64,
amount sdk.Coins, expectedIncome string, heightSpan int64, crossChain bool) MsgCreateAtomicSwap { amount sdk.Coins, expectedIncome string, heightSpan int64, crossChain bool) MsgCreateAtomicSwap {
return MsgCreateAtomicSwap{ return MsgCreateAtomicSwap{
From: from, From: from,
@ -91,49 +95,58 @@ func (msg MsgCreateAtomicSwap) GetSigners() []sdk.AccAddress {
} }
// ValidateBasic validates the MsgCreateAtomicSwap // ValidateBasic validates the MsgCreateAtomicSwap
func (msg MsgCreateAtomicSwap) ValidateBasic() sdk.Error { func (msg MsgCreateAtomicSwap) ValidateBasic() error {
if msg.From.Empty() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be empty")
}
if len(msg.From) != AddrByteCount { if len(msg.From) != AddrByteCount {
return sdk.ErrInternal(fmt.Sprintf("the expected address length is %d, actual length is %d", AddrByteCount, len(msg.From))) return fmt.Errorf("the expected address length is %d, actual length is %d", AddrByteCount, len(msg.From))
}
if msg.To.Empty() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "recipient address cannot be empty")
} }
if len(msg.To) != AddrByteCount { if len(msg.To) != AddrByteCount {
return sdk.ErrInternal(fmt.Sprintf("the expected address length is %d, actual length is %d", AddrByteCount, len(msg.To))) return fmt.Errorf("the expected address length is %d, actual length is %d", AddrByteCount, len(msg.To))
} }
if !msg.CrossChain && len(msg.RecipientOtherChain) != 0 { if !msg.CrossChain && msg.RecipientOtherChain != "" {
return sdk.ErrInternal(fmt.Sprintf("must leave recipient address on other chain to empty for single chain swap")) return errors.New("must leave recipient address on other chain to empty for single chain swap")
} }
if !msg.CrossChain && len(msg.SenderOtherChain) != 0 { if !msg.CrossChain && msg.SenderOtherChain != "" {
return sdk.ErrInternal(fmt.Sprintf("must leave sender address on other chain to empty for single chain swap")) return errors.New("must leave sender address on other chain to empty for single chain swap")
} }
if msg.CrossChain && len(msg.RecipientOtherChain) == 0 { if msg.CrossChain && strings.TrimSpace(msg.RecipientOtherChain) == "" {
return sdk.ErrInternal(fmt.Sprintf("missing recipient address on other chain for cross chain swap")) return errors.New("missing recipient address on other chain for cross chain swap")
} }
if len(msg.RecipientOtherChain) > MaxOtherChainAddrLength { if len(msg.RecipientOtherChain) > MaxOtherChainAddrLength {
return sdk.ErrInternal(fmt.Sprintf("the length of recipient address on other chain should be less than %d", MaxOtherChainAddrLength)) return fmt.Errorf("the length of recipient address on other chain should be less than %d", MaxOtherChainAddrLength)
} }
if len(msg.SenderOtherChain) > MaxOtherChainAddrLength { if len(msg.SenderOtherChain) > MaxOtherChainAddrLength {
return sdk.ErrInternal(fmt.Sprintf("the length of sender address on other chain should be less than %d", MaxOtherChainAddrLength)) return fmt.Errorf("the length of sender address on other chain should be less than %d", MaxOtherChainAddrLength)
} }
if len(msg.RandomNumberHash) != RandomNumberHashLength { if len(msg.RandomNumberHash) != RandomNumberHashLength {
return sdk.ErrInternal(fmt.Sprintf("the length of random number hash should be %d", RandomNumberHashLength)) return fmt.Errorf("the length of random number hash should be %d", RandomNumberHashLength)
} }
if msg.Timestamp <= 0 { if msg.Timestamp <= 0 {
return sdk.ErrInternal("timestamp must be positive") return errors.New("timestamp must be positive")
} }
if !msg.Amount.IsAllPositive() { if len(msg.Amount) == 0 {
return sdk.ErrInternal(fmt.Sprintf("the swapped out coin must be positive")) return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, "amount cannot be empty")
}
if !msg.Amount.IsValid() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidCoins, msg.Amount.String())
} }
if len(msg.ExpectedIncome) > MaxExpectedIncomeLength { if len(msg.ExpectedIncome) > MaxExpectedIncomeLength {
return sdk.ErrInternal(fmt.Sprintf("the length of expected income should be less than %d", MaxExpectedIncomeLength)) return fmt.Errorf("the length of expected income should be less than %d", MaxExpectedIncomeLength)
} }
expectedIncomeCoins, err := sdk.ParseCoins(msg.ExpectedIncome) expectedIncomeCoins, err := sdk.ParseCoins(msg.ExpectedIncome)
if err != nil || expectedIncomeCoins == nil { if err != nil || expectedIncomeCoins == nil {
return sdk.ErrInternal(fmt.Sprintf("expected income %s must be in valid format e.g. 10000ukava", msg.ExpectedIncome)) return fmt.Errorf("expected income %s must be in valid format e.g. 10000ukava", msg.ExpectedIncome)
} }
if expectedIncomeCoins.IsAnyGT(msg.Amount) { if expectedIncomeCoins.IsAnyGT(msg.Amount) {
return sdk.ErrInternal(fmt.Sprintf("expected income %s cannot be greater than amount %s", msg.ExpectedIncome, msg.Amount.String())) return fmt.Errorf("expected income %s cannot be greater than amount %s", msg.ExpectedIncome, msg.Amount.String())
} }
if msg.HeightSpan <= 0 { if msg.HeightSpan <= 0 {
return sdk.ErrInternal("height span must be positive") return errors.New("height span must be positive")
} }
return nil return nil
} }
@ -147,8 +160,8 @@ func (msg MsgCreateAtomicSwap) GetSignBytes() []byte {
// MsgClaimAtomicSwap defines a AtomicSwap claim // MsgClaimAtomicSwap defines a AtomicSwap claim
type MsgClaimAtomicSwap struct { type MsgClaimAtomicSwap struct {
From sdk.AccAddress `json:"from" yaml:"from"` From sdk.AccAddress `json:"from" yaml:"from"`
SwapID cmn.HexBytes `json:"swap_id" yaml:"swap_id"` SwapID tmbytes.HexBytes `json:"swap_id" yaml:"swap_id"`
RandomNumber cmn.HexBytes `json:"random_number" yaml:"random_number"` RandomNumber tmbytes.HexBytes `json:"random_number" yaml:"random_number"`
} }
// NewMsgClaimAtomicSwap initializes a new MsgClaimAtomicSwap // NewMsgClaimAtomicSwap initializes a new MsgClaimAtomicSwap
@ -182,15 +195,18 @@ func (msg MsgClaimAtomicSwap) GetSigners() []sdk.AccAddress {
} }
// ValidateBasic validates the MsgClaimAtomicSwap // ValidateBasic validates the MsgClaimAtomicSwap
func (msg MsgClaimAtomicSwap) ValidateBasic() sdk.Error { func (msg MsgClaimAtomicSwap) ValidateBasic() error {
if msg.From.Empty() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be empty")
}
if len(msg.From) != AddrByteCount { if len(msg.From) != AddrByteCount {
return sdk.ErrInternal(fmt.Sprintf("the expected address length is %d, actual length is %d", AddrByteCount, len(msg.From))) return sdkerrors.Wrapf(sdkerrors.ErrInvalidAddress, "actual address length ≠ expected length (%d ≠ %d)", len(msg.From), AddrByteCount)
} }
if len(msg.SwapID) != SwapIDLength { if len(msg.SwapID) != SwapIDLength {
return sdk.ErrInternal(fmt.Sprintf("the length of swapID should be %d", SwapIDLength)) return fmt.Errorf("the length of swapID should be %d", SwapIDLength)
} }
if len(msg.RandomNumber) == 0 { if len(msg.RandomNumber) == 0 {
return sdk.ErrInternal("the length of random number cannot be 0") return errors.New("the length of random number cannot be 0")
} }
return nil return nil
} }
@ -204,7 +220,7 @@ func (msg MsgClaimAtomicSwap) GetSignBytes() []byte {
// MsgRefundAtomicSwap defines a refund msg // MsgRefundAtomicSwap defines a refund msg
type MsgRefundAtomicSwap struct { type MsgRefundAtomicSwap struct {
From sdk.AccAddress `json:"from" yaml:"from"` From sdk.AccAddress `json:"from" yaml:"from"`
SwapID cmn.HexBytes `json:"swap_id" yaml:"swap_id"` SwapID tmbytes.HexBytes `json:"swap_id" yaml:"swap_id"`
} }
// NewMsgRefundAtomicSwap initializes a new MsgRefundAtomicSwap // NewMsgRefundAtomicSwap initializes a new MsgRefundAtomicSwap
@ -237,12 +253,15 @@ func (msg MsgRefundAtomicSwap) GetSigners() []sdk.AccAddress {
} }
// ValidateBasic validates the MsgRefundAtomicSwap // ValidateBasic validates the MsgRefundAtomicSwap
func (msg MsgRefundAtomicSwap) ValidateBasic() sdk.Error { func (msg MsgRefundAtomicSwap) ValidateBasic() error {
if msg.From.Empty() {
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be empty")
}
if len(msg.From) != AddrByteCount { if len(msg.From) != AddrByteCount {
return sdk.ErrInternal(fmt.Sprintf("the expected address length is %d, actual length is %d", AddrByteCount, len(msg.From))) return fmt.Errorf("the expected address length is %d, actual length is %d", AddrByteCount, len(msg.From))
} }
if len(msg.SwapID) != SwapIDLength { if len(msg.SwapID) != SwapIDLength {
return sdk.ErrInternal(fmt.Sprintf("the length of swapID should be %d", SwapIDLength)) return fmt.Errorf("the length of swapID should be %d", SwapIDLength)
} }
return nil return nil
} }

View File

@ -3,11 +3,14 @@ package types_test
import ( import (
"testing" "testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/x/bep3/types"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto" "github.com/tendermint/tendermint/crypto"
cmn "github.com/tendermint/tendermint/libs/common" tmbytes "github.com/tendermint/tendermint/libs/bytes"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/x/bep3/types"
) )
var ( var (
@ -33,7 +36,7 @@ func TestMsgCreateAtomicSwap(t *testing.T) {
to sdk.AccAddress to sdk.AccAddress
recipientOtherChain string recipientOtherChain string
senderOtherChain string senderOtherChain string
randomNumberHash cmn.HexBytes randomNumberHash tmbytes.HexBytes
timestamp int64 timestamp int64
amount sdk.Coins amount sdk.Coins
expectedIncome string expectedIncome string
@ -75,8 +78,8 @@ func TestMsgClaimAtomicSwap(t *testing.T) {
tests := []struct { tests := []struct {
description string description string
from sdk.AccAddress from sdk.AccAddress
swapID cmn.HexBytes swapID tmbytes.HexBytes
randomNumber cmn.HexBytes randomNumber tmbytes.HexBytes
expectPass bool expectPass bool
}{ }{
{"normal", binanceAddrs[0], swapID, randomNumberHash, true}, {"normal", binanceAddrs[0], swapID, randomNumberHash, true},
@ -102,7 +105,7 @@ func TestMsgRefundAtomicSwap(t *testing.T) {
tests := []struct { tests := []struct {
description string description string
from sdk.AccAddress from sdk.AccAddress
swapID cmn.HexBytes swapID tmbytes.HexBytes
expectPass bool expectPass bool
}{ }{
{"normal", binanceAddrs[0], swapID, true}, {"normal", binanceAddrs[0], swapID, true},

View File

@ -1,12 +1,18 @@
package types package types
import ( import (
"errors"
"fmt" "fmt"
"strings"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/params"
) )
const (
bech32MainPrefix = "kava"
)
// Parameter keys // Parameter keys
var ( var (
KeyBnbDeputyAddress = []byte("BnbDeputyAddress") KeyBnbDeputyAddress = []byte("BnbDeputyAddress")
@ -59,7 +65,11 @@ func NewParams(bnbDeputyAddress sdk.AccAddress, minBlockLock, maxBlockLock int64
// DefaultParams returns default params for bep3 module // DefaultParams returns default params for bep3 module
func DefaultParams() Params { func DefaultParams() Params {
defaultBnbDeputyAddress, _ := sdk.AccAddressFromBech32("kava1xy7hrjy9r0algz9w3gzm8u6mrpq97kwta747gj") defaultBnbDeputyAddress, err := sdk.AccAddressFromBech32("kava1xy7hrjy9r0algz9w3gzm8u6mrpq97kwta747gj")
if err != nil {
panic(err)
}
return NewParams(defaultBnbDeputyAddress, DefaultMinBlockLock, DefaultMaxBlockLock, DefaultSupportedAssets) return NewParams(defaultBnbDeputyAddress, DefaultMinBlockLock, DefaultMaxBlockLock, DefaultSupportedAssets)
} }
@ -103,44 +113,112 @@ func ParamKeyTable() params.KeyTable {
// nolint // nolint
func (p *Params) ParamSetPairs() params.ParamSetPairs { func (p *Params) ParamSetPairs() params.ParamSetPairs {
return params.ParamSetPairs{ return params.ParamSetPairs{
{Key: KeyBnbDeputyAddress, Value: &p.BnbDeputyAddress}, params.NewParamSetPair(KeyBnbDeputyAddress, &p.BnbDeputyAddress, validateBnbDeputyAddressParam),
{Key: KeyMinBlockLock, Value: &p.MinBlockLock}, params.NewParamSetPair(KeyMinBlockLock, &p.MinBlockLock, validateMinBlockLockParam),
{Key: KeyMaxBlockLock, Value: &p.MaxBlockLock}, params.NewParamSetPair(KeyMaxBlockLock, &p.MaxBlockLock, validateMaxBlockLockParam),
{Key: KeySupportedAssets, Value: &p.SupportedAssets}, params.NewParamSetPair(KeySupportedAssets, &p.SupportedAssets, validateSupportedAssetsParams),
} }
} }
// Validate ensure that params have valid values // Validate ensure that params have valid values
func (p Params) Validate() error { func (p Params) Validate() error {
if p.MinBlockLock < AbsoluteMinimumBlockLock { if err := validateBnbDeputyAddressParam(p.BnbDeputyAddress); err != nil {
return fmt.Errorf(fmt.Sprintf("minimum block lock cannot be less than %d", AbsoluteMinimumBlockLock)) return err
} }
if err := validateMinBlockLockParam(p.MinBlockLock); err != nil {
return err
}
if err := validateMaxBlockLockParam(p.MaxBlockLock); err != nil {
return err
}
if p.MinBlockLock >= p.MaxBlockLock { if p.MinBlockLock >= p.MaxBlockLock {
return fmt.Errorf("maximum block lock must be greater than minimum block lock") return fmt.Errorf("minimum block lock cannot be ≥ maximum block lock, got %d ≥ %d", p.MinBlockLock, p.MaxBlockLock)
} }
if p.MaxBlockLock > AbsoluteMaximumBlockLock {
return fmt.Errorf(fmt.Sprintf("maximum block lock cannot be greater than %d", AbsoluteMaximumBlockLock)) return validateSupportedAssetsParams(p.SupportedAssets)
} }
func validateBnbDeputyAddressParam(i interface{}) error {
addr, ok := i.(sdk.AccAddress)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
if addr.Empty() {
return errors.New("bnb deputy address cannot be empty")
}
if len(addr.Bytes()) != sdk.AddrLen {
return fmt.Errorf("bnb deputy address invalid bytes length got %d, want %d", len(addr.Bytes()), sdk.AddrLen)
}
return nil
}
func validateMinBlockLockParam(i interface{}) error {
minBlockLock, ok := i.(int64)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
if minBlockLock < AbsoluteMinimumBlockLock {
return fmt.Errorf("minimum block lock cannot be less than %d, got %d", AbsoluteMinimumBlockLock, minBlockLock)
}
return nil
}
func validateMaxBlockLockParam(i interface{}) error {
maxBlockLock, ok := i.(int64)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
if maxBlockLock > AbsoluteMaximumBlockLock {
return fmt.Errorf("maximum block lock cannot be greater than %d, got %d", AbsoluteMaximumBlockLock, maxBlockLock)
}
return nil
}
func validateSupportedAssetsParams(i interface{}) error {
assetParams, ok := i.(AssetParams)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
coinIDs := make(map[int]bool) coinIDs := make(map[int]bool)
coinDenoms := make(map[string]bool) coinDenoms := make(map[string]bool)
for _, asset := range p.SupportedAssets { for _, asset := range assetParams {
if len(asset.Denom) == 0 { if strings.TrimSpace(asset.Denom) == "" {
return fmt.Errorf("asset denom cannot be empty") return errors.New("asset denom cannot be empty")
} }
if asset.CoinID < 0 { if asset.CoinID < 0 {
return fmt.Errorf(fmt.Sprintf("asset %s must be a positive integer", asset.Denom)) return fmt.Errorf(fmt.Sprintf("asset %s must be a non negative integer", asset.Denom))
} }
if !asset.Limit.IsPositive() { if !asset.Limit.IsPositive() {
return fmt.Errorf(fmt.Sprintf("asset %s must have a positive supply limit", asset.Denom)) return fmt.Errorf(fmt.Sprintf("asset %s must have a positive supply limit", asset.Denom))
} }
if coinDenoms[asset.Denom] {
_, found := coinDenoms[asset.Denom]
if found {
return fmt.Errorf(fmt.Sprintf("asset %s cannot have duplicate denom", asset.Denom)) return fmt.Errorf(fmt.Sprintf("asset %s cannot have duplicate denom", asset.Denom))
} }
coinDenoms[asset.Denom] = true coinDenoms[asset.Denom] = true
if coinIDs[asset.CoinID] {
_, found = coinIDs[asset.CoinID]
if found {
return fmt.Errorf(fmt.Sprintf("asset %s cannot have duplicate coin id %d", asset.Denom, asset.CoinID)) return fmt.Errorf(fmt.Sprintf("asset %s cannot have duplicate coin id %d", asset.Denom, asset.CoinID))
} }
coinIDs[asset.CoinID] = true coinIDs[asset.CoinID] = true
} }
return nil return nil
} }

View File

@ -1,7 +1,6 @@
package types_test package types_test
import ( import (
"strings"
"testing" "testing"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
@ -204,10 +203,9 @@ func (suite *ParamsTestSuite) TestParamValidation() {
err := params.Validate() err := params.Validate()
if tc.expectPass { if tc.expectPass {
suite.Nil(err) suite.Require().NoError(err, tc.name)
} else { } else {
suite.NotNil(err) suite.Require().Error(err, tc.name)
suite.True(strings.Contains(err.Error(), tc.expectedErr))
} }
} }
} }

View File

@ -1,8 +1,6 @@
package types package types
import ( import tmbytes "github.com/tendermint/tendermint/libs/bytes"
cmn "github.com/tendermint/tendermint/libs/common"
)
const ( const (
// QueryGetAssetSupply command for getting info about an asset's supply // QueryGetAssetSupply command for getting info about an asset's supply
@ -17,11 +15,11 @@ const (
// QueryAssetSupply contains the params for query 'custom/bep3/supply' // QueryAssetSupply contains the params for query 'custom/bep3/supply'
type QueryAssetSupply struct { type QueryAssetSupply struct {
Denom cmn.HexBytes `json:"denom" yaml:"denom"` Denom tmbytes.HexBytes `json:"denom" yaml:"denom"`
} }
// NewQueryAssetSupply creates a new QueryAssetSupply // NewQueryAssetSupply creates a new QueryAssetSupply
func NewQueryAssetSupply(denom cmn.HexBytes) QueryAssetSupply { func NewQueryAssetSupply(denom tmbytes.HexBytes) QueryAssetSupply {
return QueryAssetSupply{ return QueryAssetSupply{
Denom: denom, Denom: denom,
} }
@ -29,11 +27,11 @@ func NewQueryAssetSupply(denom cmn.HexBytes) QueryAssetSupply {
// QueryAtomicSwapByID contains the params for query 'custom/bep3/swap' // QueryAtomicSwapByID contains the params for query 'custom/bep3/swap'
type QueryAtomicSwapByID struct { type QueryAtomicSwapByID struct {
SwapID cmn.HexBytes `json:"swap_id" yaml:"swap_id"` SwapID tmbytes.HexBytes `json:"swap_id" yaml:"swap_id"`
} }
// NewQueryAtomicSwapByID creates a new QueryAtomicSwapByID // NewQueryAtomicSwapByID creates a new QueryAtomicSwapByID
func NewQueryAtomicSwapByID(swapBytes cmn.HexBytes) QueryAtomicSwapByID { func NewQueryAtomicSwapByID(swapBytes tmbytes.HexBytes) QueryAtomicSwapByID {
return QueryAtomicSwapByID{ return QueryAtomicSwapByID{
SwapID: swapBytes, SwapID: swapBytes,
} }

View File

@ -5,13 +5,14 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
tmbytes "github.com/tendermint/tendermint/libs/bytes"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
cmn "github.com/tendermint/tendermint/libs/common"
) )
// Swap is an interface for handling common actions // Swap is an interface for handling common actions
type Swap interface { type Swap interface {
GetSwapID() cmn.HexBytes GetSwapID() tmbytes.HexBytes
GetModuleAccountCoins() sdk.Coins GetModuleAccountCoins() sdk.Coins
Validate() error Validate() error
} }
@ -20,7 +21,7 @@ type Swap interface {
type AtomicSwap struct { type AtomicSwap struct {
Swap `json:"swap" yaml:"swap"` Swap `json:"swap" yaml:"swap"`
Amount sdk.Coins `json:"amount" yaml:"amount"` Amount sdk.Coins `json:"amount" yaml:"amount"`
RandomNumberHash cmn.HexBytes `json:"random_number_hash" yaml:"random_number_hash"` RandomNumberHash tmbytes.HexBytes `json:"random_number_hash" yaml:"random_number_hash"`
ExpireHeight int64 `json:"expire_height" yaml:"expire_height"` ExpireHeight int64 `json:"expire_height" yaml:"expire_height"`
Timestamp int64 `json:"timestamp" yaml:"timestamp"` Timestamp int64 `json:"timestamp" yaml:"timestamp"`
Sender sdk.AccAddress `json:"sender" yaml:"sender"` Sender sdk.AccAddress `json:"sender" yaml:"sender"`
@ -34,7 +35,7 @@ type AtomicSwap struct {
} }
// NewAtomicSwap returns a new AtomicSwap // NewAtomicSwap returns a new AtomicSwap
func NewAtomicSwap(amount sdk.Coins, randomNumberHash cmn.HexBytes, expireHeight, timestamp int64, sender, func NewAtomicSwap(amount sdk.Coins, randomNumberHash tmbytes.HexBytes, expireHeight, timestamp int64, sender,
recipient sdk.AccAddress, senderOtherChain string, recipientOtherChain string, closedBlock int64, recipient sdk.AccAddress, senderOtherChain string, recipientOtherChain string, closedBlock int64,
status SwapStatus, crossChain bool, direction SwapDirection) AtomicSwap { status SwapStatus, crossChain bool, direction SwapDirection) AtomicSwap {
return AtomicSwap{ return AtomicSwap{
@ -54,7 +55,7 @@ func NewAtomicSwap(amount sdk.Coins, randomNumberHash cmn.HexBytes, expireHeight
} }
// GetSwapID calculates the ID of an atomic swap // GetSwapID calculates the ID of an atomic swap
func (a AtomicSwap) GetSwapID() cmn.HexBytes { func (a AtomicSwap) GetSwapID() tmbytes.HexBytes {
return CalculateSwapID(a.RandomNumberHash, a.Sender, a.SenderOtherChain) return CalculateSwapID(a.RandomNumberHash, a.Sender, a.SenderOtherChain)
} }

View File

@ -3,18 +3,21 @@ package types_test
import ( import (
"testing" "testing"
"github.com/stretchr/testify/suite"
tmbytes "github.com/tendermint/tendermint/libs/bytes"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/app" "github.com/kava-labs/kava/app"
"github.com/kava-labs/kava/x/bep3/types" "github.com/kava-labs/kava/x/bep3/types"
"github.com/stretchr/testify/suite"
cmn "github.com/tendermint/tendermint/libs/common"
) )
type AtomicSwapTestSuite struct { type AtomicSwapTestSuite struct {
suite.Suite suite.Suite
addrs []sdk.AccAddress addrs []sdk.AccAddress
timestamps []int64 timestamps []int64
randomNumberHashes []cmn.HexBytes randomNumberHashes []tmbytes.HexBytes
} }
func (suite *AtomicSwapTestSuite) SetupTest() { func (suite *AtomicSwapTestSuite) SetupTest() {
@ -25,7 +28,7 @@ func (suite *AtomicSwapTestSuite) SetupTest() {
// Generate 10 timestamps and random number hashes // Generate 10 timestamps and random number hashes
var timestamps []int64 var timestamps []int64
var randomNumberHashes []cmn.HexBytes var randomNumberHashes []tmbytes.HexBytes
for i := 0; i < 10; i++ { for i := 0; i < 10; i++ {
timestamp := ts(i) timestamp := ts(i)
randomNumber, _ := types.GenerateSecureRandomNumber() randomNumber, _ := types.GenerateSecureRandomNumber()
@ -43,7 +46,7 @@ func (suite *AtomicSwapTestSuite) SetupTest() {
func (suite *AtomicSwapTestSuite) TestNewAtomicSwap() { func (suite *AtomicSwapTestSuite) TestNewAtomicSwap() {
type args struct { type args struct {
amount sdk.Coins amount sdk.Coins
randomNumberHash cmn.HexBytes randomNumberHash tmbytes.HexBytes
expireHeight int64 expireHeight int64
timestamp int64 timestamp int64
sender sdk.AccAddress sender sdk.AccAddress
@ -127,7 +130,7 @@ func (suite *AtomicSwapTestSuite) TestNewAtomicSwap() {
suite.Nil(swap.Validate()) suite.Nil(swap.Validate())
suite.Equal(tc.args.amount, swap.GetModuleAccountCoins()) suite.Equal(tc.args.amount, swap.GetModuleAccountCoins())
expectedSwapID := types.CalculateSwapID(tc.args.randomNumberHash, tc.args.sender, tc.args.senderOtherChain) expectedSwapID := types.CalculateSwapID(tc.args.randomNumberHash, tc.args.sender, tc.args.senderOtherChain)
suite.Equal(cmn.HexBytes(expectedSwapID), swap.GetSwapID()) suite.Equal(tmbytes.HexBytes(expectedSwapID), swap.GetSwapID())
} else { } else {
suite.Error(swap.Validate()) suite.Error(swap.Validate())
} }

View File

@ -1,8 +1,3 @@
// nolint
// autogenerated code using github.com/rigelrozanski/multitool
// aliases generated for the following subdirectories:
// ALIASGEN: github.com/kava-labs/kava/x/cdp/keeper
// ALIASGEN: github.com/kava-labs/kava/x/cdp/types
package cdp package cdp
import ( import (
@ -10,26 +5,14 @@ import (
"github.com/kava-labs/kava/x/cdp/types" "github.com/kava-labs/kava/x/cdp/types"
) )
// nolint
// autogenerated code using github.com/rigelrozanski/multitool
// aliases generated for the following subdirectories:
// ALIASGEN: github.com/kava-labs/kava/x/cdp/keeper
// ALIASGEN: github.com/kava-labs/kava/x/cdp/types
const ( const (
BaseDigitFactor = keeper.BaseDigitFactor BaseDigitFactor = keeper.BaseDigitFactor
DefaultCodespace = types.DefaultCodespace
CodeCdpAlreadyExists = types.CodeCdpAlreadyExists
CodeCollateralLengthInvalid = types.CodeCollateralLengthInvalid
CodeCollateralNotSupported = types.CodeCollateralNotSupported
CodeDebtNotSupported = types.CodeDebtNotSupported
CodeExceedsDebtLimit = types.CodeExceedsDebtLimit
CodeInvalidCollateralRatio = types.CodeInvalidCollateralRatio
CodeCdpNotFound = types.CodeCdpNotFound
CodeDepositNotFound = types.CodeDepositNotFound
CodeInvalidDepositDenom = types.CodeInvalidDepositDenom
CodeInvalidPaymentDenom = types.CodeInvalidPaymentDenom
CodeDepositNotAvailable = types.CodeDepositNotAvailable
CodeInvalidCollateralDenom = types.CodeInvalidCollateralDenom
CodeInvalidWithdrawAmount = types.CodeInvalidWithdrawAmount
CodeCdpNotAvailable = types.CodeCdpNotAvailable
CodeBelowDebtFloor = types.CodeBelowDebtFloor
CodePaymentExceedsDebt = types.CodePaymentExceedsDebt
CodeLoadingAugmentedCDP = types.CodeLoadingAugmentedCDP
EventTypeCreateCdp = types.EventTypeCreateCdp EventTypeCreateCdp = types.EventTypeCreateCdp
EventTypeCdpDeposit = types.EventTypeCdpDeposit EventTypeCdpDeposit = types.EventTypeCdpDeposit
EventTypeCdpDraw = types.EventTypeCdpDraw EventTypeCdpDraw = types.EventTypeCdpDraw
@ -75,14 +58,13 @@ var (
ErrInvalidCollateralRatio = types.ErrInvalidCollateralRatio ErrInvalidCollateralRatio = types.ErrInvalidCollateralRatio
ErrCdpNotFound = types.ErrCdpNotFound ErrCdpNotFound = types.ErrCdpNotFound
ErrDepositNotFound = types.ErrDepositNotFound ErrDepositNotFound = types.ErrDepositNotFound
ErrInvalidDepositDenom = types.ErrInvalidDepositDenom ErrInvalidDeposit = types.ErrInvalidDeposit
ErrInvalidPaymentDenom = types.ErrInvalidPaymentDenom ErrInvalidPayment = types.ErrInvalidPayment
ErrDepositNotAvailable = types.ErrDepositNotAvailable ErrDepositNotAvailable = types.ErrDepositNotAvailable
ErrInvalidCollateralDenom = types.ErrInvalidCollateralDenom ErrInvalidCollateral = types.ErrInvalidCollateral
ErrInvalidWithdrawAmount = types.ErrInvalidWithdrawAmount ErrInvalidWithdrawAmount = types.ErrInvalidWithdrawAmount
ErrCdpNotAvailable = types.ErrCdpNotAvailable ErrCdpNotAvailable = types.ErrCdpNotAvailable
ErrBelowDebtFloor = types.ErrBelowDebtFloor ErrBelowDebtFloor = types.ErrBelowDebtFloor
ErrPaymentExceedsDebt = types.ErrPaymentExceedsDebt
ErrLoadingAugmentedCDP = types.ErrLoadingAugmentedCDP ErrLoadingAugmentedCDP = types.ErrLoadingAugmentedCDP
NewGenesisState = types.NewGenesisState NewGenesisState = types.NewGenesisState
DefaultGenesisState = types.DefaultGenesisState DefaultGenesisState = types.DefaultGenesisState

View File

@ -6,8 +6,8 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/version"
@ -23,7 +23,7 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
Short: "Querying commands for the cdp module", Short: "Querying commands for the cdp module",
} }
cdpQueryCmd.AddCommand(client.GetCommands( cdpQueryCmd.AddCommand(flags.GetCommands(
QueryCdpCmd(queryRoute, cdc), QueryCdpCmd(queryRoute, cdc),
QueryCdpsByDenomCmd(queryRoute, cdc), QueryCdpsByDenomCmd(queryRoute, cdc),
QueryCdpsByDenomAndRatioCmd(queryRoute, cdc), QueryCdpsByDenomAndRatioCmd(queryRoute, cdc),
@ -131,9 +131,9 @@ $ %s query %s cdps-by-ratio uatom 1.5
cliCtx := context.NewCLIContext().WithCodec(cdc) cliCtx := context.NewCLIContext().WithCodec(cdc)
// Prepare params for querier // Prepare params for querier
ratio, errSdk := sdk.NewDecFromStr(args[1]) ratio, err := sdk.NewDecFromStr(args[1])
if errSdk != nil { if err != nil {
return fmt.Errorf(errSdk.Error()) return err
} }
bz, err := cdc.MarshalJSON(types.QueryCdpsByRatioParams{ bz, err := cdc.MarshalJSON(types.QueryCdpsByRatioParams{
CollateralDenom: args[0], CollateralDenom: args[0],

View File

@ -1,13 +1,14 @@
package cli package cli
import ( import (
"bufio"
"fmt" "fmt"
"strings" "strings"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context" "github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/version"
@ -24,7 +25,7 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command {
Short: "cdp transactions subcommands", Short: "cdp transactions subcommands",
} }
cdpTxCmd.AddCommand(client.PostCommands( cdpTxCmd.AddCommand(flags.PostCommands(
GetCmdCreateCdp(cdc), GetCmdCreateCdp(cdc),
GetCmdDeposit(cdc), GetCmdDeposit(cdc),
GetCmdWithdraw(cdc), GetCmdWithdraw(cdc),
@ -48,8 +49,9 @@ $ %s tx %s create 10000000uatom 1000usdx --from myKeyName
`, version.ClientName, types.ModuleName)), `, version.ClientName, types.ModuleName)),
Args: cobra.ExactArgs(2), Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
cliCtx := context.NewCLIContext().WithCodec(cdc) cliCtx := context.NewCLIContext().WithCodec(cdc)
txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
collateral, err := sdk.ParseCoins(args[0]) collateral, err := sdk.ParseCoins(args[0])
if err != nil { if err != nil {
@ -82,8 +84,9 @@ $ %s tx %s deposit kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw 10000000uatom --f
`, version.ClientName, types.ModuleName)), `, version.ClientName, types.ModuleName)),
Args: cobra.ExactArgs(2), Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
cliCtx := context.NewCLIContext().WithCodec(cdc) cliCtx := context.NewCLIContext().WithCodec(cdc)
txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
collateral, err := sdk.ParseCoins(args[1]) collateral, err := sdk.ParseCoins(args[1])
if err != nil { if err != nil {
@ -116,8 +119,9 @@ $ %s tx %s withdraw kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw 10000000uatom --
`, version.ClientName, types.ModuleName)), `, version.ClientName, types.ModuleName)),
Args: cobra.ExactArgs(2), Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
cliCtx := context.NewCLIContext().WithCodec(cdc) cliCtx := context.NewCLIContext().WithCodec(cdc)
txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
collateral, err := sdk.ParseCoins(args[1]) collateral, err := sdk.ParseCoins(args[1])
if err != nil { if err != nil {
@ -150,8 +154,9 @@ $ %s tx %s draw uatom 1000usdx --from myKeyName
`, version.ClientName, types.ModuleName)), `, version.ClientName, types.ModuleName)),
Args: cobra.ExactArgs(2), Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
cliCtx := context.NewCLIContext().WithCodec(cdc) cliCtx := context.NewCLIContext().WithCodec(cdc)
txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
debt, err := sdk.ParseCoins(args[1]) debt, err := sdk.ParseCoins(args[1])
if err != nil { if err != nil {
@ -180,8 +185,9 @@ $ %s tx %s repay uatom 1000usdx --from myKeyName
`, version.ClientName, types.ModuleName)), `, version.ClientName, types.ModuleName)),
Args: cobra.ExactArgs(2), Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
inBuf := bufio.NewReader(cmd.InOrStdin())
cliCtx := context.NewCLIContext().WithCodec(cdc) cliCtx := context.NewCLIContext().WithCodec(cdc)
txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc)) txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
payment, err := sdk.ParseCoins(args[1]) payment, err := sdk.ParseCoins(args[1])
if err != nil { if err != nil {

View File

@ -58,7 +58,7 @@ func InitGenesis(ctx sdk.Context, k Keeper, pk PricefeedKeeper, sk SupplyKeeper,
} }
k.SetCDP(ctx, cdp) k.SetCDP(ctx, cdp)
k.IndexCdpByOwner(ctx, cdp) k.IndexCdpByOwner(ctx, cdp)
ratio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees)) ratio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
k.IndexCdpByCollateralRatio(ctx, cdp.Collateral[0].Denom, cdp.ID, ratio) k.IndexCdpByCollateralRatio(ctx, cdp.Collateral[0].Denom, cdp.ID, ratio)
k.IncrementTotalPrincipal(ctx, cdp.Collateral[0].Denom, cdp.Principal) k.IncrementTotalPrincipal(ctx, cdp.Collateral[0].Denom, cdp.Principal)
} }

View File

@ -1,14 +1,13 @@
package cdp package cdp
import ( import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
) )
// NewHandler creates an sdk.Handler for cdp messages // NewHandler creates an sdk.Handler for cdp messages
func NewHandler(k Keeper) sdk.Handler { func NewHandler(k Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) {
switch msg := msg.(type) { switch msg := msg.(type) {
case MsgCreateCDP: case MsgCreateCDP:
return handleMsgCreateCDP(ctx, k, msg) return handleMsgCreateCDP(ctx, k, msg)
@ -21,16 +20,15 @@ func NewHandler(k Keeper) sdk.Handler {
case MsgRepayDebt: case MsgRepayDebt:
return handleMsgRepayDebt(ctx, k, msg) return handleMsgRepayDebt(ctx, k, msg)
default: default:
errMsg := fmt.Sprintf("unrecognized cdp msg type: %T", msg) return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg)
return sdk.ErrUnknownRequest(errMsg).Result()
} }
} }
} }
func handleMsgCreateCDP(ctx sdk.Context, k Keeper, msg MsgCreateCDP) sdk.Result { func handleMsgCreateCDP(ctx sdk.Context, k Keeper, msg MsgCreateCDP) (*sdk.Result, error) {
err := k.AddCdp(ctx, msg.Sender, msg.Collateral, msg.Principal) err := k.AddCdp(ctx, msg.Sender, msg.Collateral, msg.Principal)
if err != nil { if err != nil {
return err.Result() return nil, err
} }
ctx.EventManager().EmitEvent( ctx.EventManager().EmitEvent(
@ -42,16 +40,16 @@ func handleMsgCreateCDP(ctx sdk.Context, k Keeper, msg MsgCreateCDP) sdk.Result
) )
id, _ := k.GetCdpID(ctx, msg.Sender, msg.Collateral[0].Denom) id, _ := k.GetCdpID(ctx, msg.Sender, msg.Collateral[0].Denom)
return sdk.Result{ return &sdk.Result{
Data: GetCdpIDBytes(id), Data: GetCdpIDBytes(id),
Events: ctx.EventManager().Events(), Events: ctx.EventManager().Events(),
} }, nil
} }
func handleMsgDeposit(ctx sdk.Context, k Keeper, msg MsgDeposit) sdk.Result { func handleMsgDeposit(ctx sdk.Context, k Keeper, msg MsgDeposit) (*sdk.Result, error) {
err := k.DepositCollateral(ctx, msg.Owner, msg.Depositor, msg.Collateral) err := k.DepositCollateral(ctx, msg.Owner, msg.Depositor, msg.Collateral)
if err != nil { if err != nil {
return err.Result() return nil, err
} }
ctx.EventManager().EmitEvent( ctx.EventManager().EmitEvent(
@ -61,13 +59,13 @@ func handleMsgDeposit(ctx sdk.Context, k Keeper, msg MsgDeposit) sdk.Result {
sdk.NewAttribute(sdk.AttributeKeySender, msg.Depositor.String()), sdk.NewAttribute(sdk.AttributeKeySender, msg.Depositor.String()),
), ),
) )
return sdk.Result{Events: ctx.EventManager().Events()} return &sdk.Result{Events: ctx.EventManager().Events()}, nil
} }
func handleMsgWithdraw(ctx sdk.Context, k Keeper, msg MsgWithdraw) sdk.Result { func handleMsgWithdraw(ctx sdk.Context, k Keeper, msg MsgWithdraw) (*sdk.Result, error) {
err := k.WithdrawCollateral(ctx, msg.Owner, msg.Depositor, msg.Collateral) err := k.WithdrawCollateral(ctx, msg.Owner, msg.Depositor, msg.Collateral)
if err != nil { if err != nil {
return err.Result() return nil, err
} }
ctx.EventManager().EmitEvent( ctx.EventManager().EmitEvent(
@ -77,13 +75,13 @@ func handleMsgWithdraw(ctx sdk.Context, k Keeper, msg MsgWithdraw) sdk.Result {
sdk.NewAttribute(sdk.AttributeKeySender, msg.Depositor.String()), sdk.NewAttribute(sdk.AttributeKeySender, msg.Depositor.String()),
), ),
) )
return sdk.Result{Events: ctx.EventManager().Events()} return &sdk.Result{Events: ctx.EventManager().Events()}, nil
} }
func handleMsgDrawDebt(ctx sdk.Context, k Keeper, msg MsgDrawDebt) sdk.Result { func handleMsgDrawDebt(ctx sdk.Context, k Keeper, msg MsgDrawDebt) (*sdk.Result, error) {
err := k.AddPrincipal(ctx, msg.Sender, msg.CdpDenom, msg.Principal) err := k.AddPrincipal(ctx, msg.Sender, msg.CdpDenom, msg.Principal)
if err != nil { if err != nil {
return err.Result() return nil, err
} }
ctx.EventManager().EmitEvent( ctx.EventManager().EmitEvent(
@ -93,13 +91,13 @@ func handleMsgDrawDebt(ctx sdk.Context, k Keeper, msg MsgDrawDebt) sdk.Result {
sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender.String()), sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender.String()),
), ),
) )
return sdk.Result{Events: ctx.EventManager().Events()} return &sdk.Result{Events: ctx.EventManager().Events()}, nil
} }
func handleMsgRepayDebt(ctx sdk.Context, k Keeper, msg MsgRepayDebt) sdk.Result { func handleMsgRepayDebt(ctx sdk.Context, k Keeper, msg MsgRepayDebt) (*sdk.Result, error) {
err := k.RepayPrincipal(ctx, msg.Sender, msg.CdpDenom, msg.Payment) err := k.RepayPrincipal(ctx, msg.Sender, msg.CdpDenom, msg.Payment)
if err != nil { if err != nil {
return err.Result() return nil, err
} }
ctx.EventManager().EmitEvent( ctx.EventManager().EmitEvent(
@ -109,5 +107,5 @@ func handleMsgRepayDebt(ctx sdk.Context, k Keeper, msg MsgRepayDebt) sdk.Result
sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender.String()), sdk.NewAttribute(sdk.AttributeKeySender, msg.Sender.String()),
), ),
) )
return sdk.Result{Events: ctx.EventManager().Events()} return &sdk.Result{Events: ctx.EventManager().Events()}, nil
} }

View File

@ -1,7 +1,6 @@
package cdp_test package cdp_test
import ( import (
"strings"
"testing" "testing"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
@ -47,16 +46,16 @@ func (suite *HandlerTestSuite) TestMsgCreateCdp() {
cs(c("xrp", 200000000)), cs(c("xrp", 200000000)),
cs(c("usdx", 10000000)), cs(c("usdx", 10000000)),
) )
res := suite.handler(suite.ctx, msg) res, err := suite.handler(suite.ctx, msg)
suite.True(res.IsOK()) suite.Require().NoError(err)
suite.Equal(cdp.GetCdpIDBytes(uint64(1)), res.Data) suite.Require().Equal(cdp.GetCdpIDBytes(uint64(1)), res.Data)
} }
func (suite *HandlerTestSuite) TestInvalidMsg() { func (suite *HandlerTestSuite) TestInvalidMsg() {
res := suite.handler(suite.ctx, sdk.NewTestMsg()) res, err := suite.handler(suite.ctx, sdk.NewTestMsg())
suite.False(res.IsOK()) suite.Require().Error(err)
suite.True(strings.Contains(res.Log, "unrecognized cdp msg type")) suite.Require().Nil(res)
} }
func TestHandlerTestSuite(t *testing.T) { func TestHandlerTestSuite(t *testing.T) {

View File

@ -43,7 +43,7 @@ func (pd partialDeposits) SumDebt() (sum sdk.Int) {
} }
// AuctionCollateral creates auctions from the input deposits which attempt to raise the corresponding amount of debt // AuctionCollateral creates auctions from the input deposits which attempt to raise the corresponding amount of debt
func (k Keeper) AuctionCollateral(ctx sdk.Context, deposits types.Deposits, debt sdk.Int, bidDenom string) sdk.Error { func (k Keeper) AuctionCollateral(ctx sdk.Context, deposits types.Deposits, debt sdk.Int, bidDenom string) error {
auctionSize := k.getAuctionSize(ctx, deposits[0].Amount[0].Denom) auctionSize := k.getAuctionSize(ctx, deposits[0].Amount[0].Denom)
partialAuctionDeposits := partialDeposits{} partialAuctionDeposits := partialDeposits{}
totalCollateral := deposits.SumCollateral() totalCollateral := deposits.SumCollateral()
@ -110,7 +110,7 @@ func (k Keeper) AuctionCollateral(ctx sdk.Context, deposits types.Deposits, debt
} }
// CreateAuctionsFromDeposit creates auctions from the input deposit until there is less than auctionSize left on the deposit // CreateAuctionsFromDeposit creates auctions from the input deposit until there is less than auctionSize left on the deposit
func (k Keeper) CreateAuctionsFromDeposit(ctx sdk.Context, dep types.Deposit, debt sdk.Int, totalCollateral sdk.Int, auctionSize sdk.Int, principalDenom string) (debtChange sdk.Int, collateralChange sdk.Int, err sdk.Error) { func (k Keeper) CreateAuctionsFromDeposit(ctx sdk.Context, dep types.Deposit, debt sdk.Int, totalCollateral sdk.Int, auctionSize sdk.Int, principalDenom string) (debtChange sdk.Int, collateralChange sdk.Int, err error) {
debtChange = sdk.ZeroInt() debtChange = sdk.ZeroInt()
collateralChange = sdk.ZeroInt() collateralChange = sdk.ZeroInt()
depositAmount := dep.Amount[0].Amount depositAmount := dep.Amount[0].Amount
@ -138,7 +138,7 @@ func (k Keeper) CreateAuctionsFromDeposit(ctx sdk.Context, dep types.Deposit, de
} }
// CreateAuctionFromPartialDeposits creates an auction from the input partial deposits // CreateAuctionFromPartialDeposits creates an auction from the input partial deposits
func (k Keeper) CreateAuctionFromPartialDeposits(ctx sdk.Context, partialDeps partialDeposits, debt sdk.Int, collateral sdk.Int, auctionSize sdk.Int, bidDenom string) (debtChange, collateralChange sdk.Int, err sdk.Error) { func (k Keeper) CreateAuctionFromPartialDeposits(ctx sdk.Context, partialDeps partialDeposits, debt sdk.Int, collateral sdk.Int, auctionSize sdk.Int, bidDenom string) (debtChange, collateralChange sdk.Int, err error) {
returnAddrs := []sdk.AccAddress{} returnAddrs := []sdk.AccAddress{}
returnWeights := []sdk.Int{} returnWeights := []sdk.Int{}
@ -159,7 +159,7 @@ func (k Keeper) CreateAuctionFromPartialDeposits(ctx sdk.Context, partialDeps pa
// NetSurplusAndDebt burns surplus and debt coins equal to the minimum of surplus and debt balances held by the liquidator module account // NetSurplusAndDebt burns surplus and debt coins equal to the minimum of surplus and debt balances held by the liquidator module account
// for example, if there is 1000 debt and 100 surplus, 100 surplus and 100 debt are burned, netting to 900 debt // for example, if there is 1000 debt and 100 surplus, 100 surplus and 100 debt are burned, netting to 900 debt
func (k Keeper) NetSurplusAndDebt(ctx sdk.Context) sdk.Error { func (k Keeper) NetSurplusAndDebt(ctx sdk.Context) error {
totalSurplus := k.GetTotalSurplus(ctx, types.LiquidatorMacc) totalSurplus := k.GetTotalSurplus(ctx, types.LiquidatorMacc)
debt := k.GetTotalDebt(ctx, types.LiquidatorMacc) debt := k.GetTotalDebt(ctx, types.LiquidatorMacc)
netAmount := sdk.MinInt(totalSurplus, debt) netAmount := sdk.MinInt(totalSurplus, debt)
@ -210,7 +210,7 @@ func (k Keeper) GetTotalDebt(ctx sdk.Context, accountName string) sdk.Int {
} }
// RunSurplusAndDebtAuctions nets the surplus and debt balances and then creates surplus or debt auctions if the remaining balance is above the auction threshold parameter // RunSurplusAndDebtAuctions nets the surplus and debt balances and then creates surplus or debt auctions if the remaining balance is above the auction threshold parameter
func (k Keeper) RunSurplusAndDebtAuctions(ctx sdk.Context) sdk.Error { func (k Keeper) RunSurplusAndDebtAuctions(ctx sdk.Context) error {
k.NetSurplusAndDebt(ctx) k.NetSurplusAndDebt(ctx)
remainingDebt := k.GetTotalDebt(ctx, types.LiquidatorMacc) remainingDebt := k.GetTotalDebt(ctx, types.LiquidatorMacc)
params := k.GetParams(ctx) params := k.GetParams(ctx)

View File

@ -6,6 +6,7 @@ import (
"github.com/cosmos/cosmos-sdk/store/prefix" "github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/kava-labs/kava/x/cdp/types" "github.com/kava-labs/kava/x/cdp/types"
) )
@ -13,7 +14,7 @@ import (
const BaseDigitFactor = 1000000000000000000 const BaseDigitFactor = 1000000000000000000
// AddCdp adds a cdp for a specific owner and collateral type // AddCdp adds a cdp for a specific owner and collateral type
func (k Keeper) AddCdp(ctx sdk.Context, owner sdk.AccAddress, collateral sdk.Coins, principal sdk.Coins) sdk.Error { func (k Keeper) AddCdp(ctx sdk.Context, owner sdk.AccAddress, collateral sdk.Coins, principal sdk.Coins) error {
// validation // validation
err := k.ValidateCollateral(ctx, collateral) err := k.ValidateCollateral(ctx, collateral)
if err != nil { if err != nil {
@ -21,7 +22,7 @@ func (k Keeper) AddCdp(ctx sdk.Context, owner sdk.AccAddress, collateral sdk.Coi
} }
_, found := k.GetCdpByOwnerAndDenom(ctx, owner, collateral[0].Denom) _, found := k.GetCdpByOwnerAndDenom(ctx, owner, collateral[0].Denom)
if found { if found {
return types.ErrCdpAlreadyExists(k.codespace, owner, collateral[0].Denom) return sdkerrors.Wrapf(types.ErrCdpAlreadyExists, "owner %s, denom %s", owner, collateral[0].Denom)
} }
err = k.ValidatePrincipalAdd(ctx, principal) err = k.ValidatePrincipalAdd(ctx, principal)
if err != nil { if err != nil {
@ -103,10 +104,10 @@ func (k Keeper) SetCdpAndCollateralRatioIndex(ctx sdk.Context, cdp types.CDP, ra
} }
// MintDebtCoins mints debt coins in the cdp module account // MintDebtCoins mints debt coins in the cdp module account
func (k Keeper) MintDebtCoins(ctx sdk.Context, moduleAccount string, denom string, principalCoins sdk.Coins) sdk.Error { func (k Keeper) MintDebtCoins(ctx sdk.Context, moduleAccount string, denom string, principalCoins sdk.Coins) error {
coinsToMint := sdk.NewCoins() coinsToMint := sdk.NewCoins()
for _, sc := range principalCoins { for _, sc := range principalCoins {
coinsToMint = coinsToMint.Add(sdk.NewCoins(sdk.NewCoin(denom, sc.Amount))) coinsToMint = coinsToMint.Add(sdk.NewCoin(denom, sc.Amount))
} }
err := k.supplyKeeper.MintCoins(ctx, moduleAccount, coinsToMint) err := k.supplyKeeper.MintCoins(ctx, moduleAccount, coinsToMint)
if err != nil { if err != nil {
@ -116,10 +117,10 @@ func (k Keeper) MintDebtCoins(ctx sdk.Context, moduleAccount string, denom strin
} }
// BurnDebtCoins burns debt coins from the cdp module account // BurnDebtCoins burns debt coins from the cdp module account
func (k Keeper) BurnDebtCoins(ctx sdk.Context, moduleAccount string, denom string, paymentCoins sdk.Coins) sdk.Error { func (k Keeper) BurnDebtCoins(ctx sdk.Context, moduleAccount string, denom string, paymentCoins sdk.Coins) error {
coinsToBurn := sdk.NewCoins() coinsToBurn := sdk.NewCoins()
for _, pc := range paymentCoins { for _, pc := range paymentCoins {
coinsToBurn = coinsToBurn.Add(sdk.NewCoins(sdk.NewCoin(denom, pc.Amount))) coinsToBurn = coinsToBurn.Add(sdk.NewCoin(denom, pc.Amount))
} }
err := k.supplyKeeper.BurnCoins(ctx, moduleAccount, coinsToBurn) err := k.supplyKeeper.BurnCoins(ctx, moduleAccount, coinsToBurn)
if err != nil { if err != nil {
@ -340,64 +341,65 @@ func (k Keeper) SetGovDenom(ctx sdk.Context, denom string) {
} }
// ValidateCollateral validates that a collateral is valid for use in cdps // ValidateCollateral validates that a collateral is valid for use in cdps
func (k Keeper) ValidateCollateral(ctx sdk.Context, collateral sdk.Coins) sdk.Error { func (k Keeper) ValidateCollateral(ctx sdk.Context, collateral sdk.Coins) error {
if len(collateral) != 1 { if len(collateral) != 1 {
return types.ErrInvalidCollateralLength(k.codespace, len(collateral)) return sdkerrors.Wrapf(types.ErrInvalidCollateralLength, "%d", len(collateral))
} }
_, found := k.GetCollateral(ctx, collateral[0].Denom) _, found := k.GetCollateral(ctx, collateral[0].Denom)
if !found { if !found {
return types.ErrCollateralNotSupported(k.codespace, collateral[0].Denom) return sdkerrors.Wrap(types.ErrCollateralNotSupported, collateral[0].Denom)
} }
return nil return nil
} }
// ValidatePrincipalAdd validates that an asset is valid for use as debt when creating a new cdp // ValidatePrincipalAdd validates that an asset is valid for use as debt when creating a new cdp
func (k Keeper) ValidatePrincipalAdd(ctx sdk.Context, principal sdk.Coins) sdk.Error { func (k Keeper) ValidatePrincipalAdd(ctx sdk.Context, principal sdk.Coins) error {
for _, dc := range principal { for _, dc := range principal {
dp, found := k.GetDebtParam(ctx, dc.Denom) dp, found := k.GetDebtParam(ctx, dc.Denom)
if !found { if !found {
return types.ErrDebtNotSupported(k.codespace, dc.Denom) return sdkerrors.Wrap(types.ErrDebtNotSupported, dc.Denom)
} }
if dc.Amount.LT(dp.DebtFloor) { if dc.Amount.LT(dp.DebtFloor) {
return types.ErrBelowDebtFloor(k.codespace, sdk.NewCoins(dc), dp.DebtFloor) return sdkerrors.Wrapf(types.ErrBelowDebtFloor, "proposed %s < minimum %s", dc, dp.DebtFloor)
} }
} }
return nil return nil
} }
// ValidatePrincipalDraw validates that an asset is valid for use as debt when drawing debt off an existing cdp // ValidatePrincipalDraw validates that an asset is valid for use as debt when drawing debt off an existing cdp
func (k Keeper) ValidatePrincipalDraw(ctx sdk.Context, principal sdk.Coins) sdk.Error { func (k Keeper) ValidatePrincipalDraw(ctx sdk.Context, principal sdk.Coins) error {
for _, dc := range principal { for _, dc := range principal {
_, found := k.GetDebtParam(ctx, dc.Denom) _, found := k.GetDebtParam(ctx, dc.Denom)
if !found { if !found {
return types.ErrDebtNotSupported(k.codespace, dc.Denom) return sdkerrors.Wrap(types.ErrDebtNotSupported, dc.Denom)
} }
} }
return nil return nil
} }
// ValidateDebtLimit validates that the input debt amount does not exceed the global debt limit or the debt limit for that collateral // ValidateDebtLimit validates that the input debt amount does not exceed the global debt limit or the debt limit for that collateral
func (k Keeper) ValidateDebtLimit(ctx sdk.Context, collateralDenom string, principal sdk.Coins) sdk.Error { func (k Keeper) ValidateDebtLimit(ctx sdk.Context, collateralDenom string, principal sdk.Coins) error {
cp, found := k.GetCollateral(ctx, collateralDenom) cp, found := k.GetCollateral(ctx, collateralDenom)
if !found { if !found {
return types.ErrCollateralNotSupported(k.codespace, collateralDenom) return sdkerrors.Wrap(types.ErrCollateralNotSupported, collateralDenom)
} }
for _, dc := range principal { for _, dc := range principal {
totalPrincipal := k.GetTotalPrincipal(ctx, collateralDenom, dc.Denom).Add(dc.Amount) totalPrincipal := k.GetTotalPrincipal(ctx, collateralDenom, dc.Denom).Add(dc.Amount)
collateralLimit := cp.DebtLimit.AmountOf(dc.Denom) collateralLimit := cp.DebtLimit.AmountOf(dc.Denom)
if totalPrincipal.GT(collateralLimit) { if totalPrincipal.GT(collateralLimit) {
return types.ErrExceedsDebtLimit(k.codespace, sdk.NewCoins(sdk.NewCoin(dc.Denom, totalPrincipal)), sdk.NewCoins(sdk.NewCoin(dc.Denom, collateralLimit))) return sdkerrors.Wrapf(types.ErrExceedsDebtLimit, "debt increase %s > collateral debt limit %s", sdk.NewCoins(sdk.NewCoin(dc.Denom, totalPrincipal)), sdk.NewCoins(sdk.NewCoin(dc.Denom, collateralLimit)))
} }
globalLimit := k.GetParams(ctx).GlobalDebtLimit.AmountOf(dc.Denom) globalLimit := k.GetParams(ctx).GlobalDebtLimit.AmountOf(dc.Denom)
if totalPrincipal.GT(globalLimit) { if totalPrincipal.GT(globalLimit) {
return types.ErrExceedsDebtLimit(k.codespace, sdk.NewCoins(sdk.NewCoin(dc.Denom, totalPrincipal)), sdk.NewCoins(sdk.NewCoin(dc.Denom, globalLimit))) return sdkerrors.Wrapf(types.ErrExceedsDebtLimit, "debt increase %s > global debt limit %s", sdk.NewCoin(dc.Denom, totalPrincipal), sdk.NewCoin(dc.Denom, globalLimit))
} }
} }
return nil return nil
} }
// ValidateCollateralizationRatio validate that adding the input principal doesn't put the cdp below the liquidation ratio // ValidateCollateralizationRatio validate that adding the input principal doesn't put the cdp below the liquidation ratio
func (k Keeper) ValidateCollateralizationRatio(ctx sdk.Context, collateral sdk.Coins, principal sdk.Coins, fees sdk.Coins) sdk.Error { func (k Keeper) ValidateCollateralizationRatio(ctx sdk.Context, collateral sdk.Coins, principal sdk.Coins, fees sdk.Coins) error {
// //
collateralizationRatio, err := k.CalculateCollateralizationRatio(ctx, collateral, principal, fees) collateralizationRatio, err := k.CalculateCollateralizationRatio(ctx, collateral, principal, fees)
if err != nil { if err != nil {
@ -405,7 +407,7 @@ func (k Keeper) ValidateCollateralizationRatio(ctx sdk.Context, collateral sdk.C
} }
liquidationRatio := k.getLiquidationRatio(ctx, collateral[0].Denom) liquidationRatio := k.getLiquidationRatio(ctx, collateral[0].Denom)
if collateralizationRatio.LT(liquidationRatio) { if collateralizationRatio.LT(liquidationRatio) {
return types.ErrInvalidCollateralRatio(k.codespace, collateral[0].Denom, collateralizationRatio, liquidationRatio) return sdkerrors.Wrapf(types.ErrInvalidCollateralRatio, "collateral %s, collateral ratio %s, liquidation ratio %s", collateral[0].Denom, collateralizationRatio, liquidationRatio)
} }
return nil return nil
} }
@ -427,12 +429,11 @@ func (k Keeper) CalculateCollateralToDebtRatio(ctx sdk.Context, collateral sdk.C
} }
// LoadAugmentedCDP creates a new augmented CDP from an existing CDP // LoadAugmentedCDP creates a new augmented CDP from an existing CDP
func (k Keeper) LoadAugmentedCDP(ctx sdk.Context, cdp types.CDP) (types.AugmentedCDP, sdk.Error) { func (k Keeper) LoadAugmentedCDP(ctx sdk.Context, cdp types.CDP) (types.AugmentedCDP, error) {
// calculate additional fees // calculate additional fees
periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix())) periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix()))
fees := k.CalculateFees(ctx, cdp.Principal.Add(cdp.AccumulatedFees), periods, cdp.Collateral[0].Denom) fees := k.CalculateFees(ctx, cdp.Principal.Add(cdp.AccumulatedFees...), periods, cdp.Collateral[0].Denom)
totalFees := cdp.AccumulatedFees.Add(fees) totalFees := cdp.AccumulatedFees.Add(fees...)
// calculate collateralization ratio // calculate collateralization ratio
collateralizationRatio, err := k.CalculateCollateralizationRatio(ctx, cdp.Collateral, cdp.Principal, totalFees) collateralizationRatio, err := k.CalculateCollateralizationRatio(ctx, cdp.Collateral, cdp.Principal, totalFees)
if err != nil { if err != nil {
@ -444,7 +445,7 @@ func (k Keeper) LoadAugmentedCDP(ctx sdk.Context, cdp types.CDP) (types.Augmente
for _, principalCoin := range cdp.Principal { for _, principalCoin := range cdp.Principal {
totalDebt += principalCoin.Amount.Int64() totalDebt += principalCoin.Amount.Int64()
} }
for _, feeCoin := range cdp.AccumulatedFees.Add(fees) { for _, feeCoin := range cdp.AccumulatedFees.Add(fees...) {
totalDebt += feeCoin.Amount.Int64() totalDebt += feeCoin.Amount.Int64()
} }
@ -459,7 +460,7 @@ func (k Keeper) LoadAugmentedCDP(ctx sdk.Context, cdp types.CDP) (types.Augmente
} }
// CalculateCollateralizationRatio returns the collateralization ratio of the input collateral to the input debt plus fees // CalculateCollateralizationRatio returns the collateralization ratio of the input collateral to the input debt plus fees
func (k Keeper) CalculateCollateralizationRatio(ctx sdk.Context, collateral sdk.Coins, principal sdk.Coins, fees sdk.Coins) (sdk.Dec, sdk.Error) { func (k Keeper) CalculateCollateralizationRatio(ctx sdk.Context, collateral sdk.Coins, principal sdk.Coins, fees sdk.Coins) (sdk.Dec, error) {
if collateral.IsZero() { if collateral.IsZero() {
return sdk.ZeroDec(), nil return sdk.ZeroDec(), nil
} }
@ -485,7 +486,7 @@ func (k Keeper) CalculateCollateralizationRatio(ctx sdk.Context, collateral sdk.
} }
// CalculateCollateralizationRatioFromAbsoluteRatio takes a coin's denom and an absolute ratio and returns the respective collateralization ratio // CalculateCollateralizationRatioFromAbsoluteRatio takes a coin's denom and an absolute ratio and returns the respective collateralization ratio
func (k Keeper) CalculateCollateralizationRatioFromAbsoluteRatio(ctx sdk.Context, collateralDenom string, absoluteRatio sdk.Dec) (sdk.Dec, sdk.Error) { func (k Keeper) CalculateCollateralizationRatioFromAbsoluteRatio(ctx sdk.Context, collateralDenom string, absoluteRatio sdk.Dec) (sdk.Dec, error) {
// get price collateral // get price collateral
marketID := k.getMarketID(ctx, collateralDenom) marketID := k.getMarketID(ctx, collateralDenom)
price, err := k.pricefeedKeeper.GetCurrentPrice(ctx, marketID) price, err := k.pricefeedKeeper.GetCurrentPrice(ctx, marketID)

View File

@ -1,6 +1,7 @@
package keeper_test package keeper_test
import ( import (
"errors"
"testing" "testing"
"time" "time"
@ -44,17 +45,17 @@ func (suite *CdpTestSuite) TestAddCdp() {
acc.SetCoins(cs(c("xrp", 200000000), c("btc", 500000000))) acc.SetCoins(cs(c("xrp", 200000000), c("btc", 500000000)))
ak.SetAccount(suite.ctx, acc) ak.SetAccount(suite.ctx, acc)
err := suite.keeper.AddCdp(suite.ctx, addrs[0], cs(c("xrp", 200000000)), cs(c("usdx", 26000000))) err := suite.keeper.AddCdp(suite.ctx, addrs[0], cs(c("xrp", 200000000)), cs(c("usdx", 26000000)))
suite.Equal(types.CodeInvalidCollateralRatio, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrInvalidCollateralRatio))
err = suite.keeper.AddCdp(suite.ctx, addrs[0], cs(c("xrp", 500000000)), cs(c("usdx", 26000000))) err = suite.keeper.AddCdp(suite.ctx, addrs[0], cs(c("xrp", 500000000)), cs(c("usdx", 26000000)))
suite.Error(err) // insufficient balance suite.Error(err) // insufficient balance
err = suite.keeper.AddCdp(suite.ctx, addrs[0], cs(c("xrp", 200000000)), cs(c("xusd", 10000000))) err = suite.keeper.AddCdp(suite.ctx, addrs[0], cs(c("xrp", 200000000)), cs(c("xusd", 10000000)))
suite.Equal(types.CodeDebtNotSupported, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrDebtNotSupported))
acc2 := ak.NewAccountWithAddress(suite.ctx, addrs[1]) acc2 := ak.NewAccountWithAddress(suite.ctx, addrs[1])
acc2.SetCoins(cs(c("btc", 500000000000))) acc2.SetCoins(cs(c("btc", 500000000000)))
ak.SetAccount(suite.ctx, acc2) ak.SetAccount(suite.ctx, acc2)
err = suite.keeper.AddCdp(suite.ctx, addrs[1], cs(c("btc", 500000000000)), cs(c("usdx", 500000000001))) err = suite.keeper.AddCdp(suite.ctx, addrs[1], cs(c("btc", 500000000000)), cs(c("usdx", 500000000001)))
suite.Equal(types.CodeExceedsDebtLimit, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrExceedsDebtLimit))
ctx := suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(time.Hour * 2)) ctx := suite.ctx.WithBlockTime(suite.ctx.BlockTime().Add(time.Hour * 2))
pk := suite.app.GetPriceFeedKeeper() pk := suite.app.GetPriceFeedKeeper()
@ -76,7 +77,7 @@ func (suite *CdpTestSuite) TestAddCdp() {
suite.Equal(cs(c("usdx", 10000000), c("xrp", 100000000), c("btc", 500000000)), acc.GetCoins()) suite.Equal(cs(c("usdx", 10000000), c("xrp", 100000000), c("btc", 500000000)), acc.GetCoins())
err = suite.keeper.AddCdp(suite.ctx, addrs[0], cs(c("btc", 500000000)), cs(c("usdx", 26667000000))) err = suite.keeper.AddCdp(suite.ctx, addrs[0], cs(c("btc", 500000000)), cs(c("usdx", 26667000000)))
suite.Equal(types.CodeInvalidCollateralRatio, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrInvalidCollateralRatio))
err = suite.keeper.AddCdp(suite.ctx, addrs[0], cs(c("btc", 500000000)), cs(c("usdx", 100000000))) err = suite.keeper.AddCdp(suite.ctx, addrs[0], cs(c("btc", 500000000)), cs(c("usdx", 100000000)))
suite.NoError(err) suite.NoError(err)
@ -90,9 +91,9 @@ func (suite *CdpTestSuite) TestAddCdp() {
suite.Equal(cs(c("usdx", 110000000), c("xrp", 100000000)), acc.GetCoins()) suite.Equal(cs(c("usdx", 110000000), c("xrp", 100000000)), acc.GetCoins())
err = suite.keeper.AddCdp(suite.ctx, addrs[0], cs(c("lol", 100)), cs(c("usdx", 10))) err = suite.keeper.AddCdp(suite.ctx, addrs[0], cs(c("lol", 100)), cs(c("usdx", 10)))
suite.Equal(types.CodeCollateralNotSupported, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrCollateralNotSupported))
err = suite.keeper.AddCdp(suite.ctx, addrs[0], cs(c("xrp", 100)), cs(c("usdx", 10))) err = suite.keeper.AddCdp(suite.ctx, addrs[0], cs(c("xrp", 100)), cs(c("usdx", 10)))
suite.Equal(types.CodeCdpAlreadyExists, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrCdpAlreadyExists))
} }
func (suite *CdpTestSuite) TestGetSetDenomByte() { func (suite *CdpTestSuite) TestGetSetDenomByte() {
@ -247,10 +248,10 @@ func (suite *CdpTestSuite) TestValidateCollateral() {
suite.NoError(err) suite.NoError(err)
c = sdk.NewCoins(sdk.NewCoin("lol", sdk.NewInt(1))) c = sdk.NewCoins(sdk.NewCoin("lol", sdk.NewInt(1)))
err = suite.keeper.ValidateCollateral(suite.ctx, c) err = suite.keeper.ValidateCollateral(suite.ctx, c)
suite.Equal(types.CodeCollateralNotSupported, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrCollateralNotSupported))
c = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1)), sdk.NewCoin("xrp", sdk.NewInt(1))) c = sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1)), sdk.NewCoin("xrp", sdk.NewInt(1)))
err = suite.keeper.ValidateCollateral(suite.ctx, c) err = suite.keeper.ValidateCollateral(suite.ctx, c)
suite.Equal(types.CodeCollateralLengthInvalid, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrInvalidCollateralLength))
} }
func (suite *CdpTestSuite) TestValidatePrincipal() { func (suite *CdpTestSuite) TestValidatePrincipal() {
@ -262,10 +263,10 @@ func (suite *CdpTestSuite) TestValidatePrincipal() {
suite.NoError(err) suite.NoError(err)
d = sdk.NewCoins(sdk.NewCoin("xusd", sdk.NewInt(1))) d = sdk.NewCoins(sdk.NewCoin("xusd", sdk.NewInt(1)))
err = suite.keeper.ValidatePrincipalAdd(suite.ctx, d) err = suite.keeper.ValidatePrincipalAdd(suite.ctx, d)
suite.Equal(types.CodeDebtNotSupported, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrDebtNotSupported))
d = sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(1000000000001))) d = sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(1000000000001)))
err = suite.keeper.ValidateDebtLimit(suite.ctx, "xrp", d) err = suite.keeper.ValidateDebtLimit(suite.ctx, "xrp", d)
suite.Equal(types.CodeExceedsDebtLimit, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrExceedsDebtLimit))
d = sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(100000000))) d = sdk.NewCoins(sdk.NewCoin("usdx", sdk.NewInt(100000000)))
err = suite.keeper.ValidateDebtLimit(suite.ctx, "xrp", d) err = suite.keeper.ValidateDebtLimit(suite.ctx, "xrp", d)
suite.NoError(err) suite.NoError(err)
@ -290,16 +291,19 @@ func (suite *CdpTestSuite) TestMintBurnDebtCoins() {
cd := cdps()[1] cd := cdps()[1]
err := suite.keeper.MintDebtCoins(suite.ctx, types.ModuleName, suite.keeper.GetDebtDenom(suite.ctx), cd.Principal) err := suite.keeper.MintDebtCoins(suite.ctx, types.ModuleName, suite.keeper.GetDebtDenom(suite.ctx), cd.Principal)
suite.NoError(err) suite.NoError(err)
err = suite.keeper.MintDebtCoins(suite.ctx, "notamodule", suite.keeper.GetDebtDenom(suite.ctx), cd.Principal) suite.Require().Panics(func() {
suite.Error(err) _ = suite.keeper.MintDebtCoins(suite.ctx, "notamodule", suite.keeper.GetDebtDenom(suite.ctx), cd.Principal)
})
sk := suite.app.GetSupplyKeeper() sk := suite.app.GetSupplyKeeper()
acc := sk.GetModuleAccount(suite.ctx, types.ModuleName) acc := sk.GetModuleAccount(suite.ctx, types.ModuleName)
suite.Equal(cs(c("debt", 10000000)), acc.GetCoins()) suite.Equal(cs(c("debt", 10000000)), acc.GetCoins())
err = suite.keeper.BurnDebtCoins(suite.ctx, types.ModuleName, suite.keeper.GetDebtDenom(suite.ctx), cd.Principal) err = suite.keeper.BurnDebtCoins(suite.ctx, types.ModuleName, suite.keeper.GetDebtDenom(suite.ctx), cd.Principal)
suite.NoError(err) suite.NoError(err)
err = suite.keeper.BurnDebtCoins(suite.ctx, "notamodule", suite.keeper.GetDebtDenom(suite.ctx), cd.Principal) suite.Require().Panics(func() {
suite.Error(err) _ = suite.keeper.BurnDebtCoins(suite.ctx, "notamodule", suite.keeper.GetDebtDenom(suite.ctx), cd.Principal)
})
sk = suite.app.GetSupplyKeeper() sk = suite.app.GetSupplyKeeper()
acc = sk.GetModuleAccount(suite.ctx, types.ModuleName) acc = sk.GetModuleAccount(suite.ctx, types.ModuleName)
suite.Equal(sdk.Coins(nil), acc.GetCoins()) suite.Equal(sdk.Coins(nil), acc.GetCoins())

View File

@ -5,23 +5,24 @@ import (
"github.com/cosmos/cosmos-sdk/store/prefix" "github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/kava-labs/kava/x/cdp/types" "github.com/kava-labs/kava/x/cdp/types"
) )
// DepositCollateral adds collateral to a cdp // DepositCollateral adds collateral to a cdp
func (k Keeper) DepositCollateral(ctx sdk.Context, owner sdk.AccAddress, depositor sdk.AccAddress, collateral sdk.Coins) sdk.Error { func (k Keeper) DepositCollateral(ctx sdk.Context, owner sdk.AccAddress, depositor sdk.AccAddress, collateral sdk.Coins) error {
err := k.ValidateCollateral(ctx, collateral) err := k.ValidateCollateral(ctx, collateral)
if err != nil { if err != nil {
return err return err
} }
cdp, found := k.GetCdpByOwnerAndDenom(ctx, owner, collateral[0].Denom) cdp, found := k.GetCdpByOwnerAndDenom(ctx, owner, collateral[0].Denom)
if !found { if !found {
return types.ErrCdpNotFound(k.codespace, owner, collateral[0].Denom) return sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, collateral %s", owner, collateral[0].Denom)
} }
deposit, found := k.GetDeposit(ctx, cdp.ID, depositor) deposit, found := k.GetDeposit(ctx, cdp.ID, depositor)
if found { if found {
deposit.Amount = deposit.Amount.Add(collateral) deposit.Amount = deposit.Amount.Add(collateral...)
} else { } else {
deposit = types.NewDeposit(cdp.ID, depositor, collateral) deposit = types.NewDeposit(cdp.ID, depositor, collateral)
} }
@ -40,45 +41,45 @@ func (k Keeper) DepositCollateral(ctx sdk.Context, owner sdk.AccAddress, deposit
k.SetDeposit(ctx, deposit) k.SetDeposit(ctx, deposit)
periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix())) periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix()))
fees := k.CalculateFees(ctx, cdp.Principal.Add(cdp.AccumulatedFees), periods, cdp.Collateral[0].Denom) fees := k.CalculateFees(ctx, cdp.Principal.Add(cdp.AccumulatedFees...), periods, cdp.Collateral[0].Denom)
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees)) oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
k.RemoveCdpCollateralRatioIndex(ctx, cdp.Collateral[0].Denom, cdp.ID, oldCollateralToDebtRatio) k.RemoveCdpCollateralRatioIndex(ctx, cdp.Collateral[0].Denom, cdp.ID, oldCollateralToDebtRatio)
cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees) cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees...)
cdp.FeesUpdated = ctx.BlockTime() cdp.FeesUpdated = ctx.BlockTime()
cdp.Collateral = cdp.Collateral.Add(collateral) cdp.Collateral = cdp.Collateral.Add(collateral...)
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees)) collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio) k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio)
return nil return nil
} }
// WithdrawCollateral removes collateral from a cdp if it does not put the cdp below the liquidation ratio // WithdrawCollateral removes collateral from a cdp if it does not put the cdp below the liquidation ratio
func (k Keeper) WithdrawCollateral(ctx sdk.Context, owner sdk.AccAddress, depositor sdk.AccAddress, collateral sdk.Coins) sdk.Error { func (k Keeper) WithdrawCollateral(ctx sdk.Context, owner sdk.AccAddress, depositor sdk.AccAddress, collateral sdk.Coins) error {
err := k.ValidateCollateral(ctx, collateral) err := k.ValidateCollateral(ctx, collateral)
if err != nil { if err != nil {
return err return err
} }
cdp, found := k.GetCdpByOwnerAndDenom(ctx, owner, collateral[0].Denom) cdp, found := k.GetCdpByOwnerAndDenom(ctx, owner, collateral[0].Denom)
if !found { if !found {
return types.ErrCdpNotFound(k.codespace, owner, collateral[0].Denom) return sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, collateral %s", owner, collateral[0].Denom)
} }
deposit, found := k.GetDeposit(ctx, cdp.ID, depositor) deposit, found := k.GetDeposit(ctx, cdp.ID, depositor)
if !found { if !found {
return types.ErrDepositNotFound(k.codespace, depositor, cdp.ID) return sdkerrors.Wrapf(types.ErrDepositNotFound, "depositor %s, collateral %s", depositor, collateral[0].Denom)
} }
if collateral.IsAnyGT(deposit.Amount) { if collateral.IsAnyGT(deposit.Amount) {
return types.ErrInvalidWithdrawAmount(k.codespace, collateral, deposit.Amount) return sdkerrors.Wrapf(types.ErrInvalidWithdrawAmount, "collateral %s, deposit %s", collateral, deposit.Amount)
} }
periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix())) periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix()))
fees := k.CalculateFees(ctx, cdp.Principal.Add(cdp.AccumulatedFees), periods, cdp.Collateral[0].Denom) fees := k.CalculateFees(ctx, cdp.Principal.Add(cdp.AccumulatedFees...), periods, cdp.Collateral[0].Denom)
collateralizationRatio, err := k.CalculateCollateralizationRatio(ctx, cdp.Collateral.Sub(collateral), cdp.Principal, cdp.AccumulatedFees.Add(fees)) collateralizationRatio, err := k.CalculateCollateralizationRatio(ctx, cdp.Collateral.Sub(collateral), cdp.Principal, cdp.AccumulatedFees.Add(fees...))
if err != nil { if err != nil {
return err return err
} }
liquidationRatio := k.getLiquidationRatio(ctx, collateral[0].Denom) liquidationRatio := k.getLiquidationRatio(ctx, collateral[0].Denom)
if collateralizationRatio.LT(liquidationRatio) { if collateralizationRatio.LT(liquidationRatio) {
return types.ErrInvalidCollateralRatio(k.codespace, collateral[0].Denom, collateralizationRatio, liquidationRatio) return sdkerrors.Wrapf(types.ErrInvalidCollateralRatio, "colateral %s, collateral ratio %s, liquidation ration %s", collateral[0].Denom, collateralizationRatio, liquidationRatio)
} }
ctx.EventManager().EmitEvent( ctx.EventManager().EmitEvent(
sdk.NewEvent( sdk.NewEvent(
@ -92,13 +93,13 @@ func (k Keeper) WithdrawCollateral(ctx sdk.Context, owner sdk.AccAddress, deposi
if err != nil { if err != nil {
panic(err) panic(err)
} }
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees)) oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
k.RemoveCdpCollateralRatioIndex(ctx, cdp.Collateral[0].Denom, cdp.ID, oldCollateralToDebtRatio) k.RemoveCdpCollateralRatioIndex(ctx, cdp.Collateral[0].Denom, cdp.ID, oldCollateralToDebtRatio)
cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees) cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees...)
cdp.FeesUpdated = ctx.BlockTime() cdp.FeesUpdated = ctx.BlockTime()
cdp.Collateral = cdp.Collateral.Sub(collateral) cdp.Collateral = cdp.Collateral.Sub(collateral)
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees)) collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio) k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio)
deposit.Amount = deposit.Amount.Sub(collateral) deposit.Amount = deposit.Amount.Sub(collateral)

View File

@ -1,6 +1,7 @@
package keeper_test package keeper_test
import ( import (
"errors"
"testing" "testing"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
@ -76,10 +77,10 @@ func (suite *DepositTestSuite) TestDepositCollateral() {
suite.Equal(i(90000000), acc.GetCoins().AmountOf("xrp")) suite.Equal(i(90000000), acc.GetCoins().AmountOf("xrp"))
err = suite.keeper.DepositCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], cs(c("btc", 1))) err = suite.keeper.DepositCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], cs(c("btc", 1)))
suite.Equal(types.CodeCdpNotFound, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrCdpNotFound))
err = suite.keeper.DepositCollateral(suite.ctx, suite.addrs[1], suite.addrs[0], cs(c("xrp", 1))) err = suite.keeper.DepositCollateral(suite.ctx, suite.addrs[1], suite.addrs[0], cs(c("xrp", 1)))
suite.Equal(types.CodeCdpNotFound, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrCdpNotFound))
err = suite.keeper.DepositCollateral(suite.ctx, suite.addrs[0], suite.addrs[1], cs(c("xrp", 10000000))) err = suite.keeper.DepositCollateral(suite.ctx, suite.addrs[0], suite.addrs[1], cs(c("xrp", 10000000)))
suite.NoError(err) suite.NoError(err)
@ -94,17 +95,17 @@ func (suite *DepositTestSuite) TestDepositCollateral() {
func (suite *DepositTestSuite) TestWithdrawCollateral() { func (suite *DepositTestSuite) TestWithdrawCollateral() {
err := suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], cs(c("xrp", 400000000))) err := suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], cs(c("xrp", 400000000)))
suite.Equal(types.CodeInvalidCollateralRatio, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrInvalidCollateralRatio))
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], cs(c("xrp", 321000000))) err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], cs(c("xrp", 321000000)))
suite.Equal(types.CodeInvalidCollateralRatio, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrInvalidCollateralRatio))
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[1], suite.addrs[0], cs(c("xrp", 10000000))) err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[1], suite.addrs[0], cs(c("xrp", 10000000)))
suite.Equal(types.CodeCdpNotFound, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrCdpNotFound))
cd, _ := suite.keeper.GetCDP(suite.ctx, "xrp", uint64(1)) cd, _ := suite.keeper.GetCDP(suite.ctx, "xrp", uint64(1))
cd.AccumulatedFees = cs(c("usdx", 1)) cd.AccumulatedFees = cs(c("usdx", 1))
suite.keeper.SetCDP(suite.ctx, cd) suite.keeper.SetCDP(suite.ctx, cd)
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], cs(c("xrp", 320000000))) err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], cs(c("xrp", 320000000)))
suite.Equal(types.CodeInvalidCollateralRatio, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrInvalidCollateralRatio))
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], cs(c("xrp", 10000000))) err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[0], suite.addrs[0], cs(c("xrp", 10000000)))
suite.NoError(err) suite.NoError(err)
@ -116,7 +117,7 @@ func (suite *DepositTestSuite) TestWithdrawCollateral() {
suite.Equal(i(110000000), acc.GetCoins().AmountOf("xrp")) suite.Equal(i(110000000), acc.GetCoins().AmountOf("xrp"))
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[0], suite.addrs[1], cs(c("xrp", 10000000))) err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[0], suite.addrs[1], cs(c("xrp", 10000000)))
suite.Equal(types.CodeDepositNotFound, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrDepositNotFound))
} }
func TestDepositTestSuite(t *testing.T) { func TestDepositTestSuite(t *testing.T) {

View File

@ -4,15 +4,16 @@ import (
"fmt" "fmt"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/kava-labs/kava/x/cdp/types" "github.com/kava-labs/kava/x/cdp/types"
) )
// AddPrincipal adds debt to a cdp if the additional debt does not put the cdp below the liquidation ratio // AddPrincipal adds debt to a cdp if the additional debt does not put the cdp below the liquidation ratio
func (k Keeper) AddPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom string, principal sdk.Coins) sdk.Error { func (k Keeper) AddPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom string, principal sdk.Coins) error {
// validation // validation
cdp, found := k.GetCdpByOwnerAndDenom(ctx, owner, denom) cdp, found := k.GetCdpByOwnerAndDenom(ctx, owner, denom)
if !found { if !found {
return types.ErrCdpNotFound(k.codespace, owner, denom) return sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, denom %s", owner, denom)
} }
err := k.ValidatePrincipalDraw(ctx, principal) err := k.ValidatePrincipalDraw(ctx, principal)
if err != nil { if err != nil {
@ -26,9 +27,9 @@ func (k Keeper) AddPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom string
// fee calculation // fee calculation
periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix())) periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix()))
fees := k.CalculateFees(ctx, cdp.Principal.Add(cdp.AccumulatedFees), periods, cdp.Collateral[0].Denom) fees := k.CalculateFees(ctx, cdp.Principal.Add(cdp.AccumulatedFees...), periods, cdp.Collateral[0].Denom)
err = k.ValidateCollateralizationRatio(ctx, cdp.Collateral, cdp.Principal.Add(principal), cdp.AccumulatedFees.Add(fees)) err = k.ValidateCollateralizationRatio(ctx, cdp.Collateral, cdp.Principal.Add(principal...), cdp.AccumulatedFees.Add(fees...))
if err != nil { if err != nil {
return err return err
} }
@ -59,19 +60,19 @@ func (k Keeper) AddPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom string
) )
// remove old collateral:debt index // remove old collateral:debt index
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees)) oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
k.RemoveCdpCollateralRatioIndex(ctx, denom, cdp.ID, oldCollateralToDebtRatio) k.RemoveCdpCollateralRatioIndex(ctx, denom, cdp.ID, oldCollateralToDebtRatio)
// update cdp state // update cdp state
cdp.Principal = cdp.Principal.Add(principal) cdp.Principal = cdp.Principal.Add(principal...)
cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees) cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees...)
cdp.FeesUpdated = ctx.BlockTime() cdp.FeesUpdated = ctx.BlockTime()
// increment total principal for the input collateral type // increment total principal for the input collateral type
k.IncrementTotalPrincipal(ctx, cdp.Collateral[0].Denom, principal) k.IncrementTotalPrincipal(ctx, cdp.Collateral[0].Denom, principal)
// set cdp state and indexes in the store // set cdp state and indexes in the store
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees)) collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio) k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio)
return nil return nil
@ -79,32 +80,32 @@ func (k Keeper) AddPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom string
// RepayPrincipal removes debt from the cdp // RepayPrincipal removes debt from the cdp
// If all debt is repaid, the collateral is returned to depositors and the cdp is removed from the store // If all debt is repaid, the collateral is returned to depositors and the cdp is removed from the store
func (k Keeper) RepayPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom string, payment sdk.Coins) sdk.Error { func (k Keeper) RepayPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom string, payment sdk.Coins) error {
// validation // validation
cdp, found := k.GetCdpByOwnerAndDenom(ctx, owner, denom) cdp, found := k.GetCdpByOwnerAndDenom(ctx, owner, denom)
if !found { if !found {
return types.ErrCdpNotFound(k.codespace, owner, denom) return sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, denom %s", owner, denom)
} }
// calculate fees // calculate fees
periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix())) periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix()))
fees := k.CalculateFees(ctx, cdp.Principal.Add(cdp.AccumulatedFees), periods, cdp.Collateral[0].Denom) fees := k.CalculateFees(ctx, cdp.Principal.Add(cdp.AccumulatedFees...), periods, cdp.Collateral[0].Denom)
err := k.ValidatePaymentCoins(ctx, cdp, payment, cdp.Principal.Add(cdp.AccumulatedFees).Add(fees)) err := k.ValidatePaymentCoins(ctx, cdp, payment, cdp.Principal.Add(cdp.AccumulatedFees...).Add(fees...))
if err != nil { if err != nil {
return err return err
} }
// calculate fee and principal payment // calculate fee and principal payment
feePayment, principalPayment := k.calculatePayment(ctx, cdp.Principal.Add(cdp.AccumulatedFees).Add(fees), cdp.AccumulatedFees.Add(fees), payment) feePayment, principalPayment := k.calculatePayment(ctx, cdp.Principal.Add(cdp.AccumulatedFees...).Add(fees...), cdp.AccumulatedFees.Add(fees...), payment)
// send the payment from the sender to the cpd module // send the payment from the sender to the cpd module
err = k.supplyKeeper.SendCoinsFromAccountToModule(ctx, owner, types.ModuleName, feePayment.Add(principalPayment)) err = k.supplyKeeper.SendCoinsFromAccountToModule(ctx, owner, types.ModuleName, feePayment.Add(principalPayment...))
if err != nil { if err != nil {
return err return err
} }
// burn the payment coins // burn the payment coins
err = k.supplyKeeper.BurnCoins(ctx, types.ModuleName, feePayment.Add(principalPayment)) err = k.supplyKeeper.BurnCoins(ctx, types.ModuleName, feePayment.Add(principalPayment...))
if err != nil { if err != nil {
panic(err) panic(err)
} }
@ -112,7 +113,7 @@ func (k Keeper) RepayPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom stri
// burn the corresponding amount of debt coins // burn the corresponding amount of debt coins
cdpDebt := k.getModAccountDebt(ctx, types.ModuleName) cdpDebt := k.getModAccountDebt(ctx, types.ModuleName)
paymentAmount := sdk.ZeroInt() paymentAmount := sdk.ZeroInt()
for _, c := range feePayment.Add(principalPayment) { for _, c := range feePayment.Add(principalPayment...) {
paymentAmount = paymentAmount.Add(c.Amount) paymentAmount = paymentAmount.Add(c.Amount)
} }
coinsToBurn := sdk.NewCoins(sdk.NewCoin(k.GetDebtDenom(ctx), paymentAmount)) coinsToBurn := sdk.NewCoins(sdk.NewCoin(k.GetDebtDenom(ctx), paymentAmount))
@ -128,24 +129,24 @@ func (k Keeper) RepayPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom stri
ctx.EventManager().EmitEvent( ctx.EventManager().EmitEvent(
sdk.NewEvent( sdk.NewEvent(
types.EventTypeCdpRepay, types.EventTypeCdpRepay,
sdk.NewAttribute(sdk.AttributeKeyAmount, feePayment.Add(principalPayment).String()), sdk.NewAttribute(sdk.AttributeKeyAmount, feePayment.Add(principalPayment...).String()),
sdk.NewAttribute(types.AttributeKeyCdpID, fmt.Sprintf("%d", cdp.ID)), sdk.NewAttribute(types.AttributeKeyCdpID, fmt.Sprintf("%d", cdp.ID)),
), ),
) )
// remove the old collateral:debt ratio index // remove the old collateral:debt ratio index
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees)) oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
k.RemoveCdpCollateralRatioIndex(ctx, denom, cdp.ID, oldCollateralToDebtRatio) k.RemoveCdpCollateralRatioIndex(ctx, denom, cdp.ID, oldCollateralToDebtRatio)
// update cdp state // update cdp state
if !principalPayment.IsZero() { if !principalPayment.IsZero() {
cdp.Principal = cdp.Principal.Sub(principalPayment) cdp.Principal = cdp.Principal.Sub(principalPayment)
} }
cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees).Sub(feePayment) cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees...).Sub(feePayment)
cdp.FeesUpdated = ctx.BlockTime() cdp.FeesUpdated = ctx.BlockTime()
// decrement the total principal for the input collateral type // decrement the total principal for the input collateral type
k.DecrementTotalPrincipal(ctx, denom, feePayment.Add(principalPayment)) k.DecrementTotalPrincipal(ctx, denom, feePayment.Add(principalPayment...))
// if the debt is fully paid, return collateral to depositors, // if the debt is fully paid, return collateral to depositors,
// and remove the cdp and indexes from the store // and remove the cdp and indexes from the store
@ -165,13 +166,13 @@ func (k Keeper) RepayPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom stri
} }
// set cdp state and update indexes // set cdp state and update indexes
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees)) collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio) k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio)
return nil return nil
} }
// ValidatePaymentCoins validates that the input coins are valid for repaying debt // ValidatePaymentCoins validates that the input coins are valid for repaying debt
func (k Keeper) ValidatePaymentCoins(ctx sdk.Context, cdp types.CDP, payment sdk.Coins, debt sdk.Coins) sdk.Error { func (k Keeper) ValidatePaymentCoins(ctx sdk.Context, cdp types.CDP, payment sdk.Coins, debt sdk.Coins) error {
subset := payment.DenomsSubsetOf(cdp.Principal) subset := payment.DenomsSubsetOf(cdp.Principal)
if !subset { if !subset {
var paymentDenoms []string var paymentDenoms []string
@ -182,13 +183,13 @@ func (k Keeper) ValidatePaymentCoins(ctx sdk.Context, cdp types.CDP, payment sdk
for _, pc := range payment { for _, pc := range payment {
paymentDenoms = append(paymentDenoms, pc.Denom) paymentDenoms = append(paymentDenoms, pc.Denom)
} }
return types.ErrInvalidPaymentDenom(k.codespace, cdp.ID, principalDenoms, paymentDenoms) return sdkerrors.Wrapf(types.ErrInvalidPayment, "cdp %d: expected %s, got %s", cdp.ID, principalDenoms, paymentDenoms)
} }
for _, dc := range payment { for _, dc := range payment {
dp, _ := k.GetDebtParam(ctx, dc.Denom) dp, _ := k.GetDebtParam(ctx, dc.Denom)
proposedBalance := cdp.Principal.AmountOf(dc.Denom).Sub(dc.Amount) proposedBalance := cdp.Principal.AmountOf(dc.Denom).Sub(dc.Amount)
if proposedBalance.GT(sdk.ZeroInt()) && proposedBalance.LT(dp.DebtFloor) { if proposedBalance.GT(sdk.ZeroInt()) && proposedBalance.LT(dp.DebtFloor) {
return types.ErrBelowDebtFloor(k.codespace, sdk.NewCoins(sdk.NewCoin(dc.Denom, proposedBalance)), dp.DebtFloor) return sdkerrors.Wrapf(types.ErrBelowDebtFloor, "proposed %s < minimum %s", sdk.NewCoins(sdk.NewCoin(dc.Denom, proposedBalance)), dp.DebtFloor)
} }
} }
return nil return nil
@ -223,12 +224,12 @@ func (k Keeper) calculatePayment(ctx sdk.Context, owed sdk.Coins, fees sdk.Coins
for _, fc := range fees { for _, fc := range fees {
if payment.AmountOf(fc.Denom).IsPositive() { if payment.AmountOf(fc.Denom).IsPositive() {
if payment.AmountOf(fc.Denom).GT(fc.Amount) { if payment.AmountOf(fc.Denom).GT(fc.Amount) {
feePayment = feePayment.Add(sdk.NewCoins(fc)) feePayment = feePayment.Add(fc)
pc := sdk.NewCoin(fc.Denom, payment.AmountOf(fc.Denom).Sub(fc.Amount)) pc := sdk.NewCoin(fc.Denom, payment.AmountOf(fc.Denom).Sub(fc.Amount))
principalPayment = principalPayment.Add(sdk.NewCoins(pc)) principalPayment = principalPayment.Add(pc)
} else { } else {
fc := sdk.NewCoin(fc.Denom, payment.AmountOf(fc.Denom)) fc := sdk.NewCoin(fc.Denom, payment.AmountOf(fc.Denom))
feePayment = feePayment.Add(sdk.NewCoins(fc)) feePayment = feePayment.Add(fc)
} }
} }
} }

View File

@ -1,6 +1,7 @@
package keeper_test package keeper_test
import ( import (
"errors"
"testing" "testing"
"time" "time"
@ -53,7 +54,7 @@ func (suite *DrawTestSuite) TestAddRepayPrincipal() {
t, _ := suite.keeper.GetCDP(suite.ctx, "xrp", uint64(1)) t, _ := suite.keeper.GetCDP(suite.ctx, "xrp", uint64(1))
suite.Equal(cs(c("usdx", 20000000)), t.Principal) suite.Equal(cs(c("usdx", 20000000)), t.Principal)
ctd := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, t.Collateral, t.Principal.Add(t.AccumulatedFees)) ctd := suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, t.Collateral, t.Principal.Add(t.AccumulatedFees...))
suite.Equal(d("20.0"), ctd) suite.Equal(d("20.0"), ctd)
ts := suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("20.0")) ts := suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("20.0"))
suite.Equal(0, len(ts)) suite.Equal(0, len(ts))
@ -69,7 +70,7 @@ func (suite *DrawTestSuite) TestAddRepayPrincipal() {
suite.NoError(err) suite.NoError(err)
t, _ = suite.keeper.GetCDP(suite.ctx, "xrp", uint64(1)) t, _ = suite.keeper.GetCDP(suite.ctx, "xrp", uint64(1))
suite.Equal(cs(c("usdx", 20000000), c("susd", 10000000)), t.Principal) suite.Equal(cs(c("usdx", 20000000), c("susd", 10000000)), t.Principal)
ctd = suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, t.Collateral, t.Principal.Add(t.AccumulatedFees)) ctd = suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, t.Collateral, t.Principal.Add(t.AccumulatedFees...))
suite.Equal(d("400000000").Quo(d("30000000")), ctd) suite.Equal(d("400000000").Quo(d("30000000")), ctd)
ts = suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("400").Quo(d("30"))) ts = suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("400").Quo(d("30")))
suite.Equal(0, len(ts)) suite.Equal(0, len(ts))
@ -82,18 +83,18 @@ func (suite *DrawTestSuite) TestAddRepayPrincipal() {
suite.Equal(cs(c("xrp", 400000000), c("debt", 30000000)), acc.GetCoins()) suite.Equal(cs(c("xrp", 400000000), c("debt", 30000000)), acc.GetCoins())
err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[1], "xrp", cs(c("usdx", 10000000))) err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[1], "xrp", cs(c("usdx", 10000000)))
suite.Equal(types.CodeCdpNotFound, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrCdpNotFound))
err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[0], "xrp", cs(c("xusd", 10000000))) err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[0], "xrp", cs(c("xusd", 10000000)))
suite.Equal(types.CodeDebtNotSupported, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrDebtNotSupported))
err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[0], "xrp", cs(c("usdx", 311000000))) err = suite.keeper.AddPrincipal(suite.ctx, suite.addrs[0], "xrp", cs(c("usdx", 311000000)))
suite.Equal(types.CodeInvalidCollateralRatio, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrInvalidCollateralRatio))
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[0], "xrp", cs(c("usdx", 10000000))) err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[0], "xrp", cs(c("usdx", 10000000)))
suite.NoError(err) suite.NoError(err)
t, _ = suite.keeper.GetCDP(suite.ctx, "xrp", uint64(1)) t, _ = suite.keeper.GetCDP(suite.ctx, "xrp", uint64(1))
suite.Equal(cs(c("usdx", 10000000), c("susd", 10000000)), t.Principal) suite.Equal(cs(c("usdx", 10000000), c("susd", 10000000)), t.Principal)
ctd = suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, t.Collateral, t.Principal.Add(t.AccumulatedFees)) ctd = suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, t.Collateral, t.Principal.Add(t.AccumulatedFees...))
suite.Equal(d("20.0"), ctd) suite.Equal(d("20.0"), ctd)
ts = suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("20.0")) ts = suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("20.0"))
suite.Equal(0, len(ts)) suite.Equal(0, len(ts))
@ -110,7 +111,7 @@ func (suite *DrawTestSuite) TestAddRepayPrincipal() {
t, _ = suite.keeper.GetCDP(suite.ctx, "xrp", uint64(1)) t, _ = suite.keeper.GetCDP(suite.ctx, "xrp", uint64(1))
suite.Equal(cs(c("usdx", 10000000)), t.Principal) suite.Equal(cs(c("usdx", 10000000)), t.Principal)
ctd = suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, t.Collateral, t.Principal.Add(t.AccumulatedFees)) ctd = suite.keeper.CalculateCollateralToDebtRatio(suite.ctx, t.Collateral, t.Principal.Add(t.AccumulatedFees...))
suite.Equal(d("40.0"), ctd) suite.Equal(d("40.0"), ctd)
ts = suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("40.0")) ts = suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("40.0"))
suite.Equal(0, len(ts)) suite.Equal(0, len(ts))
@ -123,12 +124,12 @@ func (suite *DrawTestSuite) TestAddRepayPrincipal() {
suite.Equal(cs(c("xrp", 400000000), c("debt", 10000000)), acc.GetCoins()) suite.Equal(cs(c("xrp", 400000000), c("debt", 10000000)), acc.GetCoins())
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[0], "xrp", cs(c("xusd", 10000000))) err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[0], "xrp", cs(c("xusd", 10000000)))
suite.Equal(types.CodeInvalidPaymentDenom, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrInvalidPayment))
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[1], "xrp", cs(c("xusd", 10000000))) err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[1], "xrp", cs(c("xusd", 10000000)))
suite.Equal(types.CodeCdpNotFound, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrCdpNotFound))
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[0], "xrp", cs(c("usdx", 9000000))) err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[0], "xrp", cs(c("usdx", 9000000)))
suite.Equal(types.CodeBelowDebtFloor, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrBelowDebtFloor))
err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[0], "xrp", cs(c("usdx", 10000000))) err = suite.keeper.RepayPrincipal(suite.ctx, suite.addrs[0], "xrp", cs(c("usdx", 10000000)))
suite.NoError(err) suite.NoError(err)

View File

@ -22,7 +22,7 @@ func (k Keeper) CalculateFees(ctx sdk.Context, principal sdk.Coins, periods sdk.
accumulator := sdk.NewDecFromInt(types.RelativePow(feeRateInt, periods, scalar)).Mul(sdk.SmallestDec()) accumulator := sdk.NewDecFromInt(types.RelativePow(feeRateInt, periods, scalar)).Mul(sdk.SmallestDec())
feesAccumulated := (sdk.NewDecFromInt(pc.Amount).Mul(accumulator)).Sub(sdk.NewDecFromInt(pc.Amount)) feesAccumulated := (sdk.NewDecFromInt(pc.Amount).Mul(accumulator)).Sub(sdk.NewDecFromInt(pc.Amount))
// TODO this will always round down, causing precision loss between the sum of all fees in CDPs and surplus coins in liquidator account // TODO this will always round down, causing precision loss between the sum of all fees in CDPs and surplus coins in liquidator account
newFees = newFees.Add(sdk.NewCoins(sdk.NewCoin(pc.Denom, feesAccumulated.TruncateInt()))) newFees = newFees.Add(sdk.NewCoin(pc.Denom, feesAccumulated.TruncateInt()))
} }
return newFees return newFees
} }
@ -33,7 +33,7 @@ func (k Keeper) CalculateFees(ctx sdk.Context, principal sdk.Coins, periods sdk.
// Next we store the result of the fees in the cdp.AccumulatedFees field // Next we store the result of the fees in the cdp.AccumulatedFees field
// Finally we set the cdp.FeesUpdated time to the current block time (ctx.BlockTime()) since that // Finally we set the cdp.FeesUpdated time to the current block time (ctx.BlockTime()) since that
// is when we made the update // is when we made the update
func (k Keeper) UpdateFeesForRiskyCdps(ctx sdk.Context, collateralDenom string, marketID string) sdk.Error { func (k Keeper) UpdateFeesForRiskyCdps(ctx sdk.Context, collateralDenom string, marketID string) error {
price, err := k.pricefeedKeeper.GetCurrentPrice(ctx, marketID) price, err := k.pricefeedKeeper.GetCurrentPrice(ctx, marketID)
if err != nil { if err != nil {
@ -50,7 +50,7 @@ func (k Keeper) UpdateFeesForRiskyCdps(ctx sdk.Context, collateralDenom string,
// now iterate over all the cdps based on collateral ratio // now iterate over all the cdps based on collateral ratio
k.IterateCdpsByCollateralRatio(ctx, collateralDenom, normalizedRatio, func(cdp types.CDP) bool { k.IterateCdpsByCollateralRatio(ctx, collateralDenom, normalizedRatio, func(cdp types.CDP) bool {
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees)) oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
// get the number of periods // get the number of periods
periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix())) periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix()))
@ -58,11 +58,11 @@ func (k Keeper) UpdateFeesForRiskyCdps(ctx sdk.Context, collateralDenom string,
additionalFees := k.CalculateFees(ctx, cdp.Principal, periods, collateralDenom) additionalFees := k.CalculateFees(ctx, cdp.Principal, periods, collateralDenom)
// now add the additional fees to the accumulated fees for the cdp // now add the additional fees to the accumulated fees for the cdp
cdp.AccumulatedFees = cdp.AccumulatedFees.Add(additionalFees) cdp.AccumulatedFees = cdp.AccumulatedFees.Add(additionalFees...)
// and set the fees updated time to the current block time since we just updated it // and set the fees updated time to the current block time since we just updated it
cdp.FeesUpdated = ctx.BlockTime() cdp.FeesUpdated = ctx.BlockTime()
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees)) collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
k.RemoveCdpCollateralRatioIndex(ctx, cdp.Collateral[0].Denom, cdp.ID, oldCollateralToDebtRatio) k.RemoveCdpCollateralRatioIndex(ctx, cdp.Collateral[0].Denom, cdp.ID, oldCollateralToDebtRatio)
k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio) k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio)
return false // this returns true when you want to stop iterating. Since we want to iterate through all we return false return false // this returns true when you want to stop iterating. Since we want to iterate through all we return false

View File

@ -48,7 +48,7 @@ func (suite *FeeTestSuite) TestCalculateFeesPrecisionLoss() {
suite.NoError(err) suite.NoError(err)
c := sdk.NewCoins(sdk.NewCoin("usdx", ri)) c := sdk.NewCoins(sdk.NewCoin("usdx", ri))
coins = append(coins, c) coins = append(coins, c)
total = total.Add(cs(sdk.NewCoin("usdx", ri))) total = total.Add(sdk.NewCoin("usdx", ri))
} }
numBlocks := []int{100, 1000, 10000, 100000} numBlocks := []int{100, 1000, 10000, 100000}
@ -57,13 +57,13 @@ func (suite *FeeTestSuite) TestCalculateFeesPrecisionLoss() {
bulkFees := sdk.NewCoins() bulkFees := sdk.NewCoins()
individualFees := sdk.NewCoins() individualFees := sdk.NewCoins()
for x := 0; x < nb; x++ { for x := 0; x < nb; x++ {
fee := suite.keeper.CalculateFees(suite.ctx, total.Add(bulkFees), i(7), "xrp") fee := suite.keeper.CalculateFees(suite.ctx, total.Add(bulkFees...), i(7), "xrp")
bulkFees = bulkFees.Add(fee) bulkFees = bulkFees.Add(fee...)
} }
for _, cns := range coins { for _, cns := range coins {
fee := suite.keeper.CalculateFees(suite.ctx, cns, i(int64(nb*7)), "xrp") fee := suite.keeper.CalculateFees(suite.ctx, cns, i(int64(nb*7)), "xrp")
individualFees = individualFees.Add(fee) individualFees = individualFees.Add(fee...)
} }
absError := (sdk.OneDec().Sub(sdk.NewDecFromInt(bulkFees[0].Amount).Quo(sdk.NewDecFromInt(individualFees[0].Amount)))).Abs() absError := (sdk.OneDec().Sub(sdk.NewDecFromInt(bulkFees[0].Amount).Quo(sdk.NewDecFromInt(individualFees[0].Amount)))).Abs()

View File

@ -19,21 +19,22 @@ type Keeper struct {
supplyKeeper types.SupplyKeeper supplyKeeper types.SupplyKeeper
auctionKeeper types.AuctionKeeper auctionKeeper types.AuctionKeeper
accountKeeper types.AccountKeeper accountKeeper types.AccountKeeper
codespace sdk.CodespaceType
} }
// NewKeeper creates a new keeper // NewKeeper creates a new keeper
func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramstore subspace.Subspace, pfk types.PricefeedKeeper, ak types.AuctionKeeper, sk types.SupplyKeeper, ack types.AccountKeeper, codespace sdk.CodespaceType) Keeper { func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, paramstore subspace.Subspace, pfk types.PricefeedKeeper, ak types.AuctionKeeper, sk types.SupplyKeeper, ack types.AccountKeeper) Keeper {
if !paramstore.HasKeyTable() {
paramstore = paramstore.WithKeyTable(types.ParamKeyTable())
}
return Keeper{ return Keeper{
key: key, key: key,
cdc: cdc, cdc: cdc,
paramSubspace: paramstore.WithKeyTable(types.ParamKeyTable()), paramSubspace: paramstore,
pricefeedKeeper: pfk, pricefeedKeeper: pfk,
auctionKeeper: ak, auctionKeeper: ak,
supplyKeeper: sk, supplyKeeper: sk,
accountKeeper: ack, accountKeeper: ack,
codespace: codespace,
} }
} }

View File

@ -115,7 +115,7 @@ func BenchmarkCdpIteration(b *testing.B) {
} }
var errResult sdk.Error var errResult error
func BenchmarkCdpCreation(b *testing.B) { func BenchmarkCdpCreation(b *testing.B) {
tApp := app.NewTestApp() tApp := app.NewTestApp()

View File

@ -1,16 +1,20 @@
package keeper package keeper
import ( import (
"fmt"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/kava-labs/kava/x/cdp/types" "github.com/kava-labs/kava/x/cdp/types"
) )
// NewQuerier returns a new querier function // NewQuerier returns a new querier function
func NewQuerier(keeper Keeper) sdk.Querier { func NewQuerier(keeper Keeper) sdk.Querier {
return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err error) {
switch path[0] { switch path[0] {
case types.QueryGetCdp: case types.QueryGetCdp:
return queryGetCdp(ctx, req, keeper) return queryGetCdp(ctx, req, keeper)
@ -23,85 +27,85 @@ func NewQuerier(keeper Keeper) sdk.Querier {
case types.QueryGetCdpDeposits: case types.QueryGetCdpDeposits:
return queryGetDeposits(ctx, req, keeper) return queryGetDeposits(ctx, req, keeper)
default: default:
return nil, sdk.ErrUnknownRequest("unknown cdp query endpoint") return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unknown %s query endpoint %s", types.ModuleName, path[0])
} }
} }
} }
// query a specific cdp // query a specific cdp
func queryGetCdp(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { func queryGetCdp(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
var requestParams types.QueryCdpParams var requestParams types.QueryCdpParams
err := keeper.cdc.UnmarshalJSON(req.Data, &requestParams) err := types.ModuleCdc.UnmarshalJSON(req.Data, &requestParams)
if err != nil { if err != nil {
return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
} }
_, valid := keeper.GetDenomPrefix(ctx, requestParams.CollateralDenom) _, valid := keeper.GetDenomPrefix(ctx, requestParams.CollateralDenom)
if !valid { if !valid {
return nil, types.ErrInvalidCollateralDenom(keeper.codespace, requestParams.CollateralDenom) return nil, sdkerrors.Wrap(types.ErrInvalidCollateral, requestParams.CollateralDenom)
} }
cdp, found := keeper.GetCdpByOwnerAndDenom(ctx, requestParams.Owner, requestParams.CollateralDenom) cdp, found := keeper.GetCdpByOwnerAndDenom(ctx, requestParams.Owner, requestParams.CollateralDenom)
if !found { if !found {
return nil, types.ErrCdpNotFound(keeper.codespace, requestParams.Owner, requestParams.CollateralDenom) return nil, sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, denom %s", requestParams.Owner, requestParams.CollateralDenom)
} }
augmentedCDP, err := keeper.LoadAugmentedCDP(ctx, cdp) augmentedCDP, err := keeper.LoadAugmentedCDP(ctx, cdp)
if err != nil { if err != nil {
return nil, types.ErrLoadingAugmentedCDP(keeper.codespace, cdp.ID) return nil, sdkerrors.Wrap(types.ErrLoadingAugmentedCDP, fmt.Sprintf("%v: %d", err.Error(), cdp.ID))
} }
bz, err := codec.MarshalJSONIndent(keeper.cdc, augmentedCDP) bz, err := codec.MarshalJSONIndent(types.ModuleCdc, augmentedCDP)
if err != nil { if err != nil {
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
} }
return bz, nil return bz, nil
} }
// query deposits on a particular cdp // query deposits on a particular cdp
func queryGetDeposits(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { func queryGetDeposits(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
var requestParams types.QueryCdpDeposits var requestParams types.QueryCdpDeposits
err := keeper.cdc.UnmarshalJSON(req.Data, &requestParams) err := types.ModuleCdc.UnmarshalJSON(req.Data, &requestParams)
if err != nil { if err != nil {
return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
} }
_, valid := keeper.GetDenomPrefix(ctx, requestParams.CollateralDenom) _, valid := keeper.GetDenomPrefix(ctx, requestParams.CollateralDenom)
if !valid { if !valid {
return nil, types.ErrInvalidCollateralDenom(keeper.codespace, requestParams.CollateralDenom) return nil, sdkerrors.Wrap(types.ErrInvalidCollateral, requestParams.CollateralDenom)
} }
cdp, found := keeper.GetCdpByOwnerAndDenom(ctx, requestParams.Owner, requestParams.CollateralDenom) cdp, found := keeper.GetCdpByOwnerAndDenom(ctx, requestParams.Owner, requestParams.CollateralDenom)
if !found { if !found {
return nil, types.ErrCdpNotFound(keeper.codespace, requestParams.Owner, requestParams.CollateralDenom) return nil, sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, denom %s", requestParams.Owner, requestParams.CollateralDenom)
} }
deposits := keeper.GetDeposits(ctx, cdp.ID) deposits := keeper.GetDeposits(ctx, cdp.ID)
bz, err := codec.MarshalJSONIndent(keeper.cdc, deposits) bz, err := codec.MarshalJSONIndent(types.ModuleCdc, deposits)
if err != nil { if err != nil {
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
} }
return bz, nil return bz, nil
} }
// query cdps with matching denom and ratio LESS THAN the input ratio // query cdps with matching denom and ratio LESS THAN the input ratio
func queryGetCdpsByRatio(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { func queryGetCdpsByRatio(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
var requestParams types.QueryCdpsByRatioParams var requestParams types.QueryCdpsByRatioParams
err := keeper.cdc.UnmarshalJSON(req.Data, &requestParams) err := types.ModuleCdc.UnmarshalJSON(req.Data, &requestParams)
if err != nil { if err != nil {
return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
} }
_, valid := keeper.GetDenomPrefix(ctx, requestParams.CollateralDenom) _, valid := keeper.GetDenomPrefix(ctx, requestParams.CollateralDenom)
if !valid { if !valid {
return nil, types.ErrInvalidCollateralDenom(keeper.codespace, requestParams.CollateralDenom) return nil, sdkerrors.Wrap(types.ErrInvalidCollateral, requestParams.CollateralDenom)
} }
ratio, err := keeper.CalculateCollateralizationRatioFromAbsoluteRatio(ctx, requestParams.CollateralDenom, requestParams.Ratio) ratio, err := keeper.CalculateCollateralizationRatioFromAbsoluteRatio(ctx, requestParams.CollateralDenom, requestParams.Ratio)
if err != nil { if err != nil {
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could get collateralization ratio from absolute ratio", err.Error())) return nil, sdkerrors.Wrap(err, "couldn't get collateralization ratio from absolute ratio")
} }
cdps := keeper.GetAllCdpsByDenomAndRatio(ctx, requestParams.CollateralDenom, ratio) cdps := keeper.GetAllCdpsByDenomAndRatio(ctx, requestParams.CollateralDenom, ratio)
@ -113,23 +117,23 @@ func queryGetCdpsByRatio(ctx sdk.Context, req abci.RequestQuery, keeper Keeper)
augmentedCDPs = append(augmentedCDPs, augmentedCDP) augmentedCDPs = append(augmentedCDPs, augmentedCDP)
} }
} }
bz, err := codec.MarshalJSONIndent(keeper.cdc, augmentedCDPs) bz, err := codec.MarshalJSONIndent(types.ModuleCdc, augmentedCDPs)
if err != nil { if err != nil {
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
} }
return bz, nil return bz, nil
} }
// query all cdps with matching collateral denom // query all cdps with matching collateral denom
func queryGetCdpsByDenom(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { func queryGetCdpsByDenom(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
var requestParams types.QueryCdpsParams var requestParams types.QueryCdpsParams
err := keeper.cdc.UnmarshalJSON(req.Data, &requestParams) err := types.ModuleCdc.UnmarshalJSON(req.Data, &requestParams)
if err != nil { if err != nil {
return nil, sdk.ErrUnknownRequest(sdk.AppendMsgToErr("incorrectly formatted request data", err.Error())) return nil, sdkerrors.Wrap(sdkerrors.ErrJSONUnmarshal, err.Error())
} }
_, valid := keeper.GetDenomPrefix(ctx, requestParams.CollateralDenom) _, valid := keeper.GetDenomPrefix(ctx, requestParams.CollateralDenom)
if !valid { if !valid {
return nil, types.ErrInvalidCollateralDenom(keeper.codespace, requestParams.CollateralDenom) return nil, sdkerrors.Wrap(types.ErrInvalidCollateral, requestParams.CollateralDenom)
} }
cdps := keeper.GetAllCdpsByDenom(ctx, requestParams.CollateralDenom) cdps := keeper.GetAllCdpsByDenom(ctx, requestParams.CollateralDenom)
@ -141,22 +145,22 @@ func queryGetCdpsByDenom(ctx sdk.Context, req abci.RequestQuery, keeper Keeper)
augmentedCDPs = append(augmentedCDPs, augmentedCDP) augmentedCDPs = append(augmentedCDPs, augmentedCDP)
} }
} }
bz, err := codec.MarshalJSONIndent(keeper.cdc, augmentedCDPs) bz, err := codec.MarshalJSONIndent(types.ModuleCdc, augmentedCDPs)
if err != nil { if err != nil {
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
} }
return bz, nil return bz, nil
} }
// query params in the cdp store // query params in the cdp store
func queryGetParams(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, sdk.Error) { func queryGetParams(ctx sdk.Context, req abci.RequestQuery, keeper Keeper) ([]byte, error) {
// Get params // Get params
params := keeper.GetParams(ctx) params := keeper.GetParams(ctx)
// Encode results // Encode results
bz, err := codec.MarshalJSONIndent(keeper.cdc, params) bz, err := codec.MarshalJSONIndent(types.ModuleCdc, params)
if err != nil { if err != nil {
return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", err.Error())) return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
} }
return bz, nil return bz, nil
} }

View File

@ -5,6 +5,7 @@ import (
"github.com/cosmos/cosmos-sdk/store/prefix" "github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported" supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported"
@ -13,10 +14,10 @@ import (
) )
// DistributeSavingsRate distributes surplus that has accumulated in the liquidator account to address holding stable coins according the the savings rate // DistributeSavingsRate distributes surplus that has accumulated in the liquidator account to address holding stable coins according the the savings rate
func (k Keeper) DistributeSavingsRate(ctx sdk.Context, debtDenom string) sdk.Error { func (k Keeper) DistributeSavingsRate(ctx sdk.Context, debtDenom string) error {
dp, found := k.GetDebtParam(ctx, debtDenom) dp, found := k.GetDebtParam(ctx, debtDenom)
if !found { if !found {
return types.ErrDebtNotSupported(k.codespace, debtDenom) return sdkerrors.Wrap(types.ErrDebtNotSupported, debtDenom)
} }
savingsRateMacc := k.supplyKeeper.GetModuleAccount(ctx, types.SavingsRateMacc) savingsRateMacc := k.supplyKeeper.GetModuleAccount(ctx, types.SavingsRateMacc)
surplusToDistribute := savingsRateMacc.GetCoins().AmountOf(dp.Denom) surplusToDistribute := savingsRateMacc.GetCoins().AmountOf(dp.Denom)
@ -27,7 +28,7 @@ func (k Keeper) DistributeSavingsRate(ctx sdk.Context, debtDenom string) sdk.Err
modAccountCoins := k.getModuleAccountCoins(ctx, dp.Denom) modAccountCoins := k.getModuleAccountCoins(ctx, dp.Denom)
totalSupplyLessModAccounts := k.supplyKeeper.GetSupply(ctx).GetTotal().Sub(modAccountCoins) totalSupplyLessModAccounts := k.supplyKeeper.GetSupply(ctx).GetTotal().Sub(modAccountCoins)
surplusDistributed := sdk.ZeroInt() surplusDistributed := sdk.ZeroInt()
var iterationErr sdk.Error var iterationErr error
k.accountKeeper.IterateAccounts(ctx, func(acc authexported.Account) (stop bool) { k.accountKeeper.IterateAccounts(ctx, func(acc authexported.Account) (stop bool) {
_, ok := acc.(supplyexported.ModuleAccountI) _, ok := acc.(supplyexported.ModuleAccountI)
if ok { if ok {

View File

@ -15,13 +15,13 @@ import (
// 3. moves debt coins from the cdp module to the liquidator module account, // 3. moves debt coins from the cdp module to the liquidator module account,
// 4. decrements the total amount of principal outstanding for that collateral type // 4. decrements the total amount of principal outstanding for that collateral type
// (this is the equivalent of saying that fees are no longer accumulated by a cdp once it gets liquidated) // (this is the equivalent of saying that fees are no longer accumulated by a cdp once it gets liquidated)
func (k Keeper) SeizeCollateral(ctx sdk.Context, cdp types.CDP) sdk.Error { func (k Keeper) SeizeCollateral(ctx sdk.Context, cdp types.CDP) error {
// Calculate the previous collateral ratio // Calculate the previous collateral ratio
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees)) oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
// Update fees // Update fees
periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix())) periods := sdk.NewInt(ctx.BlockTime().Unix()).Sub(sdk.NewInt(cdp.FeesUpdated.Unix()))
fees := k.CalculateFees(ctx, cdp.Principal.Add(cdp.AccumulatedFees), periods, cdp.Collateral[0].Denom) fees := k.CalculateFees(ctx, cdp.Principal.Add(cdp.AccumulatedFees...), periods, cdp.Collateral[0].Denom)
cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees) cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees...)
cdp.FeesUpdated = ctx.BlockTime() cdp.FeesUpdated = ctx.BlockTime()
// Move debt coins from cdp to liquidator account // Move debt coins from cdp to liquidator account
@ -70,7 +70,7 @@ func (k Keeper) SeizeCollateral(ctx sdk.Context, cdp types.CDP) sdk.Error {
coinsToDecrement := sdk.NewCoins(dc) coinsToDecrement := sdk.NewCoins(dc)
if feeAmount.IsPositive() { if feeAmount.IsPositive() {
feeCoins := sdk.NewCoins(sdk.NewCoin(dc.Denom, feeAmount)) feeCoins := sdk.NewCoins(sdk.NewCoin(dc.Denom, feeAmount))
coinsToDecrement = coinsToDecrement.Add(feeCoins) coinsToDecrement = coinsToDecrement.Add(feeCoins...)
} }
k.DecrementTotalPrincipal(ctx, cdp.Collateral[0].Denom, coinsToDecrement) k.DecrementTotalPrincipal(ctx, cdp.Collateral[0].Denom, coinsToDecrement)
} }
@ -100,11 +100,11 @@ func (k Keeper) HandleNewDebt(ctx sdk.Context, collateralDenom string, principal
k.MintDebtCoins(ctx, types.ModuleName, k.GetDebtDenom(ctx), newFees) k.MintDebtCoins(ctx, types.ModuleName, k.GetDebtDenom(ctx), newFees)
k.supplyKeeper.MintCoins(ctx, types.LiquidatorMacc, sdk.NewCoins(sdk.NewCoin(principalDenom, newFeesSurplus))) k.supplyKeeper.MintCoins(ctx, types.LiquidatorMacc, sdk.NewCoins(sdk.NewCoin(principalDenom, newFeesSurplus)))
k.supplyKeeper.MintCoins(ctx, types.SavingsRateMacc, sdk.NewCoins(sdk.NewCoin(principalDenom, newFeesSavings))) k.supplyKeeper.MintCoins(ctx, types.SavingsRateMacc, sdk.NewCoins(sdk.NewCoin(principalDenom, newFeesSavings)))
k.SetTotalPrincipal(ctx, collateralDenom, principalDenom, feeCoins.Add(newFees).AmountOf(principalDenom)) k.SetTotalPrincipal(ctx, collateralDenom, principalDenom, feeCoins.Add(newFees...).AmountOf(principalDenom))
} }
// LiquidateCdps seizes collateral from all CDPs below the input liquidation ratio // LiquidateCdps seizes collateral from all CDPs below the input liquidation ratio
func (k Keeper) LiquidateCdps(ctx sdk.Context, marketID string, denom string, liquidationRatio sdk.Dec) sdk.Error { func (k Keeper) LiquidateCdps(ctx sdk.Context, marketID string, denom string, liquidationRatio sdk.Dec) error {
price, err := k.pricefeedKeeper.GetCurrentPrice(ctx, marketID) price, err := k.pricefeedKeeper.GetCurrentPrice(ctx, marketID)
if err != nil { if err != nil {
return err return err

View File

@ -1,6 +1,7 @@
package keeper_test package keeper_test
import ( import (
"errors"
"math/rand" "math/rand"
"testing" "testing"
"time" "time"
@ -145,7 +146,7 @@ func (suite *SeizeTestSuite) TestSeizeCollateral() {
acc := ak.GetAccount(suite.ctx, suite.addrs[1]) acc := ak.GetAccount(suite.ctx, suite.addrs[1])
suite.Equal(p.Int64(), acc.GetCoins().AmountOf("usdx").Int64()) suite.Equal(p.Int64(), acc.GetCoins().AmountOf("usdx").Int64())
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[1], suite.addrs[1], cs(c("xrp", 10))) err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[1], suite.addrs[1], cs(c("xrp", 10)))
suite.Equal(types.CodeCdpNotFound, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrCdpNotFound))
} }
func (suite *SeizeTestSuite) TestSeizeCollateralMultiDeposit() { func (suite *SeizeTestSuite) TestSeizeCollateralMultiDeposit() {
@ -170,7 +171,7 @@ func (suite *SeizeTestSuite) TestSeizeCollateralMultiDeposit() {
acc := ak.GetAccount(suite.ctx, suite.addrs[1]) acc := ak.GetAccount(suite.ctx, suite.addrs[1])
suite.Equal(p.Int64(), acc.GetCoins().AmountOf("usdx").Int64()) suite.Equal(p.Int64(), acc.GetCoins().AmountOf("usdx").Int64())
err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[1], suite.addrs[1], cs(c("xrp", 10))) err = suite.keeper.WithdrawCollateral(suite.ctx, suite.addrs[1], suite.addrs[1], cs(c("xrp", 10)))
suite.Equal(types.CodeCdpNotFound, err.Result().Code) suite.Require().True(errors.Is(err, types.ErrCdpNotFound))
} }
func (suite *SeizeTestSuite) TestLiquidateCdps() { func (suite *SeizeTestSuite) TestLiquidateCdps() {

View File

@ -11,6 +11,7 @@ import (
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/auth"
sim "github.com/cosmos/cosmos-sdk/x/simulation" sim "github.com/cosmos/cosmos-sdk/x/simulation"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
@ -22,7 +23,7 @@ import (
var ( var (
_ module.AppModule = AppModule{} _ module.AppModule = AppModule{}
_ module.AppModuleBasic = AppModuleBasic{} _ module.AppModuleBasic = AppModuleBasic{}
_ module.AppModuleSimulation = AppModuleSimulation{} _ module.AppModuleSimulation = AppModule{}
) )
// AppModuleBasic app module basics object // AppModuleBasic app module basics object
@ -70,41 +71,22 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command {
//____________________________________________________________________________ //____________________________________________________________________________
// AppModuleSimulation defines the module simulation functions used by the cdp module.
type AppModuleSimulation struct{}
// RegisterStoreDecoder registers a decoder for cdp module's types
func (AppModuleSimulation) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
sdr[StoreKey] = simulation.DecodeStore
}
// GenerateGenesisState creates a randomized GenState of the cdp module
func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) {
simulation.RandomizedGenState(simState)
}
// RandomizedParams creates randomized cdp param changes for the simulator.
func (AppModuleSimulation) RandomizedParams(r *rand.Rand) []sim.ParamChange {
return simulation.ParamChanges(r)
}
//____________________________________________________________________________
// AppModule app module type // AppModule app module type
type AppModule struct { type AppModule struct {
AppModuleBasic AppModuleBasic
AppModuleSimulation
keeper Keeper keeper Keeper
accountKeeper auth.AccountKeeper
pricefeedKeeper PricefeedKeeper pricefeedKeeper PricefeedKeeper
supplyKeeper SupplyKeeper supplyKeeper SupplyKeeper
} }
// NewAppModule creates a new AppModule object // NewAppModule creates a new AppModule object
func NewAppModule(keeper Keeper, pricefeedKeeper PricefeedKeeper, supplyKeeper SupplyKeeper) AppModule { func NewAppModule(keeper Keeper, accountKeeper auth.AccountKeeper, pricefeedKeeper PricefeedKeeper, supplyKeeper SupplyKeeper) AppModule {
return AppModule{ return AppModule{
AppModuleBasic: AppModuleBasic{}, AppModuleBasic: AppModuleBasic{},
keeper: keeper, keeper: keeper,
accountKeeper: accountKeeper,
pricefeedKeeper: pricefeedKeeper, pricefeedKeeper: pricefeedKeeper,
supplyKeeper: supplyKeeper, supplyKeeper: supplyKeeper,
} }
@ -162,3 +144,30 @@ func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {
func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate { func (am AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
return []abci.ValidatorUpdate{} return []abci.ValidatorUpdate{}
} }
//____________________________________________________________________________
// GenerateGenesisState creates a randomized GenState of the cdp module
func (AppModuleBasic) GenerateGenesisState(simState *module.SimulationState) {
simulation.RandomizedGenState(simState)
}
// ProposalContents doesn't return any content functions for governance proposals.
func (AppModuleBasic) ProposalContents(_ module.SimulationState) []sim.WeightedProposalContent {
return nil
}
// RandomizedParams returns nil because cdp has no params.
func (AppModuleBasic) RandomizedParams(r *rand.Rand) []sim.ParamChange {
return simulation.ParamChanges(r)
}
// RegisterStoreDecoder registers a decoder for cdp module's types
func (AppModuleBasic) RegisterStoreDecoder(sdr sdk.StoreDecoderRegistry) {
sdr[StoreKey] = simulation.DecodeStore
}
// WeightedOperations returns the all the cdp module operations with their respective weights.
func (am AppModule) WeightedOperations(simState module.SimulationState) []sim.WeightedOperation {
return simulation.WeightedOperations(simState.AppParams, simState.Cdc, am.accountKeeper, am.keeper, am.pricefeedKeeper)
}

View File

@ -6,15 +6,16 @@ import (
"fmt" "fmt"
"time" "time"
"github.com/tendermint/tendermint/libs/kv"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/kava-labs/kava/x/cdp/types" "github.com/kava-labs/kava/x/cdp/types"
) )
// DecodeStore unmarshals the KVPair's Value to the corresponding cdp type // DecodeStore unmarshals the KVPair's Value to the corresponding cdp type
func DecodeStore(cdc *codec.Codec, kvA, kvB cmn.KVPair) string { func DecodeStore(cdc *codec.Codec, kvA, kvB kv.Pair) string {
switch { switch {
case bytes.Equal(kvA.Key[:1], types.CdpIDKeyPrefix): case bytes.Equal(kvA.Key[:1], types.CdpIDKeyPrefix):
var cdpIDsA, cdpIDsB []uint64 var cdpIDsA, cdpIDsB []uint64

View File

@ -6,8 +6,7 @@ import (
"time" "time"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/libs/kv"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
@ -34,17 +33,17 @@ func TestDecodeDistributionStore(t *testing.T) {
prevDistTime := time.Now().UTC() prevDistTime := time.Now().UTC()
cdp := types.CDP{ID: 1, FeesUpdated: prevDistTime, Collateral: oneCoins, Principal: oneCoins, AccumulatedFees: oneCoins} cdp := types.CDP{ID: 1, FeesUpdated: prevDistTime, Collateral: oneCoins, Principal: oneCoins, AccumulatedFees: oneCoins}
kvPairs := cmn.KVPairs{ kvPairs := kv.Pairs{
cmn.KVPair{Key: types.CdpIDKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(cdpIds)}, kv.Pair{Key: types.CdpIDKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(cdpIds)},
cmn.KVPair{Key: types.CdpKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(cdp)}, kv.Pair{Key: types.CdpKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(cdp)},
cmn.KVPair{Key: types.CdpIDKey, Value: sdk.Uint64ToBigEndian(2)}, kv.Pair{Key: types.CdpIDKey, Value: sdk.Uint64ToBigEndian(2)},
cmn.KVPair{Key: types.CollateralRatioIndexPrefix, Value: sdk.Uint64ToBigEndian(10)}, kv.Pair{Key: types.CollateralRatioIndexPrefix, Value: sdk.Uint64ToBigEndian(10)},
cmn.KVPair{Key: []byte(types.DebtDenomKey), Value: cdc.MustMarshalBinaryLengthPrefixed(denom)}, kv.Pair{Key: []byte(types.DebtDenomKey), Value: cdc.MustMarshalBinaryLengthPrefixed(denom)},
cmn.KVPair{Key: []byte(types.GovDenomKey), Value: cdc.MustMarshalBinaryLengthPrefixed(denom)}, kv.Pair{Key: []byte(types.GovDenomKey), Value: cdc.MustMarshalBinaryLengthPrefixed(denom)},
cmn.KVPair{Key: []byte(types.DepositKeyPrefix), Value: cdc.MustMarshalBinaryLengthPrefixed(deposit)}, kv.Pair{Key: []byte(types.DepositKeyPrefix), Value: cdc.MustMarshalBinaryLengthPrefixed(deposit)},
cmn.KVPair{Key: []byte(types.PrincipalKeyPrefix), Value: cdc.MustMarshalBinaryLengthPrefixed(principal)}, kv.Pair{Key: []byte(types.PrincipalKeyPrefix), Value: cdc.MustMarshalBinaryLengthPrefixed(principal)},
cmn.KVPair{Key: []byte(types.PreviousBlockTimeKey), Value: cdc.MustMarshalBinaryLengthPrefixed(prevDistTime)}, kv.Pair{Key: []byte(types.PreviousBlockTimeKey), Value: cdc.MustMarshalBinaryLengthPrefixed(prevDistTime)},
cmn.KVPair{Key: []byte{0x99}, Value: []byte{0x99}}, kv.Pair{Key: []byte{0x99}, Value: []byte{0x99}},
} }
tests := []struct { tests := []struct {

View File

@ -9,7 +9,7 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth"
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
"github.com/cosmos/cosmos-sdk/x/supply" "github.com/cosmos/cosmos-sdk/x/supply"
supplyExported "github.com/cosmos/cosmos-sdk/x/supply/exported" supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported"
"github.com/kava-labs/kava/x/cdp/types" "github.com/kava-labs/kava/x/cdp/types"
) )
@ -23,7 +23,7 @@ func RandomizedGenState(simState *module.SimulationState) {
simState.Cdc.MustUnmarshalJSON(simState.GenState[auth.ModuleName], &authGenesis) simState.Cdc.MustUnmarshalJSON(simState.GenState[auth.ModuleName], &authGenesis)
totalCdpCoins := sdk.NewCoins() totalCdpCoins := sdk.NewCoins()
for _, acc := range authGenesis.Accounts { for _, acc := range authGenesis.Accounts {
_, ok := acc.(supplyExported.ModuleAccountI) _, ok := acc.(supplyexported.ModuleAccountI)
if ok { if ok {
continue continue
} }
@ -33,18 +33,18 @@ func RandomizedGenState(simState *module.SimulationState) {
sdk.NewCoin("btc", sdk.NewInt(int64(simState.Rand.Intn(500000000)))), sdk.NewCoin("btc", sdk.NewInt(int64(simState.Rand.Intn(500000000)))),
sdk.NewCoin("usdx", sdk.NewInt(int64(simState.Rand.Intn(1000000000)))), sdk.NewCoin("usdx", sdk.NewInt(int64(simState.Rand.Intn(1000000000)))),
) )
err := acc.SetCoins(acc.GetCoins().Add(coinsToAdd)) err := acc.SetCoins(acc.GetCoins().Add(coinsToAdd...))
if err != nil { if err != nil {
panic(err) panic(err)
} }
totalCdpCoins = totalCdpCoins.Add(coinsToAdd) totalCdpCoins = totalCdpCoins.Add(coinsToAdd...)
authGenesis.Accounts = replaceOrAppendAccount(authGenesis.Accounts, acc) authGenesis.Accounts = replaceOrAppendAccount(authGenesis.Accounts, acc)
} }
simState.GenState[auth.ModuleName] = simState.Cdc.MustMarshalJSON(authGenesis) simState.GenState[auth.ModuleName] = simState.Cdc.MustMarshalJSON(authGenesis)
var supplyGenesis supply.GenesisState var supplyGenesis supply.GenesisState
simState.Cdc.MustUnmarshalJSON(simState.GenState[supply.ModuleName], &supplyGenesis) simState.Cdc.MustUnmarshalJSON(simState.GenState[supply.ModuleName], &supplyGenesis)
supplyGenesis.Supply = supplyGenesis.Supply.Add(totalCdpCoins) supplyGenesis.Supply = supplyGenesis.Supply.Add(totalCdpCoins...)
simState.GenState[supply.ModuleName] = simState.Cdc.MustMarshalJSON(supplyGenesis) simState.GenState[supply.ModuleName] = simState.Cdc.MustMarshalJSON(supplyGenesis)
fmt.Printf("Selected randomly generated %s parameters:\n%s\n", types.ModuleName, codec.MustMarshalJSONIndent(simState.Cdc, cdpGenesis)) fmt.Printf("Selected randomly generated %s parameters:\n%s\n", types.ModuleName, codec.MustMarshalJSONIndent(simState.Cdc, cdpGenesis))

View File

@ -1,48 +1,86 @@
package operations package simulation
import ( import (
"fmt"
"math/rand" "math/rand"
"github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/simapp/helpers"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/auth"
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
"github.com/cosmos/cosmos-sdk/x/simulation" "github.com/cosmos/cosmos-sdk/x/simulation"
"github.com/kava-labs/kava/x/cdp"
"github.com/kava-labs/kava/x/pricefeed" appparams "github.com/kava-labs/kava/app/params"
"github.com/kava-labs/kava/x/cdp/keeper"
"github.com/kava-labs/kava/x/cdp/types"
) )
// SimulateMsgCdp generates a MsgCreateCdp or MsgDepositCdp with random values. // Simulation operation weights constants
func SimulateMsgCdp(ak auth.AccountKeeper, k cdp.Keeper, pfk pricefeed.Keeper) simulation.Operation { const (
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account) ( OpWeightMsgCdp = "op_weight_msg_cdp"
opMsg simulation.OperationMsg, fOps []simulation.FutureOperation, err error) { )
handler := cdp.NewHandler(k) // WeightedOperations returns all the operations from the module with their respective weights
simacc := simulation.RandomAcc(r, accs) func WeightedOperations(
acc := ak.GetAccount(ctx, simacc.Address) appParams simulation.AppParams, cdc *codec.Codec, ak auth.AccountKeeper,
if acc == nil { k keeper.Keeper, pfk types.PricefeedKeeper,
return simulation.NoOpMsg(cdp.ModuleName), nil, nil ) simulation.WeightedOperations {
var weightMsgCdp int
appParams.GetOrGenerate(cdc, OpWeightMsgCdp, &weightMsgCdp, nil,
func(_ *rand.Rand) {
weightMsgCdp = appparams.DefaultWeightMsgCdp
},
)
return simulation.WeightedOperations{
simulation.NewWeightedOperation(
weightMsgCdp,
SimulateMsgCdp(ak, k, pfk),
),
} }
}
// SimulateMsgCdp generates a MsgCreateCdp or MsgDepositCdp with random values.
func SimulateMsgCdp(ak auth.AccountKeeper, k keeper.Keeper, pfk types.PricefeedKeeper) simulation.Operation {
return func(
r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account, chainID string,
) (simulation.OperationMsg, []simulation.FutureOperation, error) {
simAccount, _ := simulation.RandomAcc(r, accs)
acc := ak.GetAccount(ctx, simAccount.Address)
if acc == nil {
return simulation.NoOpMsg(types.ModuleName), nil, nil
}
coins := acc.GetCoins() coins := acc.GetCoins()
collateralParams := k.GetParams(ctx).CollateralParams collateralParams := k.GetParams(ctx).CollateralParams
if len(collateralParams) == 0 { if len(collateralParams) == 0 {
return simulation.NoOpMsg(cdp.ModuleName), nil, nil return simulation.NoOpMsg(types.ModuleName), nil, nil
} }
randCollateralParam := collateralParams[r.Intn(len(collateralParams))] randCollateralParam := collateralParams[r.Intn(len(collateralParams))]
randDebtAsset := randCollateralParam.DebtLimit[r.Intn(len(randCollateralParam.DebtLimit))] randDebtAsset := randCollateralParam.DebtLimit[r.Intn(len(randCollateralParam.DebtLimit))]
randDebtParam, _ := k.GetDebtParam(ctx, randDebtAsset.Denom) randDebtParam, _ := k.GetDebtParam(ctx, randDebtAsset.Denom)
if coins.AmountOf(randCollateralParam.Denom).IsZero() { if coins.AmountOf(randCollateralParam.Denom).IsZero() {
return simulation.NoOpMsg(cdp.ModuleName), nil, nil return simulation.NoOpMsg(types.ModuleName), nil, nil
} }
price, err := pfk.GetCurrentPrice(ctx, randCollateralParam.MarketID) price, err := pfk.GetCurrentPrice(ctx, randCollateralParam.MarketID)
if err != nil { if err != nil {
return simulation.NoOpMsg(cdp.ModuleName), nil, err return simulation.NoOpMsg(types.ModuleName), nil, err
} }
// convert the price to the same units as the debt param // convert the price to the same units as the debt param
priceShifted := ShiftDec(price.Price, randDebtParam.ConversionFactor) priceShifted := ShiftDec(price.Price, randDebtParam.ConversionFactor)
spendableCoins := acc.SpendableCoins(ctx.BlockTime())
fees, err := simulation.RandomFees(r, ctx, spendableCoins)
if err != nil {
return simulation.NoOpMsg(types.ModuleName), nil, err
}
spendableCoins = spendableCoins.Sub(fees)
existingCDP, found := k.GetCdpByOwnerAndDenom(ctx, acc.GetAddress(), randCollateralParam.Denom) existingCDP, found := k.GetCdpByOwnerAndDenom(ctx, acc.GetAddress(), randCollateralParam.Denom)
if !found { if !found {
// calculate the minimum amount of collateral that is needed to create a cdp with the debt floor amount of debt and the minimum liquidation ratio // calculate the minimum amount of collateral that is needed to create a cdp with the debt floor amount of debt and the minimum liquidation ratio
@ -52,12 +90,12 @@ func SimulateMsgCdp(ak auth.AccountKeeper, k cdp.Keeper, pfk pricefeed.Keeper) s
minCollateralDeposit = ShiftDec(minCollateralDeposit, randCollateralParam.ConversionFactor) minCollateralDeposit = ShiftDec(minCollateralDeposit, randCollateralParam.ConversionFactor)
// convert to integer and always round up // convert to integer and always round up
minCollateralDepositRounded := minCollateralDeposit.TruncateInt().Add(sdk.OneInt()) minCollateralDepositRounded := minCollateralDeposit.TruncateInt().Add(sdk.OneInt())
if coins.AmountOf(randCollateralParam.Denom).LT(minCollateralDepositRounded) { if spendableCoins.AmountOf(randCollateralParam.Denom).LT(minCollateralDepositRounded) {
// account doesn't have enough funds to open a cdp for the min debt amount // account doesn't have enough funds to open a cdp for the min debt amount
return simulation.NewOperationMsgBasic(cdp.ModuleName, "no-operation", "insufficient funds to open cdp", false, nil), nil, nil return simulation.NewOperationMsgBasic(types.ModuleName, "no-operation", "insufficient funds to open cdp", false, nil), nil, nil
} }
// set the max collateral deposit to the amount of coins in the account // set the max collateral deposit to the amount of coins in the account
maxCollateralDeposit := coins.AmountOf(randCollateralParam.Denom) maxCollateralDeposit := spendableCoins.AmountOf(randCollateralParam.Denom)
// randomly select a collateral deposit amount // randomly select a collateral deposit amount
collateralDeposit := sdk.NewInt(int64(simulation.RandIntBetween(r, int(minCollateralDepositRounded.Int64()), int(maxCollateralDeposit.Int64())))) collateralDeposit := sdk.NewInt(int64(simulation.RandIntBetween(r, int(minCollateralDepositRounded.Int64()), int(maxCollateralDeposit.Int64()))))
@ -69,53 +107,78 @@ func SimulateMsgCdp(ak auth.AccountKeeper, k cdp.Keeper, pfk pricefeed.Keeper) s
availableAssetDebt := randCollateralParam.DebtLimit.AmountOf(randDebtParam.Denom).Sub(k.GetTotalPrincipal(ctx, randCollateralParam.Denom, randDebtParam.Denom)) availableAssetDebt := randCollateralParam.DebtLimit.AmountOf(randDebtParam.Denom).Sub(k.GetTotalPrincipal(ctx, randCollateralParam.Denom, randDebtParam.Denom))
if availableAssetDebt.LTE(randDebtParam.DebtFloor) { if availableAssetDebt.LTE(randDebtParam.DebtFloor) {
// debt limit has been reached // debt limit has been reached
return simulation.NewOperationMsgBasic(cdp.ModuleName, "no-operation", "debt limit reached, cannot open cdp", false, nil), nil, nil return simulation.NewOperationMsgBasic(types.ModuleName, "no-operation", "debt limit reached, cannot open cdp", false, nil), nil, nil
} }
// ensure that the debt draw does not exceed the debt limit // ensure that the debt draw does not exceed the debt limit
maxDebtDraw = sdk.MinInt(maxDebtDraw, availableAssetDebt) maxDebtDraw = sdk.MinInt(maxDebtDraw, availableAssetDebt)
// randomly select a debt draw amount // randomly select a debt draw amount
debtDraw := sdk.NewInt(int64(simulation.RandIntBetween(r, int(randDebtParam.DebtFloor.Int64()), int(maxDebtDraw.Int64())))) debtDraw := sdk.NewInt(int64(simulation.RandIntBetween(r, int(randDebtParam.DebtFloor.Int64()), int(maxDebtDraw.Int64()))))
msg := cdp.NewMsgCreateCDP(acc.GetAddress(), sdk.NewCoins(sdk.NewCoin(randCollateralParam.Denom, collateralDeposit)), sdk.NewCoins(sdk.NewCoin(randDebtParam.Denom, debtDraw)))
err := msg.ValidateBasic() msg := types.NewMsgCreateCDP(acc.GetAddress(), sdk.NewCoins(sdk.NewCoin(randCollateralParam.Denom, collateralDeposit)), sdk.NewCoins(sdk.NewCoin(randDebtParam.Denom, debtDraw)))
tx := helpers.GenTx(
[]sdk.Msg{msg},
fees,
helpers.DefaultGenTxGas,
chainID,
[]uint64{acc.GetAccountNumber()},
[]uint64{acc.GetSequence()},
simAccount.PrivKey,
)
_, result, err := app.Deliver(tx)
if err != nil { if err != nil {
return simulation.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("expected msg to pass ValidateBasic: %v", err) return simulation.NoOpMsg(types.ModuleName), nil, err
} }
ok := submitMsg(msg, handler, ctx)
if !ok { return simulation.NewOperationMsg(msg, true, result.Log), nil, nil
return simulation.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("could not submit create cdp msg")
}
return simulation.NewOperationMsg(msg, ok, "create cdp"), nil, nil
} }
// a cdp already exists, deposit to it, draw debt from it, or repay debt to it // a cdp already exists, deposit to it, draw debt from it, or repay debt to it
// close 25% of the time // close 25% of the time
if canClose(acc, existingCDP, randDebtParam.Denom) && shouldClose(r) { if canClose(acc, existingCDP, randDebtParam.Denom) && shouldClose(r) {
repaymentAmount := coins.AmountOf(randDebtParam.Denom) repaymentAmount := spendableCoins.AmountOf(randDebtParam.Denom)
msg := cdp.NewMsgRepayDebt(acc.GetAddress(), randCollateralParam.Denom, sdk.NewCoins(sdk.NewCoin(randDebtParam.Denom, repaymentAmount))) msg := types.NewMsgRepayDebt(acc.GetAddress(), randCollateralParam.Denom, sdk.NewCoins(sdk.NewCoin(randDebtParam.Denom, repaymentAmount)))
err := msg.ValidateBasic()
tx := helpers.GenTx(
[]sdk.Msg{msg},
fees,
helpers.DefaultGenTxGas,
chainID,
[]uint64{acc.GetAccountNumber()},
[]uint64{acc.GetSequence()},
simAccount.PrivKey,
)
_, result, err := app.Deliver(tx)
if err != nil { if err != nil {
return simulation.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("expected repay (close) msg to pass ValidateBasic: %v", err) return simulation.NoOpMsg(types.ModuleName), nil, err
} }
ok := submitMsg(msg, handler, ctx)
if !ok { return simulation.NewOperationMsg(msg, true, result.Log), nil, nil
return simulation.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("could not submit repay (close) msg")
}
return simulation.NewOperationMsg(msg, ok, "repay debt (close) cdp"), nil, nil
} }
// deposit 25% of the time // deposit 25% of the time
if hasCoins(acc, randCollateralParam.Denom) && shouldDeposit(r) { if hasCoins(acc, randCollateralParam.Denom) && shouldDeposit(r) {
randDepositAmount := sdk.NewInt(int64(simulation.RandIntBetween(r, 1, int(acc.GetCoins().AmountOf(randCollateralParam.Denom).Int64())))) randDepositAmount := sdk.NewInt(int64(simulation.RandIntBetween(r, 1, int(spendableCoins.AmountOf(randCollateralParam.Denom).Int64()))))
msg := cdp.NewMsgDeposit(acc.GetAddress(), acc.GetAddress(), sdk.NewCoins(sdk.NewCoin(randCollateralParam.Denom, randDepositAmount))) msg := types.NewMsgDeposit(acc.GetAddress(), acc.GetAddress(), sdk.NewCoins(sdk.NewCoin(randCollateralParam.Denom, randDepositAmount)))
err := msg.ValidateBasic()
tx := helpers.GenTx(
[]sdk.Msg{msg},
fees,
helpers.DefaultGenTxGas,
chainID,
[]uint64{acc.GetAccountNumber()},
[]uint64{acc.GetSequence()},
simAccount.PrivKey,
)
_, result, err := app.Deliver(tx)
if err != nil { if err != nil {
return simulation.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("expected deposit msg to pass ValidateBasic: %v", err) return simulation.NoOpMsg(types.ModuleName), nil, err
} }
ok := submitMsg(msg, handler, ctx)
if !ok { return simulation.NewOperationMsg(msg, true, result.Log), nil, nil
return simulation.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("could not submit deposit msg")
}
return simulation.NewOperationMsg(msg, ok, "deposit to cdp"), nil, nil
} }
// draw debt 25% of the time // draw debt 25% of the time
@ -130,109 +193,97 @@ func SimulateMsgCdp(ak auth.AccountKeeper, k cdp.Keeper, pfk pricefeed.Keeper) s
maxDebt := (maxTotalDebt.Sub(sdk.NewDecFromInt(debt))).Mul(sdk.MustNewDecFromStr("0.95")).TruncateInt() maxDebt := (maxTotalDebt.Sub(sdk.NewDecFromInt(debt))).Mul(sdk.MustNewDecFromStr("0.95")).TruncateInt()
if maxDebt.LTE(sdk.OneInt()) { if maxDebt.LTE(sdk.OneInt()) {
// debt in cdp is maxed out // debt in cdp is maxed out
return simulation.NewOperationMsgBasic(cdp.ModuleName, "no-operation", "cdp debt maxed out, cannot draw more debt", false, nil), nil, nil return simulation.NewOperationMsgBasic(types.ModuleName, "no-operation", "cdp debt maxed out, cannot draw more debt", false, nil), nil, nil
} }
// check if the debt limit has been reached // check if the debt limit has been reached
availableAssetDebt := randCollateralParam.DebtLimit.AmountOf(randDebtParam.Denom).Sub(k.GetTotalPrincipal(ctx, randCollateralParam.Denom, randDebtParam.Denom)) availableAssetDebt := randCollateralParam.DebtLimit.AmountOf(randDebtParam.Denom).Sub(k.GetTotalPrincipal(ctx, randCollateralParam.Denom, randDebtParam.Denom))
if availableAssetDebt.LTE(sdk.OneInt()) { if availableAssetDebt.LTE(sdk.OneInt()) {
// debt limit has been reached // debt limit has been reached
return simulation.NewOperationMsgBasic(cdp.ModuleName, "no-operation", "debt limit reached, cannot draw more debt", false, nil), nil, nil return simulation.NewOperationMsgBasic(types.ModuleName, "no-operation", "debt limit reached, cannot draw more debt", false, nil), nil, nil
} }
maxDraw := sdk.MinInt(maxDebt, availableAssetDebt) maxDraw := sdk.MinInt(maxDebt, availableAssetDebt)
randDrawAmount := sdk.NewInt(int64(simulation.RandIntBetween(r, 1, int(maxDraw.Int64())))) randDrawAmount := sdk.NewInt(int64(simulation.RandIntBetween(r, 1, int(maxDraw.Int64()))))
msg := cdp.NewMsgDrawDebt(acc.GetAddress(), randCollateralParam.Denom, sdk.NewCoins(sdk.NewCoin(randDebtParam.Denom, randDrawAmount))) msg := types.NewMsgDrawDebt(acc.GetAddress(), randCollateralParam.Denom, sdk.NewCoins(sdk.NewCoin(randDebtParam.Denom, randDrawAmount)))
err := msg.ValidateBasic()
if err != nil {
return simulation.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("expected draw msg to pass ValidateBasic: %v", err)
}
ok := submitMsg(msg, handler, ctx)
if !ok {
return simulation.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("could not submit draw msg")
}
return simulation.NewOperationMsg(msg, ok, "draw debt from cdp"), nil, nil
tx := helpers.GenTx(
[]sdk.Msg{msg},
fees,
helpers.DefaultGenTxGas,
chainID,
[]uint64{acc.GetAccountNumber()},
[]uint64{acc.GetSequence()},
simAccount.PrivKey,
)
_, result, err := app.Deliver(tx)
if err != nil {
return simulation.NoOpMsg(types.ModuleName), nil, err
}
return simulation.NewOperationMsg(msg, true, result.Log), nil, nil
} }
// repay debt 25% of the time // repay debt 25% of the time
if hasCoins(acc, randDebtParam.Denom) { if hasCoins(acc, randDebtParam.Denom) {
debt := existingCDP.Principal.AmountOf(randDebtParam.Denom) debt := existingCDP.Principal.AmountOf(randDebtParam.Denom)
maxRepay := acc.GetCoins().AmountOf(randDebtParam.Denom) maxRepay := spendableCoins.AmountOf(randDebtParam.Denom)
payableDebt := debt.Sub(randDebtParam.DebtFloor) payableDebt := debt.Sub(randDebtParam.DebtFloor)
if maxRepay.GT(payableDebt) { if maxRepay.GT(payableDebt) {
maxRepay = payableDebt maxRepay = payableDebt
} }
randRepayAmount := sdk.NewInt(int64(simulation.RandIntBetween(r, 1, int(maxRepay.Int64())))) randRepayAmount := sdk.NewInt(int64(simulation.RandIntBetween(r, 1, int(maxRepay.Int64()))))
if debt.Equal(randDebtParam.DebtFloor) { if debt.Equal(randDebtParam.DebtFloor) && spendableCoins.AmountOf(randDebtParam.Denom).GTE(debt) {
if acc.GetCoins().AmountOf(randDebtParam.Denom).GTE(debt) {
randRepayAmount = debt randRepayAmount = debt
} }
}
msg := cdp.NewMsgRepayDebt(acc.GetAddress(), randCollateralParam.Denom, sdk.NewCoins(sdk.NewCoin(randDebtParam.Denom, randRepayAmount))) msg := types.NewMsgRepayDebt(acc.GetAddress(), randCollateralParam.Denom, sdk.NewCoins(sdk.NewCoin(randDebtParam.Denom, randRepayAmount)))
err := msg.ValidateBasic()
tx := helpers.GenTx(
[]sdk.Msg{msg},
fees,
helpers.DefaultGenTxGas,
chainID,
[]uint64{acc.GetAccountNumber()},
[]uint64{acc.GetSequence()},
simAccount.PrivKey,
)
_, result, err := app.Deliver(tx)
if err != nil { if err != nil {
return simulation.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("expected repay msg to pass ValidateBasic: %v", err) return simulation.NoOpMsg(types.ModuleName), nil, err
}
ok := submitMsg(msg, handler, ctx)
if !ok {
return simulation.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("could not submit repay msg")
}
return simulation.NewOperationMsg(msg, ok, "repay debt cdp"), nil, nil
} }
return simulation.NewOperationMsgBasic(cdp.ModuleName, "no-operation (no valid actions)", "", false, nil), nil, nil return simulation.NewOperationMsg(msg, true, result.Log), nil, nil
}
} }
func submitMsg(msg sdk.Msg, handler sdk.Handler, ctx sdk.Context) (ok bool) { return simulation.NoOpMsg(types.ModuleName), nil, nil
ctx, write := ctx.CacheContext()
res := handler(ctx, msg)
if res.IsOK() {
write()
} else {
fmt.Println(res.Log)
} }
return res.IsOK()
} }
func shouldDraw(r *rand.Rand) bool { func shouldDraw(r *rand.Rand) bool {
threshold := 50 threshold := 50
value := simulation.RandIntBetween(r, 1, 100) value := simulation.RandIntBetween(r, 1, 100)
if value > threshold { return value > threshold
return true
}
return false
} }
func shouldDeposit(r *rand.Rand) bool { func shouldDeposit(r *rand.Rand) bool {
threshold := 66 threshold := 66
value := simulation.RandIntBetween(r, 1, 100) value := simulation.RandIntBetween(r, 1, 100)
if value > threshold { return value > threshold
return true
}
return false
} }
func hasCoins(acc authexported.Account, denom string) bool { func hasCoins(acc authexported.Account, denom string) bool {
if acc.GetCoins().AmountOf(denom).IsZero() { return acc.GetCoins().AmountOf(denom).IsPositive()
return false
}
return true
} }
func shouldClose(r *rand.Rand) bool { func shouldClose(r *rand.Rand) bool {
threshold := 75 threshold := 75
value := simulation.RandIntBetween(r, 1, 100) value := simulation.RandIntBetween(r, 1, 100)
if value > threshold { return value > threshold
return true
}
return false
} }
func canClose(acc authexported.Account, c cdp.CDP, denom string) bool { func canClose(acc authexported.Account, c types.CDP, denom string) bool {
repaymentAmount := c.Principal.Add(c.AccumulatedFees).AmountOf(denom) repaymentAmount := c.Principal.Add(c.AccumulatedFees...).AmountOf(denom)
if acc.GetCoins().AmountOf(denom).GTE(repaymentAmount) { return acc.GetCoins().AmountOf(denom).GTE(repaymentAmount)
return true
}
return false
} }

View File

@ -1,4 +1,4 @@
package operations package simulation
import ( import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"

View File

@ -1,10 +1,10 @@
package operations_test package simulation_test
import ( import (
"testing" "testing"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/kava-labs/kava/x/cdp/simulation/operations" "github.com/kava-labs/kava/x/cdp/simulation"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -22,7 +22,7 @@ func TestShiftDec(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.value.String(), func(t *testing.T) { t.Run(tt.value.String(), func(t *testing.T) {
require.Equal(t, tt.expected, operations.ShiftDec(tt.value, tt.shift)) require.Equal(t, tt.expected, simulation.ShiftDec(tt.value, tt.shift))
}) })
} }
} }

View File

@ -1,115 +1,42 @@
// DONTCOVER
package types package types
import ( import (
"fmt" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
sdk "github.com/cosmos/cosmos-sdk/types"
) )
// Error codes specific to cdp module // DONTCOVER
const (
DefaultCodespace sdk.CodespaceType = ModuleName
CodeCdpAlreadyExists sdk.CodeType = 1
CodeCollateralLengthInvalid sdk.CodeType = 2
CodeCollateralNotSupported sdk.CodeType = 3
CodeDebtNotSupported sdk.CodeType = 4
CodeExceedsDebtLimit sdk.CodeType = 5
CodeInvalidCollateralRatio sdk.CodeType = 6
CodeCdpNotFound sdk.CodeType = 7
CodeDepositNotFound sdk.CodeType = 8
CodeInvalidDepositDenom sdk.CodeType = 9
CodeInvalidPaymentDenom sdk.CodeType = 10
CodeDepositNotAvailable sdk.CodeType = 11
CodeInvalidCollateralDenom sdk.CodeType = 12
CodeInvalidWithdrawAmount sdk.CodeType = 13
CodeCdpNotAvailable sdk.CodeType = 14
CodeBelowDebtFloor sdk.CodeType = 15
CodePaymentExceedsDebt sdk.CodeType = 16
CodeLoadingAugmentedCDP sdk.CodeType = 17
)
var (
// ErrCdpAlreadyExists error for duplicate cdps // ErrCdpAlreadyExists error for duplicate cdps
func ErrCdpAlreadyExists(codespace sdk.CodespaceType, owner sdk.AccAddress, denom string) sdk.Error { ErrCdpAlreadyExists = sdkerrors.Register(ModuleName, 2, "cdp already exists")
return sdk.NewError(codespace, CodeCdpAlreadyExists, fmt.Sprintf("cdp for owner %s and collateral %s already exists", owner, denom))
}
// ErrInvalidCollateralLength error for invalid collateral input length // ErrInvalidCollateralLength error for invalid collateral input length
func ErrInvalidCollateralLength(codespace sdk.CodespaceType, length int) sdk.Error { ErrInvalidCollateralLength = sdkerrors.Register(ModuleName, 3, "only one collateral type per cdp")
return sdk.NewError(codespace, CodeCollateralLengthInvalid, fmt.Sprintf("only one collateral type per cdp, has %d", length))
}
// ErrCollateralNotSupported error for unsupported collateral // ErrCollateralNotSupported error for unsupported collateral
func ErrCollateralNotSupported(codespace sdk.CodespaceType, denom string) sdk.Error { ErrCollateralNotSupported = sdkerrors.Register(ModuleName, 4, "collateral not supported")
return sdk.NewError(codespace, CodeCollateralNotSupported, fmt.Sprintf("collateral %s not supported", denom))
}
// ErrDebtNotSupported error for unsupported debt // ErrDebtNotSupported error for unsupported debt
func ErrDebtNotSupported(codespace sdk.CodespaceType, denom string) sdk.Error { ErrDebtNotSupported = sdkerrors.Register(ModuleName, 5, "debt not supported")
return sdk.NewError(codespace, CodeDebtNotSupported, fmt.Sprintf("collateral %s not supported", denom))
}
// ErrExceedsDebtLimit error for attempted draws that exceed debt limit // ErrExceedsDebtLimit error for attempted draws that exceed debt limit
func ErrExceedsDebtLimit(codespace sdk.CodespaceType, proposed sdk.Coins, limit sdk.Coins) sdk.Error { ErrExceedsDebtLimit = sdkerrors.Register(ModuleName, 6, "proposed debt increase would exceed debt limit")
return sdk.NewError(codespace, CodeExceedsDebtLimit, fmt.Sprintf("proposed debt increase %s would exceed debt limit of %s", proposed, limit))
}
// ErrInvalidCollateralRatio error for attempted draws that are below liquidation ratio // ErrInvalidCollateralRatio error for attempted draws that are below liquidation ratio
func ErrInvalidCollateralRatio(codespace sdk.CodespaceType, denom string, collateralRatio sdk.Dec, liquidationRatio sdk.Dec) sdk.Error { ErrInvalidCollateralRatio = sdkerrors.Register(ModuleName, 7, "proposed collateral ratio is below liquidation ratio")
return sdk.NewError(codespace, CodeInvalidCollateralRatio, fmt.Sprintf("proposed collateral ratio of %s is below liqudation ratio of %s for collateral %s", collateralRatio, liquidationRatio, denom))
}
// ErrCdpNotFound error cdp not found // ErrCdpNotFound error cdp not found
func ErrCdpNotFound(codespace sdk.CodespaceType, owner sdk.AccAddress, denom string) sdk.Error { ErrCdpNotFound = sdkerrors.Register(ModuleName, 8, "cdp not found")
return sdk.NewError(codespace, CodeCdpNotFound, fmt.Sprintf("cdp for owner %s and collateral %s not found", owner, denom))
}
// ErrDepositNotFound error for deposit not found // ErrDepositNotFound error for deposit not found
func ErrDepositNotFound(codespace sdk.CodespaceType, depositor sdk.AccAddress, cdpID uint64) sdk.Error { ErrDepositNotFound = sdkerrors.Register(ModuleName, 9, "deposit not found")
return sdk.NewError(codespace, CodeDepositNotFound, fmt.Sprintf("deposit for cdp %d not found for %s", cdpID, depositor)) // ErrInvalidDeposit error for invalid deposit
} ErrInvalidDeposit = sdkerrors.Register(ModuleName, 10, "invalid deposit")
// ErrInvalidCollateral error for invalid collateral
// ErrInvalidDepositDenom error for invalid deposit denoms ErrInvalidCollateral = sdkerrors.Register(ModuleName, 11, "collateral not supported")
func ErrInvalidDepositDenom(codespace sdk.CodespaceType, cdpID uint64, expected string, actual string) sdk.Error { // ErrInvalidPayment error for invalid payment
return sdk.NewError(codespace, CodeInvalidDepositDenom, fmt.Sprintf("invalid deposit for cdp %d, expects %s, got %s", cdpID, expected, actual)) ErrInvalidPayment = sdkerrors.Register(ModuleName, 12, "invalid payment")
}
// ErrInvalidPaymentDenom error for invalid payment denoms
func ErrInvalidPaymentDenom(codespace sdk.CodespaceType, cdpID uint64, expected []string, actual []string) sdk.Error {
return sdk.NewError(codespace, CodeInvalidPaymentDenom, fmt.Sprintf("invalid payment for cdp %d, expects %s, got %s", cdpID, expected, actual))
}
//ErrDepositNotAvailable error for withdrawing deposits in liquidation //ErrDepositNotAvailable error for withdrawing deposits in liquidation
func ErrDepositNotAvailable(codespace sdk.CodespaceType, cdpID uint64, depositor sdk.AccAddress) sdk.Error { ErrDepositNotAvailable = sdkerrors.Register(ModuleName, 13, "deposit in liquidation")
return sdk.NewError(codespace, CodeDepositNotAvailable, fmt.Sprintf("deposit from %s for cdp %d in liquidation", depositor, cdpID))
}
// ErrInvalidCollateralDenom error for invalid collateral denoms
func ErrInvalidCollateralDenom(codespace sdk.CodespaceType, denom string) sdk.Error {
return sdk.NewError(codespace, CodeInvalidDepositDenom, fmt.Sprintf("invalid denom: %s", denom))
}
// ErrInvalidWithdrawAmount error for invalid withdrawal amount // ErrInvalidWithdrawAmount error for invalid withdrawal amount
func ErrInvalidWithdrawAmount(codespace sdk.CodespaceType, withdraw sdk.Coins, deposit sdk.Coins) sdk.Error { ErrInvalidWithdrawAmount = sdkerrors.Register(ModuleName, 14, "withdrawal amount exceeds deposit")
return sdk.NewError(codespace, CodeInvalidWithdrawAmount, fmt.Sprintf("withdrawal amount of %s exceeds deposit of %s", withdraw, deposit))
}
//ErrCdpNotAvailable error for depositing to a CDP in liquidation //ErrCdpNotAvailable error for depositing to a CDP in liquidation
func ErrCdpNotAvailable(codespace sdk.CodespaceType, cdpID uint64) sdk.Error { ErrCdpNotAvailable = sdkerrors.Register(ModuleName, 15, "cannot modify cdp in liquidation")
return sdk.NewError(codespace, CodeCdpNotAvailable, fmt.Sprintf("cannot modify cdp %d, in liquidation", cdpID))
}
// ErrBelowDebtFloor error for creating a cdp with debt below the minimum // ErrBelowDebtFloor error for creating a cdp with debt below the minimum
func ErrBelowDebtFloor(codespace sdk.CodespaceType, debt sdk.Coins, floor sdk.Int) sdk.Error { ErrBelowDebtFloor = sdkerrors.Register(ModuleName, 16, "proposed cdp debt is below minimum")
return sdk.NewError(codespace, CodeBelowDebtFloor, fmt.Sprintf("proposed cdp debt of %s is below the minimum of %s", debt, floor))
}
// ErrPaymentExceedsDebt error for repayments that are greater than the debt amount
func ErrPaymentExceedsDebt(codespace sdk.CodespaceType, payment sdk.Coins, principal sdk.Coins) sdk.Error {
return sdk.NewError(codespace, CodePaymentExceedsDebt, fmt.Sprintf("payment of %s exceeds debt of %s", payment, principal))
}
// ErrLoadingAugmentedCDP error loading augmented cdp // ErrLoadingAugmentedCDP error loading augmented cdp
func ErrLoadingAugmentedCDP(codespace sdk.CodespaceType, cdpID uint64) sdk.Error { ErrLoadingAugmentedCDP = sdkerrors.Register(ModuleName, 17, "augmented cdp could not be loaded from cdp")
return sdk.NewError(codespace, CodeCdpNotFound, fmt.Sprintf("augmented cdp could not be loaded from cdp id %d", cdpID)) )
}

View File

@ -17,29 +17,29 @@ type SupplyKeeper interface {
// TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862 // TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862
SetModuleAccount(sdk.Context, supplyexported.ModuleAccountI) SetModuleAccount(sdk.Context, supplyexported.ModuleAccountI)
SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error
SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) sdk.Error SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error
BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) sdk.Error BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) error
MintCoins(ctx sdk.Context, name string, amt sdk.Coins) sdk.Error MintCoins(ctx sdk.Context, name string, amt sdk.Coins) error
GetSupply(ctx sdk.Context) (supply supplyexported.SupplyI) GetSupply(ctx sdk.Context) (supply supplyexported.SupplyI)
} }
// PricefeedKeeper defines the expected interface for the pricefeed // PricefeedKeeper defines the expected interface for the pricefeed
type PricefeedKeeper interface { type PricefeedKeeper interface {
GetCurrentPrice(sdk.Context, string) (pftypes.CurrentPrice, sdk.Error) GetCurrentPrice(sdk.Context, string) (pftypes.CurrentPrice, error)
GetParams(sdk.Context) pftypes.Params GetParams(sdk.Context) pftypes.Params
// These are used for testing TODO replace mockApp with keeper in tests to remove these // These are used for testing TODO replace mockApp with keeper in tests to remove these
SetParams(sdk.Context, pftypes.Params) SetParams(sdk.Context, pftypes.Params)
SetPrice(sdk.Context, sdk.AccAddress, string, sdk.Dec, time.Time) (pftypes.PostedPrice, sdk.Error) SetPrice(sdk.Context, sdk.AccAddress, string, sdk.Dec, time.Time) (pftypes.PostedPrice, error)
SetCurrentPrices(sdk.Context, string) sdk.Error SetCurrentPrices(sdk.Context, string) error
} }
// AuctionKeeper expected interface for the auction keeper (noalias) // AuctionKeeper expected interface for the auction keeper (noalias)
type AuctionKeeper interface { type AuctionKeeper interface {
StartSurplusAuction(ctx sdk.Context, seller string, lot sdk.Coin, bidDenom string) (uint64, sdk.Error) StartSurplusAuction(ctx sdk.Context, seller string, lot sdk.Coin, bidDenom string) (uint64, error)
StartDebtAuction(ctx sdk.Context, buyer string, bid sdk.Coin, initialLot sdk.Coin, debt sdk.Coin) (uint64, sdk.Error) StartDebtAuction(ctx sdk.Context, buyer string, bid sdk.Coin, initialLot sdk.Coin, debt sdk.Coin) (uint64, error)
StartCollateralAuction(ctx sdk.Context, seller string, lot sdk.Coin, maxBid sdk.Coin, lotReturnAddrs []sdk.AccAddress, lotReturnWeights []sdk.Int, debt sdk.Coin) (uint64, sdk.Error) StartCollateralAuction(ctx sdk.Context, seller string, lot sdk.Coin, maxBid sdk.Coin, lotReturnAddrs []sdk.AccAddress, lotReturnWeights []sdk.Int, debt sdk.Coin) (uint64, error)
} }
// AccountKeeper expected interface for the account keeper (noalias) // AccountKeeper expected interface for the account keeper (noalias)

View File

@ -1,9 +1,12 @@
package types package types
import ( import (
"errors"
"fmt" "fmt"
"strings"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
) )
// ensure Msg interface compliance at compile time // ensure Msg interface compliance at compile time
@ -38,24 +41,18 @@ func (msg MsgCreateCDP) Route() string { return RouterKey }
func (msg MsgCreateCDP) Type() string { return "create_cdp" } func (msg MsgCreateCDP) Type() string { return "create_cdp" }
// ValidateBasic does a simple validation check that doesn't require access to any other information. // ValidateBasic does a simple validation check that doesn't require access to any other information.
func (msg MsgCreateCDP) ValidateBasic() sdk.Error { func (msg MsgCreateCDP) ValidateBasic() error {
if msg.Sender.Empty() { if msg.Sender.Empty() {
return sdk.ErrInternal("invalid (empty) sender address") return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be empty")
} }
if len(msg.Collateral) != 1 { if msg.Collateral.Len() != 1 {
return sdk.ErrInvalidCoins(fmt.Sprintf("cdps do not support multiple collateral types: received %s", msg.Collateral)) return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "cdps do not support multiple collateral types: %s", msg.Collateral)
} }
if !msg.Collateral.IsValid() { if !msg.Collateral.IsValid() {
return sdk.ErrInvalidCoins(fmt.Sprintf("invalid collateral amount: %s", msg.Collateral)) return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "collateral amount %s", msg.Collateral)
} }
if !msg.Collateral.IsAllPositive() { if msg.Principal.Empty() || !msg.Principal.IsValid() {
return sdk.ErrInvalidCoins(fmt.Sprintf("negative collateral amount: %s", msg.Collateral)) return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "principal amount %s", msg.Principal)
}
if !msg.Principal.IsValid() {
return sdk.ErrInvalidCoins(fmt.Sprintf("invalid principal amount: %s", msg.Principal))
}
if !msg.Principal.IsAllPositive() {
return sdk.ErrInvalidCoins(fmt.Sprintf("negative principal amount: %s", msg.Principal))
} }
return nil return nil
} }
@ -103,21 +100,18 @@ func (msg MsgDeposit) Route() string { return RouterKey }
func (msg MsgDeposit) Type() string { return "deposit_cdp" } func (msg MsgDeposit) Type() string { return "deposit_cdp" }
// ValidateBasic does a simple validation check that doesn't require access to any other information. // ValidateBasic does a simple validation check that doesn't require access to any other information.
func (msg MsgDeposit) ValidateBasic() sdk.Error { func (msg MsgDeposit) ValidateBasic() error {
if msg.Owner.Empty() { if msg.Owner.Empty() {
return sdk.ErrInternal("invalid (empty) sender address") return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "owner address cannot be empty")
} }
if msg.Depositor.Empty() { if msg.Depositor.Empty() {
return sdk.ErrInternal("invalid (empty) owner address") return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be empty")
} }
if len(msg.Collateral) != 1 { if msg.Collateral.Len() != 1 {
return sdk.ErrInvalidCoins(fmt.Sprintf("cdps do not support multiple collateral types: received %s", msg.Collateral)) return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "cdps do not support multiple collateral types: %s", msg.Collateral)
} }
if !msg.Collateral.IsValid() { if !msg.Collateral.IsValid() {
return sdk.ErrInvalidCoins(fmt.Sprintf("invalid collateral amount: %s", msg.Collateral)) return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "collateral amount %s", msg.Collateral)
}
if !msg.Collateral.IsAllPositive() {
return sdk.ErrInvalidCoins(fmt.Sprintf("negative collateral amount: %s", msg.Collateral))
} }
return nil return nil
} }
@ -165,21 +159,18 @@ func (msg MsgWithdraw) Route() string { return RouterKey }
func (msg MsgWithdraw) Type() string { return "withdraw_cdp" } func (msg MsgWithdraw) Type() string { return "withdraw_cdp" }
// ValidateBasic does a simple validation check that doesn't require access to any other information. // ValidateBasic does a simple validation check that doesn't require access to any other information.
func (msg MsgWithdraw) ValidateBasic() sdk.Error { func (msg MsgWithdraw) ValidateBasic() error {
if msg.Owner.Empty() { if msg.Owner.Empty() {
return sdk.ErrInternal("invalid (empty) sender address") return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "owner address cannot be empty")
} }
if msg.Depositor.Empty() { if msg.Depositor.Empty() {
return sdk.ErrInternal("invalid (empty) owner address") return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be empty")
} }
if len(msg.Collateral) != 1 { if msg.Collateral.Len() != 1 {
return sdk.ErrInvalidCoins(fmt.Sprintf("cdps do not support multiple collateral types: received %s", msg.Collateral)) return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "cdps do not support multiple collateral types: %s", msg.Collateral)
} }
if !msg.Collateral.IsValid() { if !msg.Collateral.IsValid() {
return sdk.ErrInvalidCoins(fmt.Sprintf("invalid collateral amount: %s", msg.Collateral)) return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "collateral amount %s", msg.Collateral)
}
if !msg.Collateral.IsAllPositive() {
return sdk.ErrInvalidCoins(fmt.Sprintf("negative collateral amount: %s", msg.Collateral))
} }
return nil return nil
} }
@ -227,18 +218,15 @@ func (msg MsgDrawDebt) Route() string { return RouterKey }
func (msg MsgDrawDebt) Type() string { return "draw_cdp" } func (msg MsgDrawDebt) Type() string { return "draw_cdp" }
// ValidateBasic does a simple validation check that doesn't require access to any other information. // ValidateBasic does a simple validation check that doesn't require access to any other information.
func (msg MsgDrawDebt) ValidateBasic() sdk.Error { func (msg MsgDrawDebt) ValidateBasic() error {
if msg.Sender.Empty() { if msg.Sender.Empty() {
return sdk.ErrInternal("invalid (empty) sender address") return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be empty")
} }
if msg.CdpDenom == "" { if strings.TrimSpace(msg.CdpDenom) == "" {
return sdk.ErrInternal("invalid (empty) cdp denom") return errors.New("cdp denom cannot be blank")
} }
if !msg.Principal.IsValid() { if msg.Principal.Empty() || !msg.Principal.IsValid() {
return sdk.ErrInvalidCoins(fmt.Sprintf("invalid principal amount: %s", msg.Principal)) return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "principal amount %s", msg.Principal)
}
if !msg.Principal.IsAllPositive() {
return sdk.ErrInvalidCoins(fmt.Sprintf("negative principal amount: %s", msg.Principal))
} }
return nil return nil
} }
@ -286,18 +274,15 @@ func (msg MsgRepayDebt) Route() string { return RouterKey }
func (msg MsgRepayDebt) Type() string { return "repay_cdp" } func (msg MsgRepayDebt) Type() string { return "repay_cdp" }
// ValidateBasic does a simple validation check that doesn't require access to any other information. // ValidateBasic does a simple validation check that doesn't require access to any other information.
func (msg MsgRepayDebt) ValidateBasic() sdk.Error { func (msg MsgRepayDebt) ValidateBasic() error {
if msg.Sender.Empty() { if msg.Sender.Empty() {
return sdk.ErrInternal("invalid (empty) sender address") return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be empty")
} }
if msg.CdpDenom == "" { if strings.TrimSpace(msg.CdpDenom) == "" {
return sdk.ErrInternal("invalid (empty) cdp denom") return errors.New("cdp denom cannot be blank")
} }
if !msg.Payment.IsValid() { if msg.Payment.Empty() || !msg.Payment.IsValid() {
return sdk.ErrInvalidCoins(fmt.Sprintf("invalid payment amount: %s", msg.Payment)) return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "payment amount %s", msg.Payment)
}
if !msg.Payment.IsAllPositive() {
return sdk.ErrInvalidCoins(fmt.Sprintf("negative payment amount: %s", msg.Payment))
} }
return nil return nil
} }

View File

@ -33,16 +33,16 @@ func TestMsgCreateCDP(t *testing.T) {
{"create cdp empty owner", sdk.AccAddress{}, coinsSingle, coinsSingle, false}, {"create cdp empty owner", sdk.AccAddress{}, coinsSingle, coinsSingle, false},
} }
for i, tc := range tests { for _, tc := range tests {
msg := NewMsgCreateCDP( msg := NewMsgCreateCDP(
tc.sender, tc.sender,
tc.collateral, tc.collateral,
tc.principal, tc.principal,
) )
if tc.expectPass { if tc.expectPass {
require.NoError(t, msg.ValidateBasic(), "test: %v", i) require.NoError(t, msg.ValidateBasic(), "test: %v", tc.description)
} else { } else {
require.Error(t, msg.ValidateBasic(), "test: %v", i) require.Error(t, msg.ValidateBasic(), "test: %v", tc.description)
} }
} }
} }
@ -63,16 +63,16 @@ func TestMsgDeposit(t *testing.T) {
{"deposit empty depositor", addrs[0], sdk.AccAddress{}, coinsSingle, false}, {"deposit empty depositor", addrs[0], sdk.AccAddress{}, coinsSingle, false},
} }
for i, tc := range tests { for _, tc := range tests {
msg := NewMsgDeposit( msg := NewMsgDeposit(
tc.sender, tc.sender,
tc.depositor, tc.depositor,
tc.collateral, tc.collateral,
) )
if tc.expectPass { if tc.expectPass {
require.NoError(t, msg.ValidateBasic(), "test: %v", i) require.NoError(t, msg.ValidateBasic(), "test: %v", tc.description)
} else { } else {
require.Error(t, msg.ValidateBasic(), "test: %v", i) require.Error(t, msg.ValidateBasic(), "test: %v", tc.description)
} }
} }
} }
@ -93,16 +93,16 @@ func TestMsgWithdraw(t *testing.T) {
{"withdraw empty depositor", addrs[0], sdk.AccAddress{}, coinsSingle, false}, {"withdraw empty depositor", addrs[0], sdk.AccAddress{}, coinsSingle, false},
} }
for i, tc := range tests { for _, tc := range tests {
msg := NewMsgWithdraw( msg := NewMsgWithdraw(
tc.sender, tc.sender,
tc.depositor, tc.depositor,
tc.collateral, tc.collateral,
) )
if tc.expectPass { if tc.expectPass {
require.NoError(t, msg.ValidateBasic(), "test: %v", i) require.NoError(t, msg.ValidateBasic(), "test: %v", tc.description)
} else { } else {
require.Error(t, msg.ValidateBasic(), "test: %v", i) require.Error(t, msg.ValidateBasic(), "test: %v", tc.description)
} }
} }
} }
@ -122,16 +122,16 @@ func TestMsgDrawDebt(t *testing.T) {
{"draw debt empty denom", sdk.AccAddress{}, "", coinsSingle, false}, {"draw debt empty denom", sdk.AccAddress{}, "", coinsSingle, false},
} }
for i, tc := range tests { for _, tc := range tests {
msg := NewMsgDrawDebt( msg := NewMsgDrawDebt(
tc.sender, tc.sender,
tc.denom, tc.denom,
tc.principal, tc.principal,
) )
if tc.expectPass { if tc.expectPass {
require.NoError(t, msg.ValidateBasic(), "test: %v", i) require.NoError(t, msg.ValidateBasic(), "test: %v", tc.description)
} else { } else {
require.Error(t, msg.ValidateBasic(), "test: %v", i) require.Error(t, msg.ValidateBasic(), "test: %v", tc.description)
} }
} }
} }
@ -151,16 +151,16 @@ func TestMsgRepayDebt(t *testing.T) {
{"repay debt empty denom", sdk.AccAddress{}, "", coinsSingle, false}, {"repay debt empty denom", sdk.AccAddress{}, "", coinsSingle, false},
} }
for i, tc := range tests { for _, tc := range tests {
msg := NewMsgRepayDebt( msg := NewMsgRepayDebt(
tc.sender, tc.sender,
tc.denom, tc.denom,
tc.payment, tc.payment,
) )
if tc.expectPass { if tc.expectPass {
require.NoError(t, msg.ValidateBasic(), "test: %v", i) require.NoError(t, msg.ValidateBasic(), "test: %v", tc.description)
} else { } else {
require.Error(t, msg.ValidateBasic(), "test: %v", i) require.Error(t, msg.ValidateBasic(), "test: %v", tc.description)
} }
} }
} }

View File

@ -2,9 +2,11 @@ package types
import ( import (
"fmt" "fmt"
"strings"
"time" "time"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/x/params" "github.com/cosmos/cosmos-sdk/x/params"
tmtime "github.com/tendermint/tendermint/types/time" tmtime "github.com/tendermint/tendermint/types/time"
) )
@ -156,30 +158,49 @@ func ParamKeyTable() params.KeyTable {
// nolint // nolint
func (p *Params) ParamSetPairs() params.ParamSetPairs { func (p *Params) ParamSetPairs() params.ParamSetPairs {
return params.ParamSetPairs{ return params.ParamSetPairs{
{Key: KeyGlobalDebtLimit, Value: &p.GlobalDebtLimit}, params.NewParamSetPair(KeyGlobalDebtLimit, &p.GlobalDebtLimit, validateGlobalDebtLimitParam),
{Key: KeyCollateralParams, Value: &p.CollateralParams}, params.NewParamSetPair(KeyCollateralParams, &p.CollateralParams, validateCollateralParams),
{Key: KeyDebtParams, Value: &p.DebtParams}, params.NewParamSetPair(KeyDebtParams, &p.DebtParams, validateDebtParams),
{Key: KeyCircuitBreaker, Value: &p.CircuitBreaker}, params.NewParamSetPair(KeyCircuitBreaker, &p.CircuitBreaker, validateCircuitBreakerParam),
{Key: KeySurplusThreshold, Value: &p.SurplusAuctionThreshold}, params.NewParamSetPair(KeySurplusThreshold, &p.SurplusAuctionThreshold, validateSurplusAuctionThresholdParam),
{Key: KeyDebtThreshold, Value: &p.DebtAuctionThreshold}, params.NewParamSetPair(KeyDebtThreshold, &p.DebtAuctionThreshold, validateDebtAuctionThresholdParam),
{Key: KeyDistributionFrequency, Value: &p.SavingsDistributionFrequency}, params.NewParamSetPair(KeyDistributionFrequency, &p.SavingsDistributionFrequency, validateSavingsDistributionFrequencyParam),
} }
} }
// Validate checks that the parameters have valid values. // Validate checks that the parameters have valid values.
func (p Params) Validate() error { func (p Params) Validate() error {
// validate debt params if err := validateGlobalDebtLimitParam(p.GlobalDebtLimit); err != nil {
debtDenoms := make(map[string]int) return err
for _, dp := range p.DebtParams {
_, found := debtDenoms[dp.Denom]
if found {
return fmt.Errorf("duplicate debt denom: %s", dp.Denom)
} }
if dp.SavingsRate.LT(sdk.ZeroDec()) || dp.SavingsRate.GT(sdk.OneDec()) {
return fmt.Errorf("savings rate should be between 0 and 1, is %s for %s", dp.SavingsRate, dp.Denom)
}
debtDenoms[dp.Denom] = 1
if err := validateCollateralParams(p.CollateralParams); err != nil {
return err
}
if err := validateDebtParams(p.DebtParams); err != nil {
return err
}
if err := validateCircuitBreakerParam(p.CircuitBreaker); err != nil {
return err
}
if err := validateSurplusAuctionThresholdParam(p.SurplusAuctionThreshold); err != nil {
return err
}
if err := validateDebtAuctionThresholdParam(p.DebtAuctionThreshold); err != nil {
return err
}
if err := validateSavingsDistributionFrequencyParam(p.SavingsDistributionFrequency); err != nil {
return err
}
debtDenoms := make(map[string]bool)
for _, dp := range p.DebtParams {
debtDenoms[dp.Denom] = true
} }
// validate collateral params // validate collateral params
@ -187,38 +208,76 @@ func (p Params) Validate() error {
prefixDupMap := make(map[int]int) prefixDupMap := make(map[int]int)
collateralParamsDebtLimit := sdk.Coins{} collateralParamsDebtLimit := sdk.Coins{}
for _, cp := range p.CollateralParams { for _, cp := range p.CollateralParams {
prefix := int(cp.Prefix)
prefixDupMap[prefix] = 1
collateralDupMap[cp.Denom] = 1
collateralParamsDebtLimit = collateralParamsDebtLimit.Add(cp.DebtLimit...)
if cp.DebtLimit.IsAnyGT(p.GlobalDebtLimit) {
return fmt.Errorf("collateral debt limit for %s exceeds global debt limit: \n\tglobal debt limit: %s\n\tcollateral debt limits: %s",
cp.Denom, p.GlobalDebtLimit, cp.DebtLimit)
}
}
if collateralParamsDebtLimit.IsAnyGT(p.GlobalDebtLimit) {
return fmt.Errorf("collateral debt limit exceeds global debt limit:\n\tglobal debt limit: %s\n\tcollateral debt limits: %s",
p.GlobalDebtLimit, collateralParamsDebtLimit)
}
return nil
}
func validateGlobalDebtLimitParam(i interface{}) error {
globalDebtLimit, ok := i.(sdk.Coins)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
if !globalDebtLimit.IsValid() {
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "global debt limit %s", globalDebtLimit.String())
}
return nil
}
func validateCollateralParams(i interface{}) error {
collateralParams, ok := i.(CollateralParams)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
collateralDupMap := make(map[string]bool)
prefixDupMap := make(map[int]bool)
for _, cp := range collateralParams {
if strings.TrimSpace(cp.Denom) == "" {
return fmt.Errorf("debt denom cannot be blank %s", cp)
}
prefix := int(cp.Prefix) prefix := int(cp.Prefix)
if prefix < minCollateralPrefix || prefix > maxCollateralPrefix { if prefix < minCollateralPrefix || prefix > maxCollateralPrefix {
return fmt.Errorf("invalid prefix for collateral denom %s: %b", cp.Denom, cp.Prefix) return fmt.Errorf("invalid prefix for collateral denom %s: %b", cp.Denom, cp.Prefix)
} }
_, found := prefixDupMap[prefix] _, found := prefixDupMap[prefix]
if found { if found {
return fmt.Errorf("duplicate prefix for collateral denom %s: %v", cp.Denom, []byte{cp.Prefix}) return fmt.Errorf("duplicate prefix for collateral denom %s: %v", cp.Denom, []byte{cp.Prefix})
} }
prefixDupMap[prefix] = 1 prefixDupMap[prefix] = true
_, found = collateralDupMap[cp.Denom]
_, found = collateralDupMap[cp.Denom]
if found { if found {
return fmt.Errorf("duplicate collateral denom: %s", cp.Denom) return fmt.Errorf("duplicate collateral denom: %s", cp.Denom)
} }
collateralDupMap[cp.Denom] = 1
if cp.DebtLimit.IsAnyNegative() { collateralDupMap[cp.Denom] = true
if !cp.DebtLimit.IsValid() {
return fmt.Errorf("debt limit for all collaterals should be positive, is %s for %s", cp.DebtLimit, cp.Denom) return fmt.Errorf("debt limit for all collaterals should be positive, is %s for %s", cp.DebtLimit, cp.Denom)
} }
collateralParamsDebtLimit = collateralParamsDebtLimit.Add(cp.DebtLimit)
for _, dc := range cp.DebtLimit {
_, found := debtDenoms[dc.Denom]
if !found {
return fmt.Errorf("debt limit for collateral %s contains invalid debt denom %s", cp.Denom, dc.Denom)
}
}
if cp.DebtLimit.IsAnyGT(p.GlobalDebtLimit) {
return fmt.Errorf("collateral debt limit for %s exceeds global debt limit: \n\tglobal debt limit: %s\n\tcollateral debt limits: %s",
cp.Denom, p.GlobalDebtLimit, cp.DebtLimit)
}
if cp.LiquidationPenalty.LT(sdk.ZeroDec()) || cp.LiquidationPenalty.GT(sdk.OneDec()) { if cp.LiquidationPenalty.LT(sdk.ZeroDec()) || cp.LiquidationPenalty.GT(sdk.OneDec()) {
return fmt.Errorf("liquidation penalty should be between 0 and 1, is %s for %s", cp.LiquidationPenalty, cp.Denom) return fmt.Errorf("liquidation penalty should be between 0 and 1, is %s for %s", cp.LiquidationPenalty, cp.Denom)
} }
@ -229,24 +288,82 @@ func (p Params) Validate() error {
return fmt.Errorf("stability fee must be ≥ 1.0, is %s for %s", cp.StabilityFee, cp.Denom) return fmt.Errorf("stability fee must be ≥ 1.0, is %s for %s", cp.StabilityFee, cp.Denom)
} }
} }
if collateralParamsDebtLimit.IsAnyGT(p.GlobalDebtLimit) {
return fmt.Errorf("collateral debt limit exceeds global debt limit:\n\tglobal debt limit: %s\n\tcollateral debt limits: %s",
p.GlobalDebtLimit, collateralParamsDebtLimit)
}
// validate global params return nil
if p.GlobalDebtLimit.IsAnyNegative() { }
return fmt.Errorf("global debt limit should be positive for all debt tokens, is %s", p.GlobalDebtLimit)
} func validateDebtParams(i interface{}) error {
if !p.SurplusAuctionThreshold.IsPositive() { debtParams, ok := i.(DebtParams)
return fmt.Errorf("surplus auction threshold should be positive, is %s", p.SurplusAuctionThreshold) if !ok {
} return fmt.Errorf("invalid parameter type: %T", i)
if !p.DebtAuctionThreshold.IsPositive() { }
return fmt.Errorf("debt auction threshold should be positive, is %s", p.DebtAuctionThreshold)
} // validate debt params
debtDenoms := make(map[string]bool)
if p.SavingsDistributionFrequency.Seconds() <= float64(0) { for _, dp := range debtParams {
return fmt.Errorf("savings distribution frequency should be positive, is %s", p.SavingsDistributionFrequency) if strings.TrimSpace(dp.Denom) == "" {
} return fmt.Errorf("debt denom cannot be blank %s", dp)
}
_, found := debtDenoms[dp.Denom]
if found {
return fmt.Errorf("duplicate debt denom: %s", dp.Denom)
}
if dp.SavingsRate.LT(sdk.ZeroDec()) || dp.SavingsRate.GT(sdk.OneDec()) {
return fmt.Errorf("savings rate should be between 0 and 1, is %s for %s", dp.SavingsRate, dp.Denom)
}
debtDenoms[dp.Denom] = true
}
return nil
}
func validateCircuitBreakerParam(i interface{}) error {
_, ok := i.(bool)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
return nil
}
func validateSurplusAuctionThresholdParam(i interface{}) error {
sat, ok := i.(sdk.Int)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
if !sat.IsPositive() {
return fmt.Errorf("surplus auction threshold should be positive: %s", sat)
}
return nil
}
func validateDebtAuctionThresholdParam(i interface{}) error {
dat, ok := i.(sdk.Int)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
if !dat.IsPositive() {
return fmt.Errorf("debt auction threshold should be positive: %s", dat)
}
return nil
}
func validateSavingsDistributionFrequencyParam(i interface{}) error {
sdf, ok := i.(time.Duration)
if !ok {
return fmt.Errorf("invalid parameter type: %T", i)
}
if sdf.Seconds() <= float64(0) {
return fmt.Errorf("savings distribution frequency should be positive: %s", sdf)
}
return nil return nil
} }

Some files were not shown because too many files have changed in this diff Show More