mirror of
https://github.com/0glabs/0g-chain.git
synced 2024-11-20 15:05:21 +00:00
[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:
parent
0949a912cf
commit
a573625df8
109
app/app.go
109
app/app.go
@ -12,12 +12,13 @@ import (
|
||||
validatorvesting "github.com/kava-labs/kava/x/validator-vesting"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmos "github.com/tendermint/tendermint/libs/os"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
@ -26,6 +27,7 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/crisis"
|
||||
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/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||
@ -61,6 +63,7 @@ var (
|
||||
crisis.AppModuleBasic{},
|
||||
slashing.AppModuleBasic{},
|
||||
supply.AppModuleBasic{},
|
||||
evidence.AppModuleBasic{},
|
||||
auction.AppModuleBasic{},
|
||||
cdp.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 {
|
||||
*bam.BaseApp
|
||||
cdc *codec.Codec
|
||||
@ -108,6 +114,7 @@ type App struct {
|
||||
govKeeper gov.Keeper
|
||||
crisisKeeper crisis.Keeper
|
||||
paramsKeeper params.Keeper
|
||||
evidenceKeeper evidence.Keeper
|
||||
vvKeeper validatorvesting.Keeper
|
||||
auctionKeeper auction.Keeper
|
||||
cdpKeeper cdp.Keeper
|
||||
@ -136,7 +143,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
|
||||
keys := sdk.NewKVStoreKeys(
|
||||
bam.MainStoreKey, auth.StoreKey, staking.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,
|
||||
kavadist.StoreKey,
|
||||
)
|
||||
@ -151,7 +158,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
|
||||
}
|
||||
|
||||
// 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)
|
||||
bankSubspace := app.paramsKeeper.Subspace(bank.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)
|
||||
slashingSubspace := app.paramsKeeper.Subspace(slashing.DefaultParamspace)
|
||||
govSubspace := app.paramsKeeper.Subspace(gov.DefaultParamspace).WithKeyTable(gov.ParamKeyTable())
|
||||
evidenceSubspace := app.paramsKeeper.Subspace(evidence.DefaultParamspace)
|
||||
crisisSubspace := app.paramsKeeper.Subspace(crisis.DefaultParamspace)
|
||||
auctionSubspace := app.paramsKeeper.Subspace(auction.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,
|
||||
keys[auth.StoreKey],
|
||||
authSubspace,
|
||||
auth.ProtoBaseAccount)
|
||||
auth.ProtoBaseAccount,
|
||||
)
|
||||
app.bankKeeper = bank.NewBaseKeeper(
|
||||
app.accountKeeper,
|
||||
bankSubspace,
|
||||
bank.DefaultCodespace,
|
||||
app.ModuleAccountAddrs())
|
||||
app.ModuleAccountAddrs(),
|
||||
)
|
||||
app.supplyKeeper = supply.NewKeeper(
|
||||
app.cdc,
|
||||
keys[supply.StoreKey],
|
||||
app.accountKeeper,
|
||||
app.bankKeeper,
|
||||
mAccPerms)
|
||||
mAccPerms,
|
||||
)
|
||||
stakingKeeper := staking.NewKeeper(
|
||||
app.cdc,
|
||||
keys[staking.StoreKey],
|
||||
app.supplyKeeper,
|
||||
stakingSubspace,
|
||||
staking.DefaultCodespace)
|
||||
)
|
||||
app.mintKeeper = mint.NewKeeper(
|
||||
app.cdc,
|
||||
keys[mint.StoreKey],
|
||||
mintSubspace,
|
||||
&stakingKeeper,
|
||||
app.supplyKeeper,
|
||||
auth.FeeCollectorName)
|
||||
auth.FeeCollectorName,
|
||||
)
|
||||
app.distrKeeper = distr.NewKeeper(
|
||||
app.cdc,
|
||||
keys[distr.StoreKey],
|
||||
distrSubspace,
|
||||
&stakingKeeper,
|
||||
app.supplyKeeper,
|
||||
distr.DefaultCodespace,
|
||||
auth.FeeCollectorName,
|
||||
app.ModuleAccountAddrs())
|
||||
app.ModuleAccountAddrs(),
|
||||
)
|
||||
app.slashingKeeper = slashing.NewKeeper(
|
||||
app.cdc,
|
||||
keys[slashing.StoreKey],
|
||||
&stakingKeeper,
|
||||
slashingSubspace,
|
||||
slashing.DefaultCodespace)
|
||||
)
|
||||
app.crisisKeeper = crisis.NewKeeper(
|
||||
crisisSubspace,
|
||||
invCheckPeriod,
|
||||
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.
|
||||
AddRoute(gov.RouterKey, gov.ProposalHandler).
|
||||
@ -227,25 +252,28 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
|
||||
govSubspace,
|
||||
app.supplyKeeper,
|
||||
&stakingKeeper,
|
||||
gov.DefaultCodespace,
|
||||
govRouter)
|
||||
govRouter,
|
||||
)
|
||||
|
||||
app.vvKeeper = validatorvesting.NewKeeper(
|
||||
app.cdc,
|
||||
keys[validatorvesting.StoreKey],
|
||||
app.accountKeeper,
|
||||
app.bankKeeper,
|
||||
app.supplyKeeper,
|
||||
&stakingKeeper)
|
||||
&stakingKeeper,
|
||||
)
|
||||
app.pricefeedKeeper = pricefeed.NewKeeper(
|
||||
app.cdc,
|
||||
keys[pricefeed.StoreKey],
|
||||
pricefeedSubspace,
|
||||
pricefeed.DefaultCodespace)
|
||||
)
|
||||
app.auctionKeeper = auction.NewKeeper(
|
||||
app.cdc,
|
||||
keys[auction.StoreKey],
|
||||
app.supplyKeeper,
|
||||
auctionSubspace)
|
||||
auctionSubspace,
|
||||
)
|
||||
app.cdpKeeper = cdp.NewKeeper(
|
||||
app.cdc,
|
||||
keys[cdp.StoreKey],
|
||||
@ -254,19 +282,18 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
|
||||
app.auctionKeeper,
|
||||
app.supplyKeeper,
|
||||
app.accountKeeper,
|
||||
cdp.DefaultCodespace)
|
||||
)
|
||||
app.bep3Keeper = bep3.NewKeeper(
|
||||
app.cdc,
|
||||
keys[bep3.StoreKey],
|
||||
app.supplyKeeper,
|
||||
bep3Subspace,
|
||||
bep3.DefaultCodespace)
|
||||
)
|
||||
app.kavadistKeeper = kavadist.NewKeeper(
|
||||
app.cdc,
|
||||
keys[kavadist.StoreKey],
|
||||
kavadistSubspace,
|
||||
app.supplyKeeper,
|
||||
kavadist.DefaultCodespace,
|
||||
)
|
||||
|
||||
// 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),
|
||||
crisis.NewAppModule(&app.crisisKeeper),
|
||||
supply.NewAppModule(app.supplyKeeper, app.accountKeeper),
|
||||
distr.NewAppModule(app.distrKeeper, app.supplyKeeper),
|
||||
gov.NewAppModule(app.govKeeper, app.supplyKeeper),
|
||||
gov.NewAppModule(app.govKeeper, app.accountKeeper, app.supplyKeeper),
|
||||
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),
|
||||
evidence.NewAppModule(app.evidenceKeeper),
|
||||
validatorvesting.NewAppModule(app.vvKeeper, app.accountKeeper),
|
||||
auction.NewAppModule(app.auctionKeeper, app.supplyKeeper),
|
||||
cdp.NewAppModule(app.cdpKeeper, app.pricefeedKeeper, app.supplyKeeper),
|
||||
pricefeed.NewAppModule(app.pricefeedKeeper),
|
||||
bep3.NewAppModule(app.bep3Keeper, app.supplyKeeper),
|
||||
auction.NewAppModule(app.auctionKeeper, app.accountKeeper, app.supplyKeeper),
|
||||
cdp.NewAppModule(app.cdpKeeper, app.accountKeeper, app.pricefeedKeeper, app.supplyKeeper),
|
||||
pricefeed.NewAppModule(app.pricefeedKeeper, app.accountKeeper),
|
||||
bep3.NewAppModule(app.bep3Keeper, app.accountKeeper, 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
|
||||
validatorvesting.ModuleName, distr.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?
|
||||
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
|
||||
@ -325,15 +353,15 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
|
||||
validatorvesting.NewAppModule(app.vvKeeper, app.accountKeeper),
|
||||
bank.NewAppModule(app.bankKeeper, 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),
|
||||
distr.NewAppModule(app.distrKeeper, app.supplyKeeper),
|
||||
distr.NewAppModule(app.distrKeeper, app.accountKeeper, app.supplyKeeper, app.stakingKeeper),
|
||||
staking.NewAppModule(app.stakingKeeper, app.accountKeeper, app.supplyKeeper),
|
||||
slashing.NewAppModule(app.slashingKeeper, app.stakingKeeper),
|
||||
pricefeed.NewAppModule(app.pricefeedKeeper),
|
||||
cdp.NewAppModule(app.cdpKeeper, app.pricefeedKeeper, app.supplyKeeper),
|
||||
auction.NewAppModule(app.auctionKeeper, app.supplyKeeper),
|
||||
bep3.NewAppModule(app.bep3Keeper, app.supplyKeeper),
|
||||
slashing.NewAppModule(app.slashingKeeper, app.accountKeeper, app.stakingKeeper),
|
||||
pricefeed.NewAppModule(app.pricefeedKeeper, app.accountKeeper),
|
||||
cdp.NewAppModule(app.cdpKeeper, app.accountKeeper, app.pricefeedKeeper, app.supplyKeeper),
|
||||
auction.NewAppModule(app.auctionKeeper, app.accountKeeper, app.supplyKeeper),
|
||||
bep3.NewAppModule(app.bep3Keeper, app.accountKeeper, 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 {
|
||||
err := app.LoadLatestVersion(app.keys[bam.MainStoreKey])
|
||||
if err != nil {
|
||||
cmn.Exit(err.Error())
|
||||
tmos.Exit(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
@ -422,6 +450,11 @@ func (app *App) Codec() *codec.Codec {
|
||||
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.
|
||||
func GetMaccPerms() map[string][]string {
|
||||
perms := make(map[string][]string)
|
||||
|
@ -13,10 +13,9 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
)
|
||||
|
||||
// export the state of the app for a genesis file
|
||||
func (app *App) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteList []string) (
|
||||
appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
|
||||
|
||||
// ExportAppStateAndValidators export the state of the app for a genesis file
|
||||
func (app *App) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteList []string,
|
||||
) (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
|
||||
// as if they could withdraw from the start of the next block
|
||||
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)
|
||||
|
||||
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
@ -35,6 +33,8 @@ func (app *App) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteList []
|
||||
}
|
||||
|
||||
// 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) {
|
||||
applyWhiteList := false
|
||||
|
||||
@ -60,14 +60,24 @@ func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []string
|
||||
|
||||
// withdraw all validator commission
|
||||
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
|
||||
})
|
||||
|
||||
// withdraw all delegator rewards
|
||||
dels := app.stakingKeeper.GetAllDelegations(ctx)
|
||||
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
|
||||
@ -86,7 +96,7 @@ func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []string
|
||||
// donate any unwithdrawn outstanding reward fraction tokens to the community pool
|
||||
scraps := app.distrKeeper.GetValidatorOutstandingRewards(ctx, val.GetOperator())
|
||||
feePool := app.distrKeeper.GetFeePool(ctx)
|
||||
feePool.CommunityPool = feePool.CommunityPool.Add(scraps)
|
||||
feePool.CommunityPool = feePool.CommunityPool.Add(scraps...)
|
||||
app.distrKeeper.SetFeePool(ctx, feePool)
|
||||
|
||||
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)
|
||||
counter := int16(0)
|
||||
|
||||
var valConsAddrs []sdk.ConsAddress
|
||||
for ; iter.Valid(); iter.Next() {
|
||||
addr := sdk.ValAddress(iter.Key()[1:])
|
||||
validator, found := app.stakingKeeper.GetValidator(ctx, addr)
|
||||
@ -137,7 +146,6 @@ func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []string
|
||||
}
|
||||
|
||||
validator.UnbondingHeight = 0
|
||||
valConsAddrs = append(valConsAddrs, validator.ConsAddress())
|
||||
if applyWhiteList && !whiteListMap[addr.String()] {
|
||||
validator.Jailed = true
|
||||
}
|
||||
|
19
app/params/doc.go
Normal file
19
app/params/doc.go
Normal 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
15
app/params/params.go
Normal 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
|
||||
)
|
651
app/sim_test.go
651
app/sim_test.go
@ -3,69 +3,35 @@ package app
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"math/rand"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
"github.com/cosmos/cosmos-sdk/simapp/helpers"
|
||||
"github.com/cosmos/cosmos-sdk/store"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"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"
|
||||
distrsimops "github.com/cosmos/cosmos-sdk/x/distribution/simulation/operations"
|
||||
"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/params"
|
||||
paramsimops "github.com/cosmos/cosmos-sdk/x/params/simulation/operations"
|
||||
"github.com/cosmos/cosmos-sdk/x/simulation"
|
||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||
slashingsimops "github.com/cosmos/cosmos-sdk/x/slashing/simulation/operations"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
stakingsimops "github.com/cosmos/cosmos-sdk/x/staking/simulation/operations"
|
||||
"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
|
||||
const (
|
||||
StakePerAccount = "stake_per_account"
|
||||
InitiallyBondedValidators = "initially_bonded_validators"
|
||||
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"
|
||||
)
|
||||
type StoreKeysPrefixes struct {
|
||||
A sdk.StoreKey
|
||||
B sdk.StoreKey
|
||||
Prefixes [][]byte
|
||||
}
|
||||
|
||||
// TestMain runs setup and teardown code before all tests.
|
||||
func TestMain(m *testing.M) {
|
||||
@ -75,251 +41,11 @@ func TestMain(m *testing.M) {
|
||||
config.Seal()
|
||||
// load the values from simulation specific flags
|
||||
simapp.GetSimulatorFlags()
|
||||
|
||||
// run tests
|
||||
exitCode := m.Run()
|
||||
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
|
||||
// an IAVLStore for faster simulation speed.
|
||||
func fauxMerkleModeOpt(bapp *baseapp.BaseApp) {
|
||||
@ -332,197 +58,96 @@ func interBlockCacheOpt() func(*baseapp.BaseApp) {
|
||||
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) {
|
||||
if !simapp.FlagEnabledValue {
|
||||
config, db, dir, logger, skip, err := simapp.SetupSimulation("leveldb-app-sim", "Simulation")
|
||||
if skip {
|
||||
t.Skip("skipping application 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)
|
||||
require.NoError(t, err, "simulation setup failed")
|
||||
|
||||
defer func() {
|
||||
db.Close()
|
||||
_ = os.RemoveAll(dir)
|
||||
require.NoError(t, os.RemoveAll(dir))
|
||||
}()
|
||||
|
||||
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(
|
||||
t, 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 != "" {
|
||||
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,
|
||||
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
|
||||
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)
|
||||
}
|
||||
|
||||
err = simapp.CheckExportSimulation(app, config, simParams)
|
||||
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"])
|
||||
simapp.PrintStats(db)
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
|
||||
appState, _, err := app.ExportAppStateAndValidators(false, []string{})
|
||||
require.NoError(t, err)
|
||||
|
||||
fmt.Printf("importing genesis...\n")
|
||||
|
||||
newDir, _ := ioutil.TempDir("", "goleveldb-app-sim-2")
|
||||
newDB, _ := sdk.NewLevelDB("Simulation-2", dir)
|
||||
_, newDB, newDir, _, _, err := simapp.SetupSimulation("leveldb-app-sim-2", "Simulation-2")
|
||||
require.NoError(t, err, "simulation setup failed")
|
||||
|
||||
defer func() {
|
||||
newDB.Close()
|
||||
_ = os.RemoveAll(newDir)
|
||||
require.NoError(t, os.RemoveAll(newDir))
|
||||
}()
|
||||
|
||||
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
|
||||
err = app.cdc.UnmarshalJSON(appState, &genesisState)
|
||||
var genesisState GenesisState
|
||||
err = app.Codec().UnmarshalJSON(appState, &genesisState)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctxA := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()})
|
||||
ctxB := newApp.NewContext(true, abci.Header{Height: app.LastBlockHeight()})
|
||||
newApp.mm.InitGenesis(ctxB, genesisState)
|
||||
|
||||
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{
|
||||
{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{}},
|
||||
}
|
||||
|
||||
for _, storeKeysPrefix := range storeKeysPrefixes {
|
||||
storeKeyA := storeKeysPrefix.A
|
||||
storeKeyB := storeKeysPrefix.B
|
||||
prefixes := storeKeysPrefix.Prefixes
|
||||
for _, skp := range storeKeysPrefixes {
|
||||
storeA := ctxA.KVStore(skp.A)
|
||||
storeB := ctxB.KVStore(skp.B)
|
||||
|
||||
storeA := ctxA.KVStore(storeKeyA)
|
||||
storeB := ctxB.KVStore(storeKeyB)
|
||||
|
||||
failedKVAs, failedKVBs := sdk.DiffKVStores(storeA, storeB, prefixes)
|
||||
failedKVAs, failedKVBs := sdk.DiffKVStores(storeA, storeB, skp.Prefixes)
|
||||
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)
|
||||
require.Len(t, failedKVAs, 0, simapp.GetSimulationLog(storeKeyA.Name(), app.sm.StoreDecoders, app.cdc, failedKVAs, failedKVBs))
|
||||
fmt.Printf("compared %d key/value pairs between %s and %s\n", len(failedKVAs), skp.A, skp.B)
|
||||
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) {
|
||||
if !simapp.FlagEnabledValue {
|
||||
config, db, dir, logger, skip, err := simapp.SetupSimulation("leveldb-app-sim", "Simulation")
|
||||
if skip {
|
||||
t.Skip("skipping application simulation after import")
|
||||
}
|
||||
|
||||
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)
|
||||
require.NoError(t, err, "simulation setup failed")
|
||||
|
||||
defer func() {
|
||||
db.Close()
|
||||
_ = os.RemoveAll(dir)
|
||||
require.NoError(t, os.RemoveAll(dir))
|
||||
}()
|
||||
|
||||
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
|
||||
stopEarly, simParams, simErr := simulation.SimulateFromSeed(
|
||||
t, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.sm),
|
||||
testAndRunTxs(app, config), app.ModuleAccountAddrs(), config,
|
||||
t, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.SimulationManager()),
|
||||
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)
|
||||
}
|
||||
|
||||
// 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 {
|
||||
// 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"])
|
||||
simapp.PrintStats(db)
|
||||
}
|
||||
|
||||
if stopEarly {
|
||||
// we can't export or import a zero-validator genesis
|
||||
fmt.Printf("We can't export or import a zero-validator genesis, exiting test...\n")
|
||||
fmt.Println("can't export or import a zero-validator genesis, exiting test...")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("Exporting genesis...\n")
|
||||
fmt.Printf("exporting genesis...\n")
|
||||
|
||||
appState, _, err := app.ExportAppStateAndValidators(true, []string{})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
fmt.Printf("Importing genesis...\n")
|
||||
fmt.Printf("importing genesis...\n")
|
||||
|
||||
newDir, _ := ioutil.TempDir("", "goleveldb-app-sim-2")
|
||||
newDB, _ := sdk.NewLevelDB("Simulation-2", dir)
|
||||
_, newDB, newDir, _, _, err := simapp.SetupSimulation("leveldb-app-sim-2", "Simulation-2")
|
||||
require.NoError(t, err, "simulation setup failed")
|
||||
|
||||
defer func() {
|
||||
newDB.Close()
|
||||
_ = os.RemoveAll(newDir)
|
||||
require.NoError(t, os.RemoveAll(newDir))
|
||||
}()
|
||||
|
||||
newApp := NewApp(log.NewNopLogger(), newDB, nil, true, 0, fauxMerkleModeOpt)
|
||||
require.Equal(t, "kava", newApp.Name())
|
||||
newApp := NewApp(log.NewNopLogger(), newDB, nil, true, simapp.FlagPeriodValue, fauxMerkleModeOpt)
|
||||
require.Equal(t, appName, newApp.Name())
|
||||
|
||||
newApp.InitChain(abci.RequestInitChain{
|
||||
AppStateBytes: appState,
|
||||
})
|
||||
|
||||
// Run randomized simulation on imported app
|
||||
_, _, err = simulation.SimulateFromSeed(
|
||||
t, os.Stdout, newApp.BaseApp, simapp.AppStateFn(app.Codec(), app.sm),
|
||||
testAndRunTxs(newApp, config), newApp.ModuleAccountAddrs(), config,
|
||||
t, os.Stdout, newApp.BaseApp, simapp.AppStateFn(app.Codec(), app.SimulationManager()),
|
||||
simapp.SimulationOperations(newApp, newApp.Codec(), config),
|
||||
newApp.ModuleAccountAddrs(), config,
|
||||
)
|
||||
|
||||
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) {
|
||||
if !simapp.FlagEnabledValue {
|
||||
t.Skip("skipping application simulation")
|
||||
@ -661,6 +252,7 @@ func TestAppStateDeterminism(t *testing.T) {
|
||||
config.ExportParamsPath = ""
|
||||
config.OnOperation = false
|
||||
config.AllInvariants = false
|
||||
config.ChainID = helpers.SimAppChainID
|
||||
|
||||
numTimesToRunPerSeed := 2
|
||||
appHashList := make([]json.RawMessage, numTimesToRunPerSeed)
|
||||
@ -676,8 +268,9 @@ func TestAppStateDeterminism(t *testing.T) {
|
||||
)
|
||||
|
||||
_, _, err := simulation.SimulateFromSeed(
|
||||
t, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.sm),
|
||||
testAndRunTxs(app, config), app.ModuleAccountAddrs(), config,
|
||||
t, os.Stdout, app.BaseApp, simapp.AppStateFn(app.Codec(), app.SimulationManager()),
|
||||
simapp.SimulationOperations(app, app.Codec(), config),
|
||||
app.ModuleAccountAddrs(), config,
|
||||
)
|
||||
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()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -50,6 +50,10 @@ type TestApp struct {
|
||||
}
|
||||
|
||||
func NewTestApp() TestApp {
|
||||
config := sdk.GetConfig()
|
||||
SetBech32AddressPrefixes(config)
|
||||
SetBip44CoinType(config)
|
||||
|
||||
db := tmdb.NewMemDB()
|
||||
app := NewApp(log.NewNopLogger(), db, nil, true, 0)
|
||||
return TestApp{App: *app}
|
||||
|
@ -14,7 +14,6 @@ import (
|
||||
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
clientkeys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"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
|
||||
func (f *Fixtures) GDInit(moniker string, flags ...string) {
|
||||
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 initRes map[string]json.RawMessage
|
||||
@ -231,13 +230,13 @@ func (f *Fixtures) AddGenesisAccount(address sdk.AccAddress, coins sdk.Coins, fl
|
||||
// GenTx is gaiad gentx
|
||||
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)
|
||||
executeWriteCheckErr(f.T, addFlags(cmd, flags), client.DefaultKeyPass)
|
||||
executeWriteCheckErr(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
|
||||
}
|
||||
|
||||
// CollectGenTxs is gaiad collect-gentxs
|
||||
func (f *Fixtures) CollectGenTxs(flags ...string) {
|
||||
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
|
||||
@ -276,19 +275,19 @@ func (f *Fixtures) KeysDelete(name string, flags ...string) {
|
||||
// KeysAdd is gaiacli keys add
|
||||
func (f *Fixtures) KeysAdd(name string, flags ...string) {
|
||||
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
|
||||
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)
|
||||
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
|
||||
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)
|
||||
executeWriteCheckErr(f.T, addFlags(cmd, flags), client.DefaultKeyPass, mnemonic)
|
||||
executeWriteCheckErr(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass, mnemonic)
|
||||
}
|
||||
|
||||
// KeysShow is gaiacli keys show
|
||||
@ -324,25 +323,25 @@ func (f *Fixtures) CLIConfig(key, value string, flags ...string) {
|
||||
// TxSend is gaiacli tx send
|
||||
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())
|
||||
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass)
|
||||
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
|
||||
}
|
||||
|
||||
// TxSign is gaiacli tx sign
|
||||
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)
|
||||
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass)
|
||||
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
|
||||
}
|
||||
|
||||
// TxBroadcast is gaiacli tx broadcast
|
||||
func (f *Fixtures) TxBroadcast(fileName string, flags ...string) (bool, string, string) {
|
||||
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
|
||||
func (f *Fixtures) TxEncode(fileName string, flags ...string) (bool, string, string) {
|
||||
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
|
||||
@ -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(" --commission-max-rate=%v --commission-max-change-rate=%v", "0.20", "0.10")
|
||||
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
|
||||
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())
|
||||
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) {
|
||||
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)
|
||||
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass)
|
||||
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
|
||||
}
|
||||
|
||||
// TxGovDeposit is gaiacli tx gov deposit
|
||||
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())
|
||||
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass)
|
||||
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
|
||||
}
|
||||
|
||||
// TxGovVote is gaiacli tx gov vote
|
||||
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())
|
||||
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
|
||||
@ -406,7 +405,7 @@ func (f *Fixtures) TxGovSubmitParamChangeProposal(
|
||||
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
|
||||
@ -420,7 +419,7 @@ func (f *Fixtures) TxGovSubmitCommunityPoolSpendProposal(
|
||||
f.GaiacliBinary, proposalPath, from, f.Flags(),
|
||||
)
|
||||
|
||||
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), client.DefaultKeyPass)
|
||||
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), clientkeys.DefaultKeyPass)
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
|
||||
"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/rpc"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@ -48,7 +49,7 @@ func main() {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return initConfig(rootCmd)
|
||||
}
|
||||
@ -59,13 +60,13 @@ func main() {
|
||||
client.ConfigCmd(app.DefaultCLIHome),
|
||||
queryCmd(cdc),
|
||||
txCmd(cdc),
|
||||
client.LineBreak,
|
||||
flags.LineBreak,
|
||||
lcd.ServeCommand(cdc, registerRoutes),
|
||||
client.LineBreak,
|
||||
flags.LineBreak,
|
||||
getModifiedKeysCmd(),
|
||||
client.LineBreak,
|
||||
flags.LineBreak,
|
||||
version.Cmd,
|
||||
client.NewCompletionCmd(rootCmd, true),
|
||||
flags.NewCompletionCmd(rootCmd, true),
|
||||
)
|
||||
|
||||
// Add flags and prefix all env exposed with KA
|
||||
@ -87,12 +88,12 @@ func queryCmd(cdc *amino.Codec) *cobra.Command {
|
||||
|
||||
queryCmd.AddCommand(
|
||||
authcmd.GetAccountCmd(cdc),
|
||||
client.LineBreak,
|
||||
flags.LineBreak,
|
||||
rpc.ValidatorCommand(cdc),
|
||||
rpc.BlockCommand(),
|
||||
authcmd.QueryTxsByEventsCmd(cdc),
|
||||
authcmd.QueryTxCmd(cdc),
|
||||
client.LineBreak,
|
||||
flags.LineBreak,
|
||||
)
|
||||
|
||||
// add modules' query commands
|
||||
@ -109,14 +110,14 @@ func txCmd(cdc *amino.Codec) *cobra.Command {
|
||||
|
||||
txCmd.AddCommand(
|
||||
bankcmd.SendTxCmd(cdc),
|
||||
client.LineBreak,
|
||||
flags.LineBreak,
|
||||
authcmd.GetSignCommand(cdc),
|
||||
authcmd.GetMultiSignCommand(cdc),
|
||||
client.LineBreak,
|
||||
flags.LineBreak,
|
||||
authcmd.GetBroadcastCommand(cdc),
|
||||
authcmd.GetEncodeCommand(cdc),
|
||||
authcmd.GetDecodeCommand(cdc),
|
||||
client.LineBreak,
|
||||
flags.LineBreak,
|
||||
)
|
||||
|
||||
// add modules' tx commands
|
||||
@ -156,7 +157,7 @@ func initConfig(cmd *cobra.Command) error {
|
||||
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
|
||||
}
|
||||
if err := viper.BindPFlag(cli.EncodingFlag, cmd.PersistentFlags().Lookup(cli.EncodingFlag)); err != nil {
|
||||
|
@ -14,7 +14,7 @@ import (
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"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/store"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@ -59,7 +59,7 @@ func main() {
|
||||
app.DefaultCLIHome))
|
||||
rootCmd.AddCommand(genutilcli.ValidateGenesisCmd(ctx, cdc, app.ModuleBasics))
|
||||
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)
|
||||
|
||||
|
17
go.mod
17
go.mod
@ -4,15 +4,14 @@ go 1.13
|
||||
|
||||
require (
|
||||
github.com/btcsuite/btcd v0.20.1-beta // indirect
|
||||
github.com/cosmos/cosmos-sdk v0.34.4-0.20191010193331-18de630d0ae1
|
||||
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d // indirect
|
||||
github.com/cosmos/cosmos-sdk v0.38.3
|
||||
github.com/gorilla/mux v1.7.3
|
||||
github.com/spf13/cobra v0.0.5
|
||||
github.com/spf13/viper v1.4.0
|
||||
github.com/stretchr/testify v1.4.0
|
||||
github.com/tendermint/go-amino v0.15.0
|
||||
github.com/tendermint/tendermint v0.32.7
|
||||
github.com/tendermint/tm-db v0.2.0
|
||||
github.com/spf13/cobra v0.0.6
|
||||
github.com/spf13/viper v1.6.2
|
||||
github.com/stretchr/testify v1.5.1
|
||||
github.com/tendermint/go-amino v0.15.1
|
||||
github.com/tendermint/tendermint v0.33.3
|
||||
github.com/tendermint/tm-db v0.5.0
|
||||
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
409
go.sum
@ -1,21 +1,40 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
github.com/99designs/keyring v1.1.2 h1:JJauROcU6x6Nh9uZb+8JgXFvyo0GUESLo1ixhpA0Kmw=
|
||||
github.com/99designs/keyring v1.1.2/go.mod h1:657DQuMrBZRtuL/voxVyiyb6zpMehlm5vLB9Qwrv904=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
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/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/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/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/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-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-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/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/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 v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
|
||||
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/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
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/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/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/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/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/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-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/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/cosmos/cosmos-sdk v0.34.4-0.20191010193331-18de630d0ae1 h1:yb+E8HGzFnO0YwLS6OCBIAVWtN8KfCYoKeO9mgAmQN0=
|
||||
github.com/cosmos/cosmos-sdk v0.34.4-0.20191010193331-18de630d0ae1/go.mod h1:IGBhkbOK1ebLqMWjtgo99zUxWHsA5IOb6N9CI8nHs0Y=
|
||||
github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y=
|
||||
github.com/cosmos/cosmos-sdk v0.38.3 h1:qIBTiw+2T9POaSUJ5rvbBbXeq8C8btBlJxnSegPBd3Y=
|
||||
github.com/cosmos/cosmos-sdk v0.38.3/go.mod h1:rzWOofbKfRt3wxiylmYWEFHnxxGj0coyqgWl2I9obAw=
|
||||
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/ledger-cosmos-go v0.10.3 h1:Qhi5yTR5Pg1CaTpd00pxlGwNl4sFRdtK1J96OTjeFFc=
|
||||
github.com/cosmos/ledger-cosmos-go v0.10.3/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY=
|
||||
github.com/cosmos/ledger-cosmos-go v0.11.1 h1:9JIYsGnXP613pb2vPjFeMMjBI5lEDsEaF6oYorTy6J4=
|
||||
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/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/go.mod h1:SnuYRW9lp1oJrZX/dXJqr0cPK5gYXqx3EJbmjhLdK9U=
|
||||
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/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/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/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/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
|
||||
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/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/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/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/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
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.9.0 h1:wDJmvq38kDhkVxi50ni9ykkdUr1PKgqKOoi01fa0Mdk=
|
||||
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.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.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/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/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.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.3.0 h1:G8O7TerXerS4F6sx9OV7/nRfJdnXgHZu/S/7F2SN+UE=
|
||||
github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
||||
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
|
||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
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-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.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/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.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.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/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/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 v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
|
||||
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/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.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||
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.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/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/go.mod h1:NMPJylDgVpX0MLRlPy15sqSwOFv/U1GZ2m21JhFfek0=
|
||||
github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8Bppgk=
|
||||
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||
github.com/gtank/merlin v0.1.1-0.20191105220539-8318aed1a79f h1:8N8XWLZelZNibkhM1FuF+3Ad3YIbgirjdMiVA0eUkaM=
|
||||
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/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/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/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/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/go.mod h1:Q6Qx+uH3RAqyK4rFQroq9RL7mdkABMcfhEI+nNuzMJQ=
|
||||
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/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/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=
|
||||
@ -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/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/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/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
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/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/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.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
|
||||
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-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
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/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/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/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/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/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.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs=
|
||||
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/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.5.0 h1:5BakdOZdtKJ1FFk6QdL8iSGrMWsXgchNJcrnarjbmJQ=
|
||||
github.com/pelletier/go-toml v1.5.0/go.mod h1:5N711Q9dKgbdkxHL+MEfF31hpT7l0S0s/t2kKREewys=
|
||||
github.com/pelletier/go-toml v1.6.0 h1:aetoXYr0Tv7xRU/V4B4IZJ2QcbtMUFoNb3ORp7TzIK4=
|
||||
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.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
|
||||
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/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.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 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-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/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.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.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-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.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/rakyll/statik v0.1.6 h1:uICcfUXpgqtw2VopbIncslhAmE5hwc4g20TEyEENBNs=
|
||||
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-20180503174638-e2704e165165/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
|
||||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ=
|
||||
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/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/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.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/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/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/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
||||
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/cobra v0.0.1/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
|
||||
github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
|
||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||
github.com/spf13/cobra v0.0.6 h1:breEStsVwemnKh2/s6gMvSdMEkwW0sK8vGStnlVBMCs=
|
||||
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.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||
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.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
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.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.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
||||
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.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/stumble/gorocksdb v0.0.3 h1:9UU+QA1pqFYJuf9+5p7z1IqdE5k0mma4UAeu2wmX8kA=
|
||||
github.com/stumble/gorocksdb v0.0.3/go.mod h1:v6IHdFBXk5DJ1K4FZ0xi+eY737quiiBxYtSWXadLybY=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965 h1:1oFLiOyVl+W7bnBzGhf7BbIv9loSFQcieWWYIjLqcAw=
|
||||
github.com/syndtr/goleveldb v1.0.1-0.20190318030020-c3a204f8e965/go.mod h1:9OrXJhf154huy1nPWmuSrkgjPUtUNhA+Zmy+6AESzuA=
|
||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/subosito/gotenv v1.2.0 h1:Slr1R9HxAlEKefgq5jn9U+DnETlIUa6HfgEzj0g5d7s=
|
||||
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/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-20190823183015-45b1026d81ae/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk=
|
||||
github.com/tendermint/crypto v0.0.0-20191022145703-50d29ede1e15 h1:hqAk8riJvK4RMWx1aInLzndwxKalgi5rTqgfXxOxbEI=
|
||||
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.15.0 h1:TC4e66P59W7ML9+bxio17CPKnxW3nKIRAYskntMAoRk=
|
||||
github.com/tendermint/go-amino v0.15.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME=
|
||||
github.com/tendermint/iavl v0.12.4 h1:hd1woxUGISKkfUWBA4mmmTwOua6PQZTJM/F0FDrmMV8=
|
||||
github.com/tendermint/iavl v0.12.4/go.mod h1:8LHakzt8/0G3/I8FUU0ReNx98S/EP6eyPJkAUvEXT/o=
|
||||
github.com/tendermint/tendermint v0.32.1/go.mod h1:jmPDAKuNkev9793/ivn/fTBnfpA9mGBww8MPRNPNxnU=
|
||||
github.com/tendermint/tendermint v0.32.6/go.mod h1:D2+A3pNjY+Po72X0mTfaXorFhiVI8dh/Zg640FGyGtE=
|
||||
github.com/tendermint/tendermint v0.32.7 h1:Szu5Fm1L3pvn3t4uQxPAcP+7ndZEQKgLie/yokM56rU=
|
||||
github.com/tendermint/tendermint v0.32.7/go.mod h1:D2+A3pNjY+Po72X0mTfaXorFhiVI8dh/Zg640FGyGtE=
|
||||
github.com/tendermint/tm-db v0.1.1/go.mod h1:0cPKWu2Mou3IlxecH+MEUSYc1Ch537alLe6CpFrKzgw=
|
||||
github.com/tendermint/tm-db v0.2.0 h1:rJxgdqn6fIiVJZy4zLpY1qVlyD0TU6vhkT4kEf71TQQ=
|
||||
github.com/tendermint/tm-db v0.2.0/go.mod h1:0cPKWu2Mou3IlxecH+MEUSYc1Ch537alLe6CpFrKzgw=
|
||||
github.com/tendermint/go-amino v0.15.1 h1:D2uk35eT4iTsvJd9jWIetzthE5C0/k2QmMFkCN+4JgQ=
|
||||
github.com/tendermint/go-amino v0.15.1/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME=
|
||||
github.com/tendermint/iavl v0.13.2 h1:O1m08/Ciy53l9IYmf75uIRVvrNsfjEbre8u/yCu/oqk=
|
||||
github.com/tendermint/iavl v0.13.2/go.mod h1:vE1u0XAGXYjHykd4BLp8p/yivrw2PF1TuoljBcsQoGA=
|
||||
github.com/tendermint/tendermint v0.33.2/go.mod h1:25DqB7YvV1tN3tHsjWoc2vFtlwICfrub9XO6UBO+4xk=
|
||||
github.com/tendermint/tendermint v0.33.3 h1:6lMqjEoCGejCzAghbvfQgmw87snGSqEhDTo/jw+W8CI=
|
||||
github.com/tendermint/tendermint v0.33.3/go.mod h1:25DqB7YvV1tN3tHsjWoc2vFtlwICfrub9XO6UBO+4xk=
|
||||
github.com/tendermint/tm-db v0.4.1/go.mod h1:JsJ6qzYkCGiGwm5GHl/H5GLI9XLb6qZX7PRe425dHAY=
|
||||
github.com/tendermint/tm-db v0.5.0 h1:qtM5UTr1dlRnHtDY6y7MZO5Di8XAE2j3lc/pCnKJ5hQ=
|
||||
github.com/tendermint/tm-db v0.5.0/go.mod h1:lSq7q5WRR/njf1LnhiZ/lIJHk2S8Y1Zyq5oP/3o9C2U=
|
||||
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/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/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
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.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk=
|
||||
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.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
|
||||
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.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-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-20190228161510-8dd112bcdc25/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
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-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
|
||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/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-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-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-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-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-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-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-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-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/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-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-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-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-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-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-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-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-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-20191008105621-543471e840be h1:QAcqgptGM8IQBC9K/RC4o+O9YmqEm0diQn9QmZw/0mU=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
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.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-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-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-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-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-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.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-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-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/grpc v1.13.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
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.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.22.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.23.1 h1:q4XQuHFC6I28BKZpo6IYyb3mNO+l7lSOxRuYTCiDfXk=
|
||||
google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
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.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/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-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/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/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/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.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.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
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-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=
|
||||
|
@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
@ -398,8 +399,8 @@ func sendMsgToBlockchain(cdc *amino.Codec, address string, keyname string,
|
||||
|
||||
// get the account number and sequence number
|
||||
accountNumber, sequenceNumber := getAccountNumberAndSequenceNumber(cdc, address)
|
||||
|
||||
txBldr := auth.NewTxBuilderFromCLI().
|
||||
inBuf := bufio.NewReader(os.Stdin)
|
||||
txBldr := auth.NewTxBuilderFromCLI(inBuf).
|
||||
WithTxEncoder(authclient.GetTxEncoder(cdc)).WithChainID("testing").
|
||||
WithKeybase(keybase).WithAccountNumber(accountNumber).
|
||||
WithSequence(sequenceNumber).WithGas(500000)
|
||||
|
@ -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
|
||||
|
||||
import (
|
||||
@ -10,22 +5,13 @@ import (
|
||||
"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 (
|
||||
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
|
||||
EventTypeAuctionBid = types.EventTypeAuctionBid
|
||||
EventTypeAuctionClose = types.EventTypeAuctionClose
|
||||
|
@ -6,8 +6,8 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
|
||||
"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",
|
||||
}
|
||||
|
||||
auctionQueryCmd.AddCommand(client.GetCommands(
|
||||
auctionQueryCmd.AddCommand(flags.GetCommands(
|
||||
QueryGetAuctionCmd(queryRoute, cdc),
|
||||
QueryGetAuctionsCmd(queryRoute, cdc),
|
||||
QueryParamsCmd(queryRoute, cdc),
|
||||
|
@ -1,14 +1,15 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
@ -25,7 +26,7 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command {
|
||||
Short: "auction transactions subcommands",
|
||||
}
|
||||
|
||||
auctionTxCmd.AddCommand(client.PostCommands(
|
||||
auctionTxCmd.AddCommand(flags.PostCommands(
|
||||
GetCmdPlaceBid(cdc),
|
||||
)...)
|
||||
|
||||
@ -45,8 +46,9 @@ $ %s tx %s bid 34 1000usdx --from myKeyName
|
||||
`, version.ClientName, types.ModuleName)),
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
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)
|
||||
if err != nil {
|
||||
|
@ -22,7 +22,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper types.SupplyKeeper
|
||||
for _, a := range gs.Auctions {
|
||||
keeper.SetAuction(ctx, a)
|
||||
// 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
|
||||
|
@ -1,32 +1,31 @@
|
||||
package auction
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
||||
"github.com/kava-labs/kava/x/auction/types"
|
||||
)
|
||||
|
||||
// NewHandler returns a function to handle all "auction" type messages.
|
||||
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())
|
||||
|
||||
switch msg := msg.(type) {
|
||||
case MsgPlaceBid:
|
||||
return handleMsgPlaceBid(ctx, keeper, msg)
|
||||
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)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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(),
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
@ -5,18 +5,19 @@ import (
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply"
|
||||
"github.com/kava-labs/kava/x/auction/types"
|
||||
)
|
||||
|
||||
// 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(
|
||||
seller,
|
||||
lot,
|
||||
bidDenom,
|
||||
types.DistantFuture)
|
||||
types.DistantFuture,
|
||||
)
|
||||
|
||||
err := k.supplyKeeper.SendCoinsFromModuleToModule(ctx, seller, types.ModuleName, sdk.NewCoins(lot))
|
||||
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.
|
||||
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(
|
||||
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.
|
||||
macc := k.supplyKeeper.GetModuleAccount(ctx, buyer)
|
||||
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))
|
||||
@ -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.
|
||||
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)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@ -91,7 +94,8 @@ func (k Keeper) StartCollateralAuction(ctx sdk.Context, seller string, lot sdk.C
|
||||
types.DistantFuture,
|
||||
maxBid,
|
||||
weightedAddresses,
|
||||
debt)
|
||||
debt,
|
||||
)
|
||||
|
||||
err = k.supplyKeeper.SendCoinsFromModuleToModule(ctx, seller, types.ModuleName, sdk.NewCoins(lot))
|
||||
if err != nil {
|
||||
@ -120,41 +124,40 @@ func (k Keeper) StartCollateralAuction(ctx sdk.Context, seller string, lot sdk.C
|
||||
}
|
||||
|
||||
// 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)
|
||||
if !found {
|
||||
return types.ErrAuctionNotFound(k.codespace, auctionID)
|
||||
return sdkerrors.Wrapf(types.ErrAuctionNotFound, "%d", auctionID)
|
||||
}
|
||||
|
||||
// validation common to all auctions
|
||||
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
|
||||
var err sdk.Error
|
||||
var updatedAuction types.Auction
|
||||
var (
|
||||
err error
|
||||
updatedAuction types.Auction
|
||||
)
|
||||
switch a := auction.(type) {
|
||||
case types.SurplusAuction:
|
||||
if updatedAuction, err = k.PlaceBidSurplus(ctx, a, bidder, newAmount); err != nil {
|
||||
return err
|
||||
}
|
||||
updatedAuction, err = k.PlaceBidSurplus(ctx, a, bidder, newAmount)
|
||||
case types.DebtAuction:
|
||||
if updatedAuction, err = k.PlaceBidDebt(ctx, a, bidder, newAmount); err != nil {
|
||||
return err
|
||||
}
|
||||
updatedAuction, err = k.PlaceBidDebt(ctx, a, bidder, newAmount)
|
||||
case types.CollateralAuction:
|
||||
if !a.IsReversePhase() {
|
||||
updatedAuction, err = k.PlaceForwardBidCollateral(ctx, a, bidder, newAmount)
|
||||
} else {
|
||||
updatedAuction, err = k.PlaceReverseBidCollateral(ctx, a, bidder, newAmount)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return types.ErrUnrecognizedAuctionType(k.codespace)
|
||||
err = sdkerrors.Wrap(types.ErrUnrecognizedAuctionType, auction.GetType())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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.
|
||||
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
|
||||
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
|
||||
sdk.MaxInt(
|
||||
@ -175,7 +178,7 @@ func (k Keeper) PlaceBidSurplus(ctx sdk.Context, a types.SurplusAuction, bidder
|
||||
),
|
||||
)
|
||||
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
|
||||
@ -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.
|
||||
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
|
||||
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() {
|
||||
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
|
||||
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 %
|
||||
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) {
|
||||
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
|
||||
@ -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.
|
||||
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
|
||||
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() {
|
||||
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
|
||||
sdk.MaxInt(
|
||||
@ -314,10 +317,10 @@ func (k Keeper) PlaceReverseBidCollateral(ctx sdk.Context, a types.CollateralAuc
|
||||
),
|
||||
)
|
||||
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() {
|
||||
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
|
||||
@ -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.
|
||||
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
|
||||
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
|
||||
sdk.MaxInt(
|
||||
@ -380,10 +383,10 @@ func (k Keeper) PlaceBidDebt(ctx sdk.Context, a types.DebtAuction, bidder sdk.Ac
|
||||
),
|
||||
)
|
||||
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() {
|
||||
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
|
||||
@ -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.
|
||||
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)
|
||||
if !found {
|
||||
return types.ErrAuctionNotFound(k.codespace, auctionID)
|
||||
return sdkerrors.Wrapf(types.ErrAuctionNotFound, "%d", auctionID)
|
||||
}
|
||||
|
||||
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
|
||||
@ -460,7 +463,7 @@ func (k Keeper) CloseAuction(ctx sdk.Context, auctionID uint64) sdk.Error {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return types.ErrUnrecognizedAuctionType(k.codespace)
|
||||
return sdkerrors.Wrap(types.ErrUnrecognizedAuctionType, auc.GetType())
|
||||
}
|
||||
|
||||
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.
|
||||
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))
|
||||
if err != nil {
|
||||
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.
|
||||
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))
|
||||
if err != nil {
|
||||
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.
|
||||
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))
|
||||
if err != nil {
|
||||
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.
|
||||
func (k Keeper) CloseExpiredAuctions(ctx sdk.Context) sdk.Error {
|
||||
func (k Keeper) CloseExpiredAuctions(ctx sdk.Context) error {
|
||||
var expiredAuctions []uint64
|
||||
k.IterateAuctionsByTime(ctx, ctx.BlockTime(), func(id uint64) bool {
|
||||
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.
|
||||
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 {
|
||||
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)
|
||||
|
@ -267,30 +267,31 @@ func TestStartSurplusAuction(t *testing.T) {
|
||||
blockTime time.Time
|
||||
args args
|
||||
expectPass bool
|
||||
expPanic bool
|
||||
}{
|
||||
{
|
||||
"normal",
|
||||
someTime,
|
||||
args{cdp.LiquidatorMacc, c("stable", 10), "gov"},
|
||||
true,
|
||||
true, false,
|
||||
},
|
||||
{
|
||||
"no module account",
|
||||
someTime,
|
||||
args{"nonExistentModule", c("stable", 10), "gov"},
|
||||
false,
|
||||
false, true,
|
||||
},
|
||||
{
|
||||
"not enough coins",
|
||||
someTime,
|
||||
args{cdp.LiquidatorMacc, c("stable", 101), "gov"},
|
||||
false,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
"incorrect denom",
|
||||
someTime,
|
||||
args{cdp.LiquidatorMacc, c("notacoin", 10), "gov"},
|
||||
false,
|
||||
false, false,
|
||||
},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
@ -308,7 +309,15 @@ func TestStartSurplusAuction(t *testing.T) {
|
||||
keeper := tApp.GetAuctionKeeper()
|
||||
|
||||
// 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
|
||||
sk := tApp.GetSupplyKeeper()
|
||||
@ -316,11 +325,11 @@ func TestStartSurplusAuction(t *testing.T) {
|
||||
actualAuc, found := keeper.GetAuction(ctx, id)
|
||||
|
||||
if tc.expectPass {
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, err, tc.name)
|
||||
// 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
|
||||
require.True(t, found)
|
||||
require.True(t, found, tc.name)
|
||||
expectedAuction := types.Auction(types.SurplusAuction{BaseAuction: types.BaseAuction{
|
||||
ID: id,
|
||||
Initiator: tc.args.seller,
|
||||
@ -331,13 +340,13 @@ func TestStartSurplusAuction(t *testing.T) {
|
||||
EndTime: types.DistantFuture,
|
||||
MaxEndTime: types.DistantFuture,
|
||||
}})
|
||||
require.Equal(t, expectedAuction, actualAuc)
|
||||
} else {
|
||||
require.Error(t, err)
|
||||
require.Equal(t, expectedAuction, actualAuc, tc.name)
|
||||
} else if !tc.expPanic && !tc.expectPass {
|
||||
require.Error(t, err, tc.name)
|
||||
// check coins not moved
|
||||
require.Equal(t, initialLiquidatorCoins, liquidatorCoins)
|
||||
require.Equal(t, initialLiquidatorCoins, liquidatorCoins, tc.name)
|
||||
// check auction not in store
|
||||
require.False(t, found)
|
||||
require.False(t, found, tc.name)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
@ -55,319 +56,347 @@ func TestAuctionBidding(t *testing.T) {
|
||||
auctionArgs auctionArgs
|
||||
setupBids []bidArgs
|
||||
bidArgs bidArgs
|
||||
expectedError sdk.CodeType
|
||||
expectedError error
|
||||
expectedEndTime time.Time
|
||||
expectedBidder sdk.AccAddress
|
||||
expectedBid sdk.Coin
|
||||
expectpass bool
|
||||
expectPass bool
|
||||
expectPanic bool
|
||||
}{
|
||||
{
|
||||
"basic: auction doesn't exist",
|
||||
auctionArgs{Surplus, "", c("token1", 1), c("token2", 1), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
|
||||
nil,
|
||||
bidArgs{buyer, c("token2", 10)},
|
||||
types.CodeAuctionNotFound,
|
||||
types.ErrAuctionNotFound,
|
||||
someTime.Add(types.DefaultBidDuration),
|
||||
buyer,
|
||||
c("token2", 10),
|
||||
false,
|
||||
true,
|
||||
},
|
||||
{
|
||||
"basic: closed auction",
|
||||
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
|
||||
nil,
|
||||
bidArgs{buyer, c("token2", 10)},
|
||||
types.CodeAuctionHasExpired,
|
||||
types.ErrAuctionHasExpired,
|
||||
types.DistantFuture,
|
||||
nil,
|
||||
c("token2", 0),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"surplus: normal",
|
||||
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
|
||||
nil,
|
||||
bidArgs{buyer, c("token2", 10)},
|
||||
sdk.CodeType(0),
|
||||
nil,
|
||||
someTime.Add(types.DefaultBidDuration),
|
||||
buyer,
|
||||
c("token2", 10),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"surplus: second bidder",
|
||||
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
|
||||
[]bidArgs{{buyer, c("token2", 10)}},
|
||||
bidArgs{secondBuyer, c("token2", 11)},
|
||||
sdk.CodeType(0),
|
||||
nil,
|
||||
someTime.Add(types.DefaultBidDuration),
|
||||
secondBuyer,
|
||||
c("token2", 11),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"surplus: invalid bid denom",
|
||||
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 10), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
|
||||
nil,
|
||||
bidArgs{buyer, c("badtoken", 10)},
|
||||
types.CodeInvalidBidDenom,
|
||||
types.ErrInvalidBidDenom,
|
||||
types.DistantFuture,
|
||||
nil, // surplus auctions are created with initial bidder as a nil address
|
||||
c("token2", 0),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"surplus: invalid bid (less than)",
|
||||
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 0), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
|
||||
[]bidArgs{{buyer, c("token2", 100)}},
|
||||
bidArgs{buyer, c("token2", 99)},
|
||||
types.CodeBidTooSmall,
|
||||
types.ErrBidTooSmall,
|
||||
someTime.Add(types.DefaultBidDuration),
|
||||
buyer,
|
||||
c("token2", 100),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"surplus: invalid bid (equal)",
|
||||
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 0), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
|
||||
nil,
|
||||
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,
|
||||
nil, // surplus auctions are created with initial bidder as a nil address
|
||||
c("token2", 0),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"surplus: invalid bid (less than min increment)",
|
||||
auctionArgs{Surplus, modName, c("token1", 100), c("token2", 0), sdk.Coin{}, []sdk.AccAddress{}, []sdk.Int{}},
|
||||
[]bidArgs{{buyer, c("token2", 100)}},
|
||||
bidArgs{buyer, c("token2", 104)}, // min bid is 105 at default 5%
|
||||
types.CodeBidTooSmall,
|
||||
types.ErrBidTooSmall,
|
||||
someTime.Add(types.DefaultBidDuration),
|
||||
buyer,
|
||||
c("token2", 100),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"debt: normal",
|
||||
auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}}, // initial bid, lot
|
||||
nil,
|
||||
bidArgs{buyer, c("token1", 10)},
|
||||
sdk.CodeType(0),
|
||||
nil,
|
||||
someTime.Add(types.DefaultBidDuration),
|
||||
buyer,
|
||||
c("token2", 100),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"debt: second bidder",
|
||||
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{secondBuyer, c("token1", 9)},
|
||||
sdk.CodeType(0),
|
||||
nil,
|
||||
someTime.Add(types.DefaultBidDuration),
|
||||
secondBuyer,
|
||||
c("token2", 100),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"debt: invalid lot denom",
|
||||
auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}}, // initial bid, lot
|
||||
nil,
|
||||
bidArgs{buyer, c("badtoken", 10)},
|
||||
types.CodeInvalidLotDenom,
|
||||
types.ErrInvalidLotDenom,
|
||||
types.DistantFuture,
|
||||
supply.NewModuleAddress(modName),
|
||||
c("token2", 100),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"debt: invalid lot size (larger)",
|
||||
auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}},
|
||||
nil,
|
||||
bidArgs{buyer, c("token1", 21)},
|
||||
types.CodeLotTooLarge,
|
||||
types.ErrLotTooLarge,
|
||||
types.DistantFuture,
|
||||
supply.NewModuleAddress(modName),
|
||||
c("token2", 100),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"debt: invalid lot size (equal)",
|
||||
auctionArgs{Debt, modName, c("token1", 20), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}},
|
||||
nil,
|
||||
bidArgs{buyer, c("token1", 20)},
|
||||
types.CodeLotTooLarge,
|
||||
types.ErrLotTooLarge,
|
||||
types.DistantFuture,
|
||||
supply.NewModuleAddress(modName),
|
||||
c("token2", 100),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"debt: invalid lot size (larger than min increment)",
|
||||
auctionArgs{Debt, modName, c("token1", 60), c("token2", 100), c("debt", 100), []sdk.AccAddress{}, []sdk.Int{}},
|
||||
nil,
|
||||
bidArgs{buyer, c("token1", 58)}, // max lot at default 5% is 57
|
||||
types.CodeLotTooLarge,
|
||||
types.ErrLotTooLarge,
|
||||
types.DistantFuture,
|
||||
supply.NewModuleAddress(modName),
|
||||
c("token2", 100),
|
||||
false,
|
||||
false, false,
|
||||
},
|
||||
{
|
||||
"collateral [forward]: normal",
|
||||
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
||||
nil,
|
||||
bidArgs{buyer, c("token2", 10)},
|
||||
sdk.CodeType(0),
|
||||
nil,
|
||||
someTime.Add(types.DefaultBidDuration),
|
||||
buyer,
|
||||
c("token2", 10),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"collateral [forward]: second bidder",
|
||||
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
||||
[]bidArgs{{buyer, c("token2", 10)}},
|
||||
bidArgs{secondBuyer, c("token2", 11)},
|
||||
sdk.CodeType(0),
|
||||
nil,
|
||||
someTime.Add(types.DefaultBidDuration),
|
||||
secondBuyer,
|
||||
c("token2", 11),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"collateral [forward]: invalid bid denom",
|
||||
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
||||
nil,
|
||||
bidArgs{buyer, c("badtoken", 10)},
|
||||
types.CodeInvalidBidDenom,
|
||||
types.ErrInvalidBidDenom,
|
||||
types.DistantFuture,
|
||||
nil,
|
||||
c("token2", 0),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"collateral [forward]: invalid bid size (smaller)",
|
||||
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", 9)},
|
||||
types.CodeBidTooSmall,
|
||||
types.ErrBidTooSmall,
|
||||
someTime.Add(types.DefaultBidDuration),
|
||||
buyer,
|
||||
c("token2", 10),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"collateral [forward]: invalid bid size (equal)",
|
||||
auctionArgs{Collateral, modName, c("token1", 20), c("token2", 100), c("debt", 50), collateralAddrs, collateralWeights}, // lot, max bid
|
||||
nil,
|
||||
bidArgs{buyer, c("token2", 0)},
|
||||
types.CodeBidTooSmall,
|
||||
types.ErrBidTooSmall,
|
||||
types.DistantFuture,
|
||||
nil,
|
||||
c("token2", 0),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"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
|
||||
[]bidArgs{{buyer, c("token2", 50)}},
|
||||
bidArgs{buyer, c("token2", 51)},
|
||||
types.CodeBidTooSmall,
|
||||
types.ErrBidTooSmall,
|
||||
someTime.Add(types.DefaultBidDuration),
|
||||
buyer,
|
||||
c("token2", 50),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"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
|
||||
[]bidArgs{{buyer, c("token2", 99)}},
|
||||
bidArgs{buyer, c("token2", 100)}, // min bid at default 5% is 104
|
||||
sdk.CodeType(0),
|
||||
nil,
|
||||
someTime.Add(types.DefaultBidDuration),
|
||||
buyer,
|
||||
c("token2", 100),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"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
|
||||
nil,
|
||||
bidArgs{buyer, c("token2", 101)},
|
||||
types.CodeBidTooLarge,
|
||||
types.ErrBidTooLarge,
|
||||
types.DistantFuture,
|
||||
nil,
|
||||
c("token2", 0),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"collateral [reverse]: normal",
|
||||
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("token1", 15)},
|
||||
sdk.CodeType(0),
|
||||
nil,
|
||||
someTime.Add(types.DefaultBidDuration),
|
||||
buyer,
|
||||
c("token2", 50),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"collateral [reverse]: second bidder",
|
||||
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{secondBuyer, c("token1", 14)},
|
||||
sdk.CodeType(0),
|
||||
nil,
|
||||
someTime.Add(types.DefaultBidDuration),
|
||||
secondBuyer,
|
||||
c("token2", 50),
|
||||
true,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"collateral [reverse]: invalid lot denom",
|
||||
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("badtoken", 15)},
|
||||
types.CodeInvalidLotDenom,
|
||||
types.ErrInvalidLotDenom,
|
||||
someTime.Add(types.DefaultBidDuration),
|
||||
buyer,
|
||||
c("token2", 50),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"collateral [reverse]: invalid lot size (greater)",
|
||||
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("token1", 21)},
|
||||
types.CodeLotTooLarge,
|
||||
types.ErrLotTooLarge,
|
||||
someTime.Add(types.DefaultBidDuration),
|
||||
buyer,
|
||||
c("token2", 50),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"collateral [reverse]: invalid lot size (equal)",
|
||||
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("token1", 20)},
|
||||
types.CodeLotTooLarge,
|
||||
types.ErrLotTooLarge,
|
||||
someTime.Add(types.DefaultBidDuration),
|
||||
buyer,
|
||||
c("token2", 50),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"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
|
||||
[]bidArgs{{buyer, c("token2", 50)}}, // put auction into reverse phase
|
||||
bidArgs{buyer, c("token1", 58)}, // max lot at default 5% is 57
|
||||
types.CodeLotTooLarge,
|
||||
types.ErrLotTooLarge,
|
||||
someTime.Add(types.DefaultBidDuration),
|
||||
buyer,
|
||||
c("token2", 50),
|
||||
false,
|
||||
false,
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
@ -394,17 +423,26 @@ func TestAuctionBidding(t *testing.T) {
|
||||
|
||||
// Start Auction
|
||||
var id uint64
|
||||
var err sdk.Error
|
||||
var err error
|
||||
switch tc.auctionArgs.auctionType {
|
||||
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:
|
||||
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:
|
||||
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:
|
||||
t.Fail()
|
||||
}
|
||||
|
||||
require.NoError(t, err)
|
||||
|
||||
// Place setup bids
|
||||
for _, b := range tc.setupBids {
|
||||
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)
|
||||
|
||||
// Check success/failure
|
||||
if tc.expectpass {
|
||||
if tc.expectPass {
|
||||
require.Nil(t, err)
|
||||
// Check auction was found
|
||||
newAuction, found := keeper.GetAuction(ctx, id)
|
||||
@ -445,7 +483,8 @@ func TestAuctionBidding(t *testing.T) {
|
||||
case Debt:
|
||||
bidAmt = oldAuction.GetBid()
|
||||
case Collateral:
|
||||
collatAuction, _ := oldAuction.(types.CollateralAuction)
|
||||
collatAuction, ok := oldAuction.(types.CollateralAuction)
|
||||
require.True(t, ok, tc.name)
|
||||
if collatAuction.IsReversePhase() {
|
||||
bidAmt = oldAuction.GetBid()
|
||||
}
|
||||
@ -453,18 +492,18 @@ func TestAuctionBidding(t *testing.T) {
|
||||
if oldBidder.Equals(tc.bidArgs.bidder) { // same bidder
|
||||
require.Equal(t, newBidderOldCoins.Sub(cs(bidAmt.Sub(oldAuction.GetBid()))), bank.GetCoins(ctx, tc.bidArgs.bidder))
|
||||
} 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
|
||||
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, 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
|
||||
require.Equal(t, oldBidderOldCoins.Add(oldAuction.GetBid()).Add(c("debt", oldAuction.GetBid().Amount.Int64())), bank.GetCoins(ctx, oldBidder))
|
||||
} 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 {
|
||||
// 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.Equal(t, tc.expectedError, err.Result().Code)
|
||||
require.True(t, errors.Is(err, tc.expectedError))
|
||||
|
||||
// Check auction values
|
||||
newAuction, found := keeper.GetAuction(ctx, id)
|
||||
|
@ -21,7 +21,7 @@ func RegisterInvariants(ir sdk.InvariantRegistry, k Keeper) {
|
||||
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 {
|
||||
return func(ctx sdk.Context) (string, bool) {
|
||||
|
||||
@ -31,7 +31,7 @@ func ModuleAccountInvariants(k Keeper) sdk.Invariant {
|
||||
if !ok {
|
||||
panic("stored auction type does not fulfill GenesisAuction interface")
|
||||
}
|
||||
totalAuctionCoins = totalAuctionCoins.Add(a.GetModuleAccountCoins())
|
||||
totalAuctionCoins = totalAuctionCoins.Add(a.GetModuleAccountCoins()...)
|
||||
return false
|
||||
})
|
||||
|
||||
|
@ -18,7 +18,6 @@ type Keeper struct {
|
||||
storeKey sdk.StoreKey
|
||||
cdc *codec.Codec
|
||||
paramSubspace subspace.Subspace
|
||||
codespace sdk.CodespaceType
|
||||
}
|
||||
|
||||
// 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 {
|
||||
panic(fmt.Sprintf("%s module account has not been set", types.ModuleName))
|
||||
}
|
||||
|
||||
if !paramstore.HasKeyTable() {
|
||||
paramstore = paramstore.WithKeyTable(types.ParamKeyTable())
|
||||
}
|
||||
|
||||
return Keeper{
|
||||
supplyKeeper: supplyKeeper,
|
||||
storeKey: storeKey,
|
||||
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
|
||||
func (k Keeper) GetNextAuctionID(ctx sdk.Context) (uint64, sdk.Error) {
|
||||
func (k Keeper) GetNextAuctionID(ctx sdk.Context) (uint64, error) {
|
||||
store := ctx.KVStore(k.storeKey)
|
||||
bz := store.Get(types.NextAuctionIDKey)
|
||||
if bz == nil {
|
||||
return 0, types.ErrInvalidInitialAuctionID(k.codespace)
|
||||
return 0, types.ErrInvalidInitialAuctionID
|
||||
}
|
||||
return types.Uint64FromBytes(bz), nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -66,7 +70,7 @@ func (k Keeper) IncrementNextAuctionID(ctx sdk.Context) sdk.Error {
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
@ -1,16 +1,18 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
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"
|
||||
)
|
||||
|
||||
// NewQuerier is the module level router for state queries
|
||||
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] {
|
||||
case types.QueryGetAuction:
|
||||
return queryAuction(ctx, req, keeper)
|
||||
@ -19,35 +21,35 @@ func NewQuerier(keeper Keeper) sdk.Querier {
|
||||
case types.QueryGetParams:
|
||||
return queryGetParams(ctx, req, keeper)
|
||||
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
|
||||
var requestParams types.QueryAuctionParams
|
||||
err := keeper.cdc.UnmarshalJSON(req.Data, &requestParams)
|
||||
err := types.ModuleCdc.UnmarshalJSON(req.Data, &requestParams)
|
||||
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
|
||||
auction, found := keeper.GetAuction(ctx, requestParams.AuctionID)
|
||||
if !found {
|
||||
return nil, types.ErrAuctionNotFound(types.DefaultCodespace, requestParams.AuctionID)
|
||||
return nil, sdkerrors.Wrapf(types.ErrAuctionNotFound, "%d", requestParams.AuctionID)
|
||||
}
|
||||
|
||||
// Encode results
|
||||
bz, err := codec.MarshalJSONIndent(keeper.cdc, auction)
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
auctionsList := types.Auctions{}
|
||||
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
|
||||
bz, err := codec.MarshalJSONIndent(keeper.cdc, auctionsList)
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
params := keeper.GetParams(ctx)
|
||||
|
||||
// Encode results
|
||||
bz, err := codec.MarshalJSONIndent(keeper.cdc, params)
|
||||
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
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
sim "github.com/cosmos/cosmos-sdk/x/simulation"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
@ -24,7 +25,7 @@ import (
|
||||
var (
|
||||
_ module.AppModule = AppModule{}
|
||||
_ module.AppModuleBasic = AppModuleBasic{}
|
||||
_ module.AppModuleSimulation = AppModuleSimulation{}
|
||||
_ module.AppModuleSimulation = AppModule{}
|
||||
)
|
||||
|
||||
// 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.
|
||||
type AppModule struct {
|
||||
AppModuleBasic
|
||||
AppModuleSimulation
|
||||
|
||||
keeper Keeper
|
||||
supplyKeeper types.SupplyKeeper
|
||||
keeper Keeper
|
||||
accountKeeper auth.AccountKeeper
|
||||
supplyKeeper types.SupplyKeeper
|
||||
}
|
||||
|
||||
// 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{
|
||||
AppModuleBasic: AppModuleBasic{},
|
||||
keeper: keeper,
|
||||
accountKeeper: accountKeeper,
|
||||
supplyKeeper: supplyKeeper,
|
||||
}
|
||||
}
|
||||
@ -159,3 +141,30 @@ func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) {
|
||||
func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []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)
|
||||
}
|
||||
|
@ -5,14 +5,15 @@ import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
|
||||
"github.com/tendermint/tendermint/libs/kv"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
|
||||
"github.com/kava-labs/kava/x/auction/types"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
case bytes.Equal(kvA.Key[:1], types.AuctionKeyPrefix):
|
||||
var auctionA, auctionB types.Auction
|
||||
|
@ -6,8 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/libs/kv"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@ -28,11 +27,11 @@ func TestDecodeDistributionStore(t *testing.T) {
|
||||
oneCoin := sdk.NewCoin("coin", sdk.OneInt())
|
||||
auction := types.NewSurplusAuction("me", oneCoin, "coin", time.Now().UTC())
|
||||
|
||||
kvPairs := cmn.KVPairs{
|
||||
cmn.KVPair{Key: types.AuctionKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(&auction)},
|
||||
cmn.KVPair{Key: types.AuctionByTimeKeyPrefix, Value: sdk.Uint64ToBigEndian(2)},
|
||||
cmn.KVPair{Key: types.NextAuctionIDKey, Value: sdk.Uint64ToBigEndian(10)},
|
||||
cmn.KVPair{Key: []byte{0x99}, Value: []byte{0x99}},
|
||||
kvPairs := kv.Pairs{
|
||||
kv.Pair{Key: types.AuctionKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(&auction)},
|
||||
kv.Pair{Key: types.AuctionByTimeKeyPrefix, Value: sdk.Uint64ToBigEndian(2)},
|
||||
kv.Pair{Key: types.NextAuctionIDKey, Value: sdk.Uint64ToBigEndian(10)},
|
||||
kv.Pair{Key: []byte{0x99}, Value: []byte{0x99}},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
|
@ -88,7 +88,7 @@ func RandomizedGenState(simState *module.SimulationState) {
|
||||
if !ok {
|
||||
panic("can't convert Auction to GenesisAuction")
|
||||
}
|
||||
totalAuctionCoins = totalAuctionCoins.Add(a.GetModuleAccountCoins())
|
||||
totalAuctionCoins = totalAuctionCoins.Add(a.GetModuleAccountCoins()...)
|
||||
}
|
||||
auctionGenesis.NextAuctionID = startingID + uint64(len(auctions))
|
||||
auctionGenesis.Auctions = append(auctionGenesis.Auctions, auctions...)
|
||||
@ -112,7 +112,7 @@ func RandomizedGenState(simState *module.SimulationState) {
|
||||
panic("bidder not found")
|
||||
}
|
||||
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)
|
||||
}
|
||||
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
|
||||
var supplyGenesis supply.GenesisState
|
||||
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)
|
||||
|
||||
// TODO liquidator mod account doesn't need to be initialized for this example
|
||||
|
251
x/auction/simulation/operations.go
Normal file
251
x/auction/simulation/operations.go
Normal 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
|
||||
}
|
@ -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
|
||||
}
|
@ -17,29 +17,29 @@ func ParamChanges(r *rand.Rand) []simulation.ParamChange {
|
||||
// as strings in JSON (such as time.Duration) have the escaped quotes.
|
||||
// TODO should we encode the values properly with ModuleCdc.MustMarshalJSON()?
|
||||
return []simulation.ParamChange{
|
||||
simulation.NewSimParamChange(types.ModuleName, string(types.KeyBidDuration), "",
|
||||
simulation.NewSimParamChange(types.ModuleName, string(types.KeyBidDuration),
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
return fmt.Sprintf("\"%d\"", GenIncrementSurplus(r))
|
||||
return fmt.Sprintf("%d", GenIncrementSurplus(r))
|
||||
},
|
||||
),
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ func (a CollateralAuction) GetType() string { return "collateral" }
|
||||
// It is used in genesis initialize the module account correctly.
|
||||
func (a CollateralAuction) GetModuleAccountCoins() sdk.Coins {
|
||||
// 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.
|
||||
@ -276,24 +276,25 @@ type WeightedAddresses struct {
|
||||
}
|
||||
|
||||
// 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{
|
||||
Addresses: addrs,
|
||||
Weights: weights,
|
||||
}
|
||||
if err := wa.Validate(); err != nil {
|
||||
return WeightedAddresses{}, sdk.ErrInternal(err.Error())
|
||||
return WeightedAddresses{}, err
|
||||
}
|
||||
return wa, nil
|
||||
}
|
||||
|
||||
// Validate checks for that the weights are not negative and that lengths match.
|
||||
func (wa WeightedAddresses) Validate() error {
|
||||
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 {
|
||||
if w.IsNegative() {
|
||||
return fmt.Errorf("weights contain a negative amount")
|
||||
return fmt.Errorf("weights contain a negative amount: %s", w)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
@ -1,98 +1,36 @@
|
||||
// DONTCOVER
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
import sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
// DONTCOVER
|
||||
|
||||
var (
|
||||
// ErrInvalidInitialAuctionID error for when the initial auction ID hasn't been set
|
||||
ErrInvalidInitialAuctionID = sdkerrors.Register(ModuleName, 2, "initial auction ID hasn't been set")
|
||||
// ErrInvalidModulePermissions error for when module doesn't have valid permissions
|
||||
ErrInvalidModulePermissions = sdkerrors.Register(ModuleName, 3, "module does not have required permission")
|
||||
// ErrUnrecognizedAuctionType error for unrecognized auction type
|
||||
ErrUnrecognizedAuctionType = sdkerrors.Register(ModuleName, 4, "unrecognized auction type")
|
||||
// ErrAuctionNotFound error for when an auction is not found
|
||||
ErrAuctionNotFound = sdkerrors.Register(ModuleName, 5, "auction not found")
|
||||
// ErrAuctionHasNotExpired error for attempting to close an auction that has not passed its end time
|
||||
ErrAuctionHasNotExpired = sdkerrors.Register(ModuleName, 6, "auction can't be closed as curent block time has not passed auction end time")
|
||||
// ErrAuctionHasExpired error for when an auction is closed and unavailable for bidding
|
||||
ErrAuctionHasExpired = sdkerrors.Register(ModuleName, 7, "auction has closed")
|
||||
// ErrInvalidBidDenom error for when bid denom doesn't match auction bid denom
|
||||
ErrInvalidBidDenom = sdkerrors.Register(ModuleName, 8, "bid denom doesn't match auction bid denom")
|
||||
// ErrInvalidLotDenom error for when lot denom doesn't match auction lot denom
|
||||
ErrInvalidLotDenom = sdkerrors.Register(ModuleName, 9, "lot denom doesn't match auction lot denom")
|
||||
// ErrBidTooSmall error for when bid is not greater than auction's min bid amount
|
||||
ErrBidTooSmall = sdkerrors.Register(ModuleName, 10, "bid is not greater than auction's min new bid amount")
|
||||
// ErrBidTooLarge error for when bid is larger than auction's maximum allowed bid
|
||||
ErrBidTooLarge = sdkerrors.Register(ModuleName, 11, "bid is greater than auction's max bid")
|
||||
// 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")
|
||||
// ErrLotTooLarge error for when lot is not smaller than auction's max new lot amount
|
||||
ErrLotTooLarge = sdkerrors.Register(ModuleName, 13, "lot is greater than auction's max new lot amount")
|
||||
// ErrCollateralAuctionIsInReversePhase error for when attempting to place a forward bid on a collateral auction in reverse phase
|
||||
ErrCollateralAuctionIsInReversePhase = sdkerrors.Register(ModuleName, 14, "invalid bid: auction is in reverse phase")
|
||||
// ErrCollateralAuctionIsInForwardPhase error for when attempting to place a reverse bid on a collateral auction in forward phase
|
||||
ErrCollateralAuctionIsInForwardPhase = sdkerrors.Register(ModuleName, 15, "invalid bid: auction is in forward phase")
|
||||
)
|
||||
|
||||
// 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
|
||||
)
|
||||
|
||||
// ErrInvalidInitialAuctionID error for when the initial auction ID hasn't been set
|
||||
func ErrInvalidInitialAuctionID(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidInitialAuctionID, fmt.Sprintf("initial auction ID hasn't been set"))
|
||||
}
|
||||
|
||||
// ErrInvalidModulePermissions error for when module doesn't have valid permissions
|
||||
func ErrInvalidModulePermissions(codespace sdk.CodespaceType, permission string) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidModulePermissions, fmt.Sprintf("module does not have required permission '%s'", permission))
|
||||
}
|
||||
|
||||
// ErrUnrecognizedAuctionType error for unrecognized auction type
|
||||
func ErrUnrecognizedAuctionType(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeUnrecognizedAuctionType, fmt.Sprintf("unrecognized auction type"))
|
||||
}
|
||||
|
||||
// ErrAuctionNotFound error for when an auction is not found
|
||||
func ErrAuctionNotFound(codespace sdk.CodespaceType, id uint64) sdk.Error {
|
||||
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
|
||||
func ErrAuctionHasNotExpired(codespace sdk.CodespaceType, blockTime time.Time, endTime time.Time) sdk.Error {
|
||||
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
|
||||
func ErrAuctionHasExpired(codespace sdk.CodespaceType, id uint64) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeAuctionHasExpired, fmt.Sprintf("auction %d has closed", id))
|
||||
}
|
||||
|
||||
// ErrInvalidBidDenom error for when bid denom doesn't match auction bid denom
|
||||
func ErrInvalidBidDenom(codespace sdk.CodespaceType, bidDenom string, auctionBidDenom string) sdk.Error {
|
||||
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
|
||||
func ErrInvalidLotDenom(codespace sdk.CodespaceType, lotDenom string, auctionLotDenom string) sdk.Error {
|
||||
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
|
||||
func ErrBidTooSmall(codespace sdk.CodespaceType, bid sdk.Coin, minBid sdk.Coin) sdk.Error {
|
||||
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
|
||||
func ErrBidTooLarge(codespace sdk.CodespaceType, bid sdk.Coin, maxBid sdk.Coin) sdk.Error {
|
||||
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
|
||||
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
|
||||
func ErrLotTooLarge(codespace sdk.CodespaceType, lot sdk.Coin, maxLot sdk.Coin) sdk.Error {
|
||||
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
|
||||
func ErrCollateralAuctionIsInReversePhase(codespace sdk.CodespaceType, id uint64) sdk.Error {
|
||||
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
|
||||
func ErrCollateralAuctionIsInForwardPhase(codespace sdk.CodespaceType, id uint64) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeCollateralAuctionIsInForwardPhase, fmt.Sprintf("invalid bid - auction %d is in forward phase", id))
|
||||
}
|
||||
|
@ -10,10 +10,10 @@ type SupplyKeeper interface {
|
||||
GetModuleAddress(name string) sdk.AccAddress
|
||||
GetModuleAccount(ctx sdk.Context, moduleName string) supplyexported.ModuleAccountI
|
||||
|
||||
SendCoinsFromModuleToModule(ctx sdk.Context, sender, recipient string, amt sdk.Coins) sdk.Error
|
||||
SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error
|
||||
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule 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) 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
|
||||
MintCoins(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) error
|
||||
}
|
||||
|
@ -2,7 +2,9 @@ package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
// 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" }
|
||||
|
||||
// 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() {
|
||||
return sdk.ErrInvalidAddress("invalid (empty) bidder address")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "bidder address cannot be empty")
|
||||
}
|
||||
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
|
||||
}
|
||||
@ -51,3 +53,12 @@ func (msg MsgPlaceBid) GetSignBytes() []byte {
|
||||
func (msg MsgPlaceBid) GetSigners() []sdk.AccAddress {
|
||||
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)
|
||||
}
|
||||
|
@ -2,13 +2,17 @@ package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/params"
|
||||
"github.com/cosmos/cosmos-sdk/x/params/subspace"
|
||||
)
|
||||
|
||||
var emptyDec = sdk.Dec{}
|
||||
|
||||
// Defaults for auction params
|
||||
const (
|
||||
// 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.
|
||||
func (p *Params) ParamSetPairs() subspace.ParamSetPairs {
|
||||
return subspace.ParamSetPairs{
|
||||
{Key: KeyBidDuration, Value: &p.BidDuration},
|
||||
{Key: KeyMaxAuctionDuration, Value: &p.MaxAuctionDuration},
|
||||
{Key: KeyIncrementSurplus, Value: &p.IncrementSurplus},
|
||||
{Key: KeyIncrementDebt, Value: &p.IncrementDebt},
|
||||
{Key: KeyIncrementCollateral, Value: &p.IncrementCollateral},
|
||||
params.NewParamSetPair(KeyBidDuration, &p.BidDuration, validateBidDurationParam),
|
||||
params.NewParamSetPair(KeyMaxAuctionDuration, &p.MaxAuctionDuration, validateMaxAuctionDurationParam),
|
||||
params.NewParamSetPair(KeyIncrementSurplus, &p.IncrementSurplus, validateIncrementSurplusParam),
|
||||
params.NewParamSetPair(KeyIncrementDebt, &p.IncrementDebt, validateIncrementDebtParam),
|
||||
params.NewParamSetPair(KeyIncrementCollateral, &p.IncrementCollateral, validateIncrementCollateralParam),
|
||||
}
|
||||
}
|
||||
|
||||
@ -97,26 +101,102 @@ func (p Params) String() string {
|
||||
|
||||
// Validate checks that the parameters have valid values.
|
||||
func (p Params) Validate() error {
|
||||
if p.BidDuration < 0 {
|
||||
return sdk.ErrInternal("bid duration cannot be negative")
|
||||
if err := validateBidDurationParam(p.BidDuration); err != nil {
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
||||
func validateBidDurationParam(i interface{}) error {
|
||||
bidDuration, ok := i.(time.Duration)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid parameter type: %T", i)
|
||||
}
|
||||
if p.IncrementCollateral.IsNegative() {
|
||||
return sdk.ErrInternal("collateral auction increment cannot be less than zero")
|
||||
|
||||
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
|
||||
}
|
||||
|
@ -3,12 +3,14 @@ package bep3_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
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"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/kava-labs/kava/app"
|
||||
"github.com/kava-labs/kava/x/bep3"
|
||||
)
|
||||
@ -19,8 +21,8 @@ type ABCITestSuite struct {
|
||||
app app.TestApp
|
||||
ctx sdk.Context
|
||||
addrs []sdk.AccAddress
|
||||
swapIDs []cmn.HexBytes
|
||||
randomNumbers []cmn.HexBytes
|
||||
swapIDs []tmbytes.HexBytes
|
||||
randomNumbers []tmbytes.HexBytes
|
||||
}
|
||||
|
||||
func (suite *ABCITestSuite) SetupTest() {
|
||||
@ -46,8 +48,8 @@ func (suite *ABCITestSuite) SetupTest() {
|
||||
func (suite *ABCITestSuite) ResetKeeper() {
|
||||
suite.keeper = suite.app.GetBep3Keeper()
|
||||
|
||||
var swapIDs []cmn.HexBytes
|
||||
var randomNumbers []cmn.HexBytes
|
||||
var swapIDs []tmbytes.HexBytes
|
||||
var randomNumbers []tmbytes.HexBytes
|
||||
for i := 0; i < 10; i++ {
|
||||
// Set up atomic swap variables
|
||||
expireHeight := int64(360)
|
||||
|
@ -1,5 +1,3 @@
|
||||
// nolint
|
||||
// DO NOT EDIT - generated by aliasgen tool (github.com/rhuairahrighairidh/aliasgen)
|
||||
package bep3
|
||||
|
||||
import (
|
||||
@ -26,24 +24,8 @@ const (
|
||||
AttributeValueCategory = types.AttributeValueCategory
|
||||
CalcSwapID = types.CalcSwapID
|
||||
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
|
||||
CreateAtomicSwap = types.CreateAtomicSwap
|
||||
DefaultCodespace = types.DefaultCodespace
|
||||
DefaultLongtermStorageDuration = types.DefaultLongtermStorageDuration
|
||||
DefaultParamspace = types.DefaultParamspace
|
||||
DepositAtomicSwap = types.DepositAtomicSwap
|
||||
@ -144,7 +126,6 @@ type (
|
||||
AssetSupply = types.AssetSupply
|
||||
AtomicSwap = types.AtomicSwap
|
||||
AtomicSwaps = types.AtomicSwaps
|
||||
CodeType = types.CodeType
|
||||
GenesisState = types.GenesisState
|
||||
MsgClaimAtomicSwap = types.MsgClaimAtomicSwap
|
||||
MsgCreateAtomicSwap = types.MsgCreateAtomicSwap
|
||||
|
@ -6,8 +6,8 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/spf13/cobra"
|
||||
@ -24,7 +24,7 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command {
|
||||
Short: "Querying commands for the bep3 module",
|
||||
}
|
||||
|
||||
bep3QueryCmd.AddCommand(client.GetCommands(
|
||||
bep3QueryCmd.AddCommand(flags.GetCommands(
|
||||
QueryCalcSwapIDCmd(queryRoute, cdc),
|
||||
QueryCalcRandomNumberHashCmd(queryRoute, cdc),
|
||||
QueryGetAtomicSwapCmd(queryRoute, cdc),
|
||||
|
@ -1,13 +1,14 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
@ -25,7 +26,7 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command {
|
||||
Short: "bep3 transactions subcommands",
|
||||
}
|
||||
|
||||
bep3TxCmd.AddCommand(client.PostCommands(
|
||||
bep3TxCmd.AddCommand(flags.PostCommands(
|
||||
GetCmdCreateAtomicSwap(cdc),
|
||||
GetCmdClaimAtomicSwap(cdc),
|
||||
GetCmdRefundAtomicSwap(cdc),
|
||||
@ -43,8 +44,9 @@ func GetCmdCreateAtomicSwap(cdc *codec.Codec) *cobra.Command {
|
||||
version.ClientName, types.ModuleName),
|
||||
Args: cobra.ExactArgs(8),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
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)
|
||||
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),
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc))
|
||||
txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
|
||||
|
||||
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),
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
txBldr := auth.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc))
|
||||
txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
|
||||
|
||||
from := cliCtx.GetFromAddress()
|
||||
|
||||
|
@ -3,10 +3,11 @@ package rest
|
||||
import (
|
||||
"github.com/gorilla/mux"
|
||||
|
||||
tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/rest"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
)
|
||||
|
||||
// RegisterRoutes registers bep3-related REST handlers to a router
|
||||
@ -17,30 +18,30 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) {
|
||||
|
||||
// PostCreateSwapReq defines the properties of a swap create request's body
|
||||
type PostCreateSwapReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
From sdk.AccAddress `json:"from" yaml:"from"`
|
||||
To sdk.AccAddress `json:"to" yaml:"to"`
|
||||
RecipientOtherChain string `json:"recipient_other_chain" yaml:"recipient_other_chain"`
|
||||
SenderOtherChain string `json:"sender_other_chain" yaml:"sender_other_chain"`
|
||||
RandomNumberHash cmn.HexBytes `json:"random_number_hash" yaml:"random_number_hash"`
|
||||
Timestamp int64 `json:"timestamp" yaml:"timestamp"`
|
||||
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
||||
ExpectedIncome string `json:"expected_income" yaml:"expected_income"`
|
||||
HeightSpan int64 `json:"height_span" yaml:"height_span"`
|
||||
CrossChain bool `json:"cross_chain" yaml:"cross_chain"`
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
From sdk.AccAddress `json:"from" yaml:"from"`
|
||||
To sdk.AccAddress `json:"to" yaml:"to"`
|
||||
RecipientOtherChain string `json:"recipient_other_chain" yaml:"recipient_other_chain"`
|
||||
SenderOtherChain string `json:"sender_other_chain" yaml:"sender_other_chain"`
|
||||
RandomNumberHash tmbytes.HexBytes `json:"random_number_hash" yaml:"random_number_hash"`
|
||||
Timestamp int64 `json:"timestamp" yaml:"timestamp"`
|
||||
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
||||
ExpectedIncome string `json:"expected_income" yaml:"expected_income"`
|
||||
HeightSpan int64 `json:"height_span" yaml:"height_span"`
|
||||
CrossChain bool `json:"cross_chain" yaml:"cross_chain"`
|
||||
}
|
||||
|
||||
// PostClaimSwapReq defines the properties of a swap claim request's body
|
||||
type PostClaimSwapReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
From sdk.AccAddress `json:"from" yaml:"from"`
|
||||
SwapID cmn.HexBytes `json:"swap_id" yaml:"swap_id"`
|
||||
RandomNumber cmn.HexBytes `json:"random_number" yaml:"random_number"`
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
From sdk.AccAddress `json:"from" yaml:"from"`
|
||||
SwapID tmbytes.HexBytes `json:"swap_id" yaml:"swap_id"`
|
||||
RandomNumber tmbytes.HexBytes `json:"random_number" yaml:"random_number"`
|
||||
}
|
||||
|
||||
// PostRefundSwapReq defines the properties of swap refund request's body
|
||||
type PostRefundSwapReq struct {
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
From sdk.AccAddress `json:"from" yaml:"from"`
|
||||
SwapID cmn.HexBytes `json:"swap_id" yaml:"swap_id"`
|
||||
BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"`
|
||||
From sdk.AccAddress `json:"from" yaml:"from"`
|
||||
SwapID tmbytes.HexBytes `json:"swap_id" yaml:"swap_id"`
|
||||
}
|
||||
|
@ -71,9 +71,9 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper SupplyKeeper, gs G
|
||||
case Open:
|
||||
// This index expires unclaimed swaps
|
||||
keeper.InsertIntoByBlockIndex(ctx, swap)
|
||||
incomingSupplies = incomingSupplies.Add(swap.Amount)
|
||||
incomingSupplies = incomingSupplies.Add(swap.Amount...)
|
||||
case Expired:
|
||||
incomingSupplies = incomingSupplies.Add(swap.Amount)
|
||||
incomingSupplies = incomingSupplies.Add(swap.Amount...)
|
||||
case Completed:
|
||||
// This index stores swaps until deletion
|
||||
keeper.InsertIntoLongtermStorage(ctx, swap)
|
||||
@ -84,9 +84,9 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper SupplyKeeper, gs G
|
||||
switch swap.Status {
|
||||
case Open:
|
||||
keeper.InsertIntoByBlockIndex(ctx, swap)
|
||||
outgoingSupplies = outgoingSupplies.Add(swap.Amount)
|
||||
outgoingSupplies = outgoingSupplies.Add(swap.Amount...)
|
||||
case Expired:
|
||||
outgoingSupplies = outgoingSupplies.Add(swap.Amount)
|
||||
outgoingSupplies = outgoingSupplies.Add(swap.Amount...)
|
||||
case Completed:
|
||||
keeper.InsertIntoLongtermStorage(ctx, swap)
|
||||
default:
|
||||
|
@ -1,14 +1,13 @@
|
||||
package bep3
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
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
|
||||
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())
|
||||
switch msg := msg.(type) {
|
||||
case MsgCreateAtomicSwap:
|
||||
@ -18,19 +17,18 @@ func NewHandler(k Keeper) sdk.Handler {
|
||||
case MsgRefundAtomicSwap:
|
||||
return handleMsgRefundAtomicSwap(ctx, k, msg)
|
||||
default:
|
||||
errMsg := fmt.Sprintf("unrecognized %s message type: %T", ModuleName, msg)
|
||||
return sdk.ErrUnknownRequest(errMsg).Result()
|
||||
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
msg.SenderOtherChain, msg.RecipientOtherChain, msg.Amount, msg.ExpectedIncome, msg.CrossChain)
|
||||
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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(),
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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(),
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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(),
|
||||
}
|
||||
}, nil
|
||||
}
|
||||
|
@ -1,17 +1,16 @@
|
||||
package bep3_test
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
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"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/kava-labs/kava/app"
|
||||
"github.com/kava-labs/kava/x/bep3"
|
||||
)
|
||||
@ -47,7 +46,7 @@ func (suite *HandlerTestSuite) SetupTest() {
|
||||
suite.ctx = ctx
|
||||
}
|
||||
|
||||
func (suite *HandlerTestSuite) AddAtomicSwap() (cmn.HexBytes, cmn.HexBytes) {
|
||||
func (suite *HandlerTestSuite) AddAtomicSwap() (tmbytes.HexBytes, tmbytes.HexBytes) {
|
||||
expireHeight := int64(360)
|
||||
amount := cs(c("bnb", int64(50000)))
|
||||
timestamp := ts(0)
|
||||
@ -74,8 +73,9 @@ func (suite *HandlerTestSuite) TestMsgCreateAtomicSwap() {
|
||||
suite.addrs[0], suite.addrs[2], TestRecipientOtherChain, TestSenderOtherChain,
|
||||
randomNumberHash, timestamp, amount, amount.String(), int64(300), true)
|
||||
|
||||
res := suite.handler(suite.ctx, msg)
|
||||
suite.True(res.IsOK())
|
||||
res, err := suite.handler(suite.ctx, msg)
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().NotNil(res)
|
||||
}
|
||||
|
||||
func (suite *HandlerTestSuite) TestMsgClaimAtomicSwap() {
|
||||
@ -84,15 +84,16 @@ func (suite *HandlerTestSuite) TestMsgClaimAtomicSwap() {
|
||||
badRandomNumberHash := bep3.CalculateRandomHash(badRandomNumber.Bytes(), ts(0))
|
||||
badSwapID := bep3.CalculateSwapID(badRandomNumberHash, suite.addrs[0], TestSenderOtherChain)
|
||||
badMsg := bep3.NewMsgClaimAtomicSwap(suite.addrs[0], badSwapID, badRandomNumber.Bytes())
|
||||
badRes := suite.handler(suite.ctx, badMsg)
|
||||
suite.False(badRes.IsOK())
|
||||
suite.True(strings.Contains(badRes.Log, fmt.Sprintf("AtomicSwap %s was not found", hex.EncodeToString(badSwapID))))
|
||||
badRes, err := suite.handler(suite.ctx, badMsg)
|
||||
suite.Require().Error(err)
|
||||
suite.Require().Nil(badRes)
|
||||
|
||||
// Add an atomic swap before attempting new claim msg
|
||||
swapID, randomNumber := suite.AddAtomicSwap()
|
||||
msg := bep3.NewMsgClaimAtomicSwap(suite.addrs[0], swapID, randomNumber)
|
||||
res := suite.handler(suite.ctx, msg)
|
||||
suite.True(res.IsOK())
|
||||
res, err := suite.handler(suite.ctx, msg)
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().NotNil(res)
|
||||
}
|
||||
|
||||
func (suite *HandlerTestSuite) TestMsgRefundAtomicSwap() {
|
||||
@ -101,30 +102,31 @@ func (suite *HandlerTestSuite) TestMsgRefundAtomicSwap() {
|
||||
badRandomNumberHash := bep3.CalculateRandomHash(badRandomNumber.Bytes(), ts(0))
|
||||
badSwapID := bep3.CalculateSwapID(badRandomNumberHash, suite.addrs[0], TestSenderOtherChain)
|
||||
badMsg := bep3.NewMsgRefundAtomicSwap(suite.addrs[0], badSwapID)
|
||||
badRes := suite.handler(suite.ctx, badMsg)
|
||||
suite.False(badRes.IsOK())
|
||||
suite.True(strings.Contains(badRes.Log, fmt.Sprintf("AtomicSwap %s was not found", hex.EncodeToString(badSwapID))))
|
||||
badRes, err := suite.handler(suite.ctx, badMsg)
|
||||
suite.Require().Error(err)
|
||||
suite.Require().Nil(badRes)
|
||||
|
||||
// Add an atomic swap and build refund msg
|
||||
swapID, _ := suite.AddAtomicSwap()
|
||||
msg := bep3.NewMsgRefundAtomicSwap(suite.addrs[0], swapID)
|
||||
|
||||
// Attempt to refund active atomic swap
|
||||
res1 := suite.handler(suite.ctx, msg)
|
||||
suite.True(strings.Contains(res1.Log, "atomic swap is still active and cannot be refunded"))
|
||||
suite.False(res1.IsOK())
|
||||
res1, err := suite.handler(suite.ctx, msg)
|
||||
suite.Require().Error(err)
|
||||
suite.Require().Nil(res1)
|
||||
|
||||
// Expire the atomic swap with begin blocker and attempt refund
|
||||
laterCtx := suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + 400)
|
||||
bep3.BeginBlocker(laterCtx, suite.keeper)
|
||||
res2 := suite.handler(laterCtx, msg)
|
||||
suite.True(res2.IsOK())
|
||||
res2, err := suite.handler(laterCtx, msg)
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().NotNil(res2)
|
||||
}
|
||||
|
||||
func (suite *HandlerTestSuite) TestInvalidMsg() {
|
||||
res := suite.handler(suite.ctx, sdk.NewTestMsg())
|
||||
suite.False(res.IsOK())
|
||||
suite.True(strings.Contains(res.Log, "unrecognized bep3 message type"))
|
||||
res, err := suite.handler(suite.ctx, sdk.NewTestMsg())
|
||||
suite.Require().Error(err)
|
||||
suite.Require().Nil(res)
|
||||
}
|
||||
|
||||
func TestHandlerTestSuite(t *testing.T) {
|
||||
|
@ -2,19 +2,21 @@ package keeper
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
||||
"github.com/kava-labs/kava/x/bep3/types"
|
||||
)
|
||||
|
||||
// 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))
|
||||
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
|
||||
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)
|
||||
@ -23,16 +25,16 @@ func (k Keeper) IncrementCurrentAssetSupply(ctx sdk.Context, coin sdk.Coin) sdk.
|
||||
}
|
||||
|
||||
// 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))
|
||||
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
|
||||
// Use sdk.Int instead of sdk.Coin to prevent panic if true
|
||||
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)
|
||||
@ -41,16 +43,16 @@ func (k Keeper) DecrementCurrentAssetSupply(ctx sdk.Context, coin sdk.Coin) sdk.
|
||||
}
|
||||
|
||||
// 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))
|
||||
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
|
||||
totalSupply := supply.CurrentSupply.Add(supply.IncomingSupply)
|
||||
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)
|
||||
@ -59,16 +61,16 @@ func (k Keeper) IncrementIncomingAssetSupply(ctx sdk.Context, coin sdk.Coin) sdk
|
||||
}
|
||||
|
||||
// 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))
|
||||
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
|
||||
// Use sdk.Int instead of sdk.Coin to prevent panic if true
|
||||
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)
|
||||
@ -77,15 +79,15 @@ func (k Keeper) DecrementIncomingAssetSupply(ctx sdk.Context, coin sdk.Coin) sdk
|
||||
}
|
||||
|
||||
// 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))
|
||||
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
|
||||
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))
|
||||
}
|
||||
|
||||
@ -95,16 +97,16 @@ func (k Keeper) IncrementOutgoingAssetSupply(ctx sdk.Context, coin sdk.Coin) sdk
|
||||
}
|
||||
|
||||
// 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))
|
||||
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
|
||||
// Use sdk.Int instead of sdk.Coin to prevent panic if true
|
||||
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)
|
||||
|
@ -17,20 +17,23 @@ type Keeper struct {
|
||||
cdc *codec.Codec
|
||||
paramSubspace subspace.Subspace
|
||||
supplyKeeper types.SupplyKeeper
|
||||
codespace sdk.CodespaceType
|
||||
}
|
||||
|
||||
// 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 {
|
||||
panic(fmt.Sprintf("%s module account has not been set", types.ModuleName))
|
||||
}
|
||||
|
||||
if !paramstore.HasKeyTable() {
|
||||
paramstore = paramstore.WithKeyTable(types.ParamKeyTable())
|
||||
}
|
||||
|
||||
keeper := Keeper{
|
||||
key: key,
|
||||
cdc: cdc,
|
||||
paramSubspace: paramstore.WithKeyTable(types.ParamKeyTable()),
|
||||
paramSubspace: paramstore,
|
||||
supplyKeeper: sk,
|
||||
codespace: codespace,
|
||||
}
|
||||
return keeper
|
||||
}
|
||||
|
@ -2,6 +2,8 @@ package keeper
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
||||
"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
|
||||
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)
|
||||
if !found {
|
||||
return types.ErrAssetNotSupported(k.codespace, coin.Denom)
|
||||
return sdkerrors.Wrap(types.ErrAssetNotSupported, coin.Denom)
|
||||
}
|
||||
if !asset.Active {
|
||||
return types.ErrAssetNotActive(k.codespace, asset.Denom)
|
||||
return sdkerrors.Wrap(types.ErrAssetNotActive, asset.Denom)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@ -92,7 +93,7 @@ func (suite *AssetTestSuite) TestValidateLiveAsset() {
|
||||
testCases := []struct {
|
||||
name string
|
||||
args args
|
||||
expectedError sdk.CodeType
|
||||
expectedError error
|
||||
expectPass bool
|
||||
}{
|
||||
{
|
||||
@ -100,7 +101,7 @@ func (suite *AssetTestSuite) TestValidateLiveAsset() {
|
||||
args{
|
||||
coin: c("bnb", 1),
|
||||
},
|
||||
sdk.CodeType(0),
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
@ -108,7 +109,7 @@ func (suite *AssetTestSuite) TestValidateLiveAsset() {
|
||||
args{
|
||||
coin: c("bad", 1),
|
||||
},
|
||||
types.CodeAssetNotSupported,
|
||||
types.ErrAssetNotSupported,
|
||||
false,
|
||||
},
|
||||
{
|
||||
@ -116,7 +117,7 @@ func (suite *AssetTestSuite) TestValidateLiveAsset() {
|
||||
args{
|
||||
coin: c("inc", 1),
|
||||
},
|
||||
types.CodeAssetNotActive,
|
||||
types.ErrAssetNotActive,
|
||||
false,
|
||||
},
|
||||
}
|
||||
@ -127,10 +128,10 @@ func (suite *AssetTestSuite) TestValidateLiveAsset() {
|
||||
err := suite.keeper.ValidateLiveAsset(suite.ctx, tc.args.coin)
|
||||
|
||||
if tc.expectPass {
|
||||
suite.NoError(err)
|
||||
suite.Require().NoError(err)
|
||||
} else {
|
||||
suite.Error(err)
|
||||
suite.Equal(tc.expectedError, err.Result().Code)
|
||||
suite.Require().Error(err)
|
||||
suite.Require().True(errors.Is(err, tc.expectedError))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1,15 +1,18 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
||||
"github.com/kava-labs/kava/x/bep3/types"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
)
|
||||
|
||||
// NewQuerier is the module level router for state queries
|
||||
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] {
|
||||
case types.QueryGetAssetSupply:
|
||||
return queryAssetSupply(ctx, req, keeper)
|
||||
@ -20,57 +23,57 @@ func NewQuerier(keeper Keeper) sdk.Querier {
|
||||
case types.QueryGetParams:
|
||||
return queryGetParams(ctx, req, keeper)
|
||||
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
|
||||
var requestParams types.QueryAssetSupply
|
||||
err := keeper.cdc.UnmarshalJSON(req.Data, &requestParams)
|
||||
err := types.ModuleCdc.UnmarshalJSON(req.Data, &requestParams)
|
||||
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))
|
||||
if !found {
|
||||
return nil, sdk.ErrInternal("Not found")
|
||||
return nil, sdkerrors.Wrap(types.ErrAssetSupplyNotFound, string(requestParams.Denom))
|
||||
}
|
||||
|
||||
// Encode results
|
||||
bz, err := codec.MarshalJSONIndent(keeper.cdc, assetSupply)
|
||||
bz, err := codec.MarshalJSONIndent(types.ModuleCdc, assetSupply)
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
var requestParams types.QueryAtomicSwapByID
|
||||
err := keeper.cdc.UnmarshalJSON(req.Data, &requestParams)
|
||||
err := types.ModuleCdc.UnmarshalJSON(req.Data, &requestParams)
|
||||
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
|
||||
atomicSwap, found := keeper.GetAtomicSwap(ctx, requestParams.SwapID)
|
||||
if !found {
|
||||
return nil, sdk.ErrInternal("Not found")
|
||||
return nil, sdkerrors.Wrapf(types.ErrAtomicSwapNotFound, "%d", requestParams.SwapID)
|
||||
}
|
||||
|
||||
// Encode results
|
||||
bz, err := codec.MarshalJSONIndent(keeper.cdc, atomicSwap)
|
||||
bz, err := codec.MarshalJSONIndent(types.ModuleCdc, atomicSwap)
|
||||
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
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
})
|
||||
|
||||
bz, err2 := codec.MarshalJSONIndent(keeper.cdc, swaps)
|
||||
bz, err2 := codec.MarshalJSONIndent(types.ModuleCdc, swaps)
|
||||
if err2 != nil {
|
||||
return nil, sdk.ErrInternal("could not marshal result to JSON")
|
||||
return nil, sdkerrors.Wrap(sdkerrors.ErrJSONMarshal, err.Error())
|
||||
}
|
||||
|
||||
return bz, nil
|
||||
}
|
||||
|
||||
// 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
|
||||
params := keeper.GetParams(ctx)
|
||||
|
||||
// Encode results
|
||||
bz, err := codec.MarshalJSONIndent(keeper.cdc, params)
|
||||
bz, err := codec.MarshalJSONIndent(types.ModuleCdc, params)
|
||||
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
|
||||
}
|
||||
|
@ -5,14 +5,17 @@ import (
|
||||
"strings"
|
||||
"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"
|
||||
|
||||
"github.com/kava-labs/kava/app"
|
||||
"github.com/kava-labs/kava/x/bep3/keeper"
|
||||
"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 (
|
||||
@ -27,7 +30,7 @@ type QuerierTestSuite struct {
|
||||
querier sdk.Querier
|
||||
addrs []sdk.AccAddress
|
||||
isSupplyDenom map[string]bool
|
||||
swapIDs []cmn.HexBytes
|
||||
swapIDs []tmbytes.HexBytes
|
||||
isSwapID map[string]bool
|
||||
}
|
||||
|
||||
@ -55,7 +58,7 @@ func (suite *QuerierTestSuite) SetupTest() {
|
||||
suite.addrs = addrs
|
||||
|
||||
// Create atomic swaps and save IDs
|
||||
var swapIDs []cmn.HexBytes
|
||||
var swapIDs []tmbytes.HexBytes
|
||||
isSwapID := make(map[string]bool)
|
||||
for i := 0; i < 10; i++ {
|
||||
// Set up atomic swap variables
|
||||
@ -87,7 +90,7 @@ func (suite *QuerierTestSuite) TestQueryAssetSupply() {
|
||||
denom := "bnb"
|
||||
query := abci.RequestQuery{
|
||||
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
|
||||
|
@ -7,40 +7,37 @@ import (
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
||||
"github.com/kava-labs/kava/x/bep3/types"
|
||||
)
|
||||
|
||||
// CreateAtomicSwap creates a new AtomicSwap
|
||||
func (k Keeper) CreateAtomicSwap(ctx sdk.Context, randomNumberHash []byte, timestamp int64, heightSpan int64,
|
||||
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
|
||||
swapID := types.CalculateSwapID(randomNumberHash, sender, senderOtherChain)
|
||||
_, found := k.GetAtomicSwap(ctx, swapID)
|
||||
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
|
||||
// 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) {
|
||||
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
|
||||
pastTimestampLimit := ctx.BlockTime().Add(time.Duration(-15) * time.Minute).Unix()
|
||||
futureTimestampLimit := ctx.BlockTime().Add(time.Duration(30) * time.Minute).Unix()
|
||||
if timestamp < pastTimestampLimit || timestamp >= futureTimestampLimit {
|
||||
return types.ErrInvalidTimestamp(k.codespace)
|
||||
}
|
||||
|
||||
// Sanity check on recipient address
|
||||
if recipient.Empty() {
|
||||
return sdk.ErrInvalidAddress("invalid (empty) recipient address")
|
||||
return sdkerrors.Wrap(types.ErrInvalidTimestamp, time.Unix(timestamp, 0).UTC().String())
|
||||
}
|
||||
|
||||
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])
|
||||
@ -58,17 +55,15 @@ func (k Keeper) CreateAtomicSwap(ctx sdk.Context, randomNumberHash []byte, times
|
||||
|
||||
switch direction {
|
||||
case types.Incoming:
|
||||
err := k.IncrementIncomingAssetSupply(ctx, amount[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = k.IncrementIncomingAssetSupply(ctx, amount[0])
|
||||
case types.Outgoing:
|
||||
err := k.IncrementOutgoingAssetSupply(ctx, amount[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = k.IncrementOutgoingAssetSupply(ctx, amount[0])
|
||||
default:
|
||||
return sdk.ErrInternal("invalid swap direction")
|
||||
err = fmt.Errorf("invalid swap direction: %s", direction.String())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Transfer coins to module
|
||||
@ -86,16 +81,16 @@ func (k Keeper) CreateAtomicSwap(ctx sdk.Context, randomNumberHash []byte, times
|
||||
ctx.EventManager().EmitEvent(
|
||||
sdk.NewEvent(
|
||||
types.EventTypeCreateAtomicSwap,
|
||||
sdk.NewAttribute(types.AttributeKeySender, fmt.Sprintf("%s", atomicSwap.Sender)),
|
||||
sdk.NewAttribute(types.AttributeKeyRecipient, fmt.Sprintf("%s", atomicSwap.Recipient)),
|
||||
sdk.NewAttribute(types.AttributeKeyAtomicSwapID, fmt.Sprintf("%s", hex.EncodeToString(atomicSwap.GetSwapID()))),
|
||||
sdk.NewAttribute(types.AttributeKeyRandomNumberHash, fmt.Sprintf("%s", hex.EncodeToString(atomicSwap.RandomNumberHash))),
|
||||
sdk.NewAttribute(types.AttributeKeySender, atomicSwap.Sender.String()),
|
||||
sdk.NewAttribute(types.AttributeKeyRecipient, atomicSwap.Recipient.String()),
|
||||
sdk.NewAttribute(types.AttributeKeyAtomicSwapID, hex.EncodeToString(atomicSwap.GetSwapID())),
|
||||
sdk.NewAttribute(types.AttributeKeyRandomNumberHash, hex.EncodeToString(atomicSwap.RandomNumberHash)),
|
||||
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.AttributeKeyAmount, fmt.Sprintf("%s", atomicSwap.Amount[0].String())),
|
||||
sdk.NewAttribute(types.AttributeKeyExpectedIncome, fmt.Sprintf("%s", expectedIncome)),
|
||||
sdk.NewAttribute(types.AttributeKeyDirection, fmt.Sprintf("%s", atomicSwap.Direction.String())),
|
||||
sdk.NewAttribute(types.AttributeKeyAmount, atomicSwap.Amount[0].String()),
|
||||
sdk.NewAttribute(types.AttributeKeyExpectedIncome, expectedIncome),
|
||||
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
|
||||
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)
|
||||
if !found {
|
||||
return types.ErrAtomicSwapNotFound(k.codespace, swapID)
|
||||
return sdkerrors.Wrapf(types.ErrAtomicSwapNotFound, "%d", swapID)
|
||||
}
|
||||
|
||||
// Only open atomic swaps can be claimed
|
||||
if atomicSwap.Status != types.Open {
|
||||
return types.ErrSwapNotClaimable(k.codespace)
|
||||
return types.ErrSwapNotClaimable
|
||||
}
|
||||
|
||||
// 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
|
||||
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 {
|
||||
case types.Incoming:
|
||||
err := k.DecrementIncomingAssetSupply(ctx, atomicSwap.Amount[0])
|
||||
if err != nil {
|
||||
return err
|
||||
break
|
||||
}
|
||||
err = k.IncrementCurrentAssetSupply(ctx, atomicSwap.Amount[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case types.Outgoing:
|
||||
err := k.DecrementOutgoingAssetSupply(ctx, atomicSwap.Amount[0])
|
||||
err = k.DecrementOutgoingAssetSupply(ctx, atomicSwap.Amount[0])
|
||||
if err != nil {
|
||||
return err
|
||||
break
|
||||
}
|
||||
err = k.DecrementCurrentAssetSupply(ctx, atomicSwap.Amount[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return sdk.ErrInternal("invalid swap direction")
|
||||
err = fmt.Errorf("invalid swap direction: %s", atomicSwap.Direction.String())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 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 {
|
||||
return err
|
||||
}
|
||||
@ -158,11 +152,11 @@ func (k Keeper) ClaimAtomicSwap(ctx sdk.Context, from sdk.AccAddress, swapID []b
|
||||
ctx.EventManager().EmitEvent(
|
||||
sdk.NewEvent(
|
||||
types.EventTypeClaimAtomicSwap,
|
||||
sdk.NewAttribute(types.AttributeKeyClaimSender, fmt.Sprintf("%s", from)),
|
||||
sdk.NewAttribute(types.AttributeKeyRecipient, fmt.Sprintf("%s", atomicSwap.Recipient)),
|
||||
sdk.NewAttribute(types.AttributeKeyAtomicSwapID, fmt.Sprintf("%s", hex.EncodeToString(atomicSwap.GetSwapID()))),
|
||||
sdk.NewAttribute(types.AttributeKeyRandomNumberHash, fmt.Sprintf("%s", hex.EncodeToString(atomicSwap.RandomNumberHash))),
|
||||
sdk.NewAttribute(types.AttributeKeyRandomNumber, fmt.Sprintf("%s", hex.EncodeToString(randomNumber))),
|
||||
sdk.NewAttribute(types.AttributeKeyClaimSender, from.String()),
|
||||
sdk.NewAttribute(types.AttributeKeyRecipient, atomicSwap.Recipient.String()),
|
||||
sdk.NewAttribute(types.AttributeKeyAtomicSwapID, hex.EncodeToString(atomicSwap.GetSwapID())),
|
||||
sdk.NewAttribute(types.AttributeKeyRandomNumberHash, hex.EncodeToString(atomicSwap.RandomNumberHash)),
|
||||
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
|
||||
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)
|
||||
if !found {
|
||||
return types.ErrAtomicSwapNotFound(k.codespace, swapID)
|
||||
return sdkerrors.Wrapf(types.ErrAtomicSwapNotFound, "%s", swapID)
|
||||
}
|
||||
// Only expired swaps may be refunded
|
||||
if atomicSwap.Status != types.Expired {
|
||||
return types.ErrSwapNotRefundable(k.codespace)
|
||||
return types.ErrSwapNotRefundable
|
||||
}
|
||||
|
||||
var err error
|
||||
switch atomicSwap.Direction {
|
||||
case types.Incoming:
|
||||
err := k.DecrementIncomingAssetSupply(ctx, atomicSwap.Amount[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = k.DecrementIncomingAssetSupply(ctx, atomicSwap.Amount[0])
|
||||
case types.Outgoing:
|
||||
err := k.DecrementOutgoingAssetSupply(ctx, atomicSwap.Amount[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = k.DecrementOutgoingAssetSupply(ctx, atomicSwap.Amount[0])
|
||||
default:
|
||||
return sdk.ErrInternal("invalid swap direction")
|
||||
err = fmt.Errorf("invalid swap direction: %s", atomicSwap.Direction.String())
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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.
|
||||
func (k Keeper) UpdateExpiredAtomicSwaps(ctx sdk.Context) sdk.Error {
|
||||
func (k Keeper) UpdateExpiredAtomicSwaps(ctx sdk.Context) error {
|
||||
var expiredSwaps [][]byte
|
||||
k.IterateAtomicSwapsByBlock(ctx, uint64(ctx.BlockHeight()), func(id []byte) bool {
|
||||
expiredSwaps = append(expiredSwaps, id)
|
||||
@ -249,7 +242,7 @@ func (k Keeper) UpdateExpiredAtomicSwaps(ctx sdk.Context) sdk.Error {
|
||||
}
|
||||
|
||||
// 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
|
||||
k.IterateAtomicSwapsLongtermStorage(ctx, uint64(ctx.BlockHeight()), func(id []byte) bool {
|
||||
swapsToDelete = append(swapsToDelete, id)
|
||||
|
@ -5,15 +5,18 @@ import (
|
||||
"testing"
|
||||
"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"
|
||||
|
||||
"github.com/kava-labs/kava/app"
|
||||
"github.com/kava-labs/kava/x/bep3"
|
||||
"github.com/kava-labs/kava/x/bep3/keeper"
|
||||
"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 {
|
||||
@ -25,9 +28,9 @@ type AtomicSwapTestSuite struct {
|
||||
deputy sdk.AccAddress
|
||||
addrs []sdk.AccAddress
|
||||
timestamps []int64
|
||||
randomNumberHashes []cmn.HexBytes
|
||||
swapIDs []cmn.HexBytes
|
||||
randomNumbers []cmn.HexBytes
|
||||
randomNumberHashes []tmbytes.HexBytes
|
||||
swapIDs []tmbytes.HexBytes
|
||||
randomNumbers []tmbytes.HexBytes
|
||||
}
|
||||
|
||||
const (
|
||||
@ -65,8 +68,8 @@ func (suite *AtomicSwapTestSuite) SetupTest() {
|
||||
|
||||
func (suite *AtomicSwapTestSuite) GenerateSwapDetails() {
|
||||
var timestamps []int64
|
||||
var randomNumberHashes []cmn.HexBytes
|
||||
var randomNumbers []cmn.HexBytes
|
||||
var randomNumberHashes []tmbytes.HexBytes
|
||||
var randomNumbers []tmbytes.HexBytes
|
||||
for i := 0; i < 10; i++ {
|
||||
// Set up atomic swap details
|
||||
timestamp := ts(i)
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
sim "github.com/cosmos/cosmos-sdk/x/simulation"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/spf13/cobra"
|
||||
@ -21,7 +22,7 @@ import (
|
||||
var (
|
||||
_ module.AppModule = AppModule{}
|
||||
_ module.AppModuleBasic = AppModuleBasic{}
|
||||
_ module.AppModuleSimulation = AppModuleSimulation{}
|
||||
_ module.AppModuleSimulation = AppModule{}
|
||||
)
|
||||
|
||||
// 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.
|
||||
type AppModule struct {
|
||||
AppModuleBasic
|
||||
AppModuleSimulation
|
||||
|
||||
keeper Keeper
|
||||
supplyKeeper SupplyKeeper
|
||||
keeper Keeper
|
||||
accountKeeper auth.AccountKeeper
|
||||
supplyKeeper SupplyKeeper
|
||||
}
|
||||
|
||||
// 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{
|
||||
AppModuleBasic: AppModuleBasic{},
|
||||
keeper: keeper,
|
||||
accountKeeper: accountKeeper,
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
@ -4,14 +4,16 @@ import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
||||
"github.com/tendermint/tendermint/libs/kv"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
|
||||
"github.com/kava-labs/kava/x/bep3/types"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
case bytes.Equal(kvA.Key[:1], types.AtomicSwapKeyPrefix):
|
||||
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),
|
||||
bytes.Equal(kvA.Key[:1], types.AtomicSwapLongtermStoragePrefix):
|
||||
var bytesA cmn.HexBytes = kvA.Value
|
||||
var bytesB cmn.HexBytes = kvA.Value
|
||||
var bytesA tmbytes.HexBytes = kvA.Value
|
||||
var bytesB tmbytes.HexBytes = kvA.Value
|
||||
return fmt.Sprintf("%s\n%s", bytesA.String(), bytesB.String())
|
||||
|
||||
default:
|
||||
|
@ -6,7 +6,8 @@ import (
|
||||
|
||||
"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"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@ -27,14 +28,14 @@ func TestDecodeDistributionStore(t *testing.T) {
|
||||
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)
|
||||
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{
|
||||
cmn.KVPair{Key: types.AtomicSwapKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(swap)},
|
||||
cmn.KVPair{Key: types.AssetSupplyKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(supply)},
|
||||
cmn.KVPair{Key: types.AtomicSwapByBlockPrefix, Value: bz},
|
||||
cmn.KVPair{Key: types.AtomicSwapByBlockPrefix, Value: bz},
|
||||
cmn.KVPair{Key: []byte{0x99}, Value: []byte{0x99}},
|
||||
kvPairs := kv.Pairs{
|
||||
kv.Pair{Key: types.AtomicSwapKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(swap)},
|
||||
kv.Pair{Key: types.AssetSupplyKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(supply)},
|
||||
kv.Pair{Key: types.AtomicSwapByBlockPrefix, Value: bz},
|
||||
kv.Pair{Key: types.AtomicSwapByBlockPrefix, Value: bz},
|
||||
kv.Pair{Key: []byte{0x99}, Value: []byte{0x99}},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
|
@ -25,13 +25,14 @@ const (
|
||||
|
||||
var (
|
||||
MaxSupplyLimit = sdk.NewInt(1000000000000)
|
||||
Accs []simulation.Account
|
||||
accs []simulation.Account
|
||||
ConsistentDenoms = [3]string{"bnb", "xrp", "btc"}
|
||||
)
|
||||
|
||||
// GenBnbDeputyAddress randomized BnbDeputyAddress
|
||||
func GenBnbDeputyAddress(r *rand.Rand) sdk.AccAddress {
|
||||
return simulation.RandomAcc(r, Accs).Address
|
||||
// GenRandBnbDeputy randomized BnbDeputyAddress
|
||||
func GenRandBnbDeputy(r *rand.Rand) simulation.Account {
|
||||
acc, _ := simulation.RandomAcc(r, accs)
|
||||
return acc
|
||||
}
|
||||
|
||||
// GenMinBlockLock randomized MinBlockLock
|
||||
@ -77,7 +78,7 @@ func genSupportedAsset(r *rand.Rand, denom string) types.AssetParam {
|
||||
|
||||
// RandomizedGenState generates a random GenesisState
|
||||
func RandomizedGenState(simState *module.SimulationState) {
|
||||
Accs = simState.Accounts
|
||||
accs = simState.Accounts
|
||||
|
||||
bep3Genesis := loadRandomBep3GenState(simState)
|
||||
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
|
||||
simState.Cdc.MustUnmarshalJSON(simState.GenState[supply.ModuleName], &supplyGenesis)
|
||||
for _, deputyCoin := range totalCoins {
|
||||
supplyGenesis.Supply = supplyGenesis.Supply.Add(deputyCoin)
|
||||
supplyGenesis.Supply = supplyGenesis.Supply.Add(deputyCoin...)
|
||||
}
|
||||
simState.GenState[supply.ModuleName] = simState.Cdc.MustMarshalJSON(supplyGenesis)
|
||||
}
|
||||
|
||||
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
|
||||
minBlockLock := int64(types.AbsoluteMinimumBlockLock)
|
||||
@ -110,7 +111,7 @@ func loadRandomBep3GenState(simState *module.SimulationState) types.GenesisState
|
||||
|
||||
bep3Genesis := types.GenesisState{
|
||||
Params: types.Params{
|
||||
BnbDeputyAddress: bnbDeputyAddress,
|
||||
BnbDeputyAddress: bnbDeputy.Address,
|
||||
MinBlockLock: minBlockLock,
|
||||
MaxBlockLock: maxBlockLock,
|
||||
SupportedAssets: supportedAssets,
|
||||
@ -134,7 +135,7 @@ func loadAuthGenState(simState *module.SimulationState, bep3Genesis types.Genesi
|
||||
var totalCoins []sdk.Coins
|
||||
for _, asset := range bep3Genesis.Params.SupportedAssets {
|
||||
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)
|
||||
}
|
||||
totalCoins = append(totalCoins, assetCoin)
|
||||
|
210
x/bep3/simulation/operations.go
Normal file
210
x/bep3/simulation/operations.go
Normal 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
|
||||
}
|
||||
}
|
@ -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
|
||||
}
|
@ -22,22 +22,22 @@ func ParamChanges(r *rand.Rand) []simulation.ParamChange {
|
||||
minBlockLockVal := GenMinBlockLock(r)
|
||||
|
||||
return []simulation.ParamChange{
|
||||
simulation.NewSimParamChange(types.ModuleName, keyBnbDeputyAddress, "",
|
||||
simulation.NewSimParamChange(types.ModuleName, keyBnbDeputyAddress,
|
||||
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 {
|
||||
return fmt.Sprintf("\"%d\"", minBlockLockVal)
|
||||
},
|
||||
),
|
||||
simulation.NewSimParamChange(types.ModuleName, keyMaxBlockLock, "",
|
||||
simulation.NewSimParamChange(types.ModuleName, keyMaxBlockLock,
|
||||
func(r *rand.Rand) string {
|
||||
return fmt.Sprintf("\"%d\"", GenMaxBlockLock(r, minBlockLockVal))
|
||||
},
|
||||
),
|
||||
simulation.NewSimParamChange(types.ModuleName, keySupportedAssets, "",
|
||||
simulation.NewSimParamChange(types.ModuleName, keySupportedAssets,
|
||||
func(r *rand.Rand) string {
|
||||
return fmt.Sprintf("\"%v\"", GenSupportedAssets(r))
|
||||
},
|
||||
|
@ -1,118 +1,40 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
// CodeType is the local code type
|
||||
type CodeType = sdk.CodeType
|
||||
// DONTCOVER
|
||||
|
||||
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 = sdkerrors.Register(ModuleName, 2, "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 = sdkerrors.Register(ModuleName, 3, "height span is outside acceptable range")
|
||||
// ErrAssetNotSupported error for when an asset is not supported
|
||||
ErrAssetNotSupported = sdkerrors.Register(ModuleName, 4, "asset not on the list of supported assets")
|
||||
// ErrAssetNotActive error for when an asset is currently inactive
|
||||
ErrAssetNotActive = sdkerrors.Register(ModuleName, 5, "asset is currently inactive")
|
||||
// ErrAssetSupplyNotFound error for when an asset's supply is not found in the store
|
||||
ErrAssetSupplyNotFound = sdkerrors.Register(ModuleName, 6, "asset supply not found in store")
|
||||
// ErrExceedsSupplyLimit error for when the proposed supply increase would put the supply above limit
|
||||
ErrExceedsSupplyLimit = sdkerrors.Register(ModuleName, 7, "asset supply over limit")
|
||||
// ErrExceedsAvailableSupply error for when the proposed outgoing amount exceeds the total available supply
|
||||
ErrExceedsAvailableSupply = sdkerrors.Register(ModuleName, 8, "outgoing swap exceeds total available supply")
|
||||
// ErrInvalidCurrentSupply error for when the proposed decrease would result in a negative current supplyx
|
||||
ErrInvalidCurrentSupply = sdkerrors.Register(ModuleName, 9, "supply decrease puts current asset supply below 0")
|
||||
// ErrInvalidIncomingSupply error for when the proposed decrease would result in a negative incoming supply
|
||||
ErrInvalidIncomingSupply = sdkerrors.Register(ModuleName, 10, "supply decrease puts incoming asset supply below 0")
|
||||
// ErrInvalidOutgoingSupply error for when the proposed decrease would result in a negative outgoing supply
|
||||
ErrInvalidOutgoingSupply = sdkerrors.Register(ModuleName, 11, "supply decrease puts outgoing asset supply below 0")
|
||||
// ErrInvalidClaimSecret error when a submitted secret doesn't match an AtomicSwap's swapID
|
||||
ErrInvalidClaimSecret = sdkerrors.Register(ModuleName, 12, "hashed claim attempt does not match")
|
||||
// ErrAtomicSwapAlreadyExists error for when an AtomicSwap with this swapID already exists
|
||||
ErrAtomicSwapAlreadyExists = sdkerrors.Register(ModuleName, 13, "atomic swap already exists")
|
||||
// ErrAtomicSwapNotFound error for when an atomic swap is not found
|
||||
ErrAtomicSwapNotFound = sdkerrors.Register(ModuleName, 14, "atomic swap not found")
|
||||
// ErrSwapNotRefundable error for when an AtomicSwap has not expired and cannot be refunded
|
||||
ErrSwapNotRefundable = sdkerrors.Register(ModuleName, 15, "atomic swap is still active and cannot be refunded")
|
||||
// ErrSwapNotClaimable error for when an atomic swap is not open and cannot be claimed
|
||||
ErrSwapNotClaimable = sdkerrors.Register(ModuleName, 16, "atomic swap is not claimable")
|
||||
)
|
||||
|
||||
// ErrInvalidTimestamp error for when an timestamp is outside of bounds. Assumes block time of 10 seconds.
|
||||
func ErrInvalidTimestamp(codespace sdk.CodespaceType) sdk.Error {
|
||||
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
|
||||
func ErrInvalidHeightSpan(codespace sdk.CodespaceType, heightspan int64, minLockTime int64, maxLockTime int64) sdk.Error {
|
||||
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
|
||||
func ErrAssetNotSupported(codespace sdk.CodespaceType, denom string) sdk.Error {
|
||||
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
|
||||
func ErrAssetNotActive(codespace sdk.CodespaceType, denom string) sdk.Error {
|
||||
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
|
||||
func ErrAssetSupplyNotFound(codespace sdk.CodespaceType, denom string) sdk.Error {
|
||||
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
|
||||
func ErrExceedsSupplyLimit(codespace sdk.CodespaceType, increase, current, limit sdk.Coin) sdk.Error {
|
||||
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
|
||||
func ErrExceedsAvailableSupply(codespace sdk.CodespaceType, increase sdk.Coin, available sdk.Int) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeExceedsAvailableSupply,
|
||||
fmt.Sprintf("an outgoing swap with amount %s exceeds total available supply %s",
|
||||
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
|
||||
func ErrInvalidIncomingSupply(codespace sdk.CodespaceType, decrease, incoming sdk.Coin) sdk.Error {
|
||||
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
|
||||
func ErrInvalidOutgoingSupply(codespace sdk.CodespaceType, decrease, outgoing sdk.Coin) sdk.Error {
|
||||
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
|
||||
func ErrInvalidClaimSecret(codespace sdk.CodespaceType, submittedSecret []byte, swapID []byte) sdk.Error {
|
||||
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
|
||||
func ErrAtomicSwapAlreadyExists(codespace sdk.CodespaceType, swapID cmn.HexBytes) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeAtomicSwapAlreadyExists, fmt.Sprintf("atomic swap %s already exists", swapID))
|
||||
}
|
||||
|
||||
// ErrAtomicSwapNotFound error for when an atomic swap is not found
|
||||
func ErrAtomicSwapNotFound(codespace sdk.CodespaceType, id []byte) sdk.Error {
|
||||
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
|
||||
func ErrSwapNotRefundable(codespace sdk.CodespaceType) sdk.Error {
|
||||
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
|
||||
func ErrSwapNotClaimable(codespace sdk.CodespaceType) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeSwapNotClaimable, fmt.Sprintf("atomic swap is not claimable"))
|
||||
}
|
||||
|
@ -10,10 +10,10 @@ type SupplyKeeper interface {
|
||||
GetModuleAddress(name string) sdk.AccAddress
|
||||
GetModuleAccount(ctx sdk.Context, moduleName string) supplyexported.ModuleAccountI
|
||||
|
||||
SendCoinsFromModuleToModule(ctx sdk.Context, sender, recipient string, amt sdk.Coins) sdk.Error
|
||||
SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error
|
||||
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule 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) 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
|
||||
MintCoins(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) error
|
||||
}
|
||||
|
@ -1,11 +1,15 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -36,21 +40,21 @@ var (
|
||||
|
||||
// MsgCreateAtomicSwap contains an AtomicSwap struct
|
||||
type MsgCreateAtomicSwap struct {
|
||||
From sdk.AccAddress `json:"from" yaml:"from"`
|
||||
To sdk.AccAddress `json:"to" yaml:"to"`
|
||||
RecipientOtherChain string `json:"recipient_other_chain" yaml:"recipient_other_chain"`
|
||||
SenderOtherChain string `json:"sender_other_chain" yaml:"sender_other_chain"`
|
||||
RandomNumberHash cmn.HexBytes `json:"random_number_hash" yaml:"random_number_hash"`
|
||||
Timestamp int64 `json:"timestamp" yaml:"timestamp"`
|
||||
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
||||
ExpectedIncome string `json:"expected_income" yaml:"expected_income"`
|
||||
HeightSpan int64 `json:"height_span" yaml:"height_span"`
|
||||
CrossChain bool `json:"cross_chain" yaml:"cross_chain"`
|
||||
From sdk.AccAddress `json:"from" yaml:"from"`
|
||||
To sdk.AccAddress `json:"to" yaml:"to"`
|
||||
RecipientOtherChain string `json:"recipient_other_chain" yaml:"recipient_other_chain"`
|
||||
SenderOtherChain string `json:"sender_other_chain" yaml:"sender_other_chain"`
|
||||
RandomNumberHash tmbytes.HexBytes `json:"random_number_hash" yaml:"random_number_hash"`
|
||||
Timestamp int64 `json:"timestamp" yaml:"timestamp"`
|
||||
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
||||
ExpectedIncome string `json:"expected_income" yaml:"expected_income"`
|
||||
HeightSpan int64 `json:"height_span" yaml:"height_span"`
|
||||
CrossChain bool `json:"cross_chain" yaml:"cross_chain"`
|
||||
}
|
||||
|
||||
// NewMsgCreateAtomicSwap initializes a new MsgCreateAtomicSwap
|
||||
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 {
|
||||
return MsgCreateAtomicSwap{
|
||||
From: from,
|
||||
@ -91,49 +95,58 @@ func (msg MsgCreateAtomicSwap) GetSigners() []sdk.AccAddress {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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 {
|
||||
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 {
|
||||
return sdk.ErrInternal(fmt.Sprintf("must leave recipient address on other chain to empty for single chain swap"))
|
||||
if !msg.CrossChain && msg.RecipientOtherChain != "" {
|
||||
return errors.New("must leave recipient address on other chain to empty for single chain swap")
|
||||
}
|
||||
if !msg.CrossChain && len(msg.SenderOtherChain) != 0 {
|
||||
return sdk.ErrInternal(fmt.Sprintf("must leave sender address on other chain to empty for single chain swap"))
|
||||
if !msg.CrossChain && msg.SenderOtherChain != "" {
|
||||
return errors.New("must leave sender address on other chain to empty for single chain swap")
|
||||
}
|
||||
if msg.CrossChain && len(msg.RecipientOtherChain) == 0 {
|
||||
return sdk.ErrInternal(fmt.Sprintf("missing recipient address on other chain for cross chain swap"))
|
||||
if msg.CrossChain && strings.TrimSpace(msg.RecipientOtherChain) == "" {
|
||||
return errors.New("missing recipient address on other chain for cross chain swap")
|
||||
}
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
return sdk.ErrInternal("timestamp must be positive")
|
||||
return errors.New("timestamp must be positive")
|
||||
}
|
||||
if !msg.Amount.IsAllPositive() {
|
||||
return sdk.ErrInternal(fmt.Sprintf("the swapped out coin must be positive"))
|
||||
if len(msg.Amount) == 0 {
|
||||
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 {
|
||||
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)
|
||||
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) {
|
||||
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 {
|
||||
return sdk.ErrInternal("height span must be positive")
|
||||
return errors.New("height span must be positive")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -146,9 +159,9 @@ func (msg MsgCreateAtomicSwap) GetSignBytes() []byte {
|
||||
|
||||
// MsgClaimAtomicSwap defines a AtomicSwap claim
|
||||
type MsgClaimAtomicSwap struct {
|
||||
From sdk.AccAddress `json:"from" yaml:"from"`
|
||||
SwapID cmn.HexBytes `json:"swap_id" yaml:"swap_id"`
|
||||
RandomNumber cmn.HexBytes `json:"random_number" yaml:"random_number"`
|
||||
From sdk.AccAddress `json:"from" yaml:"from"`
|
||||
SwapID tmbytes.HexBytes `json:"swap_id" yaml:"swap_id"`
|
||||
RandomNumber tmbytes.HexBytes `json:"random_number" yaml:"random_number"`
|
||||
}
|
||||
|
||||
// NewMsgClaimAtomicSwap initializes a new MsgClaimAtomicSwap
|
||||
@ -182,15 +195,18 @@ func (msg MsgClaimAtomicSwap) GetSigners() []sdk.AccAddress {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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 {
|
||||
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 {
|
||||
return sdk.ErrInternal("the length of random number cannot be 0")
|
||||
return errors.New("the length of random number cannot be 0")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -203,8 +219,8 @@ func (msg MsgClaimAtomicSwap) GetSignBytes() []byte {
|
||||
|
||||
// MsgRefundAtomicSwap defines a refund msg
|
||||
type MsgRefundAtomicSwap struct {
|
||||
From sdk.AccAddress `json:"from" yaml:"from"`
|
||||
SwapID cmn.HexBytes `json:"swap_id" yaml:"swap_id"`
|
||||
From sdk.AccAddress `json:"from" yaml:"from"`
|
||||
SwapID tmbytes.HexBytes `json:"swap_id" yaml:"swap_id"`
|
||||
}
|
||||
|
||||
// NewMsgRefundAtomicSwap initializes a new MsgRefundAtomicSwap
|
||||
@ -237,12 +253,15 @@ func (msg MsgRefundAtomicSwap) GetSigners() []sdk.AccAddress {
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
@ -3,11 +3,14 @@ package types_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/kava-labs/kava/x/bep3/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"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 (
|
||||
@ -33,7 +36,7 @@ func TestMsgCreateAtomicSwap(t *testing.T) {
|
||||
to sdk.AccAddress
|
||||
recipientOtherChain string
|
||||
senderOtherChain string
|
||||
randomNumberHash cmn.HexBytes
|
||||
randomNumberHash tmbytes.HexBytes
|
||||
timestamp int64
|
||||
amount sdk.Coins
|
||||
expectedIncome string
|
||||
@ -75,8 +78,8 @@ func TestMsgClaimAtomicSwap(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
from sdk.AccAddress
|
||||
swapID cmn.HexBytes
|
||||
randomNumber cmn.HexBytes
|
||||
swapID tmbytes.HexBytes
|
||||
randomNumber tmbytes.HexBytes
|
||||
expectPass bool
|
||||
}{
|
||||
{"normal", binanceAddrs[0], swapID, randomNumberHash, true},
|
||||
@ -102,7 +105,7 @@ func TestMsgRefundAtomicSwap(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
from sdk.AccAddress
|
||||
swapID cmn.HexBytes
|
||||
swapID tmbytes.HexBytes
|
||||
expectPass bool
|
||||
}{
|
||||
{"normal", binanceAddrs[0], swapID, true},
|
||||
|
@ -1,12 +1,18 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/params"
|
||||
)
|
||||
|
||||
const (
|
||||
bech32MainPrefix = "kava"
|
||||
)
|
||||
|
||||
// Parameter keys
|
||||
var (
|
||||
KeyBnbDeputyAddress = []byte("BnbDeputyAddress")
|
||||
@ -59,7 +65,11 @@ func NewParams(bnbDeputyAddress sdk.AccAddress, minBlockLock, maxBlockLock int64
|
||||
|
||||
// DefaultParams returns default params for bep3 module
|
||||
func DefaultParams() Params {
|
||||
defaultBnbDeputyAddress, _ := sdk.AccAddressFromBech32("kava1xy7hrjy9r0algz9w3gzm8u6mrpq97kwta747gj")
|
||||
defaultBnbDeputyAddress, err := sdk.AccAddressFromBech32("kava1xy7hrjy9r0algz9w3gzm8u6mrpq97kwta747gj")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return NewParams(defaultBnbDeputyAddress, DefaultMinBlockLock, DefaultMaxBlockLock, DefaultSupportedAssets)
|
||||
}
|
||||
|
||||
@ -103,44 +113,112 @@ func ParamKeyTable() params.KeyTable {
|
||||
// nolint
|
||||
func (p *Params) ParamSetPairs() params.ParamSetPairs {
|
||||
return params.ParamSetPairs{
|
||||
{Key: KeyBnbDeputyAddress, Value: &p.BnbDeputyAddress},
|
||||
{Key: KeyMinBlockLock, Value: &p.MinBlockLock},
|
||||
{Key: KeyMaxBlockLock, Value: &p.MaxBlockLock},
|
||||
{Key: KeySupportedAssets, Value: &p.SupportedAssets},
|
||||
params.NewParamSetPair(KeyBnbDeputyAddress, &p.BnbDeputyAddress, validateBnbDeputyAddressParam),
|
||||
params.NewParamSetPair(KeyMinBlockLock, &p.MinBlockLock, validateMinBlockLockParam),
|
||||
params.NewParamSetPair(KeyMaxBlockLock, &p.MaxBlockLock, validateMaxBlockLockParam),
|
||||
params.NewParamSetPair(KeySupportedAssets, &p.SupportedAssets, validateSupportedAssetsParams),
|
||||
}
|
||||
}
|
||||
|
||||
// Validate ensure that params have valid values
|
||||
func (p Params) Validate() error {
|
||||
if p.MinBlockLock < AbsoluteMinimumBlockLock {
|
||||
return fmt.Errorf(fmt.Sprintf("minimum block lock cannot be less than %d", AbsoluteMinimumBlockLock))
|
||||
if err := validateBnbDeputyAddressParam(p.BnbDeputyAddress); err != nil {
|
||||
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 {
|
||||
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)
|
||||
coinDenoms := make(map[string]bool)
|
||||
for _, asset := range p.SupportedAssets {
|
||||
if len(asset.Denom) == 0 {
|
||||
return fmt.Errorf("asset denom cannot be empty")
|
||||
for _, asset := range assetParams {
|
||||
if strings.TrimSpace(asset.Denom) == "" {
|
||||
return errors.New("asset denom cannot be empty")
|
||||
}
|
||||
|
||||
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() {
|
||||
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))
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
coinIDs[asset.CoinID] = true
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package types_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@ -204,10 +203,9 @@ func (suite *ParamsTestSuite) TestParamValidation() {
|
||||
|
||||
err := params.Validate()
|
||||
if tc.expectPass {
|
||||
suite.Nil(err)
|
||||
suite.Require().NoError(err, tc.name)
|
||||
} else {
|
||||
suite.NotNil(err)
|
||||
suite.True(strings.Contains(err.Error(), tc.expectedErr))
|
||||
suite.Require().Error(err, tc.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
)
|
||||
import tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
||||
|
||||
const (
|
||||
// QueryGetAssetSupply command for getting info about an asset's supply
|
||||
@ -17,11 +15,11 @@ const (
|
||||
|
||||
// QueryAssetSupply contains the params for query 'custom/bep3/supply'
|
||||
type QueryAssetSupply struct {
|
||||
Denom cmn.HexBytes `json:"denom" yaml:"denom"`
|
||||
Denom tmbytes.HexBytes `json:"denom" yaml:"denom"`
|
||||
}
|
||||
|
||||
// NewQueryAssetSupply creates a new QueryAssetSupply
|
||||
func NewQueryAssetSupply(denom cmn.HexBytes) QueryAssetSupply {
|
||||
func NewQueryAssetSupply(denom tmbytes.HexBytes) QueryAssetSupply {
|
||||
return QueryAssetSupply{
|
||||
Denom: denom,
|
||||
}
|
||||
@ -29,11 +27,11 @@ func NewQueryAssetSupply(denom cmn.HexBytes) QueryAssetSupply {
|
||||
|
||||
// QueryAtomicSwapByID contains the params for query 'custom/bep3/swap'
|
||||
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
|
||||
func NewQueryAtomicSwapByID(swapBytes cmn.HexBytes) QueryAtomicSwapByID {
|
||||
func NewQueryAtomicSwapByID(swapBytes tmbytes.HexBytes) QueryAtomicSwapByID {
|
||||
return QueryAtomicSwapByID{
|
||||
SwapID: swapBytes,
|
||||
}
|
||||
|
@ -5,13 +5,14 @@ import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
)
|
||||
|
||||
// Swap is an interface for handling common actions
|
||||
type Swap interface {
|
||||
GetSwapID() cmn.HexBytes
|
||||
GetSwapID() tmbytes.HexBytes
|
||||
GetModuleAccountCoins() sdk.Coins
|
||||
Validate() error
|
||||
}
|
||||
@ -19,22 +20,22 @@ type Swap interface {
|
||||
// AtomicSwap contains the information for an atomic swap
|
||||
type AtomicSwap struct {
|
||||
Swap `json:"swap" yaml:"swap"`
|
||||
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
||||
RandomNumberHash cmn.HexBytes `json:"random_number_hash" yaml:"random_number_hash"`
|
||||
ExpireHeight int64 `json:"expire_height" yaml:"expire_height"`
|
||||
Timestamp int64 `json:"timestamp" yaml:"timestamp"`
|
||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||
Recipient sdk.AccAddress `json:"recipient" yaml:"recipient"`
|
||||
SenderOtherChain string `json:"sender_other_chain" yaml:"sender_other_chain"`
|
||||
RecipientOtherChain string `json:"recipient_other_chain" yaml:"recipient_other_chain"`
|
||||
ClosedBlock int64 `json:"closed_block" yaml:"closed_block"`
|
||||
Status SwapStatus `json:"status" yaml:"status"`
|
||||
CrossChain bool `json:"cross_chain" yaml:"cross_chain"`
|
||||
Direction SwapDirection `json:"direction" yaml:"direction"`
|
||||
Amount sdk.Coins `json:"amount" yaml:"amount"`
|
||||
RandomNumberHash tmbytes.HexBytes `json:"random_number_hash" yaml:"random_number_hash"`
|
||||
ExpireHeight int64 `json:"expire_height" yaml:"expire_height"`
|
||||
Timestamp int64 `json:"timestamp" yaml:"timestamp"`
|
||||
Sender sdk.AccAddress `json:"sender" yaml:"sender"`
|
||||
Recipient sdk.AccAddress `json:"recipient" yaml:"recipient"`
|
||||
SenderOtherChain string `json:"sender_other_chain" yaml:"sender_other_chain"`
|
||||
RecipientOtherChain string `json:"recipient_other_chain" yaml:"recipient_other_chain"`
|
||||
ClosedBlock int64 `json:"closed_block" yaml:"closed_block"`
|
||||
Status SwapStatus `json:"status" yaml:"status"`
|
||||
CrossChain bool `json:"cross_chain" yaml:"cross_chain"`
|
||||
Direction SwapDirection `json:"direction" yaml:"direction"`
|
||||
}
|
||||
|
||||
// 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,
|
||||
status SwapStatus, crossChain bool, direction SwapDirection) AtomicSwap {
|
||||
return AtomicSwap{
|
||||
@ -54,7 +55,7 @@ func NewAtomicSwap(amount sdk.Coins, randomNumberHash cmn.HexBytes, expireHeight
|
||||
}
|
||||
|
||||
// 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)
|
||||
}
|
||||
|
||||
|
@ -3,18 +3,21 @@ package types_test
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/suite"
|
||||
|
||||
tmbytes "github.com/tendermint/tendermint/libs/bytes"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
||||
"github.com/kava-labs/kava/app"
|
||||
"github.com/kava-labs/kava/x/bep3/types"
|
||||
"github.com/stretchr/testify/suite"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
)
|
||||
|
||||
type AtomicSwapTestSuite struct {
|
||||
suite.Suite
|
||||
addrs []sdk.AccAddress
|
||||
timestamps []int64
|
||||
randomNumberHashes []cmn.HexBytes
|
||||
randomNumberHashes []tmbytes.HexBytes
|
||||
}
|
||||
|
||||
func (suite *AtomicSwapTestSuite) SetupTest() {
|
||||
@ -25,7 +28,7 @@ func (suite *AtomicSwapTestSuite) SetupTest() {
|
||||
|
||||
// Generate 10 timestamps and random number hashes
|
||||
var timestamps []int64
|
||||
var randomNumberHashes []cmn.HexBytes
|
||||
var randomNumberHashes []tmbytes.HexBytes
|
||||
for i := 0; i < 10; i++ {
|
||||
timestamp := ts(i)
|
||||
randomNumber, _ := types.GenerateSecureRandomNumber()
|
||||
@ -43,7 +46,7 @@ func (suite *AtomicSwapTestSuite) SetupTest() {
|
||||
func (suite *AtomicSwapTestSuite) TestNewAtomicSwap() {
|
||||
type args struct {
|
||||
amount sdk.Coins
|
||||
randomNumberHash cmn.HexBytes
|
||||
randomNumberHash tmbytes.HexBytes
|
||||
expireHeight int64
|
||||
timestamp int64
|
||||
sender sdk.AccAddress
|
||||
@ -127,7 +130,7 @@ func (suite *AtomicSwapTestSuite) TestNewAtomicSwap() {
|
||||
suite.Nil(swap.Validate())
|
||||
suite.Equal(tc.args.amount, swap.GetModuleAccountCoins())
|
||||
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 {
|
||||
suite.Error(swap.Validate())
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
import (
|
||||
@ -10,26 +5,14 @@ import (
|
||||
"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 (
|
||||
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
|
||||
EventTypeCdpDeposit = types.EventTypeCdpDeposit
|
||||
EventTypeCdpDraw = types.EventTypeCdpDraw
|
||||
@ -75,14 +58,13 @@ var (
|
||||
ErrInvalidCollateralRatio = types.ErrInvalidCollateralRatio
|
||||
ErrCdpNotFound = types.ErrCdpNotFound
|
||||
ErrDepositNotFound = types.ErrDepositNotFound
|
||||
ErrInvalidDepositDenom = types.ErrInvalidDepositDenom
|
||||
ErrInvalidPaymentDenom = types.ErrInvalidPaymentDenom
|
||||
ErrInvalidDeposit = types.ErrInvalidDeposit
|
||||
ErrInvalidPayment = types.ErrInvalidPayment
|
||||
ErrDepositNotAvailable = types.ErrDepositNotAvailable
|
||||
ErrInvalidCollateralDenom = types.ErrInvalidCollateralDenom
|
||||
ErrInvalidCollateral = types.ErrInvalidCollateral
|
||||
ErrInvalidWithdrawAmount = types.ErrInvalidWithdrawAmount
|
||||
ErrCdpNotAvailable = types.ErrCdpNotAvailable
|
||||
ErrBelowDebtFloor = types.ErrBelowDebtFloor
|
||||
ErrPaymentExceedsDebt = types.ErrPaymentExceedsDebt
|
||||
ErrLoadingAugmentedCDP = types.ErrLoadingAugmentedCDP
|
||||
NewGenesisState = types.NewGenesisState
|
||||
DefaultGenesisState = types.DefaultGenesisState
|
||||
|
@ -6,8 +6,8 @@ import (
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"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",
|
||||
}
|
||||
|
||||
cdpQueryCmd.AddCommand(client.GetCommands(
|
||||
cdpQueryCmd.AddCommand(flags.GetCommands(
|
||||
QueryCdpCmd(queryRoute, cdc),
|
||||
QueryCdpsByDenomCmd(queryRoute, cdc),
|
||||
QueryCdpsByDenomAndRatioCmd(queryRoute, cdc),
|
||||
@ -131,9 +131,9 @@ $ %s query %s cdps-by-ratio uatom 1.5
|
||||
cliCtx := context.NewCLIContext().WithCodec(cdc)
|
||||
|
||||
// Prepare params for querier
|
||||
ratio, errSdk := sdk.NewDecFromStr(args[1])
|
||||
if errSdk != nil {
|
||||
return fmt.Errorf(errSdk.Error())
|
||||
ratio, err := sdk.NewDecFromStr(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
bz, err := cdc.MarshalJSON(types.QueryCdpsByRatioParams{
|
||||
CollateralDenom: args[0],
|
||||
|
@ -1,13 +1,14 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/flags"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
@ -24,7 +25,7 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command {
|
||||
Short: "cdp transactions subcommands",
|
||||
}
|
||||
|
||||
cdpTxCmd.AddCommand(client.PostCommands(
|
||||
cdpTxCmd.AddCommand(flags.PostCommands(
|
||||
GetCmdCreateCdp(cdc),
|
||||
GetCmdDeposit(cdc),
|
||||
GetCmdWithdraw(cdc),
|
||||
@ -48,8 +49,9 @@ $ %s tx %s create 10000000uatom 1000usdx --from myKeyName
|
||||
`, version.ClientName, types.ModuleName)),
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
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])
|
||||
if err != nil {
|
||||
@ -82,8 +84,9 @@ $ %s tx %s deposit kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw 10000000uatom --f
|
||||
`, version.ClientName, types.ModuleName)),
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
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])
|
||||
if err != nil {
|
||||
@ -116,8 +119,9 @@ $ %s tx %s withdraw kava15qdefkmwswysgg4qxgqpqr35k3m49pkx2jdfnw 10000000uatom --
|
||||
`, version.ClientName, types.ModuleName)),
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
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])
|
||||
if err != nil {
|
||||
@ -150,8 +154,9 @@ $ %s tx %s draw uatom 1000usdx --from myKeyName
|
||||
`, version.ClientName, types.ModuleName)),
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
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])
|
||||
if err != nil {
|
||||
@ -180,8 +185,9 @@ $ %s tx %s repay uatom 1000usdx --from myKeyName
|
||||
`, version.ClientName, types.ModuleName)),
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
inBuf := bufio.NewReader(cmd.InOrStdin())
|
||||
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])
|
||||
if err != nil {
|
||||
|
@ -58,7 +58,7 @@ func InitGenesis(ctx sdk.Context, k Keeper, pk PricefeedKeeper, sk SupplyKeeper,
|
||||
}
|
||||
k.SetCDP(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.IncrementTotalPrincipal(ctx, cdp.Collateral[0].Denom, cdp.Principal)
|
||||
}
|
||||
|
@ -1,14 +1,13 @@
|
||||
package cdp
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
// NewHandler creates an sdk.Handler for cdp messages
|
||||
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) {
|
||||
case MsgCreateCDP:
|
||||
return handleMsgCreateCDP(ctx, k, msg)
|
||||
@ -21,16 +20,15 @@ func NewHandler(k Keeper) sdk.Handler {
|
||||
case MsgRepayDebt:
|
||||
return handleMsgRepayDebt(ctx, k, msg)
|
||||
default:
|
||||
errMsg := fmt.Sprintf("unrecognized cdp msg type: %T", msg)
|
||||
return sdk.ErrUnknownRequest(errMsg).Result()
|
||||
return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", ModuleName, msg)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
return sdk.Result{
|
||||
return &sdk.Result{
|
||||
Data: GetCdpIDBytes(id),
|
||||
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)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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()),
|
||||
),
|
||||
)
|
||||
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)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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()),
|
||||
),
|
||||
)
|
||||
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)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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()),
|
||||
),
|
||||
)
|
||||
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)
|
||||
if err != nil {
|
||||
return err.Result()
|
||||
return nil, err
|
||||
}
|
||||
|
||||
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()),
|
||||
),
|
||||
)
|
||||
return sdk.Result{Events: ctx.EventManager().Events()}
|
||||
return &sdk.Result{Events: ctx.EventManager().Events()}, nil
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package cdp_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@ -47,16 +46,16 @@ func (suite *HandlerTestSuite) TestMsgCreateCdp() {
|
||||
cs(c("xrp", 200000000)),
|
||||
cs(c("usdx", 10000000)),
|
||||
)
|
||||
res := suite.handler(suite.ctx, msg)
|
||||
suite.True(res.IsOK())
|
||||
suite.Equal(cdp.GetCdpIDBytes(uint64(1)), res.Data)
|
||||
res, err := suite.handler(suite.ctx, msg)
|
||||
suite.Require().NoError(err)
|
||||
suite.Require().Equal(cdp.GetCdpIDBytes(uint64(1)), res.Data)
|
||||
|
||||
}
|
||||
|
||||
func (suite *HandlerTestSuite) TestInvalidMsg() {
|
||||
res := suite.handler(suite.ctx, sdk.NewTestMsg())
|
||||
suite.False(res.IsOK())
|
||||
suite.True(strings.Contains(res.Log, "unrecognized cdp msg type"))
|
||||
res, err := suite.handler(suite.ctx, sdk.NewTestMsg())
|
||||
suite.Require().Error(err)
|
||||
suite.Require().Nil(res)
|
||||
}
|
||||
|
||||
func TestHandlerTestSuite(t *testing.T) {
|
||||
|
@ -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
|
||||
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)
|
||||
partialAuctionDeposits := partialDeposits{}
|
||||
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
|
||||
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()
|
||||
collateralChange = sdk.ZeroInt()
|
||||
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
|
||||
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{}
|
||||
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
|
||||
// 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)
|
||||
debt := k.GetTotalDebt(ctx, types.LiquidatorMacc)
|
||||
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
|
||||
func (k Keeper) RunSurplusAndDebtAuctions(ctx sdk.Context) sdk.Error {
|
||||
func (k Keeper) RunSurplusAndDebtAuctions(ctx sdk.Context) error {
|
||||
k.NetSurplusAndDebt(ctx)
|
||||
remainingDebt := k.GetTotalDebt(ctx, types.LiquidatorMacc)
|
||||
params := k.GetParams(ctx)
|
||||
|
@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/store/prefix"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/kava-labs/kava/x/cdp/types"
|
||||
)
|
||||
|
||||
@ -13,7 +14,7 @@ import (
|
||||
const BaseDigitFactor = 1000000000000000000
|
||||
|
||||
// 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
|
||||
err := k.ValidateCollateral(ctx, collateral)
|
||||
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)
|
||||
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)
|
||||
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
|
||||
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()
|
||||
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)
|
||||
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
|
||||
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()
|
||||
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)
|
||||
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
|
||||
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 {
|
||||
return types.ErrInvalidCollateralLength(k.codespace, len(collateral))
|
||||
return sdkerrors.Wrapf(types.ErrInvalidCollateralLength, "%d", len(collateral))
|
||||
}
|
||||
_, found := k.GetCollateral(ctx, collateral[0].Denom)
|
||||
if !found {
|
||||
return types.ErrCollateralNotSupported(k.codespace, collateral[0].Denom)
|
||||
return sdkerrors.Wrap(types.ErrCollateralNotSupported, collateral[0].Denom)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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 {
|
||||
dp, found := k.GetDebtParam(ctx, dc.Denom)
|
||||
if !found {
|
||||
return types.ErrDebtNotSupported(k.codespace, dc.Denom)
|
||||
return sdkerrors.Wrap(types.ErrDebtNotSupported, dc.Denom)
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// 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 {
|
||||
_, found := k.GetDebtParam(ctx, dc.Denom)
|
||||
if !found {
|
||||
return types.ErrDebtNotSupported(k.codespace, dc.Denom)
|
||||
return sdkerrors.Wrap(types.ErrDebtNotSupported, dc.Denom)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
if !found {
|
||||
return types.ErrCollateralNotSupported(k.codespace, collateralDenom)
|
||||
return sdkerrors.Wrap(types.ErrCollateralNotSupported, collateralDenom)
|
||||
}
|
||||
|
||||
for _, dc := range principal {
|
||||
totalPrincipal := k.GetTotalPrincipal(ctx, collateralDenom, dc.Denom).Add(dc.Amount)
|
||||
collateralLimit := cp.DebtLimit.AmountOf(dc.Denom)
|
||||
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)
|
||||
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
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
@ -405,7 +407,7 @@ func (k Keeper) ValidateCollateralizationRatio(ctx sdk.Context, collateral sdk.C
|
||||
}
|
||||
liquidationRatio := k.getLiquidationRatio(ctx, collateral[0].Denom)
|
||||
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
|
||||
}
|
||||
@ -427,12 +429,11 @@ func (k Keeper) CalculateCollateralToDebtRatio(ctx sdk.Context, collateral sdk.C
|
||||
}
|
||||
|
||||
// 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
|
||||
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)
|
||||
totalFees := cdp.AccumulatedFees.Add(fees)
|
||||
|
||||
fees := k.CalculateFees(ctx, cdp.Principal.Add(cdp.AccumulatedFees...), periods, cdp.Collateral[0].Denom)
|
||||
totalFees := cdp.AccumulatedFees.Add(fees...)
|
||||
// calculate collateralization ratio
|
||||
collateralizationRatio, err := k.CalculateCollateralizationRatio(ctx, cdp.Collateral, cdp.Principal, totalFees)
|
||||
if err != nil {
|
||||
@ -444,7 +445,7 @@ func (k Keeper) LoadAugmentedCDP(ctx sdk.Context, cdp types.CDP) (types.Augmente
|
||||
for _, principalCoin := range cdp.Principal {
|
||||
totalDebt += principalCoin.Amount.Int64()
|
||||
}
|
||||
for _, feeCoin := range cdp.AccumulatedFees.Add(fees) {
|
||||
for _, feeCoin := range cdp.AccumulatedFees.Add(fees...) {
|
||||
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
|
||||
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() {
|
||||
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
|
||||
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
|
||||
marketID := k.getMarketID(ctx, collateralDenom)
|
||||
price, err := k.pricefeedKeeper.GetCurrentPrice(ctx, marketID)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -44,17 +45,17 @@ func (suite *CdpTestSuite) TestAddCdp() {
|
||||
acc.SetCoins(cs(c("xrp", 200000000), c("btc", 500000000)))
|
||||
ak.SetAccount(suite.ctx, acc)
|
||||
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)))
|
||||
suite.Error(err) // insufficient balance
|
||||
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.SetCoins(cs(c("btc", 500000000000)))
|
||||
ak.SetAccount(suite.ctx, acc2)
|
||||
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))
|
||||
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())
|
||||
|
||||
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)))
|
||||
suite.NoError(err)
|
||||
@ -90,9 +91,9 @@ func (suite *CdpTestSuite) TestAddCdp() {
|
||||
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)))
|
||||
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)))
|
||||
suite.Equal(types.CodeCdpAlreadyExists, err.Result().Code)
|
||||
suite.Require().True(errors.Is(err, types.ErrCdpAlreadyExists))
|
||||
}
|
||||
|
||||
func (suite *CdpTestSuite) TestGetSetDenomByte() {
|
||||
@ -247,10 +248,10 @@ func (suite *CdpTestSuite) TestValidateCollateral() {
|
||||
suite.NoError(err)
|
||||
c = sdk.NewCoins(sdk.NewCoin("lol", sdk.NewInt(1)))
|
||||
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)))
|
||||
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() {
|
||||
@ -262,10 +263,10 @@ func (suite *CdpTestSuite) TestValidatePrincipal() {
|
||||
suite.NoError(err)
|
||||
d = sdk.NewCoins(sdk.NewCoin("xusd", sdk.NewInt(1)))
|
||||
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)))
|
||||
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)))
|
||||
err = suite.keeper.ValidateDebtLimit(suite.ctx, "xrp", d)
|
||||
suite.NoError(err)
|
||||
@ -290,16 +291,19 @@ func (suite *CdpTestSuite) TestMintBurnDebtCoins() {
|
||||
cd := cdps()[1]
|
||||
err := suite.keeper.MintDebtCoins(suite.ctx, types.ModuleName, suite.keeper.GetDebtDenom(suite.ctx), cd.Principal)
|
||||
suite.NoError(err)
|
||||
err = suite.keeper.MintDebtCoins(suite.ctx, "notamodule", suite.keeper.GetDebtDenom(suite.ctx), cd.Principal)
|
||||
suite.Error(err)
|
||||
suite.Require().Panics(func() {
|
||||
_ = suite.keeper.MintDebtCoins(suite.ctx, "notamodule", suite.keeper.GetDebtDenom(suite.ctx), cd.Principal)
|
||||
})
|
||||
|
||||
sk := suite.app.GetSupplyKeeper()
|
||||
acc := sk.GetModuleAccount(suite.ctx, types.ModuleName)
|
||||
suite.Equal(cs(c("debt", 10000000)), acc.GetCoins())
|
||||
|
||||
err = suite.keeper.BurnDebtCoins(suite.ctx, types.ModuleName, suite.keeper.GetDebtDenom(suite.ctx), cd.Principal)
|
||||
suite.NoError(err)
|
||||
err = suite.keeper.BurnDebtCoins(suite.ctx, "notamodule", suite.keeper.GetDebtDenom(suite.ctx), cd.Principal)
|
||||
suite.Error(err)
|
||||
suite.Require().Panics(func() {
|
||||
_ = suite.keeper.BurnDebtCoins(suite.ctx, "notamodule", suite.keeper.GetDebtDenom(suite.ctx), cd.Principal)
|
||||
})
|
||||
sk = suite.app.GetSupplyKeeper()
|
||||
acc = sk.GetModuleAccount(suite.ctx, types.ModuleName)
|
||||
suite.Equal(sdk.Coins(nil), acc.GetCoins())
|
||||
|
@ -5,23 +5,24 @@ import (
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/store/prefix"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/kava-labs/kava/x/cdp/types"
|
||||
)
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cdp, found := k.GetCdpByOwnerAndDenom(ctx, owner, collateral[0].Denom)
|
||||
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)
|
||||
if found {
|
||||
deposit.Amount = deposit.Amount.Add(collateral)
|
||||
deposit.Amount = deposit.Amount.Add(collateral...)
|
||||
} else {
|
||||
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)
|
||||
|
||||
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)
|
||||
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees))
|
||||
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...))
|
||||
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.Collateral = cdp.Collateral.Add(collateral)
|
||||
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees))
|
||||
cdp.Collateral = cdp.Collateral.Add(collateral...)
|
||||
collateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
|
||||
k.SetCdpAndCollateralRatioIndex(ctx, cdp, collateralToDebtRatio)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
cdp, found := k.GetCdpByOwnerAndDenom(ctx, owner, collateral[0].Denom)
|
||||
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)
|
||||
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) {
|
||||
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()))
|
||||
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))
|
||||
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...))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
liquidationRatio := k.getLiquidationRatio(ctx, collateral[0].Denom)
|
||||
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(
|
||||
sdk.NewEvent(
|
||||
@ -92,13 +93,13 @@ func (k Keeper) WithdrawCollateral(ctx sdk.Context, owner sdk.AccAddress, deposi
|
||||
if err != nil {
|
||||
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)
|
||||
|
||||
cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees)
|
||||
cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees...)
|
||||
cdp.FeesUpdated = ctx.BlockTime()
|
||||
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)
|
||||
|
||||
deposit.Amount = deposit.Amount.Sub(collateral)
|
||||
|
@ -1,6 +1,7 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@ -76,10 +77,10 @@ func (suite *DepositTestSuite) TestDepositCollateral() {
|
||||
suite.Equal(i(90000000), acc.GetCoins().AmountOf("xrp"))
|
||||
|
||||
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)))
|
||||
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)))
|
||||
suite.NoError(err)
|
||||
@ -94,17 +95,17 @@ func (suite *DepositTestSuite) TestDepositCollateral() {
|
||||
|
||||
func (suite *DepositTestSuite) TestWithdrawCollateral() {
|
||||
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)))
|
||||
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)))
|
||||
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.AccumulatedFees = cs(c("usdx", 1))
|
||||
suite.keeper.SetCDP(suite.ctx, cd)
|
||||
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)))
|
||||
suite.NoError(err)
|
||||
@ -116,7 +117,7 @@ func (suite *DepositTestSuite) TestWithdrawCollateral() {
|
||||
suite.Equal(i(110000000), acc.GetCoins().AmountOf("xrp"))
|
||||
|
||||
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) {
|
||||
|
@ -4,15 +4,16 @@ import (
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"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
|
||||
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
|
||||
cdp, found := k.GetCdpByOwnerAndDenom(ctx, owner, denom)
|
||||
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)
|
||||
if err != nil {
|
||||
@ -26,9 +27,9 @@ func (k Keeper) AddPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom string
|
||||
|
||||
// fee calculation
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
@ -59,19 +60,19 @@ func (k Keeper) AddPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom string
|
||||
)
|
||||
|
||||
// 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)
|
||||
|
||||
// update cdp state
|
||||
cdp.Principal = cdp.Principal.Add(principal)
|
||||
cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees)
|
||||
cdp.Principal = cdp.Principal.Add(principal...)
|
||||
cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees...)
|
||||
cdp.FeesUpdated = ctx.BlockTime()
|
||||
|
||||
// increment total principal for the input collateral type
|
||||
k.IncrementTotalPrincipal(ctx, cdp.Collateral[0].Denom, principal)
|
||||
|
||||
// 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)
|
||||
|
||||
return nil
|
||||
@ -79,32 +80,32 @@ func (k Keeper) AddPrincipal(ctx sdk.Context, owner sdk.AccAddress, denom string
|
||||
|
||||
// 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
|
||||
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
|
||||
cdp, found := k.GetCdpByOwnerAndDenom(ctx, owner, denom)
|
||||
if !found {
|
||||
return types.ErrCdpNotFound(k.codespace, owner, denom)
|
||||
return sdkerrors.Wrapf(types.ErrCdpNotFound, "owner %s, denom %s", owner, denom)
|
||||
}
|
||||
|
||||
// calculate fees
|
||||
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)
|
||||
err := k.ValidatePaymentCoins(ctx, cdp, payment, cdp.Principal.Add(cdp.AccumulatedFees).Add(fees))
|
||||
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...))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 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
|
||||
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 {
|
||||
return err
|
||||
}
|
||||
|
||||
// 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 {
|
||||
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
|
||||
cdpDebt := k.getModAccountDebt(ctx, types.ModuleName)
|
||||
paymentAmount := sdk.ZeroInt()
|
||||
for _, c := range feePayment.Add(principalPayment) {
|
||||
for _, c := range feePayment.Add(principalPayment...) {
|
||||
paymentAmount = paymentAmount.Add(c.Amount)
|
||||
}
|
||||
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(
|
||||
sdk.NewEvent(
|
||||
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)),
|
||||
),
|
||||
)
|
||||
|
||||
// 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)
|
||||
|
||||
// update cdp state
|
||||
if !principalPayment.IsZero() {
|
||||
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()
|
||||
|
||||
// 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,
|
||||
// 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
|
||||
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)
|
||||
return nil
|
||||
}
|
||||
|
||||
// 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)
|
||||
if !subset {
|
||||
var paymentDenoms []string
|
||||
@ -182,13 +183,13 @@ func (k Keeper) ValidatePaymentCoins(ctx sdk.Context, cdp types.CDP, payment sdk
|
||||
for _, pc := range payment {
|
||||
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 {
|
||||
dp, _ := k.GetDebtParam(ctx, dc.Denom)
|
||||
proposedBalance := cdp.Principal.AmountOf(dc.Denom).Sub(dc.Amount)
|
||||
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
|
||||
@ -223,12 +224,12 @@ func (k Keeper) calculatePayment(ctx sdk.Context, owed sdk.Coins, fees sdk.Coins
|
||||
for _, fc := range fees {
|
||||
if payment.AmountOf(fc.Denom).IsPositive() {
|
||||
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))
|
||||
principalPayment = principalPayment.Add(sdk.NewCoins(pc))
|
||||
principalPayment = principalPayment.Add(pc)
|
||||
} else {
|
||||
fc := sdk.NewCoin(fc.Denom, payment.AmountOf(fc.Denom))
|
||||
feePayment = feePayment.Add(sdk.NewCoins(fc))
|
||||
feePayment = feePayment.Add(fc)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@ -53,7 +54,7 @@ func (suite *DrawTestSuite) TestAddRepayPrincipal() {
|
||||
|
||||
t, _ := suite.keeper.GetCDP(suite.ctx, "xrp", uint64(1))
|
||||
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)
|
||||
ts := suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("20.0"))
|
||||
suite.Equal(0, len(ts))
|
||||
@ -69,7 +70,7 @@ func (suite *DrawTestSuite) TestAddRepayPrincipal() {
|
||||
suite.NoError(err)
|
||||
t, _ = suite.keeper.GetCDP(suite.ctx, "xrp", uint64(1))
|
||||
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)
|
||||
ts = suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("400").Quo(d("30")))
|
||||
suite.Equal(0, len(ts))
|
||||
@ -82,18 +83,18 @@ func (suite *DrawTestSuite) TestAddRepayPrincipal() {
|
||||
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)))
|
||||
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)))
|
||||
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)))
|
||||
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)))
|
||||
suite.NoError(err)
|
||||
|
||||
t, _ = suite.keeper.GetCDP(suite.ctx, "xrp", uint64(1))
|
||||
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)
|
||||
ts = suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("20.0"))
|
||||
suite.Equal(0, len(ts))
|
||||
@ -110,7 +111,7 @@ func (suite *DrawTestSuite) TestAddRepayPrincipal() {
|
||||
|
||||
t, _ = suite.keeper.GetCDP(suite.ctx, "xrp", uint64(1))
|
||||
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)
|
||||
ts = suite.keeper.GetAllCdpsByDenomAndRatio(suite.ctx, "xrp", d("40.0"))
|
||||
suite.Equal(0, len(ts))
|
||||
@ -123,12 +124,12 @@ func (suite *DrawTestSuite) TestAddRepayPrincipal() {
|
||||
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)))
|
||||
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)))
|
||||
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)))
|
||||
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)))
|
||||
suite.NoError(err)
|
||||
|
||||
|
@ -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())
|
||||
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
|
||||
newFees = newFees.Add(sdk.NewCoins(sdk.NewCoin(pc.Denom, feesAccumulated.TruncateInt())))
|
||||
newFees = newFees.Add(sdk.NewCoin(pc.Denom, feesAccumulated.TruncateInt()))
|
||||
}
|
||||
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
|
||||
// Finally we set the cdp.FeesUpdated time to the current block time (ctx.BlockTime()) since that
|
||||
// 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)
|
||||
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
|
||||
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
|
||||
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)
|
||||
|
||||
// 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
|
||||
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.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
|
||||
|
@ -48,7 +48,7 @@ func (suite *FeeTestSuite) TestCalculateFeesPrecisionLoss() {
|
||||
suite.NoError(err)
|
||||
c := sdk.NewCoins(sdk.NewCoin("usdx", ri))
|
||||
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}
|
||||
@ -57,13 +57,13 @@ func (suite *FeeTestSuite) TestCalculateFeesPrecisionLoss() {
|
||||
bulkFees := sdk.NewCoins()
|
||||
individualFees := sdk.NewCoins()
|
||||
for x := 0; x < nb; x++ {
|
||||
fee := suite.keeper.CalculateFees(suite.ctx, total.Add(bulkFees), i(7), "xrp")
|
||||
bulkFees = bulkFees.Add(fee)
|
||||
fee := suite.keeper.CalculateFees(suite.ctx, total.Add(bulkFees...), i(7), "xrp")
|
||||
bulkFees = bulkFees.Add(fee...)
|
||||
}
|
||||
|
||||
for _, cns := range coins {
|
||||
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()
|
||||
|
@ -19,21 +19,22 @@ type Keeper struct {
|
||||
supplyKeeper types.SupplyKeeper
|
||||
auctionKeeper types.AuctionKeeper
|
||||
accountKeeper types.AccountKeeper
|
||||
codespace sdk.CodespaceType
|
||||
}
|
||||
|
||||
// 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{
|
||||
key: key,
|
||||
cdc: cdc,
|
||||
paramSubspace: paramstore.WithKeyTable(types.ParamKeyTable()),
|
||||
paramSubspace: paramstore,
|
||||
pricefeedKeeper: pfk,
|
||||
auctionKeeper: ak,
|
||||
supplyKeeper: sk,
|
||||
accountKeeper: ack,
|
||||
codespace: codespace,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,7 +115,7 @@ func BenchmarkCdpIteration(b *testing.B) {
|
||||
|
||||
}
|
||||
|
||||
var errResult sdk.Error
|
||||
var errResult error
|
||||
|
||||
func BenchmarkCdpCreation(b *testing.B) {
|
||||
tApp := app.NewTestApp()
|
||||
|
@ -1,16 +1,20 @@
|
||||
package keeper
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
|
||||
"github.com/kava-labs/kava/x/cdp/types"
|
||||
)
|
||||
|
||||
// NewQuerier returns a new querier function
|
||||
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] {
|
||||
case types.QueryGetCdp:
|
||||
return queryGetCdp(ctx, req, keeper)
|
||||
@ -23,85 +27,85 @@ func NewQuerier(keeper Keeper) sdk.Querier {
|
||||
case types.QueryGetCdpDeposits:
|
||||
return queryGetDeposits(ctx, req, keeper)
|
||||
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
|
||||
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
|
||||
err := keeper.cdc.UnmarshalJSON(req.Data, &requestParams)
|
||||
err := types.ModuleCdc.UnmarshalJSON(req.Data, &requestParams)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
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 {
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
// 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
|
||||
err := keeper.cdc.UnmarshalJSON(req.Data, &requestParams)
|
||||
err := types.ModuleCdc.UnmarshalJSON(req.Data, &requestParams)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
|
||||
bz, err := codec.MarshalJSONIndent(keeper.cdc, deposits)
|
||||
bz, err := codec.MarshalJSONIndent(types.ModuleCdc, deposits)
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
// 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
|
||||
err := keeper.cdc.UnmarshalJSON(req.Data, &requestParams)
|
||||
err := types.ModuleCdc.UnmarshalJSON(req.Data, &requestParams)
|
||||
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)
|
||||
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)
|
||||
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)
|
||||
@ -113,23 +117,23 @@ func queryGetCdpsByRatio(ctx sdk.Context, req abci.RequestQuery, keeper Keeper)
|
||||
augmentedCDPs = append(augmentedCDPs, augmentedCDP)
|
||||
}
|
||||
}
|
||||
bz, err := codec.MarshalJSONIndent(keeper.cdc, augmentedCDPs)
|
||||
bz, err := codec.MarshalJSONIndent(types.ModuleCdc, augmentedCDPs)
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
err := keeper.cdc.UnmarshalJSON(req.Data, &requestParams)
|
||||
err := types.ModuleCdc.UnmarshalJSON(req.Data, &requestParams)
|
||||
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)
|
||||
if !valid {
|
||||
return nil, types.ErrInvalidCollateralDenom(keeper.codespace, requestParams.CollateralDenom)
|
||||
return nil, sdkerrors.Wrap(types.ErrInvalidCollateral, 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)
|
||||
}
|
||||
}
|
||||
bz, err := codec.MarshalJSONIndent(keeper.cdc, augmentedCDPs)
|
||||
bz, err := codec.MarshalJSONIndent(types.ModuleCdc, augmentedCDPs)
|
||||
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
|
||||
}
|
||||
|
||||
// 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
|
||||
params := keeper.GetParams(ctx)
|
||||
|
||||
// Encode results
|
||||
bz, err := codec.MarshalJSONIndent(keeper.cdc, params)
|
||||
bz, err := codec.MarshalJSONIndent(types.ModuleCdc, params)
|
||||
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
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import (
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/store/prefix"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
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
|
||||
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)
|
||||
if !found {
|
||||
return types.ErrDebtNotSupported(k.codespace, debtDenom)
|
||||
return sdkerrors.Wrap(types.ErrDebtNotSupported, debtDenom)
|
||||
}
|
||||
savingsRateMacc := k.supplyKeeper.GetModuleAccount(ctx, types.SavingsRateMacc)
|
||||
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)
|
||||
totalSupplyLessModAccounts := k.supplyKeeper.GetSupply(ctx).GetTotal().Sub(modAccountCoins)
|
||||
surplusDistributed := sdk.ZeroInt()
|
||||
var iterationErr sdk.Error
|
||||
var iterationErr error
|
||||
k.accountKeeper.IterateAccounts(ctx, func(acc authexported.Account) (stop bool) {
|
||||
_, ok := acc.(supplyexported.ModuleAccountI)
|
||||
if ok {
|
||||
|
@ -15,13 +15,13 @@ import (
|
||||
// 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
|
||||
// (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
|
||||
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees))
|
||||
oldCollateralToDebtRatio := k.CalculateCollateralToDebtRatio(ctx, cdp.Collateral, cdp.Principal.Add(cdp.AccumulatedFees...))
|
||||
// Update fees
|
||||
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)
|
||||
cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees)
|
||||
fees := k.CalculateFees(ctx, cdp.Principal.Add(cdp.AccumulatedFees...), periods, cdp.Collateral[0].Denom)
|
||||
cdp.AccumulatedFees = cdp.AccumulatedFees.Add(fees...)
|
||||
cdp.FeesUpdated = ctx.BlockTime()
|
||||
|
||||
// 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)
|
||||
if feeAmount.IsPositive() {
|
||||
feeCoins := sdk.NewCoins(sdk.NewCoin(dc.Denom, feeAmount))
|
||||
coinsToDecrement = coinsToDecrement.Add(feeCoins)
|
||||
coinsToDecrement = coinsToDecrement.Add(feeCoins...)
|
||||
}
|
||||
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.supplyKeeper.MintCoins(ctx, types.LiquidatorMacc, sdk.NewCoins(sdk.NewCoin(principalDenom, newFeesSurplus)))
|
||||
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
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -1,6 +1,7 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math/rand"
|
||||
"testing"
|
||||
"time"
|
||||
@ -145,7 +146,7 @@ func (suite *SeizeTestSuite) TestSeizeCollateral() {
|
||||
acc := ak.GetAccount(suite.ctx, suite.addrs[1])
|
||||
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)))
|
||||
suite.Equal(types.CodeCdpNotFound, err.Result().Code)
|
||||
suite.Require().True(errors.Is(err, types.ErrCdpNotFound))
|
||||
}
|
||||
|
||||
func (suite *SeizeTestSuite) TestSeizeCollateralMultiDeposit() {
|
||||
@ -170,7 +171,7 @@ func (suite *SeizeTestSuite) TestSeizeCollateralMultiDeposit() {
|
||||
acc := ak.GetAccount(suite.ctx, suite.addrs[1])
|
||||
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)))
|
||||
suite.Equal(types.CodeCdpNotFound, err.Result().Code)
|
||||
suite.Require().True(errors.Is(err, types.ErrCdpNotFound))
|
||||
}
|
||||
|
||||
func (suite *SeizeTestSuite) TestLiquidateCdps() {
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
sim "github.com/cosmos/cosmos-sdk/x/simulation"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
@ -22,7 +23,7 @@ import (
|
||||
var (
|
||||
_ module.AppModule = AppModule{}
|
||||
_ module.AppModuleBasic = AppModuleBasic{}
|
||||
_ module.AppModuleSimulation = AppModuleSimulation{}
|
||||
_ module.AppModuleSimulation = AppModule{}
|
||||
)
|
||||
|
||||
// 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
|
||||
type AppModule struct {
|
||||
AppModuleBasic
|
||||
AppModuleSimulation
|
||||
|
||||
keeper Keeper
|
||||
accountKeeper auth.AccountKeeper
|
||||
pricefeedKeeper PricefeedKeeper
|
||||
supplyKeeper SupplyKeeper
|
||||
}
|
||||
|
||||
// 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{
|
||||
AppModuleBasic: AppModuleBasic{},
|
||||
keeper: keeper,
|
||||
accountKeeper: accountKeeper,
|
||||
pricefeedKeeper: pricefeedKeeper,
|
||||
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 {
|
||||
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)
|
||||
}
|
||||
|
@ -6,15 +6,16 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/tendermint/tendermint/libs/kv"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
|
||||
"github.com/kava-labs/kava/x/cdp/types"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
case bytes.Equal(kvA.Key[:1], types.CdpIDKeyPrefix):
|
||||
var cdpIDsA, cdpIDsB []uint64
|
||||
|
@ -6,8 +6,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/libs/kv"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
@ -34,17 +33,17 @@ func TestDecodeDistributionStore(t *testing.T) {
|
||||
prevDistTime := time.Now().UTC()
|
||||
cdp := types.CDP{ID: 1, FeesUpdated: prevDistTime, Collateral: oneCoins, Principal: oneCoins, AccumulatedFees: oneCoins}
|
||||
|
||||
kvPairs := cmn.KVPairs{
|
||||
cmn.KVPair{Key: types.CdpIDKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(cdpIds)},
|
||||
cmn.KVPair{Key: types.CdpKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(cdp)},
|
||||
cmn.KVPair{Key: types.CdpIDKey, Value: sdk.Uint64ToBigEndian(2)},
|
||||
cmn.KVPair{Key: types.CollateralRatioIndexPrefix, Value: sdk.Uint64ToBigEndian(10)},
|
||||
cmn.KVPair{Key: []byte(types.DebtDenomKey), Value: cdc.MustMarshalBinaryLengthPrefixed(denom)},
|
||||
cmn.KVPair{Key: []byte(types.GovDenomKey), Value: cdc.MustMarshalBinaryLengthPrefixed(denom)},
|
||||
cmn.KVPair{Key: []byte(types.DepositKeyPrefix), Value: cdc.MustMarshalBinaryLengthPrefixed(deposit)},
|
||||
cmn.KVPair{Key: []byte(types.PrincipalKeyPrefix), Value: cdc.MustMarshalBinaryLengthPrefixed(principal)},
|
||||
cmn.KVPair{Key: []byte(types.PreviousBlockTimeKey), Value: cdc.MustMarshalBinaryLengthPrefixed(prevDistTime)},
|
||||
cmn.KVPair{Key: []byte{0x99}, Value: []byte{0x99}},
|
||||
kvPairs := kv.Pairs{
|
||||
kv.Pair{Key: types.CdpIDKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(cdpIds)},
|
||||
kv.Pair{Key: types.CdpKeyPrefix, Value: cdc.MustMarshalBinaryLengthPrefixed(cdp)},
|
||||
kv.Pair{Key: types.CdpIDKey, Value: sdk.Uint64ToBigEndian(2)},
|
||||
kv.Pair{Key: types.CollateralRatioIndexPrefix, Value: sdk.Uint64ToBigEndian(10)},
|
||||
kv.Pair{Key: []byte(types.DebtDenomKey), Value: cdc.MustMarshalBinaryLengthPrefixed(denom)},
|
||||
kv.Pair{Key: []byte(types.GovDenomKey), Value: cdc.MustMarshalBinaryLengthPrefixed(denom)},
|
||||
kv.Pair{Key: []byte(types.DepositKeyPrefix), Value: cdc.MustMarshalBinaryLengthPrefixed(deposit)},
|
||||
kv.Pair{Key: []byte(types.PrincipalKeyPrefix), Value: cdc.MustMarshalBinaryLengthPrefixed(principal)},
|
||||
kv.Pair{Key: []byte(types.PreviousBlockTimeKey), Value: cdc.MustMarshalBinaryLengthPrefixed(prevDistTime)},
|
||||
kv.Pair{Key: []byte{0x99}, Value: []byte{0x99}},
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
"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"
|
||||
)
|
||||
|
||||
@ -23,7 +23,7 @@ func RandomizedGenState(simState *module.SimulationState) {
|
||||
simState.Cdc.MustUnmarshalJSON(simState.GenState[auth.ModuleName], &authGenesis)
|
||||
totalCdpCoins := sdk.NewCoins()
|
||||
for _, acc := range authGenesis.Accounts {
|
||||
_, ok := acc.(supplyExported.ModuleAccountI)
|
||||
_, ok := acc.(supplyexported.ModuleAccountI)
|
||||
if ok {
|
||||
continue
|
||||
}
|
||||
@ -33,18 +33,18 @@ func RandomizedGenState(simState *module.SimulationState) {
|
||||
sdk.NewCoin("btc", sdk.NewInt(int64(simState.Rand.Intn(500000000)))),
|
||||
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 {
|
||||
panic(err)
|
||||
}
|
||||
totalCdpCoins = totalCdpCoins.Add(coinsToAdd)
|
||||
totalCdpCoins = totalCdpCoins.Add(coinsToAdd...)
|
||||
authGenesis.Accounts = replaceOrAppendAccount(authGenesis.Accounts, acc)
|
||||
}
|
||||
simState.GenState[auth.ModuleName] = simState.Cdc.MustMarshalJSON(authGenesis)
|
||||
|
||||
var supplyGenesis supply.GenesisState
|
||||
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)
|
||||
|
||||
fmt.Printf("Selected randomly generated %s parameters:\n%s\n", types.ModuleName, codec.MustMarshalJSONIndent(simState.Cdc, cdpGenesis))
|
||||
|
@ -1,48 +1,86 @@
|
||||
package operations
|
||||
package simulation
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"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"
|
||||
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
"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.
|
||||
func SimulateMsgCdp(ak auth.AccountKeeper, k cdp.Keeper, pfk pricefeed.Keeper) simulation.Operation {
|
||||
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, accs []simulation.Account) (
|
||||
opMsg simulation.OperationMsg, fOps []simulation.FutureOperation, err error) {
|
||||
// Simulation operation weights constants
|
||||
const (
|
||||
OpWeightMsgCdp = "op_weight_msg_cdp"
|
||||
)
|
||||
|
||||
handler := cdp.NewHandler(k)
|
||||
simacc := simulation.RandomAcc(r, accs)
|
||||
acc := ak.GetAccount(ctx, simacc.Address)
|
||||
// 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, pfk types.PricefeedKeeper,
|
||||
) 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(cdp.ModuleName), nil, nil
|
||||
return simulation.NoOpMsg(types.ModuleName), nil, nil
|
||||
}
|
||||
|
||||
coins := acc.GetCoins()
|
||||
collateralParams := k.GetParams(ctx).CollateralParams
|
||||
if len(collateralParams) == 0 {
|
||||
return simulation.NoOpMsg(cdp.ModuleName), nil, nil
|
||||
return simulation.NoOpMsg(types.ModuleName), nil, nil
|
||||
}
|
||||
|
||||
randCollateralParam := collateralParams[r.Intn(len(collateralParams))]
|
||||
randDebtAsset := randCollateralParam.DebtLimit[r.Intn(len(randCollateralParam.DebtLimit))]
|
||||
randDebtParam, _ := k.GetDebtParam(ctx, randDebtAsset.Denom)
|
||||
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)
|
||||
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
|
||||
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)
|
||||
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
|
||||
@ -52,12 +90,12 @@ func SimulateMsgCdp(ak auth.AccountKeeper, k cdp.Keeper, pfk pricefeed.Keeper) s
|
||||
minCollateralDeposit = ShiftDec(minCollateralDeposit, randCollateralParam.ConversionFactor)
|
||||
// convert to integer and always round up
|
||||
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
|
||||
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
|
||||
maxCollateralDeposit := coins.AmountOf(randCollateralParam.Denom)
|
||||
maxCollateralDeposit := spendableCoins.AmountOf(randCollateralParam.Denom)
|
||||
|
||||
// randomly select a collateral deposit amount
|
||||
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))
|
||||
if availableAssetDebt.LTE(randDebtParam.DebtFloor) {
|
||||
// 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
|
||||
maxDebtDraw = sdk.MinInt(maxDebtDraw, availableAssetDebt)
|
||||
// randomly select a debt draw amount
|
||||
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 {
|
||||
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.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("could not submit create cdp msg")
|
||||
}
|
||||
return simulation.NewOperationMsg(msg, ok, "create cdp"), nil, nil
|
||||
|
||||
return simulation.NewOperationMsg(msg, true, result.Log), nil, nil
|
||||
}
|
||||
|
||||
// a cdp already exists, deposit to it, draw debt from it, or repay debt to it
|
||||
// close 25% of the time
|
||||
if canClose(acc, existingCDP, randDebtParam.Denom) && shouldClose(r) {
|
||||
repaymentAmount := coins.AmountOf(randDebtParam.Denom)
|
||||
msg := cdp.NewMsgRepayDebt(acc.GetAddress(), randCollateralParam.Denom, sdk.NewCoins(sdk.NewCoin(randDebtParam.Denom, repaymentAmount)))
|
||||
err := msg.ValidateBasic()
|
||||
repaymentAmount := spendableCoins.AmountOf(randDebtParam.Denom)
|
||||
msg := types.NewMsgRepayDebt(acc.GetAddress(), randCollateralParam.Denom, sdk.NewCoins(sdk.NewCoin(randDebtParam.Denom, repaymentAmount)))
|
||||
|
||||
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(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.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("could not submit repay (close) msg")
|
||||
}
|
||||
return simulation.NewOperationMsg(msg, ok, "repay debt (close) cdp"), nil, nil
|
||||
|
||||
return simulation.NewOperationMsg(msg, true, result.Log), nil, nil
|
||||
}
|
||||
|
||||
// deposit 25% of the time
|
||||
if hasCoins(acc, randCollateralParam.Denom) && shouldDeposit(r) {
|
||||
randDepositAmount := sdk.NewInt(int64(simulation.RandIntBetween(r, 1, int(acc.GetCoins().AmountOf(randCollateralParam.Denom).Int64()))))
|
||||
msg := cdp.NewMsgDeposit(acc.GetAddress(), acc.GetAddress(), sdk.NewCoins(sdk.NewCoin(randCollateralParam.Denom, randDepositAmount)))
|
||||
err := msg.ValidateBasic()
|
||||
randDepositAmount := sdk.NewInt(int64(simulation.RandIntBetween(r, 1, int(spendableCoins.AmountOf(randCollateralParam.Denom).Int64()))))
|
||||
msg := types.NewMsgDeposit(acc.GetAddress(), acc.GetAddress(), sdk.NewCoins(sdk.NewCoin(randCollateralParam.Denom, randDepositAmount)))
|
||||
|
||||
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(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.NoOpMsg(cdp.ModuleName), nil, fmt.Errorf("could not submit deposit msg")
|
||||
}
|
||||
return simulation.NewOperationMsg(msg, ok, "deposit to cdp"), nil, nil
|
||||
|
||||
return simulation.NewOperationMsg(msg, true, result.Log), nil, nil
|
||||
}
|
||||
|
||||
// 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()
|
||||
if maxDebt.LTE(sdk.OneInt()) {
|
||||
// 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
|
||||
availableAssetDebt := randCollateralParam.DebtLimit.AmountOf(randDebtParam.Denom).Sub(k.GetTotalPrincipal(ctx, randCollateralParam.Denom, randDebtParam.Denom))
|
||||
if availableAssetDebt.LTE(sdk.OneInt()) {
|
||||
// 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)
|
||||
|
||||
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)))
|
||||
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
|
||||
msg := types.NewMsgDrawDebt(acc.GetAddress(), randCollateralParam.Denom, sdk.NewCoins(sdk.NewCoin(randDebtParam.Denom, randDrawAmount)))
|
||||
|
||||
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
|
||||
if hasCoins(acc, randDebtParam.Denom) {
|
||||
debt := existingCDP.Principal.AmountOf(randDebtParam.Denom)
|
||||
maxRepay := acc.GetCoins().AmountOf(randDebtParam.Denom)
|
||||
maxRepay := spendableCoins.AmountOf(randDebtParam.Denom)
|
||||
payableDebt := debt.Sub(randDebtParam.DebtFloor)
|
||||
if maxRepay.GT(payableDebt) {
|
||||
maxRepay = payableDebt
|
||||
}
|
||||
randRepayAmount := sdk.NewInt(int64(simulation.RandIntBetween(r, 1, int(maxRepay.Int64()))))
|
||||
if debt.Equal(randDebtParam.DebtFloor) {
|
||||
if acc.GetCoins().AmountOf(randDebtParam.Denom).GTE(debt) {
|
||||
randRepayAmount = debt
|
||||
}
|
||||
if debt.Equal(randDebtParam.DebtFloor) && spendableCoins.AmountOf(randDebtParam.Denom).GTE(debt) {
|
||||
randRepayAmount = debt
|
||||
}
|
||||
msg := cdp.NewMsgRepayDebt(acc.GetAddress(), randCollateralParam.Denom, sdk.NewCoins(sdk.NewCoin(randDebtParam.Denom, randRepayAmount)))
|
||||
err := msg.ValidateBasic()
|
||||
|
||||
msg := types.NewMsgRepayDebt(acc.GetAddress(), randCollateralParam.Denom, sdk.NewCoins(sdk.NewCoin(randDebtParam.Denom, randRepayAmount)))
|
||||
|
||||
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(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.NewOperationMsg(msg, true, result.Log), nil, nil
|
||||
}
|
||||
|
||||
return simulation.NewOperationMsgBasic(cdp.ModuleName, "no-operation (no valid actions)", "", false, nil), nil, nil
|
||||
return simulation.NoOpMsg(types.ModuleName), nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
func submitMsg(msg sdk.Msg, handler sdk.Handler, ctx sdk.Context) (ok bool) {
|
||||
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 {
|
||||
threshold := 50
|
||||
value := simulation.RandIntBetween(r, 1, 100)
|
||||
if value > threshold {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return value > threshold
|
||||
}
|
||||
|
||||
func shouldDeposit(r *rand.Rand) bool {
|
||||
threshold := 66
|
||||
value := simulation.RandIntBetween(r, 1, 100)
|
||||
if value > threshold {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return value > threshold
|
||||
}
|
||||
|
||||
func hasCoins(acc authexported.Account, denom string) bool {
|
||||
if acc.GetCoins().AmountOf(denom).IsZero() {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
return acc.GetCoins().AmountOf(denom).IsPositive()
|
||||
}
|
||||
|
||||
func shouldClose(r *rand.Rand) bool {
|
||||
threshold := 75
|
||||
value := simulation.RandIntBetween(r, 1, 100)
|
||||
if value > threshold {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return value > threshold
|
||||
}
|
||||
|
||||
func canClose(acc authexported.Account, c cdp.CDP, denom string) bool {
|
||||
repaymentAmount := c.Principal.Add(c.AccumulatedFees).AmountOf(denom)
|
||||
if acc.GetCoins().AmountOf(denom).GTE(repaymentAmount) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
func canClose(acc authexported.Account, c types.CDP, denom string) bool {
|
||||
repaymentAmount := c.Principal.Add(c.AccumulatedFees...).AmountOf(denom)
|
||||
return acc.GetCoins().AmountOf(denom).GTE(repaymentAmount)
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package operations
|
||||
package simulation
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
@ -1,10 +1,10 @@
|
||||
package operations_test
|
||||
package simulation_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
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"
|
||||
)
|
||||
|
||||
@ -22,7 +22,7 @@ func TestShiftDec(t *testing.T) {
|
||||
|
||||
for _, tt := range tests {
|
||||
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))
|
||||
})
|
||||
}
|
||||
}
|
@ -1,115 +1,42 @@
|
||||
// DONTCOVER
|
||||
package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
// Error codes specific to cdp module
|
||||
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
|
||||
// DONTCOVER
|
||||
|
||||
var (
|
||||
// ErrCdpAlreadyExists error for duplicate cdps
|
||||
ErrCdpAlreadyExists = sdkerrors.Register(ModuleName, 2, "cdp already exists")
|
||||
// ErrInvalidCollateralLength error for invalid collateral input length
|
||||
ErrInvalidCollateralLength = sdkerrors.Register(ModuleName, 3, "only one collateral type per cdp")
|
||||
// ErrCollateralNotSupported error for unsupported collateral
|
||||
ErrCollateralNotSupported = sdkerrors.Register(ModuleName, 4, "collateral not supported")
|
||||
// ErrDebtNotSupported error for unsupported debt
|
||||
ErrDebtNotSupported = sdkerrors.Register(ModuleName, 5, "debt not supported")
|
||||
// ErrExceedsDebtLimit error for attempted draws that exceed debt limit
|
||||
ErrExceedsDebtLimit = sdkerrors.Register(ModuleName, 6, "proposed debt increase would exceed debt limit")
|
||||
// ErrInvalidCollateralRatio error for attempted draws that are below liquidation ratio
|
||||
ErrInvalidCollateralRatio = sdkerrors.Register(ModuleName, 7, "proposed collateral ratio is below liquidation ratio")
|
||||
// ErrCdpNotFound error cdp not found
|
||||
ErrCdpNotFound = sdkerrors.Register(ModuleName, 8, "cdp not found")
|
||||
// ErrDepositNotFound error for deposit not found
|
||||
ErrDepositNotFound = sdkerrors.Register(ModuleName, 9, "deposit not found")
|
||||
// ErrInvalidDeposit error for invalid deposit
|
||||
ErrInvalidDeposit = sdkerrors.Register(ModuleName, 10, "invalid deposit")
|
||||
// ErrInvalidCollateral error for invalid collateral
|
||||
ErrInvalidCollateral = sdkerrors.Register(ModuleName, 11, "collateral not supported")
|
||||
// ErrInvalidPayment error for invalid payment
|
||||
ErrInvalidPayment = sdkerrors.Register(ModuleName, 12, "invalid payment")
|
||||
//ErrDepositNotAvailable error for withdrawing deposits in liquidation
|
||||
ErrDepositNotAvailable = sdkerrors.Register(ModuleName, 13, "deposit in liquidation")
|
||||
// ErrInvalidWithdrawAmount error for invalid withdrawal amount
|
||||
ErrInvalidWithdrawAmount = sdkerrors.Register(ModuleName, 14, "withdrawal amount exceeds deposit")
|
||||
//ErrCdpNotAvailable error for depositing to a CDP in liquidation
|
||||
ErrCdpNotAvailable = sdkerrors.Register(ModuleName, 15, "cannot modify cdp in liquidation")
|
||||
// ErrBelowDebtFloor error for creating a cdp with debt below the minimum
|
||||
ErrBelowDebtFloor = sdkerrors.Register(ModuleName, 16, "proposed cdp debt is below minimum")
|
||||
// ErrLoadingAugmentedCDP error loading augmented cdp
|
||||
ErrLoadingAugmentedCDP = sdkerrors.Register(ModuleName, 17, "augmented cdp could not be loaded from cdp")
|
||||
)
|
||||
|
||||
// ErrCdpAlreadyExists error for duplicate cdps
|
||||
func ErrCdpAlreadyExists(codespace sdk.CodespaceType, owner sdk.AccAddress, denom string) sdk.Error {
|
||||
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
|
||||
func ErrInvalidCollateralLength(codespace sdk.CodespaceType, length int) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeCollateralLengthInvalid, fmt.Sprintf("only one collateral type per cdp, has %d", length))
|
||||
}
|
||||
|
||||
// ErrCollateralNotSupported error for unsupported collateral
|
||||
func ErrCollateralNotSupported(codespace sdk.CodespaceType, denom string) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeCollateralNotSupported, fmt.Sprintf("collateral %s not supported", denom))
|
||||
}
|
||||
|
||||
// ErrDebtNotSupported error for unsupported debt
|
||||
func ErrDebtNotSupported(codespace sdk.CodespaceType, denom string) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeDebtNotSupported, fmt.Sprintf("collateral %s not supported", denom))
|
||||
}
|
||||
|
||||
// ErrExceedsDebtLimit error for attempted draws that exceed debt limit
|
||||
func ErrExceedsDebtLimit(codespace sdk.CodespaceType, proposed sdk.Coins, limit sdk.Coins) sdk.Error {
|
||||
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
|
||||
func ErrInvalidCollateralRatio(codespace sdk.CodespaceType, denom string, collateralRatio sdk.Dec, liquidationRatio sdk.Dec) sdk.Error {
|
||||
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
|
||||
func ErrCdpNotFound(codespace sdk.CodespaceType, owner sdk.AccAddress, denom string) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeCdpNotFound, fmt.Sprintf("cdp for owner %s and collateral %s not found", owner, denom))
|
||||
}
|
||||
|
||||
// ErrDepositNotFound error for deposit not found
|
||||
func ErrDepositNotFound(codespace sdk.CodespaceType, depositor sdk.AccAddress, cdpID uint64) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeDepositNotFound, fmt.Sprintf("deposit for cdp %d not found for %s", cdpID, depositor))
|
||||
}
|
||||
|
||||
// ErrInvalidDepositDenom error for invalid deposit denoms
|
||||
func ErrInvalidDepositDenom(codespace sdk.CodespaceType, cdpID uint64, expected string, actual string) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeInvalidDepositDenom, fmt.Sprintf("invalid deposit for cdp %d, expects %s, got %s", cdpID, expected, actual))
|
||||
}
|
||||
|
||||
// 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
|
||||
func ErrDepositNotAvailable(codespace sdk.CodespaceType, cdpID uint64, depositor sdk.AccAddress) sdk.Error {
|
||||
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
|
||||
func ErrInvalidWithdrawAmount(codespace sdk.CodespaceType, withdraw sdk.Coins, deposit sdk.Coins) sdk.Error {
|
||||
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
|
||||
func ErrCdpNotAvailable(codespace sdk.CodespaceType, cdpID uint64) sdk.Error {
|
||||
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
|
||||
func ErrBelowDebtFloor(codespace sdk.CodespaceType, debt sdk.Coins, floor sdk.Int) sdk.Error {
|
||||
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
|
||||
func ErrLoadingAugmentedCDP(codespace sdk.CodespaceType, cdpID uint64) sdk.Error {
|
||||
return sdk.NewError(codespace, CodeCdpNotFound, fmt.Sprintf("augmented cdp could not be loaded from cdp id %d", cdpID))
|
||||
}
|
||||
|
@ -17,29 +17,29 @@ type SupplyKeeper interface {
|
||||
// TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862
|
||||
SetModuleAccount(sdk.Context, supplyexported.ModuleAccountI)
|
||||
|
||||
SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) sdk.Error
|
||||
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) sdk.Error
|
||||
SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) sdk.Error
|
||||
BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) sdk.Error
|
||||
MintCoins(ctx sdk.Context, name string, 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) error
|
||||
SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error
|
||||
BurnCoins(ctx sdk.Context, name string, amt sdk.Coins) error
|
||||
MintCoins(ctx sdk.Context, name string, amt sdk.Coins) error
|
||||
GetSupply(ctx sdk.Context) (supply supplyexported.SupplyI)
|
||||
}
|
||||
|
||||
// PricefeedKeeper defines the expected interface for the pricefeed
|
||||
type PricefeedKeeper interface {
|
||||
GetCurrentPrice(sdk.Context, string) (pftypes.CurrentPrice, sdk.Error)
|
||||
GetCurrentPrice(sdk.Context, string) (pftypes.CurrentPrice, error)
|
||||
GetParams(sdk.Context) pftypes.Params
|
||||
// These are used for testing TODO replace mockApp with keeper in tests to remove these
|
||||
SetParams(sdk.Context, pftypes.Params)
|
||||
SetPrice(sdk.Context, sdk.AccAddress, string, sdk.Dec, time.Time) (pftypes.PostedPrice, sdk.Error)
|
||||
SetCurrentPrices(sdk.Context, string) sdk.Error
|
||||
SetPrice(sdk.Context, sdk.AccAddress, string, sdk.Dec, time.Time) (pftypes.PostedPrice, error)
|
||||
SetCurrentPrices(sdk.Context, string) error
|
||||
}
|
||||
|
||||
// AuctionKeeper expected interface for the auction keeper (noalias)
|
||||
type AuctionKeeper interface {
|
||||
StartSurplusAuction(ctx sdk.Context, seller string, lot sdk.Coin, bidDenom string) (uint64, sdk.Error)
|
||||
StartDebtAuction(ctx sdk.Context, buyer string, bid sdk.Coin, initialLot sdk.Coin, 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, 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, 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)
|
||||
|
@ -1,9 +1,12 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
// 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" }
|
||||
|
||||
// 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() {
|
||||
return sdk.ErrInternal("invalid (empty) sender address")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be empty")
|
||||
}
|
||||
if len(msg.Collateral) != 1 {
|
||||
return sdk.ErrInvalidCoins(fmt.Sprintf("cdps do not support multiple collateral types: received %s", msg.Collateral))
|
||||
if msg.Collateral.Len() != 1 {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "cdps do not support multiple collateral types: %s", msg.Collateral)
|
||||
}
|
||||
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))
|
||||
}
|
||||
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))
|
||||
if msg.Principal.Empty() || !msg.Principal.IsValid() {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "principal amount %s", msg.Principal)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -103,21 +100,18 @@ func (msg MsgDeposit) Route() string { return RouterKey }
|
||||
func (msg MsgDeposit) Type() string { return "deposit_cdp" }
|
||||
|
||||
// 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() {
|
||||
return sdk.ErrInternal("invalid (empty) sender address")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "owner address cannot be 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 {
|
||||
return sdk.ErrInvalidCoins(fmt.Sprintf("cdps do not support multiple collateral types: received %s", msg.Collateral))
|
||||
if msg.Collateral.Len() != 1 {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "cdps do not support multiple collateral types: %s", msg.Collateral)
|
||||
}
|
||||
if !msg.Collateral.IsValid() {
|
||||
return sdk.ErrInvalidCoins(fmt.Sprintf("invalid collateral amount: %s", msg.Collateral))
|
||||
}
|
||||
if !msg.Collateral.IsAllPositive() {
|
||||
return sdk.ErrInvalidCoins(fmt.Sprintf("negative collateral amount: %s", msg.Collateral))
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "collateral amount %s", msg.Collateral)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -165,21 +159,18 @@ func (msg MsgWithdraw) Route() string { return RouterKey }
|
||||
func (msg MsgWithdraw) Type() string { return "withdraw_cdp" }
|
||||
|
||||
// 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() {
|
||||
return sdk.ErrInternal("invalid (empty) sender address")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "owner address cannot be 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 {
|
||||
return sdk.ErrInvalidCoins(fmt.Sprintf("cdps do not support multiple collateral types: received %s", msg.Collateral))
|
||||
if msg.Collateral.Len() != 1 {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "cdps do not support multiple collateral types: %s", msg.Collateral)
|
||||
}
|
||||
if !msg.Collateral.IsValid() {
|
||||
return sdk.ErrInvalidCoins(fmt.Sprintf("invalid collateral amount: %s", msg.Collateral))
|
||||
}
|
||||
if !msg.Collateral.IsAllPositive() {
|
||||
return sdk.ErrInvalidCoins(fmt.Sprintf("negative collateral amount: %s", msg.Collateral))
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "collateral amount %s", msg.Collateral)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -227,18 +218,15 @@ func (msg MsgDrawDebt) Route() string { return RouterKey }
|
||||
func (msg MsgDrawDebt) Type() string { return "draw_cdp" }
|
||||
|
||||
// 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() {
|
||||
return sdk.ErrInternal("invalid (empty) sender address")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be empty")
|
||||
}
|
||||
if msg.CdpDenom == "" {
|
||||
return sdk.ErrInternal("invalid (empty) cdp denom")
|
||||
if strings.TrimSpace(msg.CdpDenom) == "" {
|
||||
return errors.New("cdp denom cannot be blank")
|
||||
}
|
||||
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))
|
||||
if msg.Principal.Empty() || !msg.Principal.IsValid() {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "principal amount %s", msg.Principal)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -286,18 +274,15 @@ func (msg MsgRepayDebt) Route() string { return RouterKey }
|
||||
func (msg MsgRepayDebt) Type() string { return "repay_cdp" }
|
||||
|
||||
// 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() {
|
||||
return sdk.ErrInternal("invalid (empty) sender address")
|
||||
return sdkerrors.Wrap(sdkerrors.ErrInvalidAddress, "sender address cannot be empty")
|
||||
}
|
||||
if msg.CdpDenom == "" {
|
||||
return sdk.ErrInternal("invalid (empty) cdp denom")
|
||||
if strings.TrimSpace(msg.CdpDenom) == "" {
|
||||
return errors.New("cdp denom cannot be blank")
|
||||
}
|
||||
if !msg.Payment.IsValid() {
|
||||
return sdk.ErrInvalidCoins(fmt.Sprintf("invalid payment amount: %s", msg.Payment))
|
||||
}
|
||||
if !msg.Payment.IsAllPositive() {
|
||||
return sdk.ErrInvalidCoins(fmt.Sprintf("negative payment amount: %s", msg.Payment))
|
||||
if msg.Payment.Empty() || !msg.Payment.IsValid() {
|
||||
return sdkerrors.Wrapf(sdkerrors.ErrInvalidCoins, "payment amount %s", msg.Payment)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -33,16 +33,16 @@ func TestMsgCreateCDP(t *testing.T) {
|
||||
{"create cdp empty owner", sdk.AccAddress{}, coinsSingle, coinsSingle, false},
|
||||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
for _, tc := range tests {
|
||||
msg := NewMsgCreateCDP(
|
||||
tc.sender,
|
||||
tc.collateral,
|
||||
tc.principal,
|
||||
)
|
||||
if tc.expectPass {
|
||||
require.NoError(t, msg.ValidateBasic(), "test: %v", i)
|
||||
require.NoError(t, msg.ValidateBasic(), "test: %v", tc.description)
|
||||
} 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},
|
||||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
for _, tc := range tests {
|
||||
msg := NewMsgDeposit(
|
||||
tc.sender,
|
||||
tc.depositor,
|
||||
tc.collateral,
|
||||
)
|
||||
if tc.expectPass {
|
||||
require.NoError(t, msg.ValidateBasic(), "test: %v", i)
|
||||
require.NoError(t, msg.ValidateBasic(), "test: %v", tc.description)
|
||||
} 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},
|
||||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
for _, tc := range tests {
|
||||
msg := NewMsgWithdraw(
|
||||
tc.sender,
|
||||
tc.depositor,
|
||||
tc.collateral,
|
||||
)
|
||||
if tc.expectPass {
|
||||
require.NoError(t, msg.ValidateBasic(), "test: %v", i)
|
||||
require.NoError(t, msg.ValidateBasic(), "test: %v", tc.description)
|
||||
} 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},
|
||||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
for _, tc := range tests {
|
||||
msg := NewMsgDrawDebt(
|
||||
tc.sender,
|
||||
tc.denom,
|
||||
tc.principal,
|
||||
)
|
||||
if tc.expectPass {
|
||||
require.NoError(t, msg.ValidateBasic(), "test: %v", i)
|
||||
require.NoError(t, msg.ValidateBasic(), "test: %v", tc.description)
|
||||
} 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},
|
||||
}
|
||||
|
||||
for i, tc := range tests {
|
||||
for _, tc := range tests {
|
||||
msg := NewMsgRepayDebt(
|
||||
tc.sender,
|
||||
tc.denom,
|
||||
tc.payment,
|
||||
)
|
||||
if tc.expectPass {
|
||||
require.NoError(t, msg.ValidateBasic(), "test: %v", i)
|
||||
require.NoError(t, msg.ValidateBasic(), "test: %v", tc.description)
|
||||
} else {
|
||||
require.Error(t, msg.ValidateBasic(), "test: %v", i)
|
||||
require.Error(t, msg.ValidateBasic(), "test: %v", tc.description)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,11 @@ package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
"github.com/cosmos/cosmos-sdk/x/params"
|
||||
tmtime "github.com/tendermint/tendermint/types/time"
|
||||
)
|
||||
@ -156,30 +158,49 @@ func ParamKeyTable() params.KeyTable {
|
||||
// nolint
|
||||
func (p *Params) ParamSetPairs() params.ParamSetPairs {
|
||||
return params.ParamSetPairs{
|
||||
{Key: KeyGlobalDebtLimit, Value: &p.GlobalDebtLimit},
|
||||
{Key: KeyCollateralParams, Value: &p.CollateralParams},
|
||||
{Key: KeyDebtParams, Value: &p.DebtParams},
|
||||
{Key: KeyCircuitBreaker, Value: &p.CircuitBreaker},
|
||||
{Key: KeySurplusThreshold, Value: &p.SurplusAuctionThreshold},
|
||||
{Key: KeyDebtThreshold, Value: &p.DebtAuctionThreshold},
|
||||
{Key: KeyDistributionFrequency, Value: &p.SavingsDistributionFrequency},
|
||||
params.NewParamSetPair(KeyGlobalDebtLimit, &p.GlobalDebtLimit, validateGlobalDebtLimitParam),
|
||||
params.NewParamSetPair(KeyCollateralParams, &p.CollateralParams, validateCollateralParams),
|
||||
params.NewParamSetPair(KeyDebtParams, &p.DebtParams, validateDebtParams),
|
||||
params.NewParamSetPair(KeyCircuitBreaker, &p.CircuitBreaker, validateCircuitBreakerParam),
|
||||
params.NewParamSetPair(KeySurplusThreshold, &p.SurplusAuctionThreshold, validateSurplusAuctionThresholdParam),
|
||||
params.NewParamSetPair(KeyDebtThreshold, &p.DebtAuctionThreshold, validateDebtAuctionThresholdParam),
|
||||
params.NewParamSetPair(KeyDistributionFrequency, &p.SavingsDistributionFrequency, validateSavingsDistributionFrequencyParam),
|
||||
}
|
||||
}
|
||||
|
||||
// Validate checks that the parameters have valid values.
|
||||
func (p Params) Validate() error {
|
||||
// validate debt params
|
||||
debtDenoms := make(map[string]int)
|
||||
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 := validateGlobalDebtLimitParam(p.GlobalDebtLimit); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
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
|
||||
@ -187,38 +208,76 @@ func (p Params) Validate() error {
|
||||
prefixDupMap := make(map[int]int)
|
||||
collateralParamsDebtLimit := sdk.Coins{}
|
||||
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)
|
||||
if prefix < minCollateralPrefix || prefix > maxCollateralPrefix {
|
||||
return fmt.Errorf("invalid prefix for collateral denom %s: %b", cp.Denom, cp.Prefix)
|
||||
}
|
||||
|
||||
_, found := prefixDupMap[prefix]
|
||||
if found {
|
||||
return fmt.Errorf("duplicate prefix for collateral denom %s: %v", cp.Denom, []byte{cp.Prefix})
|
||||
}
|
||||
|
||||
prefixDupMap[prefix] = 1
|
||||
_, found = collateralDupMap[cp.Denom]
|
||||
prefixDupMap[prefix] = true
|
||||
|
||||
_, found = collateralDupMap[cp.Denom]
|
||||
if found {
|
||||
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)
|
||||
}
|
||||
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()) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
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
|
||||
if p.GlobalDebtLimit.IsAnyNegative() {
|
||||
return fmt.Errorf("global debt limit should be positive for all debt tokens, is %s", p.GlobalDebtLimit)
|
||||
}
|
||||
if !p.SurplusAuctionThreshold.IsPositive() {
|
||||
return fmt.Errorf("surplus auction threshold should be positive, is %s", p.SurplusAuctionThreshold)
|
||||
}
|
||||
if !p.DebtAuctionThreshold.IsPositive() {
|
||||
return fmt.Errorf("debt auction threshold should be positive, is %s", p.DebtAuctionThreshold)
|
||||
}
|
||||
|
||||
if p.SavingsDistributionFrequency.Seconds() <= float64(0) {
|
||||
return fmt.Errorf("savings distribution frequency should be positive, is %s", p.SavingsDistributionFrequency)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateDebtParams(i interface{}) error {
|
||||
debtParams, ok := i.(DebtParams)
|
||||
if !ok {
|
||||
return fmt.Errorf("invalid parameter type: %T", i)
|
||||
}
|
||||
|
||||
// validate debt params
|
||||
debtDenoms := make(map[string]bool)
|
||||
for _, dp := range debtParams {
|
||||
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
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user